Sending a Legacy Transaction
Once a web application is connected to Jelli, it can prompt the user for permission to send transactions on their behalf. Legacy transactions are the traditional Solana transaction format with a maximum size of 1,232 bytes and support for up to 35 accounts per transaction.
In order to send a transaction, a web application must:
Create an unsigned transaction
Have the transaction be signed and submitted to the network by the user's Jelli wallet
Optionally await network confirmation using a Solana JSON RPC connection
For more information about the nature of Solana transactions, refer to the solana-web3.js documentation and the Solana Cookbook.
π What You'll Learn
Signing and sending legacy transactions
Using the request() method for flexibility
Handling multiple transactions
Alternative signing methods
Error handling and debugging
π€ Sign and Send a Transaction (Recommended)
The easiest and most recommended way to send a transaction is by using the signAndSendTransaction
method on the provider. This method handles both signing and network submission in a single call.
signAndSendTransaction()
with Jelli
signAndSendTransaction()
with Jelliimport { Connection, Transaction, SystemProgram, PublicKey } from '@solana/web3.js';
const provider = window.jelli.solana; // Jelli wallet
const connection = new Connection('https://api.devnet.solana.com');
// Connect to wallet
const { publicKey } = await provider.connect();
// Create a simple transfer transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: new PublicKey('DL8vmGYQAZfy4mC84x1AjCet9tvNzpJrG1E9qVuT1ePY'),
lamports: 1000000, // 0.001 SOL
})
);
// Get recent blockhash
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.feePayer = publicKey;
// Sign and send via Jelli
const { signature } = await provider.signAndSendTransaction(transaction);
// Wait for confirmation
await connection.getSignatureStatus(signature);
console.log('π― Transaction confirmed:', signature);
Enhanced SendOptions
Support
SendOptions
Supportconst options = {
skipPreflight: false,
preflightCommitment: 'processed',
maxRetries: 3,
minContextSlot: 1000
};
const { signature } = await provider.signAndSendTransaction(transaction, options);
π Jelli Enhancement: Automatic detection and logging of transaction type (Legacy vs Versioned) with detailed timing information.
π Using the request() Method
Jelli supports both the modern object format and legacy string format for the request()
method, providing maximum compatibility.
Modern Object Format
const provider = window.jelli.solana;
const connection = new Connection('https://api.devnet.solana.com');
// Create your transaction
const transaction = new Transaction();
// ... add instructions ...
// Modern format
const { signature } = await provider.request({
method: "signAndSendTransaction",
params: {
transaction: transaction,
options: {
skipPreflight: false,
preflightCommitment: 'processed'
}
}
});
await connection.getSignatureStatus(signature);
Legacy String Format (Phantom Compatible)
import bs58 from 'bs58';
const provider = window.jelli.solana;
const connection = new Connection('https://api.devnet.solana.com');
// Create transaction
const transaction = new Transaction();
// ... add instructions and set recent blockhash ...
// Legacy format (exactly like Phantom)
const { signature } = await provider.request(
"signAndSendTransaction",
{
message: bs58.encode(transaction.serializeMessage())
}
);
await connection.getSignatureStatus(signature);
π‘ Jelli Advantage: Supports both formats seamlessly, so existing Phantom code works without changes.
π¦ Sign and Send Multiple Transactions
Jelli supports batch transaction processing through the signAndSendAllTransactions
method, which is more efficient and safer than individual transaction calls.
signAndSendAllTransactions()
with Jelli
signAndSendAllTransactions()
with Jelliconst provider = window.jelli.solana;
const connection = new Connection('https://api.devnet.solana.com');
// Create multiple transactions
const transactions = [
new Transaction().add(/* first instruction */),
new Transaction().add(/* second instruction */),
new Transaction().add(/* third instruction */)
];
// Set blockhash and fee payer for all transactions
const { blockhash } = await connection.getLatestBlockhash();
transactions.forEach(tx => {
tx.recentBlockhash = blockhash;
tx.feePayer = publicKey;
});
// Sign and send all transactions
const { signatures, publicKey: signerKey } = await provider.signAndSendAllTransactions(
transactions,
{
skipPreflight: false,
preflightCommitment: 'processed'
}
);
// Wait for all confirmations
await connection.getSignatureStatuses(signatures);
console.log('π― All transactions confirmed:', signatures);
π Jelli Enhancement: Progress tracking and detailed logging for each transaction in the batch.
β οΈ Alternative Signing Methods (Not Recommended)
The following methods are supported for legacy compatibility but are not recommended over signAndSendTransaction
. It's safer for users, and simpler for developers, for Jelli to submit transactions immediately after signing.
π’ Important: These methods are not supported in the Wallet Standard implementation and may be removed in a future release. They are only available via the
window.jelli.solana
object.
Sign a Transaction (Without Sending)
const provider = window.jelli.solana;
const connection = new Connection('https://api.devnet.solana.com');
// Create transaction
const transaction = new Transaction();
// ... add instructions ...
// Sign without sending (NOT RECOMMENDED)
const signedTransaction = await provider.signTransaction(transaction);
// Manually send the transaction (your responsibility)
const signature = await connection.sendRawTransaction(signedTransaction.serialize());
console.log('π Transaction signature:', signature);
Using request() for Signing Only
import bs58 from 'bs58';
const provider = window.jelli.solana;
const connection = new Connection('https://api.devnet.solana.com');
// Create transaction
const transaction = new Transaction();
// ... configure transaction ...
// Sign via request method
const signedTransaction = await provider.request({
method: "signTransaction",
params: {
message: bs58.encode(transaction.serializeMessage())
}
});
// Manually broadcast
const signature = await connection.sendRawTransaction(signedTransaction.serialize());
Sign Multiple Transactions (Legacy)
// Legacy batch signing (NOT RECOMMENDED for new integrations)
const signedTransactions = await provider.signAllTransactions(transactions);
// Manual broadcasting required
for (const signedTx of signedTransactions) {
const sig = await connection.sendRawTransaction(signedTx.serialize());
console.log('Transaction sent:', sig);
}
π‘οΈ Error Handling
Jelli uses exactly the same error codes as Phantom but with enhanced error messages and Jelli branding.
Complete Error Handling Example
try {
const { signature } = await provider.signAndSendTransaction(transaction);
console.log('β
Transaction successful:', signature);
} catch (error) {
switch (error.code) {
case 4001:
// User rejected the transaction
console.log('β User rejected:', error.message);
// "The user rejected the request through Jelli."
break;
case 4100:
// Wallet not connected
console.log('β Unauthorized:', error.message);
// "The requested method and/or account has not been authorized by the user."
break;
case -32003:
// Invalid transaction format
console.log('β Transaction rejected:', error.message);
// "Jelli does not recognize a valid transaction."
break;
case -32000:
// Invalid parameters
console.log('β Invalid input:', error.message);
// "Missing or invalid parameters."
break;
case -32002:
// Resource not available (transaction queue full)
console.log('β Resource unavailable:', error.message);
// "This error occurs when a dapp attempts to submit a new transaction while Jelli's approval dialog is already open..."
break;
case -32603:
// Internal error
console.log('β Internal error:', error.message);
// "Something went wrong within Jelli."
break;
default:
console.error('β Unknown error:', error.code, error.message);
}
}
Jelli Enhanced Error Details
try {
await provider.signAndSendTransaction(transaction);
} catch (error) {
// Jelli provides additional debugging information
console.log('Error details:', {
code: error.code,
message: error.message,
timestamp: error.timestamp,
transactionType: error.transactionType, // 'legacy' or 'versioned'
category: error.category,
metadata: error.metadata
});
}
π Jelli Exclusive Debugging Features
Enhanced Transaction Logging
// Enable detailed logging (Jelli-specific)
window.jelliDebug = true;
try {
const { signature } = await provider.signAndSendTransaction(transaction);
// Jelli automatically logs:
// π Transaction type detected: Legacy Transaction
// π¦ Serialized size: 245 bytes
// β±οΈ Signing time: 1.2s
// π‘ Network submission: 0.8s
// β
Total time: 2.0s
} catch (error) {
// Enhanced error context
console.log('π Jelli Debug Info:', {
transactionSize: error.metadata?.transactionSize,
networkLatency: error.metadata?.networkLatency,
userActionTime: error.metadata?.userActionTime
});
}
Performance Monitoring
// Jelli tracks performance metrics
const startTime = performance.now();
const { signature } = await provider.signAndSendTransaction(transaction);
const endTime = performance.now();
console.log('π Performance Metrics:');
console.log(` Total time: ${endTime - startTime}ms`);
console.log(` Transaction size: ${transaction.serialize().length} bytes`);
console.log(` Efficiency: ${35 - transaction.instructions.length} account slots remaining`);
π Complete Working Example
async function sendLegacyTransactionWithJelli() {
try {
// 1. Get provider and connection
const provider = window.jelli.solana;
const connection = new Connection('https://api.devnet.solana.com');
// 2. Connect wallet
const { publicKey } = await provider.connect();
console.log('π Connected to Jelli:', publicKey.toBase58());
// 3. Create legacy transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: publicKey, // Self-transfer for demo
lamports: 1000000 // 0.001 SOL
})
);
// 4. Set transaction metadata
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
// 5. Sign and send via Jelli
const { signature } = await provider.signAndSendTransaction(transaction, {
skipPreflight: false,
preflightCommitment: 'processed'
});
console.log('π― Legacy transaction sent:', signature);
// 6. Wait for confirmation
const confirmation = await connection.confirmTransaction(signature);
console.log('β
Transaction confirmed:', confirmation.value);
return signature;
} catch (error) {
console.error('β Transaction failed:', error.code, error.message);
throw error;
}
}
// Run the example
sendLegacyTransactionWithJelli()
.then(sig => console.log('π Success:', sig))
.catch(err => console.error('π₯ Failed:', err));
π References
Solana Documentation: Transactions and Instructions
Solana Web3.js: Transaction Class Reference
Solana Cookbook: Transaction Examples
Last updated