diff --git a/crates/autopilot/src/domain/eth/mod.rs b/crates/autopilot/src/domain/eth/mod.rs index 9b187526ba..29ca478683 100644 --- a/crates/autopilot/src/domain/eth/mod.rs +++ b/crates/autopilot/src/domain/eth/mod.rs @@ -312,6 +312,13 @@ pub struct TradeEvent { pub order_uid: domain::OrderUid, } +/// A trace of a Call type of action. +#[derive(Debug, Clone, Default)] +pub struct TraceCall { + pub to: Address, + pub input: Calldata, +} + /// Any type of on-chain transaction. #[derive(Debug, Clone, Default)] pub struct Transaction { @@ -319,8 +326,6 @@ pub struct Transaction { pub hash: TxId, /// The address of the sender of the transaction. pub from: Address, - /// The call data of the transaction. - pub input: Calldata, /// The block number of the block that contains the transaction. pub block: BlockNo, /// The timestamp of the block that contains the transaction. @@ -329,4 +334,6 @@ pub struct Transaction { pub gas: Gas, /// The effective gas price of the transaction. pub gas_price: EffectiveGasPrice, + /// Traces of all Calls contained in the transaction. + pub trace_calls: Vec, } diff --git a/crates/autopilot/src/domain/settlement/mod.rs b/crates/autopilot/src/domain/settlement/mod.rs index 7908789719..dbcb4e14c4 100644 --- a/crates/autopilot/src/domain/settlement/mod.rs +++ b/crates/autopilot/src/domain/settlement/mod.rs @@ -29,8 +29,6 @@ pub struct Settlement { gas: eth::Gas, /// The effective gas price of the settlement transaction. gas_price: eth::EffectiveGasPrice, - /// The address of the solver that submitted the settlement transaction. - solver: eth::Address, /// The block number of the block that contains the settlement transaction. block: eth::BlockNo, /// The associated auction. @@ -146,7 +144,6 @@ impl Settlement { .collect(); Ok(Self { - solver: settled.solver, block: settled.block, gas: settled.gas, gas_price: settled.gas_price, @@ -216,14 +213,246 @@ impl From for Error { #[cfg(test)] mod tests { use { - crate::{ - domain, - domain::{auction, eth}, - }, + crate::domain::{self, auction, eth}, hex_literal::hex, std::collections::{HashMap, HashSet}, }; + // https://etherscan.io/tx/0x030623e438f28446329d8f4ff84db897907fcac59b9943b31b7be66f23c877af + // A transfer transaction that emits a settlement event, but it's not actually a + // swap. + #[test] + fn not_a_swap() { + let calldata = hex!( + " + 13d79a0b + 0000000000000000000000000000000000000000000000000000000000000080 + 00000000000000000000000000000000000000000000000000000000000000a0 + 00000000000000000000000000000000000000000000000000000000000000c0 + 00000000000000000000000000000000000000000000000000000000000000e0 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 0000000000000000000000000000000000000000000000000000000000000080 + 00000000000000000000000000000000000000000000000000000000000017a0 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000011 + 0000000000000000000000000000000000000000000000000000000000000220 + 0000000000000000000000000000000000000000000000000000000000000360 + 00000000000000000000000000000000000000000000000000000000000004a0 + 00000000000000000000000000000000000000000000000000000000000005e0 + 0000000000000000000000000000000000000000000000000000000000000720 + 0000000000000000000000000000000000000000000000000000000000000860 + 00000000000000000000000000000000000000000000000000000000000009a0 + 0000000000000000000000000000000000000000000000000000000000000ae0 + 0000000000000000000000000000000000000000000000000000000000000c20 + 0000000000000000000000000000000000000000000000000000000000000d60 + 0000000000000000000000000000000000000000000000000000000000000ea0 + 0000000000000000000000000000000000000000000000000000000000000fe0 + 0000000000000000000000000000000000000000000000000000000000001120 + 0000000000000000000000000000000000000000000000000000000000001260 + 00000000000000000000000000000000000000000000000000000000000013a0 + 00000000000000000000000000000000000000000000000000000000000014e0 + 0000000000000000000000000000000000000000000000000000000000001620 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 000000388674df3c7f96ac76c6fa06813b758322b5b64ce14bf46f0f9b4ec6f2 + d015ff9a9008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 000000383f19e12409d5913e40bfde35a1607a1a43f1f9d26e76dd2d9d409cc7 + 50125f769008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 00000038a91a488e41e46dedbe71ae0c0d9f41be8de9f45ffc62271970362777 + 9e302e8d9008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 0000003820621f141681025ffcbce03b51c3ea78c93da8739df9202210647968 + 6d2efad59008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 000000385846bbbcee39039678e529973cf6962b90d49663d5ff49220adfb240 + 4805d11e9008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 000000388a608a3e6fd6f95797d376ffa35ae077d78440b627dce2b3d2278e04 + 8d37f7c09008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 00000038436b1ae2723b42982a435ede8f92033fbdf1505e5dac97c1099b5ffd + fc1debda9008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 00000038c31724565adeb2d0e4d6a6980f45b9fd91bb0b858fa8c8ada300e697 + 45d1ab379008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 0000003812789b110b2bf7353d054d978dd30972f2f33e54c4c7b93a1f992d20 + fd2f29619008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 00000038f527dd3ad4938713bff3fb23a62d7b454caf40bc80f3eeed77c3d269 + d9ff8eb69008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 000000388a63a1ed3d671e94aafe29b9ad479340ee04ad1fb5796c73cb71b25a + e8e2b0a49008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 000000384acca1a9694919daee72c0f20b64a2c0103750c26ce9b25cc864609f + 2f4977269008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 00000038bdbeba9388a200bfa8c3f153c31a539622e2994a2cc59bfdc8c562a3 + 2f20b9919008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 000000383649cc08adbf44018756fec310e9348d64139f33530166ef53f1834f + 2f5c8c469008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 0000003864bee671badbb222a43006744c89b70a368ca34a356dcf41f755923e + aab5b4029008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 00000000000000000000000000000000000000000000000000000000000000a4 + ec6cb13f00000000000000000000000000000000000000000000000000000000 + 0000004000000000000000000000000000000000000000000000000000000000 + 0000000100000000000000000000000000000000000000000000000000000000 + 000000382285ea60762c9a58d407e5aa3b8c3287628290793bc7260b0e0324ed + 6f8bb1269008d19f58aabd9ed0d60971565aa8510560ab41678716a000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000060 + 0000000000000000000000000000000000000000000000000000000000000044 + a9059cbb000000000000000000000000a03be496e67ec29bc62f01a428683d7f + 9c2049300000000000000000000000000000000000000000000000002136c5d9 + c1570aef00000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000" + ) + .to_vec(); + + let domain_separator = eth::DomainSeparator(hex!( + "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" + )); + let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( + "9008d19f58aabd9ed0d60971565aa8510560ab41" + ))); + let transaction = super::transaction::Transaction::try_new( + &domain::eth::Transaction { + trace_calls: vec![domain::eth::TraceCall { + to: settlement_contract, + input: calldata.into(), + }], + ..Default::default() + }, + &domain_separator, + settlement_contract, + ) + .unwrap_err(); + + // These transfer transactions don't have the auction_id attached so overall bad + // calldata is expected + assert!(matches!( + transaction, + super::transaction::Error::Decoding(_) + )); + } + // https://etherscan.io/tx/0xc48dc0d43ffb43891d8c3ad7bcf05f11465518a2610869b20b0b4ccb61497634 #[test] fn settlement() { @@ -306,12 +535,19 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let transaction = super::transaction::Transaction::new( + let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( + "9008d19f58aabd9ed0d60971565aa8510560ab41" + ))); + let transaction = super::transaction::Transaction::try_new( &domain::eth::Transaction { - input: calldata.into(), + trace_calls: vec![domain::eth::TraceCall { + to: settlement_contract, + input: calldata.into(), + }], ..Default::default() }, &domain_separator, + settlement_contract, ) .unwrap(); @@ -442,12 +678,19 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let transaction = super::transaction::Transaction::new( + let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( + "9008d19f58aabd9ed0d60971565aa8510560ab41" + ))); + let transaction = super::transaction::Transaction::try_new( &domain::eth::Transaction { - input: calldata.into(), + trace_calls: vec![domain::eth::TraceCall { + to: settlement_contract, + input: calldata.into(), + }], ..Default::default() }, &domain_separator, + settlement_contract, ) .unwrap(); @@ -610,12 +853,19 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let transaction = super::transaction::Transaction::new( + let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( + "9008d19f58aabd9ed0d60971565aa8510560ab41" + ))); + let transaction = super::transaction::Transaction::try_new( &domain::eth::Transaction { - input: calldata.into(), + trace_calls: vec![domain::eth::TraceCall { + to: settlement_contract, + input: calldata.into(), + }], ..Default::default() }, &domain_separator, + settlement_contract, ) .unwrap(); @@ -784,12 +1034,19 @@ mod tests { let domain_separator = eth::DomainSeparator(hex!( "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943" )); - let transaction = super::transaction::Transaction::new( + let settlement_contract = eth::Address(eth::H160::from_slice(&hex!( + "9008d19f58aabd9ed0d60971565aa8510560ab41" + ))); + let transaction = super::transaction::Transaction::try_new( &domain::eth::Transaction { - input: calldata.into(), + trace_calls: vec![domain::eth::TraceCall { + to: settlement_contract, + input: calldata.into(), + }], ..Default::default() }, &domain_separator, + settlement_contract, ) .unwrap(); diff --git a/crates/autopilot/src/domain/settlement/observer.rs b/crates/autopilot/src/domain/settlement/observer.rs index 631539f9ef..d142646728 100644 --- a/crates/autopilot/src/domain/settlement/observer.rs +++ b/crates/autopilot/src/domain/settlement/observer.rs @@ -66,7 +66,8 @@ impl Observer { let transaction = match self.eth.transaction(event.transaction).await { Ok(transaction) => { let separator = self.eth.contracts().settlement_domain_separator(); - settlement::Transaction::new(&transaction, separator) + let settlement_contract = self.eth.contracts().settlement().address().into(); + settlement::Transaction::try_new(&transaction, separator, settlement_contract) } Err(err) => { tracing::warn!(hash = ?event.transaction, ?err, "no tx found"); @@ -95,7 +96,17 @@ impl Observer { (auction_id, settlement) } Err(err) => { - tracing::warn!(hash = ?event.transaction, ?err, "invalid settlement transaction"); + match err { + settlement::transaction::Error::MissingCalldata => { + tracing::error!(hash = ?event.transaction, ?err, "invalid settlement transaction") + } + settlement::transaction::Error::MissingAuctionId + | settlement::transaction::Error::Decoding(_) + | settlement::transaction::Error::SignatureRecover(_) + | settlement::transaction::Error::OrderUidRecover(_) => { + tracing::warn!(hash = ?event.transaction, ?err, "invalid settlement transaction") + } + } // default values so we don't get stuck on invalid settlement transactions (0.into(), None) } diff --git a/crates/autopilot/src/domain/settlement/transaction/mod.rs b/crates/autopilot/src/domain/settlement/transaction/mod.rs index 3b0e3f4540..d5877d00db 100644 --- a/crates/autopilot/src/domain/settlement/transaction/mod.rs +++ b/crates/autopilot/src/domain/settlement/transaction/mod.rs @@ -1,6 +1,10 @@ -use crate::{ - boundary, - domain::{self, auction::order, eth}, +use { + crate::{ + boundary, + domain::{self, auction::order, eth}, + }, + ethcontract::common::FunctionExt, + std::sync::LazyLock, }; mod tokenized; @@ -12,8 +16,6 @@ pub struct Transaction { pub hash: eth::TxId, /// The associated auction id. pub auction_id: domain::auction::Id, - /// The address of the solver that submitted the transaction. - pub solver: eth::Address, /// The block number of the block that contains the transaction. pub block: eth::BlockNo, /// The timestamp of the block that contains the transaction. @@ -27,18 +29,33 @@ pub struct Transaction { } impl Transaction { - pub fn new( + pub fn try_new( transaction: ð::Transaction, domain_separator: ð::DomainSeparator, + settlement_contract: eth::Address, ) -> Result { + // find trace call to settlement contract + let calldata = transaction + .trace_calls + .iter() + .find(|trace| is_settlement_trace(trace, settlement_contract)) + .map(|trace| trace.input.clone()) + // all transactions emitting settlement events should have a /settle call, + // otherwise it's an execution client bug + .ok_or(Error::MissingCalldata)?; + /// Number of bytes that may be appended to the calldata to store an /// auction id. const META_DATA_LEN: usize = 8; - let (data, metadata) = transaction - .input - .0 - .split_at(transaction.input.0.len() - META_DATA_LEN); + let (data, metadata) = calldata.0.split_at( + calldata + .0 + .len() + .checked_sub(META_DATA_LEN) + // should contain at least 4 bytes for function selector and 8 bytes for auction id + .ok_or(Error::MissingCalldata)?, + ); let metadata: Option<[u8; META_DATA_LEN]> = metadata.try_into().ok(); let auction_id = metadata .map(crate::domain::auction::Id::from_be_bytes) @@ -46,7 +63,6 @@ impl Transaction { Ok(Self { hash: transaction.hash, auction_id, - solver: transaction.from, block: transaction.block, timestamp: transaction.timestamp, gas: transaction.gas, @@ -116,6 +132,14 @@ impl Transaction { } } +fn is_settlement_trace(trace: ð::TraceCall, settlement_contract: eth::Address) -> bool { + static SETTLE_FUNCTION_SELECTOR: LazyLock<[u8; 4]> = LazyLock::new(|| { + let abi = &contracts::GPv2Settlement::raw_contract().interface.abi; + abi.function("settle").unwrap().selector() + }); + trace.to == settlement_contract && trace.input.0.starts_with(&*SETTLE_FUNCTION_SELECTOR) +} + /// Trade containing onchain observable data specific to a settlement /// transaction. #[derive(Debug, Clone)] @@ -152,6 +176,8 @@ pub struct ClearingPrices { #[derive(Debug, thiserror::Error)] pub enum Error { + #[error("settle calldata must exist for all transactions emitting settlement event")] + MissingCalldata, #[error("missing auction id")] MissingAuctionId, #[error(transparent)] diff --git a/crates/autopilot/src/infra/blockchain/mod.rs b/crates/autopilot/src/infra/blockchain/mod.rs index 6b8f3234cc..79f0ef1d75 100644 --- a/crates/autopilot/src/infra/blockchain/mod.rs +++ b/crates/autopilot/src/infra/blockchain/mod.rs @@ -103,9 +103,10 @@ impl Ethereum { } pub async fn transaction(&self, hash: eth::TxId) -> Result { - let (transaction, receipt) = tokio::try_join!( + let (transaction, receipt, traces) = tokio::try_join!( self.web3.eth().transaction(hash.0.into()), - self.web3.eth().transaction_receipt(hash.0) + self.web3.eth().transaction_receipt(hash.0), + self.web3.trace().transaction(hash.0), )?; let transaction = transaction.ok_or(Error::TransactionNotFound)?; let receipt = receipt.ok_or(Error::TransactionNotFound)?; @@ -121,13 +122,15 @@ impl Ethereum { .block(block_hash.into()) .await? .ok_or(Error::TransactionNotFound)?; - into_domain(transaction, receipt, block.timestamp).map_err(Error::IncompleteTransactionData) + into_domain(transaction, receipt, traces, block.timestamp) + .map_err(Error::IncompleteTransactionData) } } fn into_domain( transaction: web3::types::Transaction, receipt: web3::types::TransactionReceipt, + traces: Vec, timestamp: U256, ) -> anyhow::Result { Ok(eth::Transaction { @@ -136,7 +139,6 @@ fn into_domain( .from .ok_or(anyhow::anyhow!("missing from"))? .into(), - input: transaction.input.0.into(), block: receipt .block_number .ok_or(anyhow::anyhow!("missing block_number"))? @@ -151,6 +153,16 @@ fn into_domain( .ok_or(anyhow::anyhow!("missing effective_gas_price"))? .into(), timestamp: timestamp.as_u32(), + trace_calls: traces + .into_iter() + .filter_map(|trace| match trace.action { + web3::types::Action::Call(call) => Some(eth::TraceCall { + to: call.to.into(), + input: call.input.0.into(), + }), + _ => None, + }) + .collect(), }) }