Deep EVM #16: Bundling und Konfliktloesung — Von der Simulation zur Block-Submission
Engineering Team
Von der Simulation zum Bundle
Nachdem Sie profitable Arbitrage-Zyklen gefunden und lokal simuliert haben, muessen Sie die Transaktionen in ein Bundle verpacken und an einen Block Builder senden. Dieser letzte Schritt entscheidet ueber Gewinn oder Verlust.
Was ist ein Bundle?
Ein Bundle ist ein geordnetes Paket von Transaktionen, das atomar ausgefuehrt werden muss:
- Alle Transaktionen werden in der angegebenen Reihenfolge ausgefuehrt
- Wenn eine Transaktion fehlschlaegt, wird das gesamte Bundle verworfen
- Der Searcher zahlt eine Gebuehr (“tip”) an den Block Builder
struct Bundle {
transactions: Vec<SignedTransaction>,
block_number: u64,
min_timestamp: Option<u64>,
max_timestamp: Option<u64>,
}
Konfliktloesung zwischen Strategien
Wenn Sie mehrere MEV-Strategien gleichzeitig ausfuehren, koennen sie in Konflikt geraten:
Zustandskonflikte
Zwei Strategien greifen auf denselben Pool zu:
- Strategie A: ETH -> USDC auf Uniswap V2
- Strategie B: USDC -> DAI auf Uniswap V2
Beide aendern den Zustand des USDC/ETH-Pools. Die zweite Strategie muss den neuen Zustand nach der ersten beruecksichtigen.
Loesungsstrategie: Greedy-Optimierung
fn resolve_conflicts(
strategies: &[Strategy],
db: &CacheDB<impl Database>,
) -> Vec<Strategy> {
let mut selected = Vec::new();
let mut current_db = db.clone();
// Strategien nach erwartetem Gewinn sortieren
let mut sorted = strategies.to_vec();
sorted.sort_by(|a, b| b.expected_profit.cmp(&a.expected_profit));
for strategy in sorted {
// Mit aktuellem Zustand neu simulieren
match simulate(&mut current_db.clone(), &strategy) {
Ok(result) if result.profit > MIN_PROFIT => {
// Zustand anwenden
apply_state_changes(&mut current_db, &result);
selected.push(strategy);
}
_ => continue, // Nicht mehr profitabel
}
}
selected
}
Bundle an Builder senden
Flashbots-kompatible Builder akzeptieren Bundles ueber eine JSON-RPC-API:
use reqwest::Client;
async fn send_bundle(
client: &Client,
bundle: &Bundle,
builder_url: &str,
) -> Result<BundleResponse, Error> {
let payload = json!({
"jsonrpc": "2.0",
"method": "eth_sendBundle",
"params": [{
"txs": bundle.transactions.iter()
.map(|tx| format!("0x{}", hex::encode(tx.rlp())))
.collect::<Vec<_>>(),
"blockNumber": format!("0x{:x}", bundle.block_number),
}],
"id": 1,
});
let response = client.post(builder_url)
.header("X-Flashbots-Signature", sign_payload(&payload)?)
.json(&payload)
.send()
.await?;
response.json().await
}
Gebuehren-Optimierung
Die Gebuehr (“tip”) bestimmt, ob Ihr Bundle in den Block aufgenommen wird:
- Zu niedrig: Builder ignoriert Ihr Bundle
- Zu hoch: Sie verschenken Ihren Gewinn
- Optimal: Gerade genug, um bevorzugt behandelt zu werden
Faustregel: 80-90% des Nettogewinns als Tip bieten. In einem wettbewerbsintensiven Markt werden die Margen immer kleiner.
MEV-Share Integration
Flashbots MEV-Share ermoeglicht es Searchern, MEV-Erloes mit den Benutzern zu teilen, deren Transaktionen sie nutzen:
async fn send_mev_share_bundle(
bundle: &Bundle,
refund_percent: u8, // z.B. 90% Rueckerstattung an den Benutzer
) -> Result<(), Error> {
// MEV-Share-spezifische Parameter
let mev_share_bundle = json!({
"version": "v0.1",
"inclusion": {
"block": format!("0x{:x}", bundle.block_number),
},
"body": bundle.transactions,
"validity": {
"refund": [{
"bodyIdx": 0,
"percent": refund_percent,
}],
},
});
// An MEV-Share Relay senden
send_to_relay(&mev_share_bundle).await
}
Fazit
Bundling und Konfliktloesung sind die letzten Schritte in der MEV-Pipeline. Von der Zyklen-Erkennung ueber die Simulation bis zur Bundle-Submission — jeder Schritt muss in Millisekunden ablaufen, um wettbewerbsfaehig zu bleiben. Die Integration mit Flashbots MEV-Share fuegt eine ethische Dimension hinzu: Gewinne mit Benutzern teilen statt sie auszubeuten.