Deep EVM #16 : Bundling et résolution de conflits — Empaqueter les transactions MEV rentables
Engineering Team
Qu’est-ce qu’un bundle MEV ?
Un bundle MEV est un ensemble ordonné de transactions soumis à un constructeur de blocs comme un tout atomique. Soit toutes les transactions du bundle sont incluses dans l’ordre spécifié, soit aucune ne l’est.
Les bundles permettent aux chercheurs de :
- Garantir l’ordonnancement des transactions
- Inclure des transactions de backrun après les transactions d’autres utilisateurs
- Soumettre plusieurs opportunités atomiquement
Détection de conflits
Deux opportunités MEV sont en conflit si elles modifient le même état. L’exécuter dans un ordre produit un résultat différent de l’autre ordre, ou l’une invalide l’autre.
struct StateAccess {
reads: HashSet<(Address, U256)>, // (contrat, slot)
writes: HashSet<(Address, U256)>, // (contrat, slot)
}
fn conflicts(a: &StateAccess, b: &StateAccess) -> bool {
// Conflit si A écrit ce que B lit, ou vice versa
!a.writes.is_disjoint(&b.reads) ||
!b.writes.is_disjoint(&a.reads) ||
!a.writes.is_disjoint(&b.writes)
}
La détection de conflits provient de la simulation — revm peut tracer tous les SLOAD/SSTORE pendant l’exécution.
Ordonnancement optimal
Étant donné N opportunités non conflictuelles, l’ordonnancement optimal maximise le profit total en tenant compte de l’impact de chaque transaction sur l’état :
fn order_bundle(
opportunities: &mut Vec<Opportunity>,
state: &CacheDB,
) -> Vec<Transaction> {
// Trier par profit décroissant comme heuristique initiale
opportunities.sort_by(|a, b| b.profit.cmp(&a.profit));
let mut bundle = Vec::new();
let mut current_state = state.clone();
for opp in opportunities {
// Resimule sur l'état courant (après les transactions précédentes)
let result = simulate_on_state(¤t_state, &opp);
if result.success && result.profit > result.gas_cost {
bundle.push(result.transaction);
current_state = result.new_state;
}
}
bundle
}
Enchères pour les constructeurs
Les constructeurs de blocs choisissent les bundles qui leur rapportent le plus. Votre enchère doit être suffisante pour battre les concurrents, mais pas trop pour maximiser votre profit.
Stratégie courante : offrir 90 % du profit comme frais de priorité :
fn calculate_bid(profit: U256, gas_used: u64) -> U256 {
let bid_percentage = 90; // 90% au constructeur, 10% de profit
let total_bid = profit * bid_percentage / 100;
total_bid / gas_used // Convertir en prix par unité de gas
}
Soumission via Flashbots
La soumission de bundles se fait via l’API Flashbots :
async fn submit_bundle(
transactions: Vec<Bytes>,
target_block: u64,
) -> Result<BundleHash> {
let bundle = FlashbotsBundle {
txs: transactions,
block_number: target_block,
min_timestamp: None,
max_timestamp: None,
};
let response = flashbots_client
.send_bundle(&bundle)
.await?;
Ok(response.bundle_hash)
}
Stratégies de soumission
- Multi-bloc — Soumettez le même bundle pour les 3-5 prochains blocs
- Multi-constructeur — Soumettez simultanément à plusieurs constructeurs
- Escalade dynamique — Augmentez progressivement l’enchère si le bundle n’est pas inclus
- Bundle conditionnel — Incluez une vérification d’état au début pour annuler si les conditions ont changé
Métriques de suivi
Suivez les performances de vos bundles :
- Taux d’inclusion — Pourcentage de bundles soumis qui sont inclus
- Profit moyen — Profit net par bundle inclus
- Latence — Temps entre détection de l’opportunité et soumission
- Taux de revert — Pourcentage de bundles qui revertent on-chain
Conclusion
Le bundling est l’étape finale du pipeline MEV. La détection de conflits d’état, l’ordonnancement optimal et les enchères stratégiques déterminent le profit réalisé. Combiné avec les articles précédents sur la détection d’opportunités et la simulation, vous disposez maintenant des fondements complets d’un bot MEV en Rust.