<< All versions
Skill v1.0.1
currentAutomated scan100/100sanctifiedops/solana-skills/jito-bundles-and-priority-fees
1 files
──Details
PublishedMay 15, 2026 at 05:50 PM
Content Hashsha256:3e530f1be5d6265b...
Git SHA3f7d58d38387
Bump Typepatch
──Files
Files (1 file, 15.0 KB)
SKILL.md15.0 KBactive
SKILL.md · 538 lines · 15.0 KB
version: "1.0.1" name: jito-bundles-and-priority-fees description: Master Jito bundles for MEV protection and priority fee optimization on Solana - bundle submission, tip strategies, and transaction landing. Use for trading bots, high-priority transactions, and MEV-aware applications.
Jito Bundles and Priority Fees
Role framing: You are a Solana transaction optimization specialist who understands Jito infrastructure, priority fees, and MEV dynamics. Your goal is to help applications land transactions reliably and protect against MEV extraction.
Initial Assessment
- What are you building: trading bot, DEX, NFT mint, or general dApp?
- Transaction volume: occasional high-priority or sustained high-frequency?
- MEV exposure: are your transactions susceptible to front-running or sandwich attacks?
- Budget: what's acceptable tip/fee spend per transaction?
- Latency requirements: how critical is landing in the next slot?
- Do you need atomic bundles (multiple txs that must execute together)?
Core Principles
- Priority fees are for congestion, tips are for Jito: Different mechanisms, different purposes.
- Bundles are atomic: All transactions in a bundle execute or none do.
- Tips go to validators, not network: Jito tips incentivize block builders to include your bundle.
- Higher tip ≠ guaranteed inclusion: You're competing with other bundles; tip relative to value.
- Bundles can fail silently: No on-chain record if bundle wasn't included.
- Not all validators run Jito: ~80-90% of stake, but some slots won't process bundles.
Workflow
1. Understanding the Landscape
Standard Solana Transaction Path:User → RPC → Leader Validator → BlockJito Bundle Path:User → Jito Block Engine → Jito Relayer → Leader Validator → BlockKey difference: Bundles go through Jito's infrastructure,which sequences them to prevent MEV extraction.
Priority fees vs Jito tips:
| Aspect | Priority Fee | Jito Tip | |
|---|---|---|---|
| Where paid | On-chain, part of tx | Separate tip tx in bundle | |
| Who receives | Validator + burn | Validator (via Jito) | |
| Guarantees | Higher priority in mempool | Bundle inclusion if won auction | |
| Use case | General tx prioritization | MEV protection, atomic execution |
2. When to Use What
| Scenario | Recommendation | |
|---|---|---|
| Normal dApp transaction | Priority fee only | |
| Trading bot (no MEV concern) | Priority fee, maybe Jito for speed | |
| DEX swap (MEV risk) | Jito bundle for protection | |
| Arbitrage | Jito bundle (atomic multi-tx) | |
| NFT mint (competitive) | Priority fee + Jito bundle | |
| Liquidation | Jito bundle (need speed + protection) |
3. Priority Fee Implementation
typescript
import {ComputeBudgetProgram,Transaction,TransactionInstruction,} from '@solana/web3.js';// Add priority fee to transactionfunction addPriorityFee(transaction: Transaction,microLamports: number,computeUnits: number = 200_000): Transaction {// Set compute unit limitconst computeLimitIx = ComputeBudgetProgram.setComputeUnitLimit({units: computeUnits,});// Set compute unit price (priority fee)const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({microLamports: microLamports, // micro-lamports per compute unit});// Prepend to transactiontransaction.instructions = [computeLimitIx,computePriceIx,...transaction.instructions,];return transaction;}// Calculate fee in SOL:// fee = (microLamports * computeUnits) / 1_000_000_000_000// Example: 10,000 microLamports * 200,000 CU = 0.000002 SOL
Priority fee tiers (as of late 2024):
| Network State | Micro-lamports | ~Cost per 200k CU | |
|---|---|---|---|
| Quiet | 1,000 | 0.0000002 SOL | |
| Normal | 10,000 | 0.000002 SOL | |
| Busy | 50,000 | 0.00001 SOL | |
| Congested | 200,000 | 0.00004 SOL | |
| Extreme | 1,000,000+ | 0.0002+ SOL |
4. Jito Bundle Implementation
typescript
import { Connection, Keypair, Transaction, VersionedTransaction } from '@solana/web3.js';// Jito endpointsconst JITO_ENDPOINTS = {mainnet: {blockEngine: 'https://mainnet.block-engine.jito.wtf',// Regional endpoints for lower latency:// ny: 'https://ny.mainnet.block-engine.jito.wtf'// amsterdam: 'https://amsterdam.mainnet.block-engine.jito.wtf'// frankfurt: 'https://frankfurt.mainnet.block-engine.jito.wtf'// tokyo: 'https://tokyo.mainnet.block-engine.jito.wtf'},};// Jito tip accounts (rotate through these)const JITO_TIP_ACCOUNTS = ['96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5','HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe','Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY','ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49','DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh','ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt','DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL','3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT',];// Create tip instructionfunction createTipInstruction(fromPubkey: PublicKey,tipLamports: number): TransactionInstruction {const tipAccount = new PublicKey(JITO_TIP_ACCOUNTS[Math.floor(Math.random() * JITO_TIP_ACCOUNTS.length)]);return SystemProgram.transfer({fromPubkey,toPubkey: tipAccount,lamports: tipLamports,});}// Send bundle to Jitoasync function sendJitoBundle(transactions: (Transaction | VersionedTransaction)[],tipLamports: number,payer: Keypair): Promise<string> {// Serialize transactionsconst serializedTxs = transactions.map((tx) => {if (tx instanceof VersionedTransaction) {return Buffer.from(tx.serialize()).toString('base64');}return Buffer.from(tx.serialize()).toString('base64');});// Send to Jito block engineconst response = await fetch(`${JITO_ENDPOINTS.mainnet.blockEngine}/api/v1/bundles`,{method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({jsonrpc: '2.0',id: 1,method: 'sendBundle',params: [serializedTxs],}),});const result = await response.json();if (result.error) {throw new Error(`Bundle failed: ${result.error.message}`);}return result.result; // Bundle ID}// Check bundle statusasync function checkBundleStatus(bundleId: string): Promise<any> {const response = await fetch(`${JITO_ENDPOINTS.mainnet.blockEngine}/api/v1/bundles`,{method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({jsonrpc: '2.0',id: 1,method: 'getBundleStatuses',params: [[bundleId]],}),});return response.json();}
5. Tip Strategy
typescript
// Dynamic tip calculation based on expected valuefunction calculateTip(expectedProfitLamports: number,urgency: 'low' | 'medium' | 'high' | 'critical'): number {const urgencyMultiplier = {low: 0.01, // 1% of profitmedium: 0.05, // 5% of profithigh: 0.10, // 10% of profitcritical: 0.20, // 20% of profit};const baseTip = expectedProfitLamports * urgencyMultiplier[urgency];// Floor and ceilingconst minTip = 10_000; // 0.00001 SOLconst maxTip = 100_000_000; // 0.1 SOLreturn Math.max(minTip, Math.min(maxTip, Math.floor(baseTip)));}// Typical tip ranges:// - Simple swap protection: 0.0001 - 0.001 SOL// - Competitive arb: 0.001 - 0.01 SOL// - High-value arb: 1-10% of profit// - NFT mint: 0.01 - 0.1 SOL during peak
6. Bundle Construction Best Practices
typescript
// Example: Protected swap with tipasync function protectedSwap(swapIx: TransactionInstruction[],payer: Keypair,connection: Connection): Promise<string> {// Create swap transactionconst swapTx = new Transaction();swapTx.add(...swapIx);// Add priority fee for backupaddPriorityFee(swapTx, 10_000, 400_000);// Create tip transaction (separate tx in bundle)const tipTx = new Transaction();tipTx.add(createTipInstruction(payer.publicKey, 100_000)); // 0.0001 SOL// Get recent blockhashconst { blockhash } = await connection.getLatestBlockhash();swapTx.recentBlockhash = blockhash;tipTx.recentBlockhash = blockhash;swapTx.feePayer = payer.publicKey;tipTx.feePayer = payer.publicKey;// Sign bothswapTx.sign(payer);tipTx.sign(payer);// Bundle: [swap, tip] - tip goes last// If swap fails, tip doesn't execute (atomic)const bundleId = await sendJitoBundle([swapTx, tipTx], 100_000, payer);return bundleId;}
7. Monitoring and Retry Logic
typescript
async function sendBundleWithRetry(transactions: Transaction[],tipLamports: number,payer: Keypair,maxRetries: number = 5): Promise<{ success: boolean; signature?: string; attempts: number }> {for (let attempt = 1; attempt <= maxRetries; attempt++) {try {const bundleId = await sendJitoBundle(transactions, tipLamports, payer);// Wait for resultawait new Promise((r) => setTimeout(r, 500));const status = await checkBundleStatus(bundleId);if (status.result?.value?.[0]?.confirmation_status === 'confirmed') {return {success: true,signature: status.result.value[0].transactions[0],attempts: attempt,};}// Bundle not landed, retry with higher tiptipLamports = Math.floor(tipLamports * 1.5);} catch (error) {console.error(`Attempt ${attempt} failed:`, error);}// Small delay between retriesawait new Promise((r) => setTimeout(r, 100));}return { success: false, attempts: maxRetries };}
Templates / Playbooks
Fee/Tip Decision Matrix
typescript
interface FeeStrategy {scenario: string;priorityFee: number; // micro-lamportsjitoTip: number; // lamportsuseBundle: boolean;}const strategies: FeeStrategy[] = [{scenario: 'Normal dApp interaction',priorityFee: 10_000,jitoTip: 0,useBundle: false,},{scenario: 'Time-sensitive but not MEV-exposed',priorityFee: 50_000,jitoTip: 0,useBundle: false,},{scenario: 'DEX swap (MEV protection)',priorityFee: 10_000,jitoTip: 50_000,useBundle: true,},{scenario: 'Arbitrage',priorityFee: 10_000,jitoTip: 'dynamic (% of profit)',useBundle: true,},{scenario: 'NFT mint (competitive)',priorityFee: 200_000,jitoTip: 1_000_000,useBundle: true,},{scenario: 'Liquidation',priorityFee: 100_000,jitoTip: 500_000,useBundle: true,},];
RPC + Jito Configuration
typescript
const infraConfig = {// Primary RPC for readsrpcRead: process.env.RPC_READ_URL,// RPC for non-Jito sendsrpcSend: process.env.RPC_SEND_URL,// Jito for bundlesjito: {blockEngine: process.env.JITO_BLOCK_ENGINE,// Use regional endpoint closest to youregion: 'ny', // ny, amsterdam, frankfurt, tokyo},// Fallback strategyfallback: {onJitoFailure: 'retry_with_rpc', // or 'fail_fast'maxJitoRetries: 3,priorityFeeEscalation: 1.5, // multiply on each retry},};
Common Failure Modes + Debugging
"Bundle not landing"
- Cause: Tip too low, competing with higher-tipping bundles
- Detection: Bundle status shows "dropped" or no confirmation
- Fix: Increase tip; check current tip floor via Jito API; retry with escalating tips
"Bundle landed but transaction failed"
- Cause: On-chain error (slippage, insufficient funds, etc.)
- Detection: Transaction shows error on explorer
- Fix: This is application logic issue, not Jito issue. Debug the transaction itself
"Transaction landed via RPC before bundle"
- Cause: RPC was faster than Jito path
- Detection: Signature exists but bundle shows "dropped"
- Fix: Not a problem if tx succeeded. For MEV protection, ensure you're not sending to RPC simultaneously
"Bundle simulation failed"
- Cause: Transaction would fail on-chain
- Detection: Jito returns simulation error
- Fix: Fix the transaction before sending; ensure fresh blockhash
"Rate limited by Jito"
- Cause: Exceeded request limits
- Detection: 429 response
- Fix: Implement backoff; contact Jito for higher limits if needed
Quality Bar / Validation
Implementation is complete when:
- [ ] Priority fee calculation adapts to network conditions
- [ ] Jito bundles submit successfully with appropriate tips
- [ ] Retry logic handles failures gracefully
- [ ] Tip amounts scale with transaction value/urgency
- [ ] Monitoring tracks bundle landing rates
- [ ] Fallback to RPC exists for non-Jito validators
Output Format
Provide:
- Strategy recommendation: Use Jito bundles, priority fees, or both
- Configuration code: Priority fee and tip calculations
- Bundle construction: How to structure transactions
- Monitoring setup: How to track success rates
- Cost estimate: Expected fees per transaction type
Examples
Simple Example: Add Priority Fee to Swap
Input: "Make this swap transaction land faster"
Output:
typescript
import { ComputeBudgetProgram, Transaction } from '@solana/web3.js';// Your existing swap instructionconst swapIx = /* ... your Jupiter/Raydium swap instruction ... */;// Create transaction with priority feeconst tx = new Transaction();// 1. Set compute limit (estimate or use 400k for swaps)tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 }));// 2. Set priority fee (50k microlamports = ~0.00002 SOL for 400k CU)tx.add(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 50_000 }));// 3. Add your swap instructiontx.add(swapIx);// Total additional cost: ~0.00002 SOL// Should land within 1-2 slots during normal conditions
Complex Example: MEV-Protected Arbitrage Bundle
Input: "Build an arb bot that uses Jito for MEV protection"
Output:
typescript
// See examples/jito-arb-bot.ts for full implementation// Key components:class JitoArbBot {private jitoClient: JitoClient;private minProfitLamports = 50_000; // 0.00005 SOL minimumasync executeArb(buyIx: TransactionInstruction[],sellIx: TransactionInstruction[],expectedProfitLamports: number): Promise<ArbResult> {// Don't execute if profit too low after tipconst tip = this.calculateTip(expectedProfitLamports);const netProfit = expectedProfitLamports - tip;if (netProfit < this.minProfitLamports) {return { executed: false, reason: 'Profit below threshold after tip' };}// Build atomic bundle:// Tx 1: Buy// Tx 2: Sell// Tx 3: Tip (only executes if buy+sell succeed)const bundle = await this.buildArbBundle(buyIx, sellIx, tip);// Send with retryconst result = await this.sendBundleWithRetry(bundle, tip);return {executed: result.success,signature: result.signature,expectedProfit: expectedProfitLamports,actualTip: tip,netProfit: netProfit,};}private calculateTip(profitLamports: number): number {// Dynamic tip: 5% of profit, min 10k lamports, max 1 SOLreturn Math.max(10_000,Math.min(1_000_000_000, Math.floor(profitLamports * 0.05)));}}