skills/infra/jito-bundles-and-priority-fees/SKILL.md
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.
npx skillsauth add sanctifiedops/solana-skills jito-bundles-and-priority-feesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
Standard Solana Transaction Path:
User → RPC → Leader Validator → Block
Jito Bundle Path:
User → Jito Block Engine → Jito Relayer → Leader Validator → Block
Key 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 |
| 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) |
import {
ComputeBudgetProgram,
Transaction,
TransactionInstruction,
} from '@solana/web3.js';
// Add priority fee to transaction
function addPriorityFee(
transaction: Transaction,
microLamports: number,
computeUnits: number = 200_000
): Transaction {
// Set compute unit limit
const computeLimitIx = ComputeBudgetProgram.setComputeUnitLimit({
units: computeUnits,
});
// Set compute unit price (priority fee)
const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: microLamports, // micro-lamports per compute unit
});
// Prepend to transaction
transaction.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 |
import { Connection, Keypair, Transaction, VersionedTransaction } from '@solana/web3.js';
// Jito endpoints
const 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 instruction
function 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 Jito
async function sendJitoBundle(
transactions: (Transaction | VersionedTransaction)[],
tipLamports: number,
payer: Keypair
): Promise<string> {
// Serialize transactions
const 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 engine
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: '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 status
async 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();
}
// Dynamic tip calculation based on expected value
function calculateTip(
expectedProfitLamports: number,
urgency: 'low' | 'medium' | 'high' | 'critical'
): number {
const urgencyMultiplier = {
low: 0.01, // 1% of profit
medium: 0.05, // 5% of profit
high: 0.10, // 10% of profit
critical: 0.20, // 20% of profit
};
const baseTip = expectedProfitLamports * urgencyMultiplier[urgency];
// Floor and ceiling
const minTip = 10_000; // 0.00001 SOL
const maxTip = 100_000_000; // 0.1 SOL
return 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
// Example: Protected swap with tip
async function protectedSwap(
swapIx: TransactionInstruction[],
payer: Keypair,
connection: Connection
): Promise<string> {
// Create swap transaction
const swapTx = new Transaction();
swapTx.add(...swapIx);
// Add priority fee for backup
addPriorityFee(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 blockhash
const { blockhash } = await connection.getLatestBlockhash();
swapTx.recentBlockhash = blockhash;
tipTx.recentBlockhash = blockhash;
swapTx.feePayer = payer.publicKey;
tipTx.feePayer = payer.publicKey;
// Sign both
swapTx.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;
}
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 result
await 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 tip
tipLamports = Math.floor(tipLamports * 1.5);
} catch (error) {
console.error(`Attempt ${attempt} failed:`, error);
}
// Small delay between retries
await new Promise((r) => setTimeout(r, 100));
}
return { success: false, attempts: maxRetries };
}
interface FeeStrategy {
scenario: string;
priorityFee: number; // micro-lamports
jitoTip: number; // lamports
useBundle: 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,
},
];
const infraConfig = {
// Primary RPC for reads
rpcRead: process.env.RPC_READ_URL,
// RPC for non-Jito sends
rpcSend: process.env.RPC_SEND_URL,
// Jito for bundles
jito: {
blockEngine: process.env.JITO_BLOCK_ENGINE,
// Use regional endpoint closest to you
region: 'ny', // ny, amsterdam, frankfurt, tokyo
},
// Fallback strategy
fallback: {
onJitoFailure: 'retry_with_rpc', // or 'fail_fast'
maxJitoRetries: 3,
priorityFeeEscalation: 1.5, // multiply on each retry
},
};
Implementation is complete when:
Provide:
Input: "Make this swap transaction land faster"
Output:
import { ComputeBudgetProgram, Transaction } from '@solana/web3.js';
// Your existing swap instruction
const swapIx = /* ... your Jupiter/Raydium swap instruction ... */;
// Create transaction with priority fee
const 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 instruction
tx.add(swapIx);
// Total additional cost: ~0.00002 SOL
// Should land within 1-2 slots during normal conditions
Input: "Build an arb bot that uses Jito for MEV protection"
Output:
// See examples/jito-arb-bot.ts for full implementation
// Key components:
class JitoArbBot {
private jitoClient: JitoClient;
private minProfitLamports = 50_000; // 0.00005 SOL minimum
async executeArb(
buyIx: TransactionInstruction[],
sellIx: TransactionInstruction[],
expectedProfitLamports: number
): Promise<ArbResult> {
// Don't execute if profit too low after tip
const 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 retry
const 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 SOL
return Math.max(
10_000,
Math.min(1_000_000_000, Math.floor(profitLamports * 0.05))
);
}
}
development
--- name: transparency-and-disclosures description: Write clear disclosures for Solana projects: risks, unlocks, authority states, and data sources. Use for websites, docs, and announcements. --- # Transparency and Disclosures Role framing: You are a disclosures officer. Your goal is to communicate risks and facts plainly with verifiable links. ## Initial Assessment - What products/tokens are live? What risks exist (smart contract, market, custodial)? - Upcoming events (unlocks, upgrades)? -
testing
Comprehensive rug detection for Solana tokens - red flags, contract analysis, LP verification, insider patterns, and escape routes. Use before buying any token to protect against scams.
development
--- name: reputation-recovery-playbook description: Recover credibility after mistakes: incident comms, restitution, roadmap resets, and monitoring sentiment. Use after exploits, missteps, or comms errors. --- # Reputation Recovery Playbook Role framing: You are a crisis manager. Your goal is to respond to incidents transparently and rebuild trust. ## Initial Assessment - What happened? Impacted users/funds? Root cause known? - Current status (contained/ongoing)? - Evidence available (txids,
development
--- name: legitimacy-signals description: How to project legitimacy for Solana projects: disclosures, address registry, audits, comms patterns, red-flag avoidance. Use for project pages, announcements, and community trust work. --- # Legitimacy Signals Role framing: You are a trust & safety operator for Solana launches. Your goal is to surface credible signals, avoid scams cues, and give buyers clear risk context. ## Initial Assessment - Project type (token, dApp, NFT, bot) and stage (pre-lau