mev-analysis について
Solana DEX取引におけるMEVリスクを分析するスキルで、サンドイッチ攻撃、アービトラージ、清算抽出を扱います。リスク推定・検出スクリプトと、取引前後のリスクを抑える方法を提供します。
主な機能
- 01Solana DEXのMEVタイプの把握
- 02取引のMEVリスク推定
- 03取引前後のサンドイッチ攻撃検出
- 04スリッページ、Jito、RPCによる保護策
- 05大口取引の分割案の計算
活用シーン
- 01取引前のMEVリスク評価
- 02取引がサンドイッチ攻撃を受けたか確認
- 03流動性の低いプール向けの保護策設定
- 04大口取引の分割によるリスク低減
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agiprolabs/ claude-trading-skills --skill mev-analysisインストール後、Claude Code で/mev-analysisを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/protection_strategies.mdsolana_mev_mechanics.mdscripts/mev_risk_estimator.pysandwich_detector.py詳細
Solana DEX 取引における MEV 分析
最大抽出可能価値(MEV)とは、バリデーターやサーチャーがブロック内のトランザクションを並べ替えたり、挿入したり、検閲したりして得る利益です。Solana の DEX では、MEV は主にスワップに対するサンドイッチ攻撃、DEX 間のアービトラージ、清算利益の抽出として現れます。このスキルでは、検出、推定、保護戦略を扱います。
Solana における MEV とは?
MEV は、トランザクションの順序を決める権限を持つ誰かが、他のトレーダーの損失を利用して利益を得るときに発生します。Solana における MEV のサプライチェーンは次のとおりです。
- RPC エンドポイント経由でスワップを送信する
- サーチャーが(RPC 転送、ブロックエンジンへのアクセス、またはリーダーの TPU の盗聴を通じて)トランザクションを監視する
- サーチャーが利益を得られるバンドルを構築する(例:スワップをサンドイッチする)
- バリデーターへのチップを添えて、Jito ブロックエンジンにバンドルを送信する
- バリデーターがブロックにバンドルを含め、チップを得る
- あなたの約定条件が悪化し、サーチャーが差額を利益として得る
Solana の MEV と Ethereum の MEV の違い
| 項目 | Ethereum | Solana |
|---|---|---|
| ブロック時間 | 12 秒 | 約 400 ms のスロット |
| メモリプール | パブリックメモリプール | メモリプールなし(ただし、転送中のトランザクションは可視) |
| 順序付け | 提案者とビルダーの分離(PBS) | Jito ブロックエンジン(バリデーターの約 85%以上) |
| バンドルシステム | Flashbots バンドル | チップ付きの Jito バンドル |
| MEV コスト | ガスの優先手数料 | Jito のチップ(SOL) |
| レイテンシーの制約 | 中程度 | 非常に厳しい(100 ms 未満での判断) |
Solana 固有の主な要因:
- パブリックメモリプールがない:トランザクションは RPC → TPU → リーダーへと流れますが、サーチャーは Jito のブロックエンジンや改変されたバリデーターを通じて、この流れを監視します
- リーダースケジュールが既知:リーダー(ブロック生成者)のスケジュールは約 2 エポック先まで分かるため、サーチャーは特定のリーダーを狙えます
- Jito の優勢:バリデーターの約 85%以上が Jito 改変クライアントを実行しているため、Jito バンドルが主要な MEV の手段となっています
- 速度:スロットが 400 ms のため、MEV ボットはマイクロ秒単位で動作する必要があり、同一拠点に配置されたインフラストラクチャが有利です
Solana における MEV の種類
1. サンドイッチ攻撃
個人トレーダーを狙う最も一般的な MEV 攻撃です。
仕組み:
1. Attacker sees your pending swap: Buy 10 SOL worth of TOKEN_X
2. Front-run: Attacker buys TOKEN_X first → price rises
3. Your swap: You buy TOKEN_X at higher price → worse execution
4. Back-run: Attacker sells TOKEN_X → profits the difference
あなたの損失 = フロントランによる価格への影響 + 攻撃者の利益幅 攻撃者の利益 = あなたの損失 - Jito のチップ - トランザクション手数料
リスク要因:
- 取引サイズ:取引が大きいほど、サンドイッチによる利益が大きくなります
- トークンの流動性:流動性の低いトークンほど、価格を操作しやすくなります
- スリッページ設定:スリッページ許容幅が広いほど、攻撃者が利用できる余地が広がります
- プールの種類:集中した価格範囲では、CPMM プールは CLMM プールより脆弱です
2. アービトラージ(DEX 間)
サーチャーは DEX 間の価格差を利用します。
Pool A: TOKEN_X = 1.00 USDC
Pool B: TOKEN_X = 1.02 USDC
→ Buy on A, sell on B, profit 0.02 USDC per token (minus fees)
これは一般に市場にとって有益であり、取引所間の価格を均等化します。ただし、あなたの取引が、サーチャーに利用されるアービトラージの機会を生み出す場合があります。
3. 清算利益の抽出
DeFi ポジション(Solend、Marginfi、Kamino)の担保が不足すると、サーチャーは清算を急ぎ、清算ボーナス(通常 5~10%)を獲得します。
4. JIT(ジャストインタイム)流動性
サーチャーは、大規模なスワップの直前に CLMM プールへ集中流動性を追加し、直後にそれを引き上げます。これにより、継続的なインパーマネントロスのリスクを負わずにスワップ手数料を得ます。これは高度な MEV の形態であり、スワップを行う側の約定を改善する場合もあります。
5. バックランニング
価格を動かした大規模なスワップの直後に取引し、価格の反転を捉えます。あなたの約定条件を悪化させず、取引に対する市場の反応から利益を得るため、サンドイッチ攻撃ほど有害ではありません。
MEV エクスポージャーの推定
取引を実行する前に、MEV リスクを推定します。
import httpx
def estimate_mev_risk(
trade_size_sol: float,
pool_liquidity_usd: float,
slippage_bps: int,
token_daily_volume_usd: float,
) -> dict:
"""Estimate sandwich attack profitability for a given trade.
Returns risk assessment with estimated cost and recommendations.
"""
# Trade as percentage of pool liquidity
sol_price = 150.0 # approximate; fetch live price in production
trade_usd = trade_size_sol * sol_price
trade_pct_of_pool = (trade_usd / pool_liquidity_usd) * 100
# Estimated price impact from constant-product AMM
# price_impact ≈ trade_size / pool_liquidity (simplified)
price_impact_bps = int(trade_pct_of_pool * 100)
# Sandwich profitability: attacker captures portion of slippage headroom
# Rough model: sandwich_profit ≈ 0.5 * slippage_headroom * trade_size
slippage_headroom_bps = slippage_bps - price_impact_bps
if slippage_headroom_bps < 0:
slippage_headroom_bps = 0
sandwich_profit_usd = (slippage_headroom_bps / 10000) * trade_usd * 0.5
jito_tip_cost = 0.001 * sol_price # ~0.001 SOL typical tip
tx_fees = 0.000015 * sol_price * 2 # two transactions for sandwich
net_mev_profit = sandwich_profit_usd - jito_tip_cost - tx_fees
is_profitable_to_sandwich = net_mev_profit > 0.10 # $0.10 minimum
# Volume ratio indicates MEV bot attention level
volume_ratio = trade_usd / max(token_daily_volume_usd, 1)
risk_level = "LOW"
if is_profitable_to_sandwich and trade_pct_of_pool > 1.0:
risk_level = "HIGH"
elif is_profitable_to_sandwich or trade_pct_of_pool > 0.5:
risk_level = "MEDIUM"
return {
"risk_level": risk_level,
"trade_pct_of_pool": round(trade_pct_of_pool, 2),
"estimated_price_impact_bps": price_impact_bps,
"slippage_headroom_bps": slippage_headroom_bps,
"estimated_sandwich_cost_usd": round(max(net_mev_profit, 0), 2),
"is_profitable_to_sandwich": is_profitable_to_sandwich,
"recommendations": _get_recommendations(
risk_level, trade_size_sol, slippage_bps, trade_pct_of_pool
),
}
def _get_recommendations(
risk_level: str,
trade_size_sol: float,
slippage_bps: int,
trade_pct_of_pool: float,
) -> list[str]:
"""Generate protection recommendations based on risk assessment."""
recs = []
if risk_level == "HIGH":
recs.append("Use Jito bundle with 0.001-0.005 SOL tip")
recs.append("Use private/protected RPC endpoint")
if trade_pct_of_pool > 2.0:
n_splits = max(2, int(trade_pct_of_pool))
recs.append(f"Split into {n_splits} trades over 2-5 minutes")
if slippage_bps > 100:
recs.append(f"Reduce slippage from {slippage_bps}bps to 50-100bps")
if risk_level in ("MEDIUM", "HIGH"):
recs.append("Enable Jupiter dynamic slippage / MEV protection")
if not recs:
recs.append("Standard execution is likely safe for this trade size")
return recs
MEV 対策
戦略 1:スリッページ設定を厳しくする
slippageBpsを可能な限り低く設定してください。サンドイッチ攻撃による利益は、許容するスリッページによって上限が決まります。
| トークンの流動性 | 推奨スリッページ |
|---|---|
| > $5M プール | 50 bps (0.5%) |
| $1M - $5M プール | 100 bps (1%) |
| $100K - $1M プール | 150-200 bps |
| < $100K プール | 200-500 bps(高リスク) |
**トレードオフ:**スリッページを厳しくしすぎるとトランザクションが失敗し、約定しないまま手数料が発生します。
戦略 2:Jito バンドル
優先チップを付けて、スワップを Jito バンドルとして送信します。
import httpx
JITO_BLOCK_ENGINE = "https://mainnet.block-engine.jito.wtf"
async def submit_jito_bundle(
signed_transactions: list[str],
tip_lamports: int = 1_000_000, # 0.001 SOL
) -> str:
"""Submit a transaction bundle to Jito block engine.
Args:
signed_transactions: Base64-encoded signed transactions.
tip_lamports: Tip amount in lamports (1 SOL = 1e9 lamports).
Returns:
Bundle ID for tracking.
"""
async with httpx.AsyncClient() as client:
resp = await client.post(
f"{JITO_BLOCK_ENGINE}/api/v1/bundles",
json={
"jsonrpc": "2.0",
"id": 1,
"method": "sendBundle",
"params": [signed_transactions],
},
timeout=10.0,
)
resp.raise_for_status()
result = resp.json()
return result.get("result", "")
チップの目安:
- 通常の優先度:0.0001 - 0.001 SOL
- 高優先度:0.001 - 0.01 SOL
- 緊急(市場が不安定な場合):0.01 - 0.05 SOL
戦略 3:プライベート/保護された RPC
サーチャーにトランザクションを公開しないエンドポイント経由で送信します。
- Jito バンドル(前述)
- ステーク接続を使用した Helius priority fee API
- QuickNode のプライベートトランザクション送信
- TPU への直接転送(インフラが必要)
戦略 4:取引の分割
大規模な取引(プール流動性の 1% 超)の場合、実行を分割します。
def compute_split_plan(
total_sol: float,
pool_liquidity_usd: float,
sol_price: float = 150.0,
max_pct_per_trade: float = 0.5,
) -> list[dict]:
"""Compute a trade splitting plan to minimize MEV exposure."""
total_usd = total_sol * sol_price
trade_pct = (total_usd / pool_liquidity_usd) * 100
if trade_pct <= max_pct_per_trade:
return [{"sol_amount": total_sol, "delay_seconds": 0}]
n_splits = max(2, int(trade_pct / max_pct_per_trade) + 1)
per_trade = total_sol / n_splits
delay = 30 # seconds between trades
return [
{"sol_amount": round(per_trade, 4), "delay_seconds": i * delay}
for i in range(n_splits)
]
戦略 5:Jupiter MEV 保護
Jupiter v6 には、MEV 保護機能が組み込まれています。
- 動的スリッページ:サンドイッチ攻撃の機会を最小限に抑えるため、スリッページを自動調整します
- 優先手数料の推定:適切なコンピュートユニット価格を設定します
- トランザクション着地の最適化:優先度を上げながら再試行します
Jupiter API で有効にします。
params = {
"inputMint": "So11111111111111111111111111111111111111112",
"outputMint": token_mint,
"amount": str(amount_lamports),
"slippageBps": "50",
"dynamicSlippage": "true", # Auto-adjust slippage
"prioritizationFeeLamports": "auto", # Auto priority fee
}
サンドイッチ攻撃の検出
取引後に、サンドイッチ攻撃を受けたかどうかを確認します。
- トランザクションを取得し、スロットを特定します
- そのスロット内の、同じトークンに関わるすべてのトランザクションを取得します
- 次のパターンを探します。
- トランザクション A:TOKEN_X を購入(スロット内の順序で、あなたのトランザクションより前)
- あなたのトランザクション:TOKEN_X を購入(予想より不利な価格)
- トランザクション B:TOKEN_X を売却(あなたのトランザクションより後で、A と同じ署名者)
- 確認:A と B の署名者が同じウォレット(攻撃者)であることを確認します
- コストを推定:予想約定価格と実際の約定価格の差を求めます
実装例については、scripts/sandwich_detector.pyを参照してください。
既知の MEV 指標:
- トランザクション署名者が 1 日に数千件のトランザクションを処理している
- あなたのスワップ前後に、同じスロット内で同一トークンの買いと売りが行われている
- 署名者が Jito tip program と頻繁にやり取りしている
- ウォレットにトークンの保有がない(売買の出入りのみ)
他のスキルとの連携
slippage-modeling:スリッページの推定値を使って保護上限を設定しますliquidity-analysis:プール流動性によって MEV の脆弱性が決まりますjupiter-api:Jupiter の MEV 保護機能とスワップの実行solana-onchain:サンドイッチ攻撃検出のためのオンチェーントランザクション分析helius-api:トランザクションの解析と履歴分析
ファイル
リファレンス
references/solana_mev_mechanics.md— Solana のブロック生成、Jito ブロックエンジン、MEV サプライチェーン、トランザクションの経路references/protection_strategies.md— 実装ガイダンス、費用対効果分析、判断マトリクスを含む詳細な保護戦略
スクリプト
scripts/sandwich_detector.py— オンチェーンデータを使って、指定されたトランザクション署名の前後に発生したサンドイッチ攻撃を検出しますscripts/mev_risk_estimator.py— トークンの流動性、取引サイズ、スリッページ設定に基づいて、計画中の取引に対する MEV エクスポージャーを推定します