diff --git a/crates/driver/src/boundary/score.rs b/crates/driver/src/boundary/score.rs index 4f7ad90681..def6d4e63b 100644 --- a/crates/driver/src/boundary/score.rs +++ b/crates/driver/src/boundary/score.rs @@ -22,7 +22,7 @@ pub fn score( ) -> Result { match ScoreCalculator::new(score_cap.0.get().to_big_rational()).compute_score( &objective_value.0.get().to_big_rational(), - failure_cost.0 .0.to_big_rational(), + failure_cost.get().0.to_big_rational(), success_probability.0, ) { Ok(score) => Ok(score.try_into()?), diff --git a/crates/driver/src/domain/competition/mod.rs b/crates/driver/src/domain/competition/mod.rs index 410d704182..7efdc42f84 100644 --- a/crates/driver/src/domain/competition/mod.rs +++ b/crates/driver/src/domain/competition/mod.rs @@ -352,13 +352,13 @@ pub struct Revealed { #[derive(Debug)] pub struct Settled { + /// The transaction hash in which the solution was submitted. + pub tx_hash: eth::TxId, pub internalized_calldata: Bytes>, /// The uninternalized calldata must be known so that the CoW solver team /// can manually enforce certain rules which can not be enforced /// automatically. pub uninternalized_calldata: Bytes>, - /// The transaction hash in which the solution was submitted. - pub tx_hash: eth::TxId, } #[derive(Debug, thiserror::Error)] diff --git a/crates/driver/src/domain/competition/score.rs b/crates/driver/src/domain/competition/score.rs index e5c8e6b43a..72a94d1f8f 100644 --- a/crates/driver/src/domain/competition/score.rs +++ b/crates/driver/src/domain/competition/score.rs @@ -126,9 +126,9 @@ pub mod risk { type Output = Result; fn sub(self, other: GasCost) -> Self::Output { - if self.0 > other.0 .0 { + if self.0 > other.get().0 { Ok(ObjectiveValue( - eth::NonZeroU256::new(self.0 - other.0 .0).unwrap(), + eth::NonZeroU256::new(self.0 - other.get().0).unwrap(), )) } else { Err(Error::ObjectiveValueNonPositive(self, other)) diff --git a/crates/driver/src/domain/competition/solution/settlement.rs b/crates/driver/src/domain/competition/solution/settlement.rs index b0dec87f58..d2d5b8a83b 100644 --- a/crates/driver/src/domain/competition/solution/settlement.rs +++ b/crates/driver/src/domain/competition/solution/settlement.rs @@ -4,7 +4,7 @@ use { boundary, domain::{ competition::{self, auction, order, score, solution}, - eth, + eth::{self, GasCost}, mempools, }, infra::{blockchain::Ethereum, observe, Simulator}, @@ -12,7 +12,6 @@ use { }, bigdecimal::Signed, futures::future::try_join_all, - num::zero, std::collections::{BTreeSet, HashMap, HashSet}, }; @@ -273,14 +272,14 @@ impl Settlement { let score = match self.boundary.score() { competition::SolverScore::Solver(score) => score.try_into()?, competition::SolverScore::RiskAdjusted(success_probability) => { - let gas_cost = self.gas.estimate * auction.gas_price(); + let gas_cost = self.gas.estimate * auction.gas_price().effective(); let success_probability = success_probability.try_into()?; let objective_value = (quality - gas_cost)?; // The cost in case of a revert can deviate non-deterministically from the cost // in case of success and it is often significantly smaller. Thus, we go with // the full cost as a safe assumption. let failure_cost = match revert_protection { - mempools::RevertProtection::Enabled => zero(), + mempools::RevertProtection::Enabled => GasCost::zero(), mempools::RevertProtection::Disabled => gas_cost, }; competition::Score::new( diff --git a/crates/driver/src/domain/eth/gas.rs b/crates/driver/src/domain/eth/gas.rs index eeccf5459b..5882f83466 100644 --- a/crates/driver/src/domain/eth/gas.rs +++ b/crates/driver/src/domain/eth/gas.rs @@ -1,6 +1,8 @@ use { super::{Ether, U256}, - std::ops, + bigdecimal::Zero, + num::zero, + std::{ops, ops::Add}, }; /// Gas amount in gas units. @@ -28,6 +30,24 @@ impl From for U256 { } } +impl Add for Gas { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Zero for Gas { + fn zero() -> Self { + Self(U256::zero()) + } + + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + /// An EIP-1559 gas price estimate. /// /// https://eips.ethereum.org/EIPS/eip-1559#specification @@ -108,37 +128,64 @@ impl From for U256 { } } -impl ops::Mul for Gas { - type Output = GasCost; +impl Add for EffectiveGasPrice { + type Output = Self; - fn mul(self, rhs: GasPrice) -> Self::Output { - Ether::from(self.0 * rhs.effective().0 .0).into() + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) } } -#[derive(Debug, Clone, Copy)] -pub struct GasCost(pub Ether); +impl Zero for EffectiveGasPrice { + fn zero() -> Self { + Self(Ether::zero()) + } -impl From for GasCost { - fn from(value: Ether) -> Self { - Self(value) + fn is_zero(&self) -> bool { + self.0.is_zero() } } -impl ops::Add for GasCost { - type Output = Self; +impl ops::Mul for Gas { + type Output = GasCost; - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) + fn mul(self, rhs: EffectiveGasPrice) -> Self::Output { + GasCost::new(self, rhs) } } -impl num::Zero for GasCost { - fn zero() -> Self { - Self(Ether::zero()) +/// Gas cost in Ether. +/// +/// The amount of Ether that is paid in transaction fees. +#[derive(Clone, Copy)] +pub struct GasCost { + gas: Gas, + price: EffectiveGasPrice, +} + +impl GasCost { + pub fn new(gas: Gas, price: EffectiveGasPrice) -> Self { + Self { gas, price } } - fn is_zero(&self) -> bool { - self.0.is_zero() + pub fn get(&self) -> Ether { + (self.gas.0 * self.price.0 .0).into() + } + + pub fn zero() -> Self { + Self { + gas: zero(), + price: zero(), + } + } +} + +impl std::fmt::Debug for GasCost { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("GasCost") + .field("gas", &self.gas.0) + .field("price", &self.price.0 .0) + .field("gas_cost", &self.get().0) + .finish() } } diff --git a/crates/driver/src/infra/observe/mod.rs b/crates/driver/src/infra/observe/mod.rs index bbf0cd0cf6..7fc8459858 100644 --- a/crates/driver/src/infra/observe/mod.rs +++ b/crates/driver/src/infra/observe/mod.rs @@ -349,5 +349,5 @@ pub fn order_excluded_from_auction( /// Observe that a settlement was simulated pub fn simulated(tx: ð::Tx, gas: Gas) { - tracing::debug!(?tx, gas = ?gas.0, "simulated settlement"); + tracing::debug!(gas = ?gas.0, ?tx, "simulated settlement"); } diff --git a/crates/driver/src/infra/solver/dto/notification.rs b/crates/driver/src/infra/solver/dto/notification.rs index af4148bed9..c45ecf92cc 100644 --- a/crates/driver/src/infra/solver/dto/notification.rs +++ b/crates/driver/src/infra/solver/dto/notification.rs @@ -52,7 +52,7 @@ impl Notification { gas_cost, )) => Kind::ScoringFailed(ScoreKind::ObjectiveValueNonPositive { quality: quality.0, - gas_cost: gas_cost.0 .0, + gas_cost: gas_cost.get().0, }), notify::Kind::NonBufferableTokensUsed(tokens) => Kind::NonBufferableTokensUsed { tokens: tokens.into_iter().map(|token| token.0 .0).collect(),