Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions crates/driver/example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ max-additional-tip = "5000000000"
additional-tip-percentage = 0.05
mines-reverting-txs = true

# Optional list of block builders to submit to directly. When it is non-empty
# the driver signs the settlement itself and broadcasts the raw transaction to
# every builder, and cancellations take the same route; `url` above then only
# serves nonce and txpool queries. The submission succeeds as long as one
# builder accepts the transaction. Builders mine reverting transactions, so
# `mines-reverting-txs` keeps its usual default of `true`. Requests carry an
# `X-Flashbots-Signature` header signed by the settlement account, which
# builders that authenticate their callers (e.g. BuilderNet) require and the
# rest ignore.
#
# A settlement that may revert only races the best configured tier: the
# mempools with builders, else the ones with `mines-reverting-txs = false`,
# else the public ones. So configuring builders takes every other mempool out
# of the race for those settlements.
# [[submission.mempool.builders]]
# name = "titan"
# url = "https://rpc.titanbuilder.xyz/"

[contracts] # Optionally override the contract addresses, necessary on less popular blockchains
gp-v2-settlement = "0x9008D19f58AAbD9eD0D60971565AA8510560ab41"
weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
Expand Down
60 changes: 36 additions & 24 deletions crates/driver/src/domain/mempools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,28 +97,21 @@ impl Mempools {
Ok(res?.tx_hash)
}

/// A mempool is disabled if all of the following are true:
/// * the settlement may revert (see [`Settlement::may_revert`])
/// * the pool has revert protection enabled (see
/// [`Self::revert_protection`])
/// * reverts can get mined (see [`infra::Mempool::reverts_can_get_mined`])
/// A settlement that may revert (see [`Settlement::may_revert`]) only
/// races the best configured [`Tier`], so a mempool of a worse tier is
/// disabled. Settlements that cannot revert race every mempool.
fn is_disabled(&self, mempool: &infra::Mempool, settlement: &Settlement) -> bool {
settlement.may_revert()
&& matches!(self.revert_protection(), RevertProtection::Enabled)
&& mempool.reverts_can_get_mined()
settlement.may_revert() && Tier::of(mempool) > self.best_tier()
}

/// Defines if the mempools are configured in a way that guarantees that
/// settled solution will not revert.
pub fn revert_protection(&self) -> RevertProtection {
match self
.mempools
/// The best tier among the configured mempools.
fn best_tier(&self) -> Tier {
self.mempools
.iter()
.all(|mempool| mempool.reverts_can_get_mined())
{
true => RevertProtection::Disabled,
false => RevertProtection::Enabled,
}
.map(Tier::of)
.min()
// `try_new` rejects an empty list of mempools.
.expect("no mempools configured")
}

async fn submit(
Expand Down Expand Up @@ -600,12 +593,31 @@ impl SubmissionSuccess {
#[error("no mempools configured, cannot execute settlements")]
pub struct NoMempools;

/// Defines if the mempools are configured in a way that guarantees that
/// /settle'd solution will not revert.
#[derive(Debug, Clone, Copy)]
pub enum RevertProtection {
Enabled,
Disabled,
/// Where a settlement that may revert can go, best tier first. Only the best
/// configured tier races: the builders if there are any, else the revert
/// protected mempools, else the public ones.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum Tier {
/// Handed straight to block builders. They mine reverting txs but offer
/// the best inclusion.
Builders,
/// An RPC that drops reverting txs instead of mining them, e.g. MEV
/// Blocker.
RevertProtected,
/// A public mempool, which mines reverting txs.
Public,
}

impl Tier {
fn of(mempool: &infra::Mempool) -> Self {
if mempool.submits_to_builders() {
Self::Builders
} else if mempool.reverts_can_get_mined() {
Self::Public
} else {
Self::RevertProtected
}
}
}

#[derive(Debug, thiserror::Error)]
Expand Down
2 changes: 1 addition & 1 deletion crates/driver/src/domain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ pub use {
flashloan::Flashloan,
interaction::Interaction,
liquidity::Liquidity,
mempools::{Mempools, RevertProtection},
mempools::Mempools,
};
8 changes: 8 additions & 0 deletions crates/driver/src/infra/config/file/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,14 @@ pub async fn load(chain: Chain, path: &Path) -> infra::Config {
},
max_additional_tip: mempool.max_additional_tip,
additional_tip_percentage: mempool.additional_tip_percentage,
builders: mempool
.builders
.iter()
.map(|builder| mempool::Builder {
name: builder.name.clone(),
url: builder.url.clone(),
})
.collect(),
})
.collect(),
simulator: config.simulator,
Expand Down
18 changes: 17 additions & 1 deletion crates/driver/src/infra/config/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ impl From<BlockNumber> for BlockNumberOrTag {

#[serde_as]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
struct Mempool {
/// Name for better logging and metrics.
name: Option<String>,
Expand All @@ -175,6 +175,22 @@ struct Mempool {
/// assume reverting transactions will get mined eventually.
#[serde(default = "default_mines_reverting_txs")]
mines_reverting_txs: bool,
/// Block builders to send the settlement transaction to directly. When
/// this is non-empty settlements and cancellations both go to the builders
/// and `url` only serves nonce and txpool queries.
#[serde(default)]
builders: Vec<Builder>,
}

/// A block builder that accepts settlement transactions over
/// `eth_sendRawTransaction`.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
struct Builder {
/// Name for better logging and metrics.
name: String,
/// The RPC URL to send the signed transaction to.
url: Url,
}

#[derive(Debug, Deserialize)]
Expand Down
Loading
Loading