From fab0fe4264827041c08711a425349ffa44d614d4 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Wed, 6 Sep 2023 09:47:40 +0200 Subject: [PATCH] Magic: StorageAccessbile Based Simulations (#1831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow up to https://github.com/cowprotocol/services/pull/1827#discussion_r1310425237 - thanks @fleupold for the wonderful idea! This PR changes instances of `eth_call` with state override simulations **where we are only overriding the Settlement contract code** to make use of `StorageAccessible`. It does this with an additional support `Reader` contract in order to avoid needing to manage deployments on-chain for the `StorageAccessible` target (i.e. the reader logic). See the comment in the `Reader.sol` file for more details on how this works. Specifically, we changed the following two simulations to no longer require state overrides (i.e. we do not need a special node to handle those requests, and it will Just Work™ on Gnosis Chain): * Account balance simulations with pre-hooks * ERC-1271 signature validation with pre-hooks In a follow up PRs I will: 1. https://github.com/cowprotocol/services/pull/1832 2. Remove the redundant `Web3` strategy for both account balance and signature verification simulation ### Release notes Hooks E2E test continues to pass **without the nasty `----account-balances-optimistic-pre-interaction-handling=true` hack** which used to disable balance checks for orders with pre-hooks. This means that not only are we E2E testing that executing orders with pre-hooks are working, we are also checking that balance simulations work 🎉. You can double check this is actually doing something by applying a patch like this: ```diff diff --git a/crates/e2e/tests/e2e/hooks.rs b/crates/e2e/tests/e2e/hooks.rs index 42d8d072..84d978b5 100644 --- a/crates/e2e/tests/e2e/hooks.rs +++ b/crates/e2e/tests/e2e/hooks.rs @@ -66,7 +66,7 @@ async fn test(web3: Web3) { full: json!({ "metadata": { "hooks": { - "pre": [permit, steal_cow], + "pre": [/*permit, */steal_cow], "post": [steal_weth], }, }, ``` And see the E2E test fail as expected with: ``` thread 'hooks::local_node_test' panicked at 'called `Result::unwrap()` on an `Err` value: (400, "{\"errorType\":\"InsufficientAllowance\",\"description\":\"order owner must give allowance to VaultRelayer\"}")', crates/e2e/tests/e2e/hooks.rs:83:41 ``` I also ran the `cargo test -p shared -- --nocapture --ignored account_balances::simulation` manual test which continues to work. --- crates/autopilot/src/lib.rs | 10 --- crates/contracts/artifacts/SimulateCode.json | 1 + crates/contracts/build.rs | 5 +- crates/contracts/solidity/Makefile | 9 ++- crates/contracts/solidity/SimulateCode.sol | 46 ++++++++++++ .../interfaces/IStorageAccessible.sol | 7 ++ crates/contracts/src/lib.rs | 4 +- crates/contracts/src/storage_accessible.rs | 41 +++++++++++ crates/e2e/tests/e2e/colocation_hooks.rs | 4 +- crates/e2e/tests/e2e/hooks.rs | 8 +-- crates/orderbook/src/run.rs | 10 --- .../shared/src/account_balances/arguments.rs | 72 +++---------------- .../shared/src/account_balances/simulation.rs | 47 +++++------- .../src/signature_validator/arguments.rs | 61 ++-------------- .../src/signature_validator/simulation.rs | 40 ++++------- crates/solver/src/run.rs | 8 --- 16 files changed, 158 insertions(+), 215 deletions(-) create mode 100644 crates/contracts/artifacts/SimulateCode.json create mode 100644 crates/contracts/solidity/SimulateCode.sol create mode 100644 crates/contracts/solidity/interfaces/IStorageAccessible.sol create mode 100644 crates/contracts/src/storage_accessible.rs diff --git a/crates/autopilot/src/lib.rs b/crates/autopilot/src/lib.rs index 5ee54e8615..4aadc2d34d 100644 --- a/crates/autopilot/src/lib.rs +++ b/crates/autopilot/src/lib.rs @@ -172,11 +172,6 @@ pub async fn main(args: arguments::Arguments) { vault_relayer, }, web3.clone(), - simulation_web3.clone(), - args.shared - .tenderly - .get_api_instance(&http_factory, "signature_validating".into()) - .unwrap(), ); let balance_fetcher = args.shared.balances.cached( @@ -187,11 +182,6 @@ pub async fn main(args: arguments::Arguments) { vault: vault.as_ref().map(|contract| contract.address()), }, web3.clone(), - simulation_web3.clone(), - args.shared - .tenderly - .get_api_instance(&http_factory, "balance_fetching".into()) - .unwrap(), current_block_stream.clone(), ); diff --git a/crates/contracts/artifacts/SimulateCode.json b/crates/contracts/artifacts/SimulateCode.json new file mode 100644 index 0000000000..dcea76fb67 --- /dev/null +++ b/crates/contracts/artifacts/SimulateCode.json @@ -0,0 +1 @@ +{"abi":[{"inputs":[{"internalType":"contract IStorageAccessible","name":"target","type":"address"},{"internalType":"bytes","name":"code","type":"bytes"},{"internalType":"bytes","name":"call","type":"bytes"}],"stateMutability":"nonpayable","type":"constructor"}],"bytecode":"0x608060405234801561001057600080fd5b5060405161027e38038061027e83398101604081905261002f9161017d565b600082516020840134f090506000846001600160a01b031663f84436bd83856040518363ffffffff1660e01b815260040161006b9291906101ff565b6000604051808303816000875af115801561008a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526100b29190810190610241565b9050805181602001f35b634e487b7160e01b600052604160045260246000fd5b60005b838110156100ed5781810151838201526020016100d5565b50506000910152565b600082601f83011261010757600080fd5b81516001600160401b0380821115610121576101216100bc565b604051601f8301601f19908116603f01168101908282118183101715610149576101496100bc565b8160405283815286602085880101111561016257600080fd5b6101738460208301602089016100d2565b9695505050505050565b60008060006060848603121561019257600080fd5b83516001600160a01b03811681146101a957600080fd5b60208501519093506001600160401b03808211156101c657600080fd5b6101d2878388016100f6565b935060408601519150808211156101e857600080fd5b506101f5868287016100f6565b9150509250925092565b60018060a01b0383168152604060208201526000825180604084015261022c8160608501602087016100d2565b601f01601f1916919091016060019392505050565b60006020828403121561025357600080fd5b81516001600160401b0381111561026957600080fd5b610275848285016100f6565b94935050505056fe","deployedBytecode":"0x6080604052600080fdfea164736f6c6343000811000a","devdoc":{"methods":{}},"userdoc":{"methods":{}}} diff --git a/crates/contracts/build.rs b/crates/contracts/build.rs index be132705de..1db7aeaebf 100644 --- a/crates/contracts/build.rs +++ b/crates/contracts/build.rs @@ -523,11 +523,10 @@ fn main() { generate_contract("Trader"); generate_contract("Solver"); - // Support contract used for balance simulation. + // Support contracts used for various order simulations. generate_contract("Balances"); - - // Support contract used for ERC-1271 signature verification simulation. generate_contract("Signatures"); + generate_contract("SimulateCode"); // Support contract used for global block stream. generate_contract("FetchBlock"); diff --git a/crates/contracts/solidity/Makefile b/crates/contracts/solidity/Makefile index 4c37f0c0ba..f9fa3b9073 100644 --- a/crates/contracts/solidity/Makefile +++ b/crates/contracts/solidity/Makefile @@ -7,7 +7,14 @@ SOLFLAGS := --overwrite --abi --bin --bin-runtime --metadata-hash none --optimiz TARGETDIR := ../../../target/solidity ARTIFACTDIR := ../artifacts -CONTRACTS := Balances.sol FetchBlock.sol Multicall.sol Trader.sol Signatures.sol Solver.sol +CONTRACTS := \ + Balances.sol \ + FetchBlock.sol \ + Multicall.sol \ + Signatures.sol \ + SimulateCode.sol \ + Solver.sol \ + Trader.sol ARTIFACTS := $(patsubst %.sol,$(ARTIFACTDIR)/%.json,$(CONTRACTS)) .PHONY: artifacts diff --git a/crates/contracts/solidity/SimulateCode.sol b/crates/contracts/solidity/SimulateCode.sol new file mode 100644 index 0000000000..771d873c71 --- /dev/null +++ b/crates/contracts/solidity/SimulateCode.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import { IStorageAccessible } from "./interfaces/IStorageAccessible.sol"; + +/// @title A contract for simulating arbitrary code in the context of a +/// `StorageAccessible` contract. +contract SimulateCode { + /// @dev This looks like a constructor but it is not... In fact, nodes + /// support `eth_call`s for contract creation and **return the code of the + /// contract that would be created**. This means we can use constructors to + /// execute arbitrary code on the current state of the EVM, and "manually" + /// return with some inline assembly that data (as this is the mechanism + /// used for contract creation). See the `FetchBlock.sol` contract for + /// another application of this trick. + /// + /// The contract does this to: + /// 1. Deploy some arbitrary contract code + /// 2. Use the `StorageAccessible` pattern to execute the contract code + /// deployed in step 1. within the another contract context (usually the + /// settlement contract - which implements this pattern) + /// + /// This allows us to make use of `StorageAccessible` without actually + /// deploying a contract :). + /// + /// Returns the return data from the simulation code. + /// + /// @param target - The `StorageAccessible` implementation. + /// @param code - Creation code for the reader contract. + /// @param call - The calldata to pass in the `DELEGATECALL` simulation. + constructor( + IStorageAccessible target, + bytes memory code, + bytes memory call + ) { + address implementation; + assembly { + implementation := create(callvalue(), add(code, 32), mload(code)) + } + + bytes memory result = target.simulateDelegatecall(implementation, call); + assembly { + return(add(32, result), mload(result)) + } + } +} diff --git a/crates/contracts/solidity/interfaces/IStorageAccessible.sol b/crates/contracts/solidity/interfaces/IStorageAccessible.sol new file mode 100644 index 0000000000..5cded05b1d --- /dev/null +++ b/crates/contracts/solidity/interfaces/IStorageAccessible.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +/// @title Storage accessible interface. +interface IStorageAccessible { + function simulateDelegatecall(address reader, bytes memory call) external returns (bytes memory result); +} diff --git a/crates/contracts/src/lib.rs b/crates/contracts/src/lib.rs index bc8400ea9b..9d445a5606 100644 --- a/crates/contracts/src/lib.rs +++ b/crates/contracts/src/lib.rs @@ -7,6 +7,7 @@ mod macros; #[cfg(feature = "bin")] pub mod paths; +pub mod storage_accessible; pub mod vault; pub mod web3; @@ -71,9 +72,10 @@ pub mod support { Balances; FetchBlock; Multicall; - Trader; Signatures; + SimulateCode; Solver; + Trader; } } diff --git a/crates/contracts/src/storage_accessible.rs b/crates/contracts/src/storage_accessible.rs new file mode 100644 index 0000000000..e0c38b7cd4 --- /dev/null +++ b/crates/contracts/src/storage_accessible.rs @@ -0,0 +1,41 @@ +//! Module to help encoding `eth_call`s for the `StorageAccessible` contracts. + +use { + crate::support::SimulateCode, + ethcontract::{ + common::abi, + tokens::Tokenize, + web3::types::{Bytes, CallRequest}, + H160, + }, +}; + +/// Encode a call to a `StorageAccessible` `target` to execute `call` with the +/// contract created with `code` +pub fn call(target: H160, code: Bytes, call: Bytes) -> CallRequest { + // Unfortunately, the `ethcontract` crate does not expose the logic to build + // creation code for a contract. Luckily, it isn't complicated - you just + // append the ABI-encoded constructor arguments. + let args = abi::encode(&[ + target.into_token(), + ethcontract::Bytes(code.0).into_token(), + ethcontract::Bytes(call.0).into_token(), + ]); + + CallRequest { + data: Some( + [ + SimulateCode::raw_contract() + .bytecode + .to_bytes() + .unwrap() + .0 + .as_slice(), + &args, + ] + .concat() + .into(), + ), + ..Default::default() + } +} diff --git a/crates/e2e/tests/e2e/colocation_hooks.rs b/crates/e2e/tests/e2e/colocation_hooks.rs index 279b463fab..2f53213957 100644 --- a/crates/e2e/tests/e2e/colocation_hooks.rs +++ b/crates/e2e/tests/e2e/colocation_hooks.rs @@ -51,14 +51,14 @@ async fn test(web3: Web3) { let services = Services::new(onchain.contracts()).await; services.start_autopilot(vec![ - "--account-balances-optimistic-pre-interaction-handling=true".to_string(), + "--account-balances=simulation".to_string(), "--enable-colocation=true".to_string(), "--drivers=http://localhost:11088/test_solver".to_string(), ]); services .start_api(vec![ + "--account-balances=simulation".to_string(), "--enable-custom-interactions=true".to_string(), - "--account-balances-optimistic-pre-interaction-handling=true".to_string(), ]) .await; diff --git a/crates/e2e/tests/e2e/hooks.rs b/crates/e2e/tests/e2e/hooks.rs index 2015e3767f..42d8d072bd 100644 --- a/crates/e2e/tests/e2e/hooks.rs +++ b/crates/e2e/tests/e2e/hooks.rs @@ -46,13 +46,11 @@ async fn test(web3: Web3) { .await; let services = Services::new(onchain.contracts()).await; - services.start_autopilot(vec![ - "--account-balances-optimistic-pre-interaction-handling=true".to_string(), - ]); + services.start_autopilot(vec!["--account-balances=simulation".to_string()]); services .start_api(vec![ + "--account-balances=simulation".to_string(), "--enable-custom-interactions=true".to_string(), - "--account-balances-optimistic-pre-interaction-handling=true".to_string(), ]) .await; @@ -90,7 +88,7 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); services.start_old_driver( solver.private_key(), - vec!["--account-balances-optimistic-pre-interaction-handling=true".to_string()], + vec!["--account-balances=simulation".to_string()], ); let trade_happened = || async { cow.balance_of(trader.address()) diff --git a/crates/orderbook/src/run.rs b/crates/orderbook/src/run.rs index 3efa5ba407..e2afc75d38 100644 --- a/crates/orderbook/src/run.rs +++ b/crates/orderbook/src/run.rs @@ -116,11 +116,6 @@ pub async fn run(args: Arguments) { vault_relayer, }, web3.clone(), - simulation_web3.clone(), - args.shared - .tenderly - .get_api_instance(&http_factory, "signature_validating".into()) - .unwrap(), ); let vault = match args.shared.balancer_v2_vault_address { @@ -158,11 +153,6 @@ pub async fn run(args: Arguments) { vault: vault.as_ref().map(|contract| contract.address()), }, web3.clone(), - simulation_web3.clone(), - args.shared - .tenderly - .get_api_instance(&http_factory, "balance_fetching".into()) - .unwrap(), ); let gas_price_estimator = Arc::new(InstrumentedGasEstimator::new( diff --git a/crates/shared/src/account_balances/arguments.rs b/crates/shared/src/account_balances/arguments.rs index 3ee3a5bbc3..0e94057c16 100644 --- a/crates/shared/src/account_balances/arguments.rs +++ b/crates/shared/src/account_balances/arguments.rs @@ -1,10 +1,5 @@ use { super::{BalanceFetching, CachingBalanceFetcher, SimulationBalanceFetcher, Web3BalanceFetcher}, - crate::{ - arguments::{display_option, CodeSimulatorKind}, - code_simulation::{CodeSimulating, TenderlyCodeSimulator, Web3ThenTenderly}, - tenderly_api::TenderlyApi, - }, ethcontract::H160, ethrpc::{current_block::CurrentBlockStream, Web3}, std::{ @@ -21,11 +16,6 @@ pub struct Arguments { #[clap(long, env, default_value = "web3", value_enum)] pub account_balances: Strategy, - /// The code simulation implementation to use. Can be one of `Web3`, - /// `Tenderly` or `Web3ThenTenderly`. - #[clap(long, env, value_enum)] - pub account_balances_simulator: Option, - /// Whether or not to optimistically treat account balance queries with /// pre-interactions as if sufficient token balance and allowance is always /// available. Useful for partially supporting pre-interactions in @@ -60,13 +50,7 @@ pub struct Contracts { } impl Arguments { - pub fn fetcher( - &self, - contracts: Contracts, - web3: Web3, - simulation_web3: Option, - tenderly: Option>, - ) -> Arc { + pub fn fetcher(&self, contracts: Contracts, web3: Web3) -> Arc { match self.account_balances { Strategy::Web3 => Arc::new(Web3BalanceFetcher::new( web3, @@ -75,37 +59,12 @@ impl Arguments { contracts.settlement, self.account_balances_optimistic_pre_interaction_handling, )), - Strategy::Simulation => { - let web3_simulator = - move || simulation_web3.expect("simulation web3 not configured"); - let tenderly_simulator = move || { - TenderlyCodeSimulator::new( - tenderly.expect("tenderly api not configured"), - contracts.chain_id, - ) - }; - - let simulator = match self - .account_balances_simulator - .expect("account balances simulator not configured") - { - CodeSimulatorKind::Web3 => { - Arc::new(web3_simulator()) as Arc - } - CodeSimulatorKind::Tenderly => Arc::new(tenderly_simulator()), - CodeSimulatorKind::Web3ThenTenderly => Arc::new(Web3ThenTenderly::new( - web3_simulator(), - tenderly_simulator(), - )), - }; - - Arc::new(SimulationBalanceFetcher::new( - simulator, - contracts.settlement, - contracts.vault_relayer, - contracts.vault, - )) - } + Strategy::Simulation => Arc::new(SimulationBalanceFetcher::new( + web3, + contracts.settlement, + contracts.vault_relayer, + contracts.vault, + )), } } @@ -113,16 +72,9 @@ impl Arguments { &self, contracts: Contracts, web3: Web3, - simulation_web3: Option, - tenderly: Option>, blocks: CurrentBlockStream, ) -> Arc { - let cached = Arc::new(CachingBalanceFetcher::new(self.fetcher( - contracts, - web3, - simulation_web3, - tenderly, - ))); + let cached = Arc::new(CachingBalanceFetcher::new(self.fetcher(contracts, web3))); cached.spawn_background_task(blocks); cached } @@ -131,14 +83,6 @@ impl Arguments { impl Display for Arguments { fn fmt(&self, f: &mut Formatter) -> fmt::Result { writeln!(f, "account_balances: {:?}", self.account_balances)?; - display_option( - f, - "account_balances_simulator", - &self - .account_balances_simulator - .as_ref() - .map(|value| format!("{value:?}")), - )?; Ok(()) } diff --git a/crates/shared/src/account_balances/simulation.rs b/crates/shared/src/account_balances/simulation.rs index c64b89b55d..16b5da407f 100644 --- a/crates/shared/src/account_balances/simulation.rs +++ b/crates/shared/src/account_balances/simulation.rs @@ -4,31 +4,22 @@ use { super::{BalanceFetching, Query, TransferSimulationError}, - crate::code_simulation::CodeSimulating, anyhow::{Context, Result}, - contracts::{deployed_bytecode, dummy_contract}, ethcontract::{tokens::Tokenize, Bytes, H160, U256}, - ethrpc::extensions::StateOverride, + ethrpc::Web3, futures::future, - maplit::hashmap, - std::sync::Arc, - web3::{ethabi::Token, types::CallRequest}, + web3::ethabi::Token, }; pub struct Balances { - simulator: Arc, + web3: Web3, settlement: H160, vault_relayer: H160, vault: H160, } impl Balances { - pub fn new( - simulator: Arc, - settlement: H160, - vault_relayer: H160, - vault: Option, - ) -> Self { + pub fn new(web3: Web3, settlement: H160, vault_relayer: H160, vault: Option) -> Self { // Note that the balances simulation **will fail** if the `vault` // address is not a contract and the `source` is set to one of // `SellTokenSource::{External, Internal}` (i.e. the Vault contract is @@ -39,7 +30,7 @@ impl Balances { let vault = vault.unwrap_or_default(); Self { - simulator, + web3, settlement, vault_relayer, vault, @@ -54,7 +45,7 @@ impl Balances { // settlement // // This allows us to end up with very accurate balance simulations. - let balances = dummy_contract!(contracts::support::Balances, self.settlement); + let balances = contracts::dummy_contract!(contracts::support::Balances, self.settlement); let tx = balances .methods() .balance( @@ -71,20 +62,14 @@ impl Balances { ) .tx; - let call = CallRequest { - to: tx.to, - data: tx.data, - ..Default::default() - }; - let overrides = hashmap! { - balances.address() => StateOverride { - code: Some(deployed_bytecode!(contracts::support::Balances)), - ..Default::default() - }, - }; - - let output = self.simulator.simulate(call, overrides).await?; - let simulation = Simulation::decode(&output)?; + let call = contracts::storage_accessible::call( + self.settlement, + contracts::bytecode!(contracts::support::Balances), + tx.data.unwrap(), + ); + + let output = self.web3.eth().call(call, None).await?; + let simulation = Simulation::decode(&output.0)?; tracing::trace!(?query, ?amount, ?simulation, "simulated balances"); Ok(simulation) @@ -170,7 +155,7 @@ mod tests { #[tokio::test] async fn test_for_user() { let balances = Balances::new( - Arc::new(Web3::new(ethrpc::create_env_test_transport())), + Web3::new(ethrpc::create_env_test_transport()), addr!("9008d19f58aabd9ed0d60971565aa8510560ab41"), addr!("C92E8bdf79f0507f65a392b0ab4667716BFE0110"), Some(addr!("BA12222222228d8Ba445958a75a0704d566BF2C8")), @@ -193,6 +178,6 @@ mod tests { ) .await .unwrap(); - println!("{owner} can transfer {amount} {token}!"); + println!("{owner:?} can transfer {amount} {token:?}!"); } } diff --git a/crates/shared/src/signature_validator/arguments.rs b/crates/shared/src/signature_validator/arguments.rs index 1140a4e53a..7b6fde1782 100644 --- a/crates/shared/src/signature_validator/arguments.rs +++ b/crates/shared/src/signature_validator/arguments.rs @@ -1,10 +1,5 @@ use { super::{SignatureValidating, SimulationSignatureValidator, Web3SignatureValidator}, - crate::{ - arguments::{display_option, CodeSimulatorKind}, - code_simulation::{CodeSimulating, TenderlyCodeSimulator, Web3ThenTenderly}, - tenderly_api::TenderlyApi, - }, ethcontract::H160, ethrpc::Web3, std::{ @@ -20,11 +15,6 @@ pub struct Arguments { /// The ERC-1271 signature validation strategy to use. #[clap(long, env, default_value = "web3", value_enum)] pub eip1271_signature_validator: Strategy, - - /// The code simulation implementation to use. Can be one of `Web3`, - /// `Tenderly` or `Web3ThenTenderly`. - #[clap(long, env, value_enum)] - pub eip1271_signature_validator_simulator: Option, } /// Support token owner finding strategies. @@ -51,45 +41,14 @@ pub struct Contracts { } impl Arguments { - pub fn validator( - &self, - contracts: Contracts, - web3: Web3, - simulation_web3: Option, - tenderly: Option>, - ) -> Arc { + pub fn validator(&self, contracts: Contracts, web3: Web3) -> Arc { match self.eip1271_signature_validator { Strategy::Web3 => Arc::new(Web3SignatureValidator::new(web3)), - Strategy::Simulation => { - let web3_simulator = - move || simulation_web3.expect("simulation web3 not configured"); - let tenderly_simulator = move || { - TenderlyCodeSimulator::new( - tenderly.expect("tenderly api not configured"), - contracts.chain_id, - ) - }; - - let simulator = match self - .eip1271_signature_validator_simulator - .expect("ERC-1271 signature validator simulator not configured") - { - CodeSimulatorKind::Web3 => { - Arc::new(web3_simulator()) as Arc - } - CodeSimulatorKind::Tenderly => Arc::new(tenderly_simulator()), - CodeSimulatorKind::Web3ThenTenderly => Arc::new(Web3ThenTenderly::new( - web3_simulator(), - tenderly_simulator(), - )), - }; - - Arc::new(SimulationSignatureValidator::new( - simulator, - contracts.settlement, - contracts.vault_relayer, - )) - } + Strategy::Simulation => Arc::new(SimulationSignatureValidator::new( + web3, + contracts.settlement, + contracts.vault_relayer, + )), } } } @@ -101,14 +60,6 @@ impl Display for Arguments { "eip1271_signature_validator: {:?}", self.eip1271_signature_validator )?; - display_option( - f, - "eip1271_signature_validator_simulator", - &self - .eip1271_signature_validator_simulator - .as_ref() - .map(|value| format!("{value:?}")), - )?; Ok(()) } diff --git a/crates/shared/src/signature_validator/simulation.rs b/crates/shared/src/signature_validator/simulation.rs index 41863c8406..dbe4bbb521 100644 --- a/crates/shared/src/signature_validator/simulation.rs +++ b/crates/shared/src/signature_validator/simulation.rs @@ -5,27 +5,23 @@ use { super::{SignatureCheck, SignatureValidating, SignatureValidationError}, - crate::code_simulation::{CodeSimulating, SimulationError}, anyhow::{Context, Result}, ethcontract::{common::abi::Token, tokens::Tokenize, Bytes}, - ethrpc::extensions::StateOverride, + ethrpc::Web3, futures::future, - maplit::hashmap, primitive_types::{H160, U256}, - std::sync::Arc, - web3::types::CallRequest, }; pub struct Validator { - simulator: Arc, + web3: Web3, settlement: H160, vault_relayer: H160, } impl Validator { - pub fn new(simulator: Arc, settlement: H160, vault_relayer: H160) -> Self { + pub fn new(web3: Web3, settlement: H160, vault_relayer: H160) -> Self { Self { - simulator, + web3, settlement, vault_relayer, } @@ -57,20 +53,14 @@ impl Validator { ) .tx; - let call = CallRequest { - to: tx.to, - data: tx.data, - ..Default::default() - }; - let overrides = hashmap! { - signatures.address() => StateOverride { - code: Some(contracts::deployed_bytecode!(contracts::support::Signatures)), - ..Default::default() - }, - }; - - let output = self.simulator.simulate(call, overrides).await?; - let simulation = Simulation::decode(&output)?; + let call = contracts::storage_accessible::call( + self.settlement, + contracts::bytecode!(contracts::support::Signatures), + tx.data.unwrap(), + ); + + let output = self.web3.eth().call(call, None).await?; + let simulation = Simulation::decode(&output.0)?; tracing::trace!(?check, ?simulation, "simulated signatures"); match simulation.result { @@ -131,7 +121,7 @@ impl Simulation { fn decode(output: &[u8]) -> Result { let function = contracts::support::Signatures::raw_contract() .abi - .function("balance") + .function("validate") .unwrap(); let tokens = function.decode_output(output).context("decode")?; let (result, gas_used) = Tokenize::from_token(Token::Tuple(tokens))?; @@ -154,8 +144,8 @@ impl SimulationResult { } } -impl From for SignatureValidationError { - fn from(err: SimulationError) -> Self { +impl From for SignatureValidationError { + fn from(err: web3::error::Error) -> Self { Self::Other(err.into()) } } diff --git a/crates/solver/src/run.rs b/crates/solver/src/run.rs index a0f244709b..3b499838d0 100644 --- a/crates/solver/src/run.rs +++ b/crates/solver/src/run.rs @@ -78,9 +78,6 @@ pub async fn run(args: Arguments) { &args.shared.node_url, "base", ); - let simulation_web3 = args.shared.simulation_node_url.as_ref().map(|node_url| { - shared::ethrpc::web3(&args.shared.ethrpc, &http_factory, node_url, "simulation") - }); let chain_id = web3 .eth() @@ -544,11 +541,6 @@ pub async fn run(args: Arguments) { vault: vault_contract.as_ref().map(|contract| contract.address()), }, web3.clone(), - simulation_web3.clone(), - args.shared - .tenderly - .get_api_instance(&http_factory, "balance_fetching".into()) - .unwrap(), ); let mut driver = Driver::new(