jito-bundles
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseJito Bundle Submission for Solana
Solana上的Jito Bundle提交指南
Jito bundles allow you to submit up to 5 Solana transactions that execute atomically — either all land in the same slot or none do. This is the primary mechanism for MEV protection and competitive transaction execution on Solana. Approximately 85%+ of Solana validators run the Jito-modified client, making bundles the standard for reliable, front-run-resistant execution.
EXECUTION SKILL — SAFETY WARNING: Submitting bundles spends real SOL on tips. Always test withmode first. Never submit bundles with real funds without explicit confirmation. Default to simulation/dry-run in all scripts and examples.--demo
Jito Bundle允许你提交最多5笔Solana交易,这些交易将原子化执行——要么全部在同一个slot中落地,要么全部不落地。这是Solana上实现MEV防护和竞争性交易执行的核心机制。约85%以上的Solana验证节点运行Jito修改版客户端,使得Bundle成为可靠、防抢先交易执行的标准方案。
执行技能——安全警告:提交Bundle会消耗真实SOL作为小费。请始终先使用模式进行测试。未经明确确认,切勿使用真实资金提交Bundle。所有脚本和示例默认使用模拟/试运行模式。--demo
When to Use Bundles
何时使用Bundle
| Scenario | Use Bundle? | Why |
|---|---|---|
| Swap on illiquid token | Yes | Prevents sandwich attacks |
| Multi-step arbitrage | Yes | Atomic execution prevents partial fills |
| Liquidation | Yes | Competitive — tip determines priority |
| Simple SOL transfer | No | Priority fees are cheaper and sufficient |
| Time-insensitive swap | Maybe | Bundles cost tips; priority fees may suffice |
| NFT mint / competitive action | Yes | Guarantees ordering within the slot |
| 场景 | 是否使用Bundle? | 原因 |
|---|---|---|
| 在非流动性代币上进行兑换 | 是 | 防止三明治攻击 |
| 多步骤套利 | 是 | 原子化执行避免部分成交 |
| 清算操作 | 是 | 具有竞争性——小费决定优先级 |
| 简单SOL转账 | 否 | 优先费用更便宜且足够 |
| 时间不敏感的兑换 | 可能 | Bundle需要支付小费;优先费用可能已足够 |
| NFT铸造 / 竞争性操作 | 是 | 保证slot内的交易顺序 |
Core Concepts
核心概念
Bundle Anatomy
Bundle结构
A Jito bundle is a JSON-RPC request containing 1-5 base58-encoded signed transactions. The transactions execute sequentially and atomically within a single slot.
Bundle = [Tx1, Tx2, ..., TxN] (N <= 5)
- All transactions must be signed
- Transactions execute in order: Tx1 → Tx2 → ... → TxN
- If ANY transaction fails, the ENTIRE bundle is dropped
- The tip instruction goes in the LAST transaction (last instruction)
- Bundle has ~2 slots (~800ms) to land before expiryJito Bundle是一个JSON-RPC请求,包含1-5个base58编码的已签名交易。这些交易在单个slot内按顺序原子化执行。
Bundle = [Tx1, Tx2, ..., TxN] (N <= 5)
- 所有交易必须已签名
- 交易按顺序执行:Tx1 → Tx2 → ... → TxN
- 若任何一笔交易失败,整个Bundle会被丢弃
- 小费指令需放在最后一笔交易的最后一个指令中
- Bundle在过期前有约2个slot(约800ms)的时间窗口落地Tip Mechanism
小费机制
Tips are SOL transfers to one of Jito's 8 tip accounts. The tip incentivizes validators to include your bundle.
python
undefined小费是向Jito的8个小费账户之一转账SOL。小费用于激励验证节点包含你的Bundle。
python
undefinedTip is a standard SOL transfer instruction
小费是标准的SOL转账指令
tip_instruction = transfer(
from_pubkey=your_wallet,
to_pubkey=tip_account, # One of 8 Jito tip accounts
lamports=tip_amount # Tip in lamports (1 SOL = 1e9 lamports)
)
tip_instruction = transfer(
from_pubkey=your_wallet,
to_pubkey=tip_account, # Jito的8个小费账户之一
lamports=tip_amount # 小费以lamports为单位(1 SOL = 1e9 lamports)
)
Add as the LAST instruction of the LAST transaction in the bundle
添加为Bundle中最后一笔交易的最后一个指令
Tip accounts are fetched dynamically via `getTipAccounts`. Rotate through them to distribute load.
小费账户可通过`getTipAccounts`动态获取。轮换使用账户以分散负载。Block Engine Endpoints
区块引擎端点
Jito operates geographically distributed block engines. Choose the one closest to your infrastructure:
| Region | Endpoint |
|---|---|
| New York | |
| Amsterdam | |
| Frankfurt | |
| Tokyo | |
All endpoints accept JSON-RPC over HTTPS on port 443. The path handles bundle operations.
/api/v1/bundlesJito运营着地理分布的区块引擎。选择离你的基础设施最近的端点:
| 地区 | 端点 |
|---|---|
| 纽约 | |
| 阿姆斯特丹 | |
| 法兰克福 | |
| 东京 | |
所有端点通过HTTPS端口443接受JSON-RPC请求。路径处理Bundle相关操作。
/api/v1/bundlesAPI Methods
API方法
sendBundle
sendBundle
Submit a bundle of up to 5 transactions.
python
import httpx
BLOCK_ENGINE = "https://mainnet.block-engine.jito.wtf"
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "sendBundle",
"params": [
[tx1_base58, tx2_base58], # List of base58-encoded signed txs
]
}
resp = httpx.post(f"{BLOCK_ENGINE}/api/v1/bundles", json=payload)
data = resp.json()
bundle_id = data["result"] # UUID string提交最多包含5笔交易的Bundle。
python
import httpx
BLOCK_ENGINE = "https://mainnet.block-engine.jito.wtf"
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "sendBundle",
"params": [
[tx1_base58, tx2_base58], # base58编码的已签名交易列表
]
}
resp = httpx.post(f"{BLOCK_ENGINE}/api/v1/bundles", json=payload)
data = resp.json()
bundle_id = data["result"] # UUID字符串getBundleStatuses
getBundleStatuses
Check the landing status of submitted bundles (up to 5 bundle IDs per request).
python
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "getBundleStatuses",
"params": [[bundle_id]]
}
resp = httpx.post(f"{BLOCK_ENGINE}/api/v1/bundles", json=payload)
statuses = resp.json()["result"]["value"]查询已提交Bundle的落地状态(每次请求最多支持5个Bundle ID)。
python
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "getBundleStatuses",
"params": [[bundle_id]]
}
resp = httpx.post(f"{BLOCK_ENGINE}/api/v1/bundles", json=payload)
statuses = resp.json()["result"]["value"]Each status: {bundle_id, status, slot, transactions: [{signature, ...}]}
每个状态结构:{bundle_id, status, slot, transactions: [{signature, ...}]}
status: "Invalid", "Pending", "Failed", "Landed"
status可选值: "Invalid", "Pending", "Failed", "Landed"
undefinedundefinedgetTipAccounts
getTipAccounts
Fetch the current list of Jito tip accounts.
python
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "getTipAccounts",
"params": []
}
resp = httpx.post(f"{BLOCK_ENGINE}/api/v1/bundles", json=payload)
tip_accounts = resp.json()["result"] # List of 8 base58 pubkeys获取当前Jito小费账户列表。
python
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "getTipAccounts",
"params": []
}
resp = httpx.post(f"{BLOCK_ENGINE}/api/v1/bundles", json=payload)
tip_accounts = resp.json()["result"] # 8个base58公钥的列表getInflightBundleStatuses
getInflightBundleStatuses
Check status of bundles that haven't landed yet (in-flight).
python
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "getInflightBundleStatuses",
"params": [[bundle_id]]
}
resp = httpx.post(f"{BLOCK_ENGINE}/api/v1/bundles", json=payload)查询尚未落地的Bundle(在途)状态。
python
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "getInflightBundleStatuses",
"params": [[bundle_id]]
}
resp = httpx.post(f"{BLOCK_ENGINE}/api/v1/bundles", json=payload)status: "Pending", "Failed", "Landed"
status可选值: "Pending", "Failed", "Landed"
undefinedundefinedBundle Construction Pattern
Bundle构建模式
A typical bundle for a protected swap:
python
from solders.transaction import VersionedTransaction
from solders.message import MessageV0
from solders.instruction import Instruction
from solders.system_program import transfer, TransferParams
from solders.pubkey import Pubkey
import random
def build_protected_swap_bundle(
swap_ix: Instruction,
payer: Pubkey,
tip_lamports: int,
tip_accounts: list[str],
recent_blockhash: str,
) -> list[VersionedTransaction]:
"""Build a 1-tx bundle: swap + tip in the same transaction.
For simple swaps, a single-transaction bundle is sufficient.
The tip instruction is appended as the last instruction.
"""
# Pick a random tip account
tip_account = Pubkey.from_string(random.choice(tip_accounts))
# Tip instruction
tip_ix = transfer(TransferParams(
from_pubkey=payer,
to_pubkey=tip_account,
lamports=tip_lamports,
))
# Build transaction with swap + tip
msg = MessageV0.try_compile(
payer=payer,
instructions=[swap_ix, tip_ix],
address_lookup_table_accounts=[],
recent_blockhash=recent_blockhash,
)
tx = VersionedTransaction(msg, [keypair])
return [tx]用于防护型兑换的典型Bundle:
python
from solders.transaction import VersionedTransaction
from solders.message import MessageV0
from solders.instruction import Instruction
from solders.system_program import transfer, TransferParams
from solders.pubkey import Pubkey
import random
def build_protected_swap_bundle(
swap_ix: Instruction,
payer: Pubkey,
tip_lamports: int,
tip_accounts: list[str],
recent_blockhash: str,
) -> list[VersionedTransaction]:
"""构建单交易Bundle:兑换 + 小费在同一笔交易中。
对于简单兑换,单交易Bundle已足够。
小费指令追加为最后一个指令。
"""
# 随机选择一个小费账户
tip_account = Pubkey.from_string(random.choice(tip_accounts))
# 小费指令
tip_ix = transfer(TransferParams(
from_pubkey=payer,
to_pubkey=tip_account,
lamports=tip_lamports,
))
# 构建包含兑换+小费的交易
msg = MessageV0.try_compile(
payer=payer,
instructions=[swap_ix, tip_ix],
address_lookup_table_accounts=[],
recent_blockhash=recent_blockhash,
)
tx = VersionedTransaction(msg, [keypair])
return [tx]Tip Sizing Guide
小费规模指南
| Scenario | Tip Range (lamports) | Tip Range (SOL) |
|---|---|---|
| Normal swap (low urgency) | 1,000 - 10,000 | 0.000001 - 0.00001 |
| Normal swap (standard) | 10,000 - 50,000 | 0.00001 - 0.00005 |
| Competitive action (arb, liquidation) | 50,000 - 500,000 | 0.00005 - 0.0005 |
| Highly competitive (NFT mint, MEV) | 500,000 - 5,000,000 | 0.0005 - 0.005 |
| Emergency (must land this slot) | 5,000,000+ | 0.005+ |
Dynamic tip calculation based on recent tip levels:
python
def calculate_dynamic_tip(
base_tip: int = 10_000,
urgency_multiplier: float = 1.0,
recent_tip_percentile_50: int = 15_000,
) -> int:
"""Calculate tip based on urgency and recent network tips.
Args:
base_tip: Minimum tip in lamports.
urgency_multiplier: 1.0 = normal, 2.0 = urgent, 5.0 = critical.
recent_tip_percentile_50: Median tip from recent bundles.
Returns:
Tip amount in lamports.
"""
dynamic_tip = max(base_tip, int(recent_tip_percentile_50 * urgency_multiplier))
# Cap at 0.01 SOL to prevent accidents
return min(dynamic_tip, 10_000_000)| 场景 | 小费范围(lamports) | 小费范围(SOL) |
|---|---|---|
| 普通兑换(低紧急度) | 1,000 - 10,000 | 0.000001 - 0.00001 |
| 普通兑换(标准) | 10,000 - 50,000 | 0.00001 - 0.00005 |
| 竞争性操作(套利、清算) | 50,000 - 500,000 | 0.00005 - 0.0005 |
| 高竞争性操作(NFT铸造、MEV) | 500,000 - 5,000,000 | 0.0005 - 0.005 |
| 紧急操作(必须在当前slot落地) | 5,000,000+ | 0.005+ |
基于近期小费水平的动态小费计算:
python
def calculate_dynamic_tip(
base_tip: int = 10_000,
urgency_multiplier: float = 1.0,
recent_tip_percentile_50: int = 15_000,
) -> int:
"""根据紧急度和近期网络小费计算小费金额。
参数:
base_tip: 最小小费(lamports)。
urgency_multiplier: 1.0=正常, 2.0=紧急, 5.0=关键。
recent_tip_percentile_50: 近期Bundle的中位小费。
返回:
小费金额(lamports)。
"""
dynamic_tip = max(base_tip, int(recent_tip_percentile_50 * urgency_multiplier))
# 上限为0.01 SOL以防止意外超额支付
return min(dynamic_tip, 10_000_000)Common Errors and Fixes
常见错误与修复方案
| Error | Cause | Fix |
|---|---|---|
| Bundle didn't land within 2 slots | Retry with fresh blockhash; consider higher tip |
| A tx in the bundle would fail on-chain | Simulate each tx individually to find the failing one |
| Duplicate bundle ID | Expected on retry; check status instead |
| Too many requests to block engine | Back off; rotate between block engine endpoints |
| Malformed or unsigned transaction | Verify all txs are signed and base58-encoded |
| Stale blockhash | Use |
| 错误 | 原因 | 修复 |
|---|---|---|
| Bundle未在2个slot内落地 | 使用新鲜blockhash重试;考虑提高小费 |
| Bundle中某笔交易在链上会执行失败 | 单独模拟每笔交易以找出失败的交易 |
| 重复的Bundle ID | 重试时属于预期情况;请检查状态 |
| 向区块引擎发送请求过于频繁 | 退避重试;轮换使用区块引擎端点 |
| 交易格式错误或未签名 | 验证所有交易已签名且为base58编码 |
| Blockhash已过期 | 使用 |
Landing Rate Optimization
落地率优化策略
Strategies to maximize bundle landing probability:
-
Multi-region submission: Send the same bundle to multiple block engines simultaneously. The first to reach the current leader wins.
-
Fresh blockhash: Usewith
getLatestBlockhashcommitment immediately before building. Stale blockhashes are the #1 cause of dropped bundles.confirmed -
Retry with backoff: If a bundle doesn't land within 2-3 seconds, rebuild with a fresh blockhash and resubmit. Do NOT resubmit with the same blockhash.
-
Adequate tipping: Under-tipped bundles are deprioritized. Monitor the network's tip distribution and tip at or above the 50th percentile for your urgency level.
-
Minimal bundle size: Fewer transactions = less simulation time = higher landing rate. Use single-transaction bundles when possible.
python
async def submit_with_retry(
bundle_txs: list[str],
endpoints: list[str],
max_retries: int = 3,
) -> str | None:
"""Submit bundle to multiple endpoints with retry logic.
Returns bundle_id if submitted, None if all retries exhausted.
"""
for attempt in range(max_retries):
# Submit to all endpoints in parallel
async with httpx.AsyncClient() as client:
tasks = [
client.post(
f"{ep}/api/v1/bundles",
json={
"jsonrpc": "2.0", "id": 1,
"method": "sendBundle",
"params": [bundle_txs],
},
timeout=5.0,
)
for ep in endpoints
]
# Process first successful response
for resp in asyncio.as_completed(tasks):
result = (await resp).json()
if "result" in result:
return result["result"]
# Wait before retry with fresh blockhash
await asyncio.sleep(0.5 * (attempt + 1))
return None最大化Bundle落地概率的策略:
-
多地区提交:同时向多个区块引擎发送相同的Bundle。最先到达当前领导者的请求会被优先处理。
-
新鲜Blockhash:在构建Bundle前立即使用并指定
getLatestBlockhash确认级别。过期Blockhash是Bundle被丢弃的首要原因。confirmed -
退避重试:如果Bundle在2-3秒内未落地,使用新鲜Blockhash重新构建并重新提交。请勿使用相同的Blockhash重新提交。
-
充足小费:小费不足的Bundle会被降级处理。监控网络小费分布,根据你的紧急度水平,小费不低于50分位数。
-
最小化Bundle规模:交易越少=模拟时间越短=落地率越高。尽可能使用单交易Bundle。
python
async def submit_with_retry(
bundle_txs: list[str],
endpoints: list[str],
max_retries: int = 3,
) -> str | None:
"""向多个端点提交Bundle并带有重试逻辑。
提交成功则返回bundle_id,所有重试耗尽则返回None。
"""
for attempt in range(max_retries):
# 并行提交到所有端点
async with httpx.AsyncClient() as client:
tasks = [
client.post(
f"{ep}/api/v1/bundles",
json={
"jsonrpc": "2.0", "id": 1,
"method": "sendBundle",
"params": [bundle_txs],
},
timeout=5.0,
)
for ep in endpoints
]
# 处理第一个成功响应
for resp in asyncio.as_completed(tasks):
result = (await resp).json()
if "result" in result:
return result["result"]
# 重试前等待,使用新鲜Blockhash
await asyncio.sleep(0.5 * (attempt + 1))
return NoneSafety Checklist (Execution)
执行安全检查清单
Before submitting any bundle with real funds:
- Simulated all transactions individually via
simulateTransaction - Verified tip amount is reasonable (not accidentally SOL instead of lamports)
- Confirmed blockhash is fresh (< 60 seconds old)
- Verified all transactions are properly signed
- Checked wallet balance covers all transaction costs + tip
- Tested with devnet or --demo mode first
- Set maximum tip cap to prevent accidental overpayment
在使用真实资金提交任何Bundle前:
- 通过单独模拟所有交易
simulateTransaction - 验证小费金额合理(未误将SOL当作lamports)
- 确认Blockhash是新鲜的(生成时间<60秒)
- 验证所有交易已正确签名
- 检查钱包余额足以覆盖所有交易成本+小费
- 先在devnet或--demo模式中测试
- 设置最大小费上限以防止意外超额支付
Files
文件
References
参考资料
- — Complete JSON-RPC API reference with request/response schemas and error codes
references/bundle_api.md - — Tip calculation strategies, dynamic tipping, cost optimization
references/tip_strategies.md - — Bundle construction patterns, landing rate optimization, common pitfalls
references/best_practices.md
- — 完整的JSON-RPC API参考,包含请求/响应 schema和错误码
references/bundle_api.md - — 小费计算策略、动态小费、成本优化
references/tip_strategies.md - — Bundle构建模式、落地率优化、常见陷阱
references/best_practices.md
Scripts
脚本
- — Bundle construction with tip instruction;
scripts/build_bundle.pymode builds but does not submit--demo - — Bundle status checking and tip account fetching;
scripts/check_bundle_status.pymode uses mock responses--demo
- — 带有小费指令的Bundle构建;
scripts/build_bundle.py模式仅构建不提交--demo - — Bundle状态查询和小费账户获取;
scripts/check_bundle_status.py模式使用模拟响应--demo