signet_bundle/send/
driver.rs1use crate::send::SignetEthBundle;
2use alloy::primitives::U256;
3use signet_evm::{
4 DriveBundleResult, EvmErrored, EvmNeedsTx, EvmTransacted, SignetInspector, SignetLayered,
5};
6use signet_types::{AggregateFills, MarketError, SignedPermitError};
7use tracing::{debug, error};
8use trevm::{
9 helpers::Ctx,
10 inspectors::{Layered, TimeLimit},
11 revm::{
12 context::result::EVMError, inspector::InspectorEvmTr, Database, DatabaseCommit, Inspector,
13 },
14 trevm_bail, trevm_ensure, trevm_try, BundleDriver, BundleError,
15};
16
17pub type SignetEthBundleInsp<I> = Layered<TimeLimit, I>;
20
21#[derive(thiserror::Error)]
23pub enum SignetEthBundleError<Db: Database> {
24 #[error(transparent)]
26 BundleError(#[from] BundleError<Db>),
27
28 #[error(transparent)]
30 SignedPermitError(#[from] SignedPermitError),
31
32 #[error(transparent)]
34 ContractError(#[from] alloy::contract::Error),
35}
36
37impl<Db: Database> core::fmt::Debug for SignetEthBundleError<Db> {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 match self {
40 SignetEthBundleError::BundleError(bundle_error) => {
41 f.debug_tuple("BundleError").field(bundle_error).finish()
42 }
43 SignetEthBundleError::SignedPermitError(signed_order_error) => {
44 f.debug_tuple("SignedPermitError").field(signed_order_error).finish()
45 }
46 SignetEthBundleError::ContractError(contract_error) => {
47 f.debug_tuple("ContractError").field(contract_error).finish()
48 }
49 }
50 }
51}
52
53impl<Db: Database> From<EVMError<Db::Error>> for SignetEthBundleError<Db> {
54 fn from(err: EVMError<Db::Error>) -> Self {
55 Self::BundleError(BundleError::from(err))
56 }
57}
58
59#[derive(Debug, Clone)]
61pub struct SignetEthBundleDriver<'a> {
62 bundle: &'a SignetEthBundle,
64
65 deadline: std::time::Instant,
68
69 agg_fills: AggregateFills,
71
72 total_gas_used: u64,
74 beneficiary_balance_increase: U256,
76}
77
78impl<'a> SignetEthBundleDriver<'a> {
79 pub fn new(
82 bundle: &'a SignetEthBundle,
83 host_chain_id: u64,
84 deadline: std::time::Instant,
85 ) -> Self {
86 let mut agg_fills = AggregateFills::default();
87 if let Some(host_fills) = &bundle.host_fills {
88 agg_fills.add_signed_fill(host_chain_id, host_fills);
89 }
90
91 Self {
92 bundle,
93 deadline,
94 agg_fills,
95 total_gas_used: 0,
96 beneficiary_balance_increase: U256::ZERO,
97 }
98 }
99
100 pub const fn bundle(&self) -> &SignetEthBundle {
102 self.bundle
103 }
104
105 pub const fn deadline(&self) -> std::time::Instant {
107 self.deadline
108 }
109
110 pub const fn total_gas_used(&self) -> u64 {
112 self.total_gas_used
113 }
114
115 pub const fn beneficiary_balance_increase(&self) -> U256 {
117 self.beneficiary_balance_increase
118 }
119
120 pub const fn agg_fills(&self) -> &AggregateFills {
125 &self.agg_fills
126 }
127
128 pub(crate) fn check_fills<Db, Insp>(
135 &mut self,
136 trevm: &mut EvmTransacted<Db, Insp>,
137 ) -> Result<(), MarketError>
138 where
139 Db: Database + DatabaseCommit,
140 Insp: Inspector<Ctx<Db>>,
141 {
142 let (agg_orders, agg_fills) =
144 trevm.inner_mut_unchecked().inspector.as_mut_detector().take_aggregates();
145
146 self.agg_fills.checked_remove_ru_tx_events(&agg_orders, &agg_fills)
149 }
150}
151
152impl<Db, Insp> BundleDriver<Db, SignetLayered<Layered<TimeLimit, Insp>>>
153 for SignetEthBundleDriver<'_>
154where
155 Db: Database + DatabaseCommit,
156 Insp: Inspector<Ctx<Db>>,
157{
158 type Error = SignetEthBundleError<Db>;
159
160 fn run_bundle(
161 &mut self,
162 mut trevm: EvmNeedsTx<Db, SignetEthBundleInsp<Insp>>,
163 ) -> DriveBundleResult<Self, Db, SignetEthBundleInsp<Insp>> {
164 let bundle = &self.bundle.bundle;
165
166 self.total_gas_used = 0;
169 self.beneficiary_balance_increase = U256::ZERO;
170
171 let beneficiary = trevm.beneficiary();
173 let inital_beneficiary_balance =
174 trevm_try!(trevm.try_read_balance(beneficiary).map_err(EVMError::Database), trevm);
175
176 trevm_ensure!(!bundle.txs.is_empty(), trevm, BundleError::BundleEmpty.into());
178
179 trevm_ensure!(
181 trevm.block_number().to::<u64>() == bundle.block_number,
182 trevm,
183 BundleError::BlockNumberMismatch.into()
184 );
185
186 let timestamp = trevm.block_timestamp();
188 trevm_ensure!(
189 self.bundle.is_valid_at_timestamp(timestamp.to()),
190 trevm,
191 BundleError::TimestampOutOfRange.into()
192 );
193
194 if self.bundle().validate_fills_offchain(timestamp.to()).is_err() {
196 return Err(trevm.errored(BundleError::BundleReverted.into()));
197 }
198
199 let txs = trevm_try!(self.bundle.decode_and_validate_txs(), trevm);
201
202 for tx in txs.into_iter() {
203 let _span = tracing::debug_span!("bundle_tx_loop", tx_hash = %tx.hash()).entered();
204
205 let limit = trevm.inner_mut_unchecked().ctx_inspector().1.outer_mut().outer_mut();
207 *limit = TimeLimit::new(self.deadline - std::time::Instant::now());
208
209 let tx_hash = tx.hash();
210
211 let mut t = trevm
215 .run_tx(&tx)
216 .map_err(EvmErrored::err_into)
217 .inspect_err(|err| error!(err = %err.error(), "error while running transaction"))?;
218
219 let result = t.result();
221
222 let gas_used = result.gas_used();
223
224 if result.is_success() {
229 if self.check_fills(&mut t).is_err() {
230 debug!("transaction dropped due to insufficient fills");
231 if self.bundle.reverting_tx_hashes().contains(tx_hash) {
232 trevm = t.reject();
233 continue;
234 } else {
235 return Err(t.errored(BundleError::BundleReverted.into()));
236 }
237 }
238
239 self.total_gas_used = self.total_gas_used.saturating_add(gas_used);
240 } else {
241 if !self.bundle.reverting_tx_hashes().contains(tx_hash) {
245 debug!("transaction reverted, not marked as revertible");
246 return Err(t.errored(BundleError::BundleReverted.into()));
247 }
248 self.total_gas_used = self.total_gas_used.saturating_add(gas_used);
249 }
250
251 trevm = t.accept_state()
254 }
255
256 let beneficiary_balance =
257 trevm_try!(trevm.try_read_balance(beneficiary).map_err(EVMError::Database), trevm);
258
259 self.beneficiary_balance_increase =
260 beneficiary_balance.saturating_sub(inital_beneficiary_balance);
261
262 Ok(trevm)
263 }
264
265 fn post_bundle(
266 &mut self,
267 _trevm: &EvmNeedsTx<Db, SignetEthBundleInsp<Insp>>,
268 ) -> Result<(), Self::Error> {
269 Ok(())
270 }
271}