MEV(最大抽出可能価値)完全解説 — Flashbots・Jito・MEV戦略の実践
MEVとは
MEV(Maximal Extractable Value / 最大抽出可能価値)とは、ブロック内のトランザクションの順序を操作することで得られる追加的な利益のことです。元々は「Miner Extractable Value」と呼ばれていましたが、EthereumがPoSに移行した後は「Maximal Extractable Value」と再定義されました。
MEVの基本概念
[通常のトランザクション処理]
ユーザーA: トランザクション送信 → メモリプール → ブロックに含まれる
[MEVが発生する場面]
ユーザーA: Uniswapで大量のETH→USDC スワップを送信
→ メモリプールで公開される
→ MEVサーチャーが検知
→ サーチャーが自分のTXをユーザーAの前後に挿入
→ 価格差から利益を抽出
MEVの規模
| 指標 | Ethereum | Solana |
|---|---|---|
| 累計抽出MEV | $6B以上 | $1B以上 |
| 日次MEV(平均) | $2-5M | $0.5-2M |
| アクティブサーチャー数 | 数百 | 数百 |
| MEV保護利用率 | 約30% | 約20% |
MEVの種類
1. フロントランニング(Front-running)
ユーザーのトランザクションを検知し、先に同じ取引を実行して利益を得る手法です。
[フロントランニングの例]
ユーザー: Uniswapで10 ETH → USDC を実行予定
現在のレート: 1 ETH = 3,000 USDC
MEVサーチャー:
1. メモリプールでユーザーのTXを検知
2. ユーザーの前に5 ETH → USDC を実行
→ レートが 1 ETH = 3,000.5 USDC に変動
3. ユーザーのTXが実行される
→ レートが 1 ETH = 3,005 USDC に変動
4. サーチャーはUSDC → ETH で戻す
→ 差額分(約$25)が利益
時系列:
[サーチャーのTX] → [ユーザーのTX]
↑ フロントラン
2. バックランニング(Back-running)
特定のイベント(大口取引、オラクル更新、新トークンリスティング等)の直後にトランザクションを実行して利益を得る手法です。
[バックランニングの例: オラクル更新]
Chainlinkオラクル: ETH/USD価格を $3,000 → $3,050 に更新
MEVサーチャー:
オラクル更新TXの直後に:
1. Aave等で古い価格基準のポジションを清算
2. 清算報酬(5-10%)を獲得
時系列:
[オラクル更新TX] → [サーチャーの清算TX]
↑ バックラン
3. サンドイッチ攻撃(Sandwich Attack)
フロントランニングとバックランニングを組み合わせ、ユーザーの取引を挟み込む手法です。最も一般的かつ議論の多いMEV戦略です。
[サンドイッチ攻撃の詳細]
ユーザー: USDCで100 ETH を購入(スリッページ許容: 0.5%)
攻撃者のアクション:
TX1 (フロントラン): 50 ETH を購入 → 価格上昇
TX2 (ユーザーのTX): 100 ETH を購入 → さらに価格上昇(不利なレート)
TX3 (バックラン): 50 ETH を売却 → 上昇分の利益を確保
価格の推移:
$3,000 →[TX1]→ $3,010 →[TX2]→ $3,040 →[TX3]→ $3,020
攻撃者の利益: (3,020 - 3,010) × 50 = $500
ユーザーの損失: 本来 $3,000 で買えたETHを $3,010-3,040 で購入
4. DEXアービトラージ
同一トークンペアの複数DEX間の価格差を利用したアービトラージです。最もポジティブなMEV活動とされ、市場効率性に貢献します。
# DEXアービトラージの基本ロジック(概念コード)
class DEXArbitrage:
"""複数DEX間の価格差を利用したアービトラージ"""
def __init__(self):
self.dexes = {
"uniswap_v3": UniswapV3Client(),
"sushiswap": SushiSwapClient(),
"curve": CurveClient(),
}
def find_opportunities(self, token_pair: tuple) -> list:
"""アービトラージ機会を検索"""
prices = {}
for name, dex in self.dexes.items():
prices[name] = dex.get_price(token_pair)
opportunities = []
for buy_dex, buy_price in prices.items():
for sell_dex, sell_price in prices.items():
if buy_dex != sell_dex:
spread = (sell_price - buy_price) / buy_price
if spread > self.min_spread:
opportunities.append({
"buy_dex": buy_dex,
"sell_dex": sell_dex,
"buy_price": buy_price,
"sell_price": sell_price,
"spread": spread,
"estimated_profit": self.calculate_profit(
spread, self.trade_size, gas_cost=0.005
)
})
return sorted(opportunities, key=lambda x: x["estimated_profit"], reverse=True)
def execute_atomic(self, opportunity: dict):
"""フラッシュローンを使ったアトミック実行"""
# 1. フラッシュローンで資金調達
# 2. DEX Aで購入
# 3. DEX Bで売却
# 4. フラッシュローンを返済 + 手数料
# 5. 利益を確保
# すべて1トランザクションで実行(失敗時は全体がリバート)
pass
5. 清算(Liquidation)
レンディングプロトコルで担保率が閾値を下回ったポジションを清算し、清算報酬を獲得する戦略です。
| プロトコル | 清算閾値 | 清算報酬 | 清算方式 |
|---|---|---|---|
| Aave V3 | 変動(80-90%) | 5-10% | 即時清算 |
| Compound V3 | 変動 | ~5% | 吸収方式 |
| MakerDAO | 150% | 13% | オランダ式オークション |
| Morpho | 変動 | 変動 | 即時清算 |
MEV種類の比較
| MEV種類 | 倫理性 | 難易度 | 平均利益 | ユーザーへの影響 |
|---|---|---|---|---|
| DEXアービトラージ | ポジティブ | 中 | $10-1,000/TX | 価格均一化に貢献 |
| 清算 | 中立 | 中〜高 | $50-10,000/TX | プロトコルの健全性維持 |
| バックランニング | 中立 | 中 | $10-500/TX | 直接的被害なし |
| フロントランニング | ネガティブ | 高 | $10-1,000/TX | ユーザーが不利なレート |
| サンドイッチ攻撃 | ネガティブ | 高 | $10-5,000/TX | ユーザーが直接的に損失 |
MEVサプライチェーン
Ethereum(PoS)におけるMEVのサプライチェーンは、PBS(Proposer-Builder Separation)によって構造化されています。
MEV-Boost アーキテクチャ
[MEV サプライチェーン]
サーチャー (Searcher)
│ MEV機会を発見し、バンドルを作成
│ 例: アービトラージ、清算、サンドイッチ
↓
ビルダー (Builder)
│ 複数のバンドルとユーザーTXを組み合わせて
│ 最も収益性の高いブロックを構築
│ 例: Flashbots Builder, BloXroute, Titan
↓
リレー (Relay)
│ ビルダーのブロックをバリデーターに仲介
│ ブロック内容を隠蔽(MEV盗難防止)
│ 例: Flashbots Relay, BloXroute, Ultra Sound
↓
バリデーター (Validator/Proposer)
│ 最も高い入札のブロックを選択・提案
│ ブロック報酬 + MEV報酬を受取
↓
ブロック確定
各プレイヤーの収益分配
| プレイヤー | 役割 | 収益源 | 収益割合(目安) |
|---|---|---|---|
| サーチャー | MEV機会の発見・実行 | MEV利益 - ビルダーへの入札 | 10-30% |
| ビルダー | ブロック構築 | サーチャーからの手数料 - バリデーターへの入札 | 5-15% |
| バリデーター | ブロック提案 | ビルダーからの入札額 | 50-80% |
| リレー | 仲介 | 通常無料(公共財) | 0% |
Flashbots
Flashbots(フラッシュボッツ)は、MEVの民主化と透明化を目指すリサーチ&開発組織です。Ethereum上のMEVインフラの中核を担っています。
Flashbots の主要プロダクト
| プロダクト | 説明 | 対象 |
|---|---|---|
| MEV-Boost | PBS実装、バリデーター用 | バリデーター |
| Flashbots Protect | プライベートTX送信RPC | 一般ユーザー |
| Flashbots Builder | ブロックビルダー | ビルダー |
| MEV-Share | MEV利益のユーザー還元 | サーチャー/ユーザー |
| SUAVE | 次世代MEVインフラ(開発中) | 全参加者 |
Flashbots Protect の使い方
[Flashbots Protect を MetaMask に追加]
ネットワーク設定:
ネットワーク名: Flashbots Protect
RPC URL: https://rpc.flashbots.net
チェーンID: 1
通貨シンボル: ETH
効果:
✓ トランザクションがパブリックメモリプールに公開されない
✓ サンドイッチ攻撃から保護
✓ フロントランニングから保護
✓ 失敗したTXのガス代が不要(リバートプロテクション)
MEV-Share: ユーザーへのMEV還元
MEV-Shareは、ユーザーのトランザクションから生じるMEV利益の一部をユーザーに還元する仕組みです。
[MEV-Share のフロー]
1. ユーザーがFlashbots Protect経由でTX送信
2. Flashbotsがトランザクションの一部情報をサーチャーに公開
(完全な情報ではなく、ヒント情報のみ)
3. サーチャーがバックランTXを作成
4. MEV利益が発生
5. 利益の一部がユーザーに還元
利益分配:
ユーザー: 50-90%(設定可能)
サーチャー: 10-50%
SUAVE — 次世代MEVインフラ(構想)
SUAVE(Single Unifying Auction for Value Expression)は、Flashbotsが構想する次世代のMEVインフラです。
SUAVEの目標:
├── チェーン非依存のMEVインフラ
│ └── Ethereum, Solana, L2等すべてに対応
├── プライバシー保護
│ └── TEE(Trusted Execution Environment)の活用
├── 分散化
│ └── 単一のビルダーへの集中を排除
└── MEVの民主化
└── 誰でもサーチャー/ビルダーに参加可能
Jito — Solana MEVインフラ
Jito(ジト)は、Solana上のMEVインフラを提供するプロトコルです。バンドルトランザクションとブロックエンジンを通じて、Solana版のFlashbotsとも言える役割を果たしています。
Jito の仕組み
[Jito MEV サプライチェーン(Solana)]
サーチャー
│ バンドルトランザクションを作成
│ チップ(入札)を付与
↓
Jito Block Engine
│ バンドルを受信・最適化
│ バリデーターに配信
↓
Jito-Solana バリデーター
│ Jitoクライアント(修正版Solanaバリデーター)を実行
│ バンドルを含むブロックを提案
↓
ブロック確定
Jito バンドルの送信例
# Jito バンドルトランザクション送信(概念コード)
import httpx
import base58
class JitoClient:
"""Jito Block Engine クライアント"""
BLOCK_ENGINE_URL = "https://mainnet.block-engine.jito.wtf"
async def send_bundle(self, transactions: list, tip_lamports: int = 10000):
"""バンドルトランザクションを送信"""
# チップトランザクションを追加
# Jitoのチップアカウントの一つに送金
tip_accounts = [
"96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
"HFqU5x63VTqvQss8hp11i4bVqkfRtQ7NmXwkiNPLArUT",
# ... 他のチップアカウント
]
tip_tx = self.create_tip_transaction(
to=random.choice(tip_accounts),
amount=tip_lamports
)
transactions.append(tip_tx)
# バンドルを送信
serialized = [
base58.b58encode(tx.serialize()).decode()
for tx in transactions
]
response = await httpx.AsyncClient().post(
f"{self.BLOCK_ENGINE_URL}/api/v1/bundles",
json={
"jsonrpc": "2.0",
"id": 1,
"method": "sendBundle",
"params": [serialized]
}
)
return response.json()
async def get_tip_floor(self) -> int:
"""現在のチップフロア(最低入札額)を取得"""
response = await httpx.AsyncClient().post(
f"{self.BLOCK_ENGINE_URL}/api/v1/bundles",
json={
"jsonrpc": "2.0",
"id": 1,
"method": "getTipAccounts",
"params": []
}
)
return response.json()
Jito のステーキング(JitoSOL)
| 指標 | 値 |
|---|---|
| JitoSOL TVL | $2B以上 |
| APY | 約7-8%(ベースステーキング + MEV報酬) |
| MEV報酬割合 | APYの約1-2%がMEV由来 |
| バリデーター数 | 200以上 |
MEV Bot開発の基礎
開発に必要な技術スタック
| レイヤー | 技術 | 用途 |
|---|---|---|
| ブロックチェーン接続 | WebSocket RPC, geth/reth | メモリプール監視、TX送信 |
| スマートコントラクト | Solidity, Foundry | アトミック実行コントラクト |
| バックエンド | Rust, Go, Python | 戦略ロジック、高速処理 |
| データ | Redis, ClickHouse | 状態管理、分析 |
| インフラ | 低レイテンシVPS | バリデーターに近いサーバー |
シンプルなアービトラージBotの構造
# MEV アービトラージBot の基本構造(概念実装)
import asyncio
from web3 import Web3
from web3.middleware import geth_poa_middleware
class SimpleArbBot:
"""DEXアービトラージの基本Bot"""
def __init__(self, config: dict):
self.w3 = Web3(Web3.WebsocketProvider(config["ws_url"]))
self.account = self.w3.eth.account.from_key(config["private_key"])
self.arb_contract = self.w3.eth.contract(
address=config["arb_contract"],
abi=config["arb_abi"]
)
self.min_profit_wei = Web3.to_wei(0.005, "ether") # 最低利益
async def monitor_mempool(self):
"""メモリプールを監視してMEV機会を検知"""
async for tx_hash in self.w3.eth.subscribe("pendingTransactions"):
try:
tx = await self.w3.eth.get_transaction(tx_hash)
if self.is_target_dex(tx["to"]):
opportunity = await self.analyze_opportunity(tx)
if opportunity["profitable"]:
await self.execute(opportunity)
except Exception as e:
continue
async def analyze_opportunity(self, pending_tx: dict) -> dict:
"""保留中TXを分析してアービトラージ機会を評価"""
# デコードして取引内容を把握
decoded = self.decode_swap(pending_tx)
# 価格インパクトをシミュレーション
price_after = self.simulate_price_impact(
decoded["pool"],
decoded["amount"],
decoded["direction"]
)
# 反対方向の取引で利益が出るか計算
profit = self.calculate_backrun_profit(
decoded["pool"],
price_after,
gas_price=pending_tx["gasPrice"]
)
return {
"profitable": profit > self.min_profit_wei,
"expected_profit": profit,
"pending_tx": pending_tx,
"strategy": "backrun"
}
async def execute(self, opportunity: dict):
"""Flashbotsバンドルとして実行"""
bundle = [
opportunity["pending_tx"], # 元のTX
self.build_backrun_tx(opportunity) # バックランTX
]
# Flashbots Relay に送信
result = await self.flashbots.send_bundle(
bundle,
target_block=self.w3.eth.block_number + 1
)
if result["bundleHash"]:
print(f"Bundle submitted: {result['bundleHash']}")
print(f"Expected profit: {opportunity['expected_profit']} wei")
アトミック実行コントラクト
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@aave/v3-core/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol";
contract ArbExecutor is FlashLoanSimpleReceiverBase {
address public owner;
constructor(address _poolProvider)
FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_poolProvider))
{
owner = msg.sender;
}
/// @notice フラッシュローンを使ったDEXアービトラージ
function executeArb(
address token,
uint256 amount,
bytes calldata swapData
) external {
require(msg.sender == owner, "Not owner");
// Aave V3 フラッシュローン実行
POOL.flashLoanSimple(
address(this),
token,
amount,
swapData,
0 // referralCode
);
}
/// @notice フラッシュローンのコールバック
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external override returns (bool) {
// 1. DEX Aで売却
// 2. DEX Bで購入
// 3. 利益確認
(address dexA, address dexB, bytes memory swapParamsA, bytes memory swapParamsB)
= abi.decode(params, (address, address, bytes, bytes));
// DEX Aでスワップ
IERC20(asset).approve(dexA, amount);
(bool successA,) = dexA.call(swapParamsA);
require(successA, "Swap A failed");
// DEX Bでスワップ(戻す)
uint256 intermediateBalance = IERC20(intermediateToken).balanceOf(address(this));
IERC20(intermediateToken).approve(dexB, intermediateBalance);
(bool successB,) = dexB.call(swapParamsB);
require(successB, "Swap B failed");
// フラッシュローン返済(元本 + 手数料)
uint256 totalDebt = amount + premium;
uint256 finalBalance = IERC20(asset).balanceOf(address(this));
require(finalBalance >= totalDebt, "Not profitable");
IERC20(asset).approve(address(POOL), totalDebt);
// 利益をオーナーに送金
uint256 profit = finalBalance - totalDebt;
if (profit > 0) {
IERC20(asset).transfer(owner, profit);
}
return true;
}
}
MEV保護手段
ユーザー向けMEV保護
| 保護手段 | 方法 | 効果 |
|---|---|---|
| Flashbots Protect | プライベートRPCを使用 | サンドイッチ攻撃から保護 |
| MEV Blocker | Flashbotsの代替プライベートRPC | MEV利益の一部を還元 |
| CowSwap | バッチオークション方式 | MEVフリーの取引執行 |
| 1inch Fusion | リゾルバーネットワーク | MEV保護+最良レート |
| スリッページ設定 | 許容スリッページを最小に | 攻撃の利益を制限 |
| 分割取引 | 大口注文を分割 | 価格インパクトを軽減 |
プロトコル設計によるMEV対策
[MEV-Resistant DEX 設計パターン]
1. バッチオークション(CowSwap方式)
すべての注文を一定期間収集 → 一括で約定
→ 注文の順序に意味がなくなる → MEV排除
2. 暗号化メモリプール(Threshold Encryption)
TX内容を暗号化 → ブロックに含まれた後に復号
→ サーチャーがTX内容を事前に知れない
3. オフチェーンオーダーブック(Intent-based)
注文をオフチェーンで収集 → ソルバーが最適に実行
→ メモリプールに公開されない → MEV排除
4. タイムウェイテッドオーダー
大口注文を時間分散して実行
→ 1回のブロックでの価格インパクトを低減
MEVの倫理的議論
MEVは「良い」のか「悪い」のか
| 立場 | 主張 |
|---|---|
| MEV肯定派 | 市場効率性の向上(DEXアービトラージ)、プロトコルの健全性維持(清算)、バリデーターの収益源 |
| MEV否定派 | 一般ユーザーからの価値搾取(サンドイッチ)、ネットワークの混雑(ガスオークション)、中央集権化リスク |
| 中立派 | MEVは不可避、適切な制度設計で悪影響を最小化し、良い側面を最大化すべき |
MEVの分類
[ポジティブMEV]
├── DEXアービトラージ → 価格の均一化、市場効率性
├── 清算 → レンディングプロトコルの健全性維持
└── オラクル更新後の価格修正
[ネガティブMEV]
├── サンドイッチ攻撃 → ユーザーへの直接的損害
├── フロントランニング → 不公平な取引環境
└── タイムバンディット攻撃 → ブロックチェーンの安全性への脅威
[中立MEV]
├── バックランニング → 直接的被害なし
└── NFTミントスナイピング → 早い者勝ちの市場原理
MEV戦略の実践に向けて
初心者向けロードマップ
| ステップ | 内容 | 推定期間 |
|---|---|---|
| 1 | Solidityの基礎学習 | 2-4週間 |
| 2 | DeFiプロトコルの理解(Uniswap, Aave等) | 2-4週間 |
| 3 | Foundryでのテスト・シミュレーション | 2-4週間 |
| 4 | メモリプール監視の実装 | 1-2週間 |
| 5 | テストネットでのバックランBot実装 | 2-4週間 |
| 6 | Flashbots統合 | 1-2週間 |
| 7 | メインネットでの運用開始(小額) | - |
競争環境の現実
MEVは極めて競争の激しい分野です。以下の点を認識する必要があります:
- レイテンシ勝負 — ミリ秒単位の速度差が勝敗を分ける
- 資本要件 — フラッシュローンで軽減可能だが、ガス代は必要
- インフラコスト — 低レイテンシサーバー、専用ノードが必要
- 競合の技術力 — プロフェッショナルチームが多数参入
- 利益率の低下 — 競争激化により利益率は年々低下傾向
MEVは高度な技術力と深いDeFi理解を要求する分野ですが、ブロックチェーンの仕組みを根本から理解するための最良の学習テーマでもあります。実際に利益を上げることが目的でなくても、MEVの知識はDeFi開発者・トレーダーにとって不可欠な基盤知識です。