From b3e5de093f1a44b7542de36493c869176444cadb Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Wed, 14 Feb 2024 17:03:11 -0400 Subject: [PATCH 01/19] chore: add alloy contract --- Cargo.lock | 1 + crates/cast/Cargo.toml | 2 ++ crates/cast/bin/cmd/storage.rs | 46 +++++++++++++++------------------- crates/cast/src/lib.rs | 22 ++++++++++------ 4 files changed, 37 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af9328a22583..dfc5ffee96eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1257,6 +1257,7 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" name = "cast" version = "0.2.0" dependencies = [ + "alloy-consensus", "alloy-contract", "alloy-dyn-abi", "alloy-json-abi", diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index e97ae59c5241..1f5cbadba89c 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -33,6 +33,8 @@ alloy-rlp.workspace = true alloy-providers.workspace = true alloy-rpc-types.workspace = true alloy-signer.workspace = true +alloy-contract.workspace = true +alloy-consensus.workspace = true ethers-core.workspace = true ethers-providers.workspace = true diff --git a/crates/cast/bin/cmd/storage.rs b/crates/cast/bin/cmd/storage.rs index e1a033a0f463..7b31690050e6 100644 --- a/crates/cast/bin/cmd/storage.rs +++ b/crates/cast/bin/cmd/storage.rs @@ -1,10 +1,10 @@ use crate::opts::parse_slot; -use alloy_primitives::{B256, U256}; +use alloy_primitives::{Address, B256, U256}; +use alloy_providers::provider::TempProvider; +use alloy_rpc_types::BlockId; use cast::Cast; use clap::Parser; use comfy_table::{presets::ASCII_MARKDOWN, Table}; -use ethers_core::types::{BlockId, NameOrAddress}; -use ethers_providers::Middleware; use eyre::Result; use foundry_block_explorers::Client; use foundry_cli::{ @@ -14,8 +14,7 @@ use foundry_cli::{ use foundry_common::{ abi::find_source, compile::{etherscan_project, ProjectCompiler}, - provider::ethers::RetryProvider, - types::{ToAlloy, ToEthers}, + ens::NameOrAddress, }; use foundry_compilers::{ artifacts::StorageLayout, Artifact, ConfigurableContractArtifact, Project, Solc, @@ -80,20 +79,20 @@ impl StorageArgs { let config = Config::from(&self); let Self { address, slot, block, build, .. } = self; - - let provider = utils::get_provider(&config)?; - let alloy_provider = utils::get_alloy_provider(&config)?; + let provider = utils::get_alloy_provider(&config)?; + let ethers_provider = utils::get_provider(&config)?; + let address = address.resolve(&provider).await?; // Slot was provided, perform a simple RPC call if let Some(slot) = slot { - let cast = Cast::new(provider, alloy_provider); - println!("{}", cast.storage(address, slot.to_ethers(), block).await?); + let cast = Cast::new(ethers_provider, provider); + println!("{}", cast.storage(address, slot, block).await?); return Ok(()); } // No slot was provided // Get deployed bytecode at given address - let address_code = provider.get_code(address.clone(), block).await?.to_alloy(); + let address_code = provider.get_code_at(address, block).await?; if address_code.is_empty() { eyre::bail!("Provided address has no deployed code and thus no storage"); } @@ -121,14 +120,10 @@ impl StorageArgs { eyre::bail!("You must provide an Etherscan API key if you're fetching a remote contract's storage."); } - let chain = utils::get_chain(config.chain, &provider).await?; + let chain = utils::get_chain(config.chain, ðers_provider).await?; let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); let client = Client::new(chain, api_key)?; - let addr = address - .as_address() - .ok_or_else(|| eyre::eyre!("Could not resolve address"))? - .to_alloy(); - let source = find_source(client, addr).await?; + let source = find_source(client, address).await?; let metadata = source.items.first().unwrap(); if metadata.is_vyper() { eyre::bail!("Contract at provided address is not a valid Solidity contract") @@ -210,9 +205,9 @@ impl StorageValue { } } -async fn fetch_and_print_storage( - provider: RetryProvider, - address: NameOrAddress, +async fn fetch_and_print_storage( + provider: P, + address: Address, block: Option, artifact: &ConfigurableContractArtifact, pretty: bool, @@ -227,18 +222,17 @@ async fn fetch_and_print_storage( } } -async fn fetch_storage_slots( - provider: RetryProvider, - address: NameOrAddress, +async fn fetch_storage_slots( + provider: P, + address: Address, block: Option, layout: &StorageLayout, ) -> Result> { let requests = layout.storage.iter().map(|storage_slot| async { let slot = B256::from(U256::from_str(&storage_slot.slot)?); - let raw_slot_value = - provider.get_storage_at(address.clone(), slot.to_ethers(), block).await?.to_alloy(); + let raw_slot_value = provider.get_storage_at(address.clone(), slot.into(), block).await?; - let value = StorageValue { slot, raw_slot_value }; + let value = StorageValue { slot, raw_slot_value: raw_slot_value.into() }; Ok(value) }); diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 8467fd8de637..91cf546cac2c 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -6,7 +6,7 @@ use alloy_primitives::{ }; use alloy_providers::provider::TempProvider; use alloy_rlp::Decodable; -use alloy_rpc_types::{BlockHashOrNumber, BlockNumberOrTag}; +use alloy_rpc_types::{BlockHashOrNumber, BlockId as AlloyBlockId, BlockNumberOrTag}; use base::{Base, NumberWithBase, ToBase}; use chrono::NaiveDateTime; use ethers_core::{ @@ -22,6 +22,7 @@ use eyre::{Context, ContextCompat, Result}; use foundry_block_explorers::Client; use foundry_common::{ abi::{encode_function_args, get_func}, + ens::NameOrAddress as ENSNameOrAddress, fmt::*, types::{ToAlloy, ToEthers}, TransactionReceiptWithRevertReason, @@ -33,7 +34,10 @@ use std::{ io, path::PathBuf, str::FromStr, - sync::atomic::{AtomicBool, Ordering}, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, }; use tokio::signal::ctrl_c; use tx::{TxBuilderOutput, TxBuilderPeekOutput}; @@ -57,7 +61,7 @@ use rlp_converter::Item; pub struct Cast { provider: M, - alloy_provider: P, + alloy_provider: Arc

, } impl Cast @@ -79,7 +83,7 @@ where /// # } /// ``` pub fn new(provider: M, alloy_provider: P) -> Self { - Self { provider, alloy_provider } + Self { provider, alloy_provider: Arc::new(alloy_provider) } } /// Makes a read-only call to the specified address @@ -789,13 +793,15 @@ where /// # Ok(()) /// # } /// ``` - pub async fn storage + Send + Sync>( + pub async fn storage + Send + Sync>( &self, from: T, - slot: H256, - block: Option, + slot: B256, + block: Option, ) -> Result { - Ok(format!("{:?}", self.provider.get_storage_at(from, slot, block).await?)) + let from: ENSNameOrAddress = from.into(); + let from = from.resolve(&self.alloy_provider).await?; + Ok(format!("{:?}", self.alloy_provider.get_storage_at(from, slot.into(), block).await?)) } pub async fn filter_logs(&self, filter: Filter, to_json: bool) -> Result { From 7b35383ac4ba4dc7008f87ea681bbd2e6337c99d Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Wed, 14 Feb 2024 17:03:29 -0400 Subject: [PATCH 02/19] feat(cast): migrate most methods to alloy --- crates/cast/bin/cmd/logs.rs | 6 +-- crates/cast/bin/cmd/storage.rs | 7 ++- crates/cast/bin/main.rs | 23 +++++--- crates/cast/bin/opts.rs | 38 +++++++------- crates/cast/src/lib.rs | 95 ++++++++++++++-------------------- crates/common/src/types.rs | 16 ++++++ 6 files changed, 95 insertions(+), 90 deletions(-) diff --git a/crates/cast/bin/cmd/logs.rs b/crates/cast/bin/cmd/logs.rs index fc195b63fcf7..5021b7a3ffa6 100644 --- a/crates/cast/bin/cmd/logs.rs +++ b/crates/cast/bin/cmd/logs.rs @@ -1,4 +1,4 @@ -use alloy_rpc_types::BlockHashOrNumber; +use alloy_rpc_types::BlockId; use cast::Cast; use clap::Parser; use ethers_core::{ @@ -23,13 +23,13 @@ pub struct LogsArgs { /// /// Can also be the tags earliest, finalized, safe, latest, or pending. #[clap(long)] - from_block: Option, + from_block: Option, /// The block height to stop query at. /// /// Can also be the tags earliest, finalized, safe, latest, or pending. #[clap(long)] - to_block: Option, + to_block: Option, /// The contract address to filter on. #[clap( diff --git a/crates/cast/bin/cmd/storage.rs b/crates/cast/bin/cmd/storage.rs index 7b31690050e6..a7047f52dc6e 100644 --- a/crates/cast/bin/cmd/storage.rs +++ b/crates/cast/bin/cmd/storage.rs @@ -107,8 +107,7 @@ impl StorageArgs { artifact.get_deployed_bytecode_bytes().is_some_and(|b| *b == address_code) }); if let Some((_, artifact)) = artifact { - return fetch_and_print_storage(provider, address.clone(), block, artifact, true) - .await; + return fetch_and_print_storage(provider, address, block, artifact, true).await; } } @@ -230,7 +229,7 @@ async fn fetch_storage_slots( ) -> Result> { let requests = layout.storage.iter().map(|storage_slot| async { let slot = B256::from(U256::from_str(&storage_slot.slot)?); - let raw_slot_value = provider.get_storage_at(address.clone(), slot.into(), block).await?; + let raw_slot_value = provider.get_storage_at(address, slot.into(), block).await?; let value = StorageValue { slot, raw_slot_value: raw_slot_value.into() }; @@ -261,7 +260,7 @@ fn print_storage(layout: StorageLayout, values: Vec, pretty: bool) storage_type.map_or("?", |t| &t.label), &slot.slot, &slot.offset.to_string(), - &storage_type.map_or("?", |t| &t.number_of_bytes), + (storage_type.map_or("?", |t| &t.number_of_bytes)), &converted_value.to_string(), &value.to_string(), &slot.contract, diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 96d3a30ad440..a6b3f68d023d 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -1,7 +1,9 @@ #[macro_use] extern crate tracing; +use alloy_consensus::{TxEnvelope, TxType}; use alloy_primitives::{keccak256, Address, B256}; +use alloy_rpc_types::Transaction; use cast::{Cast, SimpleCast, TxBuilder}; use clap::{CommandFactory, Parser}; use clap_complete::generate; @@ -209,6 +211,7 @@ async fn main() -> Result<()> { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let alloy_provider = utils::get_alloy_provider(&config)?; + let account_addr = who.resolve(&alloy_provider).await?; match erc20 { Some(token) => { @@ -222,11 +225,6 @@ async fn main() -> Result<()> { ) .await?; - let account_addr = match who { - NameOrAddress::Name(ens_name) => provider.resolve_name(&ens_name).await?, - NameOrAddress::Address(addr) => addr, - }; - builder .set_args( "balanceOf(address) returns (uint256)", @@ -236,11 +234,14 @@ async fn main() -> Result<()> { let builder_output = builder.build(); println!( "{}", - Cast::new(provider, alloy_provider).call(builder_output, block).await? + Cast::new(provider, alloy_provider) + .call(builder_output, block.map(ToEthers::to_ethers)) + .await? ); } None => { - let value = Cast::new(provider, alloy_provider).balance(who, block).await?; + let value = + Cast::new(provider, alloy_provider).balance(account_addr, block).await?; if ether { println!("{}", SimpleCast::from_wei(&value.to_string(), "eth")?); } else { @@ -298,6 +299,7 @@ async fn main() -> Result<()> { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let alloy_provider = utils::get_alloy_provider(&config)?; + let who = who.resolve(&alloy_provider).await?; println!( "{}", Cast::new(provider, alloy_provider).code(who, block, disassemble).await? @@ -307,6 +309,7 @@ async fn main() -> Result<()> { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let alloy_provider = utils::get_alloy_provider(&config)?; + let who = who.resolve(&alloy_provider).await?; println!("{}", Cast::new(provider, alloy_provider).codesize(who, block).await?); } CastSubcommand::ComputeAddress { address, nonce, rpc } => { @@ -359,18 +362,21 @@ async fn main() -> Result<()> { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let alloy_provider = utils::get_alloy_provider(&config)?; + let who = who.resolve(&alloy_provider).await?; println!("{}", Cast::new(provider, alloy_provider).implementation(who, block).await?); } CastSubcommand::Admin { block, who, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let alloy_provider = utils::get_alloy_provider(&config)?; + let who = who.resolve(&alloy_provider).await?; println!("{}", Cast::new(provider, alloy_provider).admin(who, block).await?); } CastSubcommand::Nonce { block, who, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let alloy_provider = utils::get_alloy_provider(&config)?; + let who = who.resolve(&alloy_provider).await?; println!("{}", Cast::new(provider, alloy_provider).nonce(who, block).await?); } CastSubcommand::Proof { address, slots, rpc, block } => { @@ -576,8 +582,9 @@ async fn main() -> Result<()> { CastSubcommand::Logs(cmd) => cmd.run().await?, CastSubcommand::DecodeTransaction { tx } => { let tx = stdin::unwrap_line(tx)?; - let (tx, sig) = SimpleCast::decode_raw_transaction(&tx)?; + let tx_envelope = SimpleCast::decode_raw_transaction(&tx)?; + // TODO: Conversion from TxEnvelope to RPC Transaction // Serialize tx, sig and constructed a merged json string let mut tx = serde_json::to_value(&tx)?; let tx_map = tx.as_object_mut().unwrap(); diff --git a/crates/cast/bin/opts.rs b/crates/cast/bin/opts.rs index 2f09c2534830..ac63684b588a 100644 --- a/crates/cast/bin/opts.rs +++ b/crates/cast/bin/opts.rs @@ -4,10 +4,12 @@ use crate::cmd::{ rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs, wallet::WalletSubcommands, }; use alloy_primitives::{Address, B256, U256}; +use alloy_rpc_types::BlockId as AlloyBlockId; use clap::{Parser, Subcommand, ValueHint}; use ethers_core::types::{BlockId, NameOrAddress}; use eyre::Result; use foundry_cli::opts::{EtherscanOpts, RpcOpts}; +use foundry_common::ens::NameOrAddress as EnsNameOrAddress; use std::{path::PathBuf, str::FromStr}; const VERSION_MESSAGE: &str = concat!( @@ -516,11 +518,11 @@ pub enum CastSubcommand { /// /// Can also be the tags earliest, finalized, safe, latest, or pending. #[clap(long, short = 'B')] - block: Option, + block: Option, /// The address to get the nonce for. - #[clap(value_parser = NameOrAddress::from_str)] - who: NameOrAddress, + #[clap(value_parser = EnsNameOrAddress::from_str)] + who: EnsNameOrAddress, #[clap(flatten)] rpc: RpcOpts, @@ -533,11 +535,11 @@ pub enum CastSubcommand { /// /// Can also be the tags earliest, finalized, safe, latest, or pending. #[clap(long, short = 'B')] - block: Option, + block: Option, /// The address to get the nonce for. - #[clap(value_parser = NameOrAddress::from_str)] - who: NameOrAddress, + #[clap(value_parser = EnsNameOrAddress::from_str)] + who: EnsNameOrAddress, #[clap(flatten)] rpc: RpcOpts, @@ -613,11 +615,11 @@ pub enum CastSubcommand { /// /// Can also be the tags earliest, finalized, safe, latest, or pending. #[clap(long, short = 'B')] - block: Option, + block: Option, /// The account to query. - #[clap(value_parser = NameOrAddress::from_str)] - who: NameOrAddress, + #[clap(value_parser = EnsNameOrAddress::from_str)] + who: EnsNameOrAddress, /// Format the balance in ether. #[clap(long, short)] @@ -651,11 +653,11 @@ pub enum CastSubcommand { /// /// Can also be the tags earliest, finalized, safe, latest, or pending. #[clap(long, short = 'B')] - block: Option, + block: Option, /// The contract address. - #[clap(value_parser = NameOrAddress::from_str)] - who: NameOrAddress, + #[clap(value_parser = EnsNameOrAddress::from_str)] + who: EnsNameOrAddress, /// Disassemble bytecodes into individual opcodes. #[clap(long, short)] @@ -672,11 +674,11 @@ pub enum CastSubcommand { /// /// Can also be the tags earliest, finalized, safe, latest, or pending. #[clap(long, short = 'B')] - block: Option, + block: Option, /// The contract address. - #[clap(value_parser = NameOrAddress::from_str)] - who: NameOrAddress, + #[clap(value_parser = EnsNameOrAddress::from_str)] + who: EnsNameOrAddress, #[clap(flatten)] rpc: RpcOpts, @@ -763,11 +765,11 @@ pub enum CastSubcommand { /// /// Can also be the tags earliest, finalized, safe, latest, or pending. #[clap(long, short = 'B')] - block: Option, + block: Option, /// The address to get the nonce for. - #[clap(value_parser = NameOrAddress::from_str)] - who: NameOrAddress, + #[clap(value_parser = EnsNameOrAddress::from_str)] + who: EnsNameOrAddress, #[clap(flatten)] rpc: RpcOpts, diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 91cf546cac2c..a1130603182e 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -1,3 +1,4 @@ +use alloy_consensus::TxEnvelope; use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt}; use alloy_json_abi::ContractObject; use alloy_primitives::{ @@ -6,13 +7,12 @@ use alloy_primitives::{ }; use alloy_providers::provider::TempProvider; use alloy_rlp::Decodable; -use alloy_rpc_types::{BlockHashOrNumber, BlockId as AlloyBlockId, BlockNumberOrTag}; +use alloy_rpc_types::{BlockId as AlloyBlockId, BlockNumberOrTag}; use base::{Base, NumberWithBase, ToBase}; use chrono::NaiveDateTime; use ethers_core::{ types::{ - transaction::eip2718::TypedTransaction, BlockId, Filter, NameOrAddress, Signature, H160, - H256, + transaction::eip2718::TypedTransaction, BlockId, Filter, NameOrAddress, Signature, H256, }, utils::rlp, }; @@ -22,9 +22,8 @@ use eyre::{Context, ContextCompat, Result}; use foundry_block_explorers::Client; use foundry_common::{ abi::{encode_function_args, get_func}, - ens::NameOrAddress as ENSNameOrAddress, fmt::*, - types::{ToAlloy, ToEthers}, + types::ToAlloy, TransactionReceiptWithRevertReason, }; use foundry_config::Chain; @@ -206,12 +205,8 @@ where Ok(res) } - pub async fn balance + Send + Sync>( - &self, - who: T, - block: Option, - ) -> Result { - Ok(self.provider.get_balance(who, block).await?.to_alloy()) + pub async fn balance(&self, who: Address, block: Option) -> Result { + Ok(self.alloy_provider.get_balance(who, block).await?) } /// Sends a transaction to the specified address @@ -498,12 +493,8 @@ where /// # Ok(()) /// # } /// ``` - pub async fn nonce + Send + Sync>( - &self, - who: T, - block: Option, - ) -> Result { - Ok(self.provider.get_transaction_count(who, block).await?.to_alloy().to()) + pub async fn nonce(&self, who: Address, block: Option) -> Result { + Ok(self.alloy_provider.get_transaction_count(who, block).await?.to()) } /// # Example @@ -523,15 +514,16 @@ where /// # Ok(()) /// # } /// ``` - pub async fn implementation + Send + Sync>( + pub async fn implementation( &self, - who: T, - block: Option, + who: Address, + block: Option, ) -> Result { let slot = - H256::from_str("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc")?; - let value = self.provider.get_storage_at(who, slot, block).await?; - let addr: H160 = value.into(); + B256::from_str("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc")?; + let value = + TempProvider::get_storage_at(&self.alloy_provider, who, slot.into(), block).await?; + let addr = Address::from_word(value.into()); Ok(format!("{addr:?}")) } @@ -552,15 +544,12 @@ where /// # Ok(()) /// # } /// ``` - pub async fn admin + Send + Sync>( - &self, - who: T, - block: Option, - ) -> Result { + pub async fn admin(&self, who: Address, block: Option) -> Result { let slot = - H256::from_str("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103")?; - let value = self.provider.get_storage_at(who, slot, block).await?; - let addr: H160 = value.into(); + B256::from_str("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103")?; + let value = + TempProvider::get_storage_at(&self.alloy_provider, who, slot.into(), block).await?; + let addr = Address::from_word(value.into()); Ok(format!("{addr:?}")) } @@ -582,8 +571,7 @@ where /// # } /// ``` pub async fn compute_address(&self, address: Address, nonce: Option) -> Result

{ - let unpacked = - if let Some(n) = nonce { n } else { self.nonce(address.to_ethers(), None).await? }; + let unpacked = if let Some(n) = nonce { n } else { self.nonce(address, None).await? }; Ok(address.create(unpacked)) } @@ -604,17 +592,17 @@ where /// # Ok(()) /// # } /// ``` - pub async fn code + Send + Sync>( + pub async fn code( &self, - who: T, - block: Option, + who: Address, + block: Option, disassemble: bool, ) -> Result { if disassemble { - let code = self.provider.get_code(who, block).await?.to_vec(); + let code = self.alloy_provider.get_code_at(who, block).await?.to_vec(); Ok(format_operations(disassemble_bytes(code)?)?) } else { - Ok(format!("{}", self.provider.get_code(who, block).await?)) + Ok(format!("{}", self.alloy_provider.get_code_at(who, block).await?)) } } @@ -635,12 +623,8 @@ where /// # Ok(()) /// # } /// ``` - pub async fn codesize + Send + Sync>( - &self, - who: T, - block: Option, - ) -> Result { - let code = self.provider.get_code(who, block).await?.to_vec(); + pub async fn codesize(&self, who: Address, block: Option) -> Result { + let code = self.alloy_provider.get_code_at(who, block).await?.to_vec(); Ok(format!("{}", code.len())) } @@ -793,14 +777,12 @@ where /// # Ok(()) /// # } /// ``` - pub async fn storage + Send + Sync>( + pub async fn storage( &self, - from: T, + from: Address, slot: B256, block: Option, ) -> Result { - let from: ENSNameOrAddress = from.into(); - let from = from.resolve(&self.alloy_provider).await?; Ok(format!("{:?}", self.alloy_provider.get_storage_at(from, slot.into(), block).await?)) } @@ -856,15 +838,14 @@ where /// ``` pub async fn convert_block_number( &self, - block: Option, + block: Option, ) -> Result, eyre::Error> { match block { Some(block) => match block { - BlockHashOrNumber::Number(block_number) => { - Ok(Some(BlockNumberOrTag::Number(block_number))) - } - BlockHashOrNumber::Hash(hash) => { - let block = self.alloy_provider.get_block_by_hash(hash, false).await?; + AlloyBlockId::Number(block_number) => Ok(Some(block_number)), + AlloyBlockId::Hash(hash) => { + let block = + self.alloy_provider.get_block_by_hash(hash.block_hash, false).await?; Ok(block .map(|block| block.header.number.unwrap().to::()) .map(BlockNumberOrTag::from)) @@ -1964,10 +1945,10 @@ impl SimpleCast { /// let tx = "0x02f8f582a86a82058d8459682f008508351050808303fd84948e42f2f4101563bf679975178e880fd87d3efd4e80b884659ac74b00000000000000000000000080f0c1c49891dcfdd40b6e0f960f84e6042bcb6f000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e00000000000000000000000000000000000000000000000000000000007ff4e20000000000000000000000000000000000000000000000000000000000000064c001a05d429597befe2835396206781b199122f2e8297327ed4a05483339e7a8b2022aa04c23a7f70fb29dda1b4ee342fb10a625e9b8ddc6a603fb4e170d4f6f37700cb8"; /// let (tx, sig) = Cast::decode_raw_transaction(&tx)?; /// # Ok::<(), eyre::Report>(()) - pub fn decode_raw_transaction(tx: &str) -> Result<(TypedTransaction, Signature)> { + pub fn decode_raw_transaction(tx: &str) -> Result { let tx_hex = hex::decode(strip_0x(tx))?; - let tx_rlp = rlp::Rlp::new(tx_hex.as_slice()); - Ok(TypedTransaction::decode_signed(&tx_rlp)?) + let envelope = TxEnvelope::decode(&mut tx_hex.as_slice())?; + Ok(envelope) } } diff --git a/crates/common/src/types.rs b/crates/common/src/types.rs index 85b7e87ba568..73366f298dbc 100644 --- a/crates/common/src/types.rs +++ b/crates/common/src/types.rs @@ -276,3 +276,19 @@ impl ToEthers for BlockNumberOrTag { } } } + +impl ToEthers for alloy_rpc_types::BlockId { + type To = ethers_core::types::BlockId; + + #[inline(always)] + fn to_ethers(self) -> Self::To { + match self { + alloy_rpc_types::BlockId::Hash(h) => { + ethers_core::types::BlockId::Hash(h.block_hash.to_ethers()) + } + alloy_rpc_types::BlockId::Number(n) => { + ethers_core::types::BlockId::Number(n.to_ethers()) + } + } + } +} From ed3337863b2dd92373a84ce0fba7a7cec5b2e5d6 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Wed, 14 Feb 2024 17:07:18 -0400 Subject: [PATCH 03/19] chore: leave todo for converting a tx envelope into an rpc tx --- crates/cast/bin/main.rs | 15 +++++++-------- crates/cast/src/lib.rs | 16 ++++------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index a6b3f68d023d..ca7dae91c3d5 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -1,9 +1,8 @@ #[macro_use] extern crate tracing; -use alloy_consensus::{TxEnvelope, TxType}; use alloy_primitives::{keccak256, Address, B256}; -use alloy_rpc_types::Transaction; + use cast::{Cast, SimpleCast, TxBuilder}; use clap::{CommandFactory, Parser}; use clap_complete::generate; @@ -586,13 +585,13 @@ async fn main() -> Result<()> { // TODO: Conversion from TxEnvelope to RPC Transaction // Serialize tx, sig and constructed a merged json string - let mut tx = serde_json::to_value(&tx)?; - let tx_map = tx.as_object_mut().unwrap(); - serde_json::to_value(sig)?.as_object().unwrap().iter().for_each(|(k, v)| { - tx_map.entry(k).or_insert(v.clone()); - }); + // let mut tx = serde_json::to_value(&tx)?; + // let tx_map = tx.as_object_mut().unwrap(); + // serde_json::to_value(sig)?.as_object().unwrap().iter().for_each(|(k, v)| { + // tx_map.entry(k).or_insert(v.clone()); + // }); - println!("{}", serde_json::to_string_pretty(&tx)?); + // println!("{}", serde_json::to_string_pretty(&tx)?); } }; Ok(()) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index a1130603182e..523f8d0b2661 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -10,12 +10,7 @@ use alloy_rlp::Decodable; use alloy_rpc_types::{BlockId as AlloyBlockId, BlockNumberOrTag}; use base::{Base, NumberWithBase, ToBase}; use chrono::NaiveDateTime; -use ethers_core::{ - types::{ - transaction::eip2718::TypedTransaction, BlockId, Filter, NameOrAddress, Signature, H256, - }, - utils::rlp, -}; +use ethers_core::types::{BlockId, Filter, NameOrAddress, H256}; use ethers_providers::{Middleware, PendingTransaction, PubsubClient}; use evm_disassembler::{disassemble_bytes, disassemble_str, format_operations}; use eyre::{Context, ContextCompat, Result}; @@ -33,10 +28,7 @@ use std::{ io, path::PathBuf, str::FromStr, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, + sync::atomic::{AtomicBool, Ordering}, }; use tokio::signal::ctrl_c; use tx::{TxBuilderOutput, TxBuilderPeekOutput}; @@ -60,7 +52,7 @@ use rlp_converter::Item; pub struct Cast { provider: M, - alloy_provider: Arc

, + alloy_provider: P, } impl Cast @@ -82,7 +74,7 @@ where /// # } /// ``` pub fn new(provider: M, alloy_provider: P) -> Self { - Self { provider, alloy_provider: Arc::new(alloy_provider) } + Self { provider, alloy_provider } } /// Makes a read-only call to the specified address From 2bf461601e7a30f62b11c74170f8e7733c9a9d70 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 09:29:25 -0400 Subject: [PATCH 04/19] fix: use proper type for storage --- crates/cast/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 523f8d0b2661..bd4f8ec95563 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -775,7 +775,7 @@ where slot: B256, block: Option, ) -> Result { - Ok(format!("{:?}", self.alloy_provider.get_storage_at(from, slot.into(), block).await?)) + Ok(format!("{:?}", B256::from(self.alloy_provider.get_storage_at(from, slot.into(), block).await?))) } pub async fn filter_logs(&self, filter: Filter, to_json: bool) -> Result { From 1c127b2055e2200d263c18f2ca2511c65f73866c Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 10:10:35 -0400 Subject: [PATCH 05/19] readd decodetx for now --- crates/cast/bin/main.rs | 17 ++++++++--------- crates/cast/src/lib.rs | 9 ++++----- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index ca7dae91c3d5..62a024ba59fe 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -581,17 +581,16 @@ async fn main() -> Result<()> { CastSubcommand::Logs(cmd) => cmd.run().await?, CastSubcommand::DecodeTransaction { tx } => { let tx = stdin::unwrap_line(tx)?; - let tx_envelope = SimpleCast::decode_raw_transaction(&tx)?; + let (tx, sig) = SimpleCast::decode_raw_transaction(&tx)?; - // TODO: Conversion from TxEnvelope to RPC Transaction - // Serialize tx, sig and constructed a merged json string - // let mut tx = serde_json::to_value(&tx)?; - // let tx_map = tx.as_object_mut().unwrap(); - // serde_json::to_value(sig)?.as_object().unwrap().iter().for_each(|(k, v)| { - // tx_map.entry(k).or_insert(v.clone()); - // }); + // Serialize tx, sig and construct a merged json string + let mut tx = serde_json::to_value(&tx)?; + let tx_map = tx.as_object_mut().unwrap(); + serde_json::to_value(sig)?.as_object().unwrap().iter().for_each(|(k, v)| { + tx_map.entry(k).or_insert(v.clone()); + }); - // println!("{}", serde_json::to_string_pretty(&tx)?); + println!("{}", serde_json::to_string_pretty(&tx)?); } }; Ok(()) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index bd4f8ec95563..f45b2c9f1ae0 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -1,4 +1,3 @@ -use alloy_consensus::TxEnvelope; use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt}; use alloy_json_abi::ContractObject; use alloy_primitives::{ @@ -10,7 +9,7 @@ use alloy_rlp::Decodable; use alloy_rpc_types::{BlockId as AlloyBlockId, BlockNumberOrTag}; use base::{Base, NumberWithBase, ToBase}; use chrono::NaiveDateTime; -use ethers_core::types::{BlockId, Filter, NameOrAddress, H256}; +use ethers_core::{types::{transaction::eip2718::TypedTransaction, BlockId, Filter, NameOrAddress, Signature, H256}, utils::rlp}; use ethers_providers::{Middleware, PendingTransaction, PubsubClient}; use evm_disassembler::{disassemble_bytes, disassemble_str, format_operations}; use eyre::{Context, ContextCompat, Result}; @@ -1937,10 +1936,10 @@ impl SimpleCast { /// let tx = "0x02f8f582a86a82058d8459682f008508351050808303fd84948e42f2f4101563bf679975178e880fd87d3efd4e80b884659ac74b00000000000000000000000080f0c1c49891dcfdd40b6e0f960f84e6042bcb6f000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e00000000000000000000000000000000000000000000000000000000007ff4e20000000000000000000000000000000000000000000000000000000000000064c001a05d429597befe2835396206781b199122f2e8297327ed4a05483339e7a8b2022aa04c23a7f70fb29dda1b4ee342fb10a625e9b8ddc6a603fb4e170d4f6f37700cb8"; /// let (tx, sig) = Cast::decode_raw_transaction(&tx)?; /// # Ok::<(), eyre::Report>(()) - pub fn decode_raw_transaction(tx: &str) -> Result { + pub fn decode_raw_transaction(tx: &str) -> Result<(TypedTransaction, Signature)> { let tx_hex = hex::decode(strip_0x(tx))?; - let envelope = TxEnvelope::decode(&mut tx_hex.as_slice())?; - Ok(envelope) + let tx_rlp = rlp::Rlp::new(tx_hex.as_slice()); + Ok(TypedTransaction::decode_signed(&tx_rlp)?) } } From 26cb20a230a88e10bcce35cd11805d0c26cf61bd Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 13:14:01 -0400 Subject: [PATCH 06/19] chore: extend txbuilder to build an alloy tx request --- crates/cast/src/tx.rs | 105 +++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index 1bfd0c40ff67..494299832b83 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -1,21 +1,23 @@ use crate::errors::FunctionSignatureError; use alloy_json_abi::Function; -use alloy_primitives::{Address, U256}; +use alloy_primitives::{Address, Bytes, U256, U64}; +use alloy_rpc_types::request::{TransactionInput, TransactionRequest as AlloyTransactionRequest}; use ethers_core::types::{ - transaction::eip2718::TypedTransaction, Eip1559TransactionRequest, NameOrAddress, - TransactionRequest, + transaction::eip2718::TypedTransaction, Eip1559TransactionRequest, TransactionRequest, }; use ethers_providers::Middleware; -use eyre::{eyre, Result}; +use eyre::Result; use foundry_common::{ abi::{encode_function_args, get_func, get_func_etherscan}, - types::{ToAlloy, ToEthers}, + types::ToEthers, }; use foundry_config::Chain; use futures::future::join_all; pub type TxBuilderOutput = (TypedTransaction, Option); +pub type TxBuilderAlloyOutput = (AlloyTransactionRequest, Option); pub type TxBuilderPeekOutput<'a> = (&'a TypedTransaction, &'a Option); +pub type TxBuilderPeekAlloyOutput<'a> = (&'a AlloyTransactionRequest, &'a Option); /// Transaction builder /// @@ -38,6 +40,7 @@ pub struct TxBuilder<'a, M: Middleware> { to: Option

, chain: Chain, tx: TypedTransaction, + alloy_tx: AlloyTransactionRequest, func: Option, etherscan_api_key: Option, provider: &'a M, @@ -50,35 +53,46 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { /// `to` - `to`. Could be a ENS /// `chain` - chain to construct the tx for /// `legacy` - use type 1 transaction - pub async fn new, T: Into>( + pub async fn new( provider: &'a M, - from: F, - to: Option, + from: Address, + to: Option
, chain: impl Into, legacy: bool, ) -> Result> { let chain = chain.into(); - let from_addr = resolve_ens(provider, from).await?; - let mut tx: TypedTransaction = if chain.is_legacy() || legacy { - TransactionRequest::new().from(from_addr.to_ethers()).chain_id(chain.id()).into() + let (mut tx, mut alloy_tx): (TypedTransaction, AlloyTransactionRequest) = if chain + .is_legacy() || + legacy + { + ( + TransactionRequest::new().from(from.to_ethers()).chain_id(chain.id()).into(), + AlloyTransactionRequest::default().from(from).transaction_type(0), + ) } else { - Eip1559TransactionRequest::new().from(from_addr.to_ethers()).chain_id(chain.id()).into() + ( + Eip1559TransactionRequest::new().from(from.to_ethers()).chain_id(chain.id()).into(), + AlloyTransactionRequest::default().from(from).transaction_type(2), + ) }; let to_addr = if let Some(to) = to { - let addr = resolve_ens(provider, to).await?; - tx.set_to(addr.to_ethers()); - Some(addr) + tx.set_to(to.to_ethers()); + Some(to) } else { None }; - Ok(Self { to: to_addr, chain, tx, func: None, etherscan_api_key: None, provider }) + + alloy_tx.to = to_addr; + + Ok(Self { to: to_addr, chain, tx, alloy_tx, func: None, etherscan_api_key: None, provider }) } /// Set gas for tx pub fn set_gas(&mut self, v: U256) -> &mut Self { self.tx.set_gas(v.to_ethers()); + self.alloy_tx.gas = Some(v); self } @@ -93,6 +107,7 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { /// Set gas price pub fn set_gas_price(&mut self, v: U256) -> &mut Self { self.tx.set_gas_price(v.to_ethers()); + self.alloy_tx.gas_price = Some(v); self } @@ -109,6 +124,11 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { if let TypedTransaction::Eip1559(tx) = &mut self.tx { tx.max_priority_fee_per_gas = Some(v.to_ethers()) } + + if let Some(2) = self.alloy_tx.transaction_type.map(|v| v.to::()) { + self.alloy_tx.max_priority_fee_per_gas = Some(v); + } + self } @@ -123,6 +143,7 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { /// Set value pub fn set_value(&mut self, v: U256) -> &mut Self { self.tx.set_value(v.to_ethers()); + self.alloy_tx.value = Some(v); self } @@ -137,6 +158,7 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { /// Set nonce pub fn set_nonce(&mut self, v: U256) -> &mut Self { self.tx.set_nonce(v.to_ethers()); + self.alloy_tx.nonce = Some(v.to::()); self } @@ -163,7 +185,8 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { } pub fn set_data(&mut self, v: Vec) -> &mut Self { - self.tx.set_data(v.into()); + self.tx.set_data(v.clone().into()); + self.alloy_tx.input = TransactionInput::new(Bytes::from(v.clone())); self } @@ -238,22 +261,19 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { (self.tx, self.func) } + /// Consuming build: returns alloy transaction and optional function call + pub fn build_alloy(self) -> TxBuilderAlloyOutput { + (self.alloy_tx, self.func) + } + /// Non-consuming build: peek into the tx content pub fn peek(&self) -> TxBuilderPeekOutput { (&self.tx, &self.func) } -} -async fn resolve_ens>( - provider: &M, - addr: T, -) -> Result
{ - let from_addr = match addr.into() { - NameOrAddress::Name(ref ens_name) => provider.resolve_name(ens_name).await, - NameOrAddress::Address(addr) => Ok(addr), + pub fn peek_alloy(&self) -> TxBuilderPeekAlloyOutput { + (&self.alloy_tx, &self.func) } - .map_err(|x| eyre!("Failed to resolve ENS name: {x}"))?; - Ok(from_addr.to_alloy()) } async fn resolve_name_args(args: &[String], provider: &M) -> Vec { @@ -276,15 +296,14 @@ mod tests { use crate::TxBuilder; use alloy_primitives::{Address, U256}; use async_trait::async_trait; - use ethers_core::types::{transaction::eip2718::TypedTransaction, NameOrAddress, H160}; + use ethers_core::types::{transaction::eip2718::TypedTransaction, NameOrAddress}; use ethers_providers::{JsonRpcClient, Middleware, ProviderError}; use foundry_common::types::ToEthers; use foundry_config::NamedChain; use serde::{de::DeserializeOwned, Serialize}; - use std::str::FromStr; - const ADDR_1: &str = "0000000000000000000000000000000000000001"; - const ADDR_2: &str = "0000000000000000000000000000000000000002"; + const ADDR_1: Address = Address::with_last_byte(1); + const ADDR_2: Address = Address::with_last_byte(2); #[derive(Debug)] struct MyProvider {} @@ -312,26 +331,16 @@ mod tests { fn inner(&self) -> &Self::Inner { self } - - async fn resolve_name(&self, ens_name: &str) -> Result { - match ens_name { - "a.eth" => Ok(H160::from_str(ADDR_1).unwrap()), - "b.eth" => Ok(H160::from_str(ADDR_2).unwrap()), - _ => unreachable!("don't know how to resolve {ens_name}"), - } - } } + #[tokio::test(flavor = "multi_thread")] async fn builder_new_non_legacy() -> eyre::Result<()> { let provider = MyProvider {}; let builder = - TxBuilder::new(&provider, "a.eth", Some("b.eth"), NamedChain::Mainnet, false).await?; + TxBuilder::new(&provider, ADDR_1, Some(ADDR_2), NamedChain::Mainnet, false).await?; let (tx, args) = builder.build(); - assert_eq!(*tx.from().unwrap(), Address::from_str(ADDR_1).unwrap().to_ethers()); - assert_eq!( - *tx.to().unwrap(), - NameOrAddress::Address(Address::from_str(ADDR_2).unwrap().to_ethers()) - ); + assert_eq!(*tx.from().unwrap(), ADDR_1.to_ethers()); + assert_eq!(*tx.to().unwrap(), NameOrAddress::Address(ADDR_2.to_ethers())); assert_eq!(args, None); match tx { @@ -347,7 +356,7 @@ mod tests { async fn builder_new_legacy() -> eyre::Result<()> { let provider = MyProvider {}; let builder = - TxBuilder::new(&provider, "a.eth", Some("b.eth"), NamedChain::Mainnet, true).await?; + TxBuilder::new(&provider, ADDR_1, Some(ADDR_2), NamedChain::Mainnet, true).await?; // don't check anything other than the tx type - the rest is covered in the non-legacy case let (tx, _) = builder.build(); match tx { @@ -363,7 +372,7 @@ mod tests { async fn builder_fields() -> eyre::Result<()> { let provider = MyProvider {}; let mut builder = - TxBuilder::new(&provider, "a.eth", Some("b.eth"), NamedChain::Mainnet, false) + TxBuilder::new(&provider, ADDR_1, Some(ADDR_2), NamedChain::Mainnet, false) .await .unwrap(); builder @@ -387,7 +396,7 @@ mod tests { async fn builder_args() -> eyre::Result<()> { let provider = MyProvider {}; let mut builder = - TxBuilder::new(&provider, "a.eth", Some("b.eth"), NamedChain::Mainnet, false) + TxBuilder::new(&provider, ADDR_1, Some(ADDR_2), NamedChain::Mainnet, false) .await .unwrap(); builder.args(Some(("what_a_day(int)", vec![String::from("31337")]))).await?; From 53a524f85384a04d344be7b30c5b4301de6f469a Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 13:18:40 -0400 Subject: [PATCH 07/19] feat: migrate most methods bar send/decode raw tx --- crates/cast/bin/cmd/access_list.rs | 30 ++++++++++++---------- crates/cast/bin/cmd/call.rs | 19 +++++++++----- crates/cast/bin/cmd/estimate.rs | 13 ++++++++-- crates/cast/bin/cmd/send.rs | 21 ++++++++++----- crates/cast/bin/main.rs | 18 ++++--------- crates/cast/src/lib.rs | 41 +++++++++++++++++------------- 6 files changed, 83 insertions(+), 59 deletions(-) diff --git a/crates/cast/bin/cmd/access_list.rs b/crates/cast/bin/cmd/access_list.rs index 3bb215c7d721..62e1a7f5f5f5 100644 --- a/crates/cast/bin/cmd/access_list.rs +++ b/crates/cast/bin/cmd/access_list.rs @@ -1,14 +1,15 @@ +use alloy_primitives::Address; use alloy_providers::provider::TempProvider; +use alloy_rpc_types::BlockId; use cast::{Cast, TxBuilder}; use clap::Parser; -use ethers_core::types::{BlockId, NameOrAddress}; use ethers_providers::Middleware; use eyre::{Result, WrapErr}; use foundry_cli::{ opts::{EthereumOpts, TransactionOpts}, utils, }; -use foundry_common::types::ToEthers; +use foundry_common::ens::NameOrAddress; use foundry_config::{Chain, Config}; use std::str::FromStr; @@ -65,10 +66,18 @@ impl AccessListArgs { let chain = utils::get_chain(config.chain, &provider).await?; let sender = eth.wallet.sender().await; + let to = match to { + Some(NameOrAddress::Name(name)) => { + Some(NameOrAddress::Name(name).resolve(&alloy_provider).await?) + } + Some(NameOrAddress::Address(addr)) => Some(addr), + None => None, + }; + access_list( &provider, alloy_provider, - sender.to_ethers(), + sender, to, sig, args, @@ -84,16 +93,11 @@ impl AccessListArgs { } #[allow(clippy::too_many_arguments)] -async fn access_list< - M: Middleware, - P: TempProvider, - F: Into, - T: Into, ->( +async fn access_list( provider: M, alloy_provider: P, - from: F, - to: Option, + from: Address, + to: Option
, sig: Option, args: Vec, data: Option, @@ -122,11 +126,11 @@ where builder.set_data(hex::decode(data).wrap_err("Expected hex encoded function data")?); } - let builder_output = builder.peek(); + let builder_output = builder.peek_alloy(); let cast = Cast::new(&provider, alloy_provider); - let access_list: String = cast.access_list(builder_output, block, to_json).await?; + let access_list: String = cast.access_list(builder_output.0.clone(), block, to_json).await?; println!("{}", access_list); diff --git a/crates/cast/bin/cmd/call.rs b/crates/cast/bin/cmd/call.rs index 1c6c5b1de566..4aa71ea0511e 100644 --- a/crates/cast/bin/cmd/call.rs +++ b/crates/cast/bin/cmd/call.rs @@ -1,16 +1,13 @@ use alloy_primitives::U256; +use alloy_rpc_types::BlockId; use cast::{Cast, TxBuilder}; use clap::Parser; -use ethers_core::types::{BlockId, NameOrAddress}; use eyre::{Result, WrapErr}; use foundry_cli::{ opts::{EthereumOpts, TransactionOpts}, utils::{self, handle_traces, parse_ether_value, TraceResult}, }; -use foundry_common::{ - runtime_client::RuntimeClient, - types::{ToAlloy, ToEthers}, -}; +use foundry_common::{ens::NameOrAddress, runtime_client::RuntimeClient, types::ToAlloy}; use foundry_compilers::EvmVersion; use foundry_config::{find_project_root_path, Config}; use foundry_evm::{executors::TracingExecutor, opts::EvmOpts}; @@ -120,8 +117,16 @@ impl CallArgs { let chain = utils::get_chain(config.chain, &provider).await?; let sender = eth.wallet.sender().await; + let to = match to { + Some(NameOrAddress::Name(name)) => { + Some(NameOrAddress::Name(name).resolve(&alloy_provider).await?) + } + Some(NameOrAddress::Address(addr)) => Some(addr), + None => None, + }; + let mut builder: TxBuilder<'_, Provider> = - TxBuilder::new(&provider, sender.to_ethers(), to, chain, tx.legacy).await?; + TxBuilder::new(&provider, sender, to, chain, tx.legacy).await?; builder .gas(tx.gas_limit) @@ -196,7 +201,7 @@ impl CallArgs { } }; - let builder_output = builder.build(); + let builder_output = builder.build_alloy(); println!("{}", Cast::new(provider, alloy_provider).call(builder_output, block).await?); Ok(()) diff --git a/crates/cast/bin/cmd/estimate.rs b/crates/cast/bin/cmd/estimate.rs index c963cfcacdae..f481aa0080df 100644 --- a/crates/cast/bin/cmd/estimate.rs +++ b/crates/cast/bin/cmd/estimate.rs @@ -1,12 +1,12 @@ use alloy_primitives::U256; use cast::{Cast, TxBuilder}; use clap::Parser; -use ethers_core::types::NameOrAddress; use eyre::Result; use foundry_cli::{ opts::{EtherscanOpts, RpcOpts}, utils::{self, parse_ether_value}, }; +use foundry_common::ens::NameOrAddress; use foundry_config::{figment::Figment, Config}; use std::str::FromStr; @@ -87,6 +87,15 @@ impl EstimateArgs { let chain = utils::get_chain(config.chain, &provider).await?; let api_key = config.get_etherscan_api_key(Some(chain)); + let from = from.resolve(&alloy_provider).await?; + let to = match to { + Some(NameOrAddress::Name(name)) => { + Some(NameOrAddress::Name(name).resolve(&alloy_provider).await?) + } + Some(NameOrAddress::Address(addr)) => Some(addr), + None => None, + }; + let mut builder = TxBuilder::new(&provider, from, to, chain, false).await?; builder.etherscan_api_key(api_key); @@ -109,7 +118,7 @@ impl EstimateArgs { } }; - let builder_output = builder.peek(); + let builder_output = builder.peek_alloy(); let gas = Cast::new(&provider, alloy_provider).estimate(builder_output).await?; println!("{gas}"); Ok(()) diff --git a/crates/cast/bin/cmd/send.rs b/crates/cast/bin/cmd/send.rs index e208b7ed39e4..60b11f902528 100644 --- a/crates/cast/bin/cmd/send.rs +++ b/crates/cast/bin/cmd/send.rs @@ -1,7 +1,7 @@ +use alloy_primitives::Address; use alloy_providers::provider::TempProvider; use cast::{Cast, TxBuilder}; use clap::Parser; -use ethers_core::types::NameOrAddress; use ethers_middleware::MiddlewareBuilder; use ethers_providers::Middleware; use ethers_signers::Signer; @@ -12,6 +12,7 @@ use foundry_cli::{ }; use foundry_common::{ cli_warn, + ens::NameOrAddress, types::{ToAlloy, ToEthers}, }; use foundry_config::{Chain, Config}; @@ -119,6 +120,14 @@ impl SendTxArgs { let chain = utils::get_chain(config.chain, &provider).await?; let api_key = config.get_etherscan_api_key(Some(chain)); + let to = match to { + Some(NameOrAddress::Name(name)) => { + Some(NameOrAddress::Name(name).resolve(&alloy_provider).await?) + } + Some(NameOrAddress::Address(addr)) => Some(addr), + None => None, + }; + // Case 1: // Default to sending via eth_sendTransaction if the --unlocked flag is passed. // This should be the only way this RPC method is used as it requires a local node @@ -155,7 +164,7 @@ impl SendTxArgs { cast_send( provider, alloy_provider, - config.sender.to_ethers(), + config.sender, to, code, (sig, args), @@ -199,7 +208,7 @@ corresponds to the sender, or let foundry automatically detect it by not specify cast_send( provider, alloy_provider, - from, + from.to_alloy(), to, code, (sig, args), @@ -216,11 +225,11 @@ corresponds to the sender, or let foundry automatically detect it by not specify } #[allow(clippy::too_many_arguments)] -async fn cast_send, T: Into>( +async fn cast_send( provider: M, alloy_provider: P, - from: F, - to: Option, + from: Address, + to: Option
, code: Option, args: (String, Vec), tx: TransactionOpts, diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 62a024ba59fe..baa21b6f895d 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -6,7 +6,7 @@ use alloy_primitives::{keccak256, Address, B256}; use cast::{Cast, SimpleCast, TxBuilder}; use clap::{CommandFactory, Parser}; use clap_complete::generate; -use ethers_core::types::{BlockId, BlockNumber::Latest, NameOrAddress}; +use ethers_core::types::{BlockId, BlockNumber::Latest}; use ethers_providers::{Middleware, Provider}; use eyre::Result; use foundry_cli::{handler, prompt, stdin, utils}; @@ -215,14 +215,8 @@ async fn main() -> Result<()> { match erc20 { Some(token) => { let chain = utils::get_chain(config.chain, &provider).await?; - let mut builder: TxBuilder<'_, Provider> = TxBuilder::new( - &provider, - NameOrAddress::Address(Address::ZERO.to_ethers()), - Some(NameOrAddress::Address(token.to_ethers())), - chain, - true, - ) - .await?; + let mut builder: TxBuilder<'_, Provider> = + TxBuilder::new(&provider, Address::ZERO, Some(token), chain, true).await?; builder .set_args( @@ -230,12 +224,10 @@ async fn main() -> Result<()> { vec![format!("{account_addr:#x}")], ) .await?; - let builder_output = builder.build(); + let builder_output = builder.build_alloy(); println!( "{}", - Cast::new(provider, alloy_provider) - .call(builder_output, block.map(ToEthers::to_ethers)) - .await? + Cast::new(provider, alloy_provider).call(builder_output, block).await? ); } None => { diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index f45b2c9f1ae0..1a38e17672e0 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -6,10 +6,13 @@ use alloy_primitives::{ }; use alloy_providers::provider::TempProvider; use alloy_rlp::Decodable; -use alloy_rpc_types::{BlockId as AlloyBlockId, BlockNumberOrTag}; +use alloy_rpc_types::{request::TransactionRequest, BlockId as AlloyBlockId, BlockNumberOrTag}; use base::{Base, NumberWithBase, ToBase}; use chrono::NaiveDateTime; -use ethers_core::{types::{transaction::eip2718::TypedTransaction, BlockId, Filter, NameOrAddress, Signature, H256}, utils::rlp}; +use ethers_core::{ + types::{transaction::eip2718::TypedTransaction, BlockId, Filter, Signature, H256}, + utils::rlp, +}; use ethers_providers::{Middleware, PendingTransaction, PubsubClient}; use evm_disassembler::{disassemble_bytes, disassemble_str, format_operations}; use eyre::{Context, ContextCompat, Result}; @@ -17,7 +20,6 @@ use foundry_block_explorers::Client; use foundry_common::{ abi::{encode_function_args, get_func}, fmt::*, - types::ToAlloy, TransactionReceiptWithRevertReason, }; use foundry_config::Chain; @@ -30,7 +32,7 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; use tokio::signal::ctrl_c; -use tx::{TxBuilderOutput, TxBuilderPeekOutput}; +use tx::{TxBuilderAlloyOutput, TxBuilderOutput, TxBuilderPeekAlloyOutput}; pub use foundry_evm::*; pub use rusoto_core::{ @@ -103,11 +105,11 @@ where /// ``` pub async fn call<'a>( &self, - builder_output: TxBuilderOutput, - block: Option, + builder_output: TxBuilderAlloyOutput, + block: Option, ) -> Result { let (tx, func) = builder_output; - let res = self.provider.call(&tx, block).await?; + let res = self.alloy_provider.call(tx.clone(), block).await?; let mut decoded = vec![]; @@ -119,8 +121,8 @@ where // ensure the address is a contract if res.is_empty() { // check that the recipient is a contract that can be called - if let Some(NameOrAddress::Address(addr)) = tx.to() { - if let Ok(code) = self.provider.get_code(*addr, block).await { + if let Some(addr) = tx.to { + if let Ok(code) = self.alloy_provider.get_code_at(addr, block).await { if code.is_empty() { eyre::bail!("contract {addr:?} does not have any code") } @@ -170,19 +172,19 @@ where /// ``` pub async fn access_list( &self, - builder_output: TxBuilderPeekOutput<'_>, - block: Option, + tx_request: TransactionRequest, + block: Option, to_json: bool, ) -> Result { - let (tx, _) = builder_output; - let access_list = self.provider.create_access_list(tx, block).await?; + let tx = tx_request; + let access_list = self.alloy_provider.create_access_list(tx, block).await?; let res = if to_json { serde_json::to_string(&access_list)? } else { let mut s = vec![format!("gas used: {}", access_list.gas_used), "access list:".to_string()]; for al in access_list.access_list.0 { - s.push(format!("- address: {}", &al.address.to_alloy().to_checksum(None))); + s.push(format!("- address: {}", &al.address.to_checksum(None))); if !al.storage_keys.is_empty() { s.push(" keys:".to_string()); for key in al.storage_keys { @@ -292,12 +294,12 @@ where /// # Ok(()) /// # } /// ``` - pub async fn estimate(&self, builder_output: TxBuilderPeekOutput<'_>) -> Result { + pub async fn estimate(&self, builder_output: TxBuilderPeekAlloyOutput<'_>) -> Result { let (tx, _) = builder_output; - let res = self.provider.estimate_gas(tx, None).await?; + let res = self.alloy_provider.estimate_gas(tx.clone(), None).await?; - Ok::<_, eyre::Error>(res.to_alloy()) + Ok::<_, eyre::Error>(res) } /// # Example @@ -774,7 +776,10 @@ where slot: B256, block: Option, ) -> Result { - Ok(format!("{:?}", B256::from(self.alloy_provider.get_storage_at(from, slot.into(), block).await?))) + Ok(format!( + "{:?}", + B256::from(self.alloy_provider.get_storage_at(from, slot.into(), block).await?) + )) } pub async fn filter_logs(&self, filter: Filter, to_json: bool) -> Result { From f3cfe926e64d22ed9333f07f7a856c4d4a573529 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 13:59:20 -0400 Subject: [PATCH 08/19] fix: include tx data --- crates/cast/src/tx.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index 494299832b83..a620121c3ac3 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -36,6 +36,7 @@ pub type TxBuilderPeekAlloyOutput<'a> = (&'a AlloyTransactionRequest, &'a Option /// # Ok(()) /// # } /// ``` +#[derive(Debug)] pub struct TxBuilder<'a, M: Middleware> { to: Option
, chain: Chain, @@ -240,7 +241,8 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { args: Vec, ) -> Result<&mut TxBuilder<'a, M>> { let (data, func) = self.create_args(sig, args).await?; - self.tx.set_data(data.into()); + self.tx.set_data(data.clone().into()); + self.alloy_tx.input = TransactionInput::new(Bytes::from(data)); self.func = Some(func); Ok(self) } From 1d0334fa081e436b98d3369ae0a2b22b2d43f833 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 14:12:52 -0400 Subject: [PATCH 09/19] simplify txbuilder --- crates/cast/bin/cmd/access_list.rs | 2 +- crates/cast/bin/cmd/estimate.rs | 2 +- crates/cast/src/lib.rs | 4 ++-- crates/cast/src/tx.rs | 8 +------- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/crates/cast/bin/cmd/access_list.rs b/crates/cast/bin/cmd/access_list.rs index 62e1a7f5f5f5..d584e0d8357f 100644 --- a/crates/cast/bin/cmd/access_list.rs +++ b/crates/cast/bin/cmd/access_list.rs @@ -126,7 +126,7 @@ where builder.set_data(hex::decode(data).wrap_err("Expected hex encoded function data")?); } - let builder_output = builder.peek_alloy(); + let builder_output = builder.peek(); let cast = Cast::new(&provider, alloy_provider); diff --git a/crates/cast/bin/cmd/estimate.rs b/crates/cast/bin/cmd/estimate.rs index f481aa0080df..271fa07a7ef0 100644 --- a/crates/cast/bin/cmd/estimate.rs +++ b/crates/cast/bin/cmd/estimate.rs @@ -118,7 +118,7 @@ impl EstimateArgs { } }; - let builder_output = builder.peek_alloy(); + let builder_output = builder.peek(); let gas = Cast::new(&provider, alloy_provider).estimate(builder_output).await?; println!("{gas}"); Ok(()) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 1a38e17672e0..79bc82b2ddf3 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -32,7 +32,7 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; use tokio::signal::ctrl_c; -use tx::{TxBuilderAlloyOutput, TxBuilderOutput, TxBuilderPeekAlloyOutput}; +use tx::{TxBuilderAlloyOutput, TxBuilderOutput, TxBuilderPeekOutput}; pub use foundry_evm::*; pub use rusoto_core::{ @@ -294,7 +294,7 @@ where /// # Ok(()) /// # } /// ``` - pub async fn estimate(&self, builder_output: TxBuilderPeekAlloyOutput<'_>) -> Result { + pub async fn estimate(&self, builder_output: TxBuilderPeekOutput<'_>) -> Result { let (tx, _) = builder_output; let res = self.alloy_provider.estimate_gas(tx.clone(), None).await?; diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index a620121c3ac3..b48a504e4d0d 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -16,8 +16,7 @@ use futures::future::join_all; pub type TxBuilderOutput = (TypedTransaction, Option); pub type TxBuilderAlloyOutput = (AlloyTransactionRequest, Option); -pub type TxBuilderPeekOutput<'a> = (&'a TypedTransaction, &'a Option); -pub type TxBuilderPeekAlloyOutput<'a> = (&'a AlloyTransactionRequest, &'a Option); +pub type TxBuilderPeekOutput<'a> = (&'a AlloyTransactionRequest, &'a Option); /// Transaction builder /// @@ -268,12 +267,7 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { (self.alloy_tx, self.func) } - /// Non-consuming build: peek into the tx content pub fn peek(&self) -> TxBuilderPeekOutput { - (&self.tx, &self.func) - } - - pub fn peek_alloy(&self) -> TxBuilderPeekAlloyOutput { (&self.alloy_tx, &self.func) } } From 78804df044306a2b9d7b0b5c18c9f144ab4bf371 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 14:47:57 -0400 Subject: [PATCH 10/19] chore: simplify back access_list --- crates/cast/bin/cmd/access_list.rs | 2 +- crates/cast/src/lib.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/cast/bin/cmd/access_list.rs b/crates/cast/bin/cmd/access_list.rs index d584e0d8357f..b6254d2f1718 100644 --- a/crates/cast/bin/cmd/access_list.rs +++ b/crates/cast/bin/cmd/access_list.rs @@ -130,7 +130,7 @@ where let cast = Cast::new(&provider, alloy_provider); - let access_list: String = cast.access_list(builder_output.0.clone(), block, to_json).await?; + let access_list: String = cast.access_list(builder_output, block, to_json).await?; println!("{}", access_list); diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 79bc82b2ddf3..376f869b49ee 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -6,7 +6,7 @@ use alloy_primitives::{ }; use alloy_providers::provider::TempProvider; use alloy_rlp::Decodable; -use alloy_rpc_types::{request::TransactionRequest, BlockId as AlloyBlockId, BlockNumberOrTag}; +use alloy_rpc_types::{BlockId as AlloyBlockId, BlockNumberOrTag}; use base::{Base, NumberWithBase, ToBase}; use chrono::NaiveDateTime; use ethers_core::{ @@ -172,12 +172,12 @@ where /// ``` pub async fn access_list( &self, - tx_request: TransactionRequest, + builder_output: TxBuilderPeekOutput<'_>, block: Option, to_json: bool, ) -> Result { - let tx = tx_request; - let access_list = self.alloy_provider.create_access_list(tx, block).await?; + let (tx, _) = builder_output; + let access_list = self.alloy_provider.create_access_list(tx.clone(), block).await?; let res = if to_json { serde_json::to_string(&access_list)? } else { From 568bff48e9a33ee2be55cbd15a6ce4f523c2a644 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 14:55:06 -0400 Subject: [PATCH 11/19] chore: remove unnecesary conversion --- crates/common/src/types.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/crates/common/src/types.rs b/crates/common/src/types.rs index 73366f298dbc..f317a15bd756 100644 --- a/crates/common/src/types.rs +++ b/crates/common/src/types.rs @@ -275,20 +275,4 @@ impl ToEthers for BlockNumberOrTag { BlockNumberOrTag::Safe => BlockNumber::Safe, } } -} - -impl ToEthers for alloy_rpc_types::BlockId { - type To = ethers_core::types::BlockId; - - #[inline(always)] - fn to_ethers(self) -> Self::To { - match self { - alloy_rpc_types::BlockId::Hash(h) => { - ethers_core::types::BlockId::Hash(h.block_hash.to_ethers()) - } - alloy_rpc_types::BlockId::Number(n) => { - ethers_core::types::BlockId::Number(n.to_ethers()) - } - } - } -} +} \ No newline at end of file From cd07ee9c50b3a20bef1eda4b0373f161d3cd7f0a Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 14:57:04 -0400 Subject: [PATCH 12/19] fmt --- crates/common/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common/src/types.rs b/crates/common/src/types.rs index f317a15bd756..85b7e87ba568 100644 --- a/crates/common/src/types.rs +++ b/crates/common/src/types.rs @@ -275,4 +275,4 @@ impl ToEthers for BlockNumberOrTag { BlockNumberOrTag::Safe => BlockNumber::Safe, } } -} \ No newline at end of file +} From f24ed9b9f70057719be7935fa3279c9e56e3c748 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 16:26:17 -0400 Subject: [PATCH 13/19] doctests --- crates/cast/src/lib.rs | 8 ++++++-- crates/cast/src/tx.rs | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 376f869b49ee..0db29825d931 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -67,10 +67,12 @@ where /// ``` /// use cast::Cast; /// use ethers_providers::{Http, Provider}; + /// use foundry_common::provider::alloy::get_http_provider; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; - /// let cast = Cast::new(provider); + /// let alloy_provider = get_http_provider("http://localhost:8545"); + /// let cast = Cast::new(provider, alloy_provider); /// # Ok(()) /// # } /// ``` @@ -86,10 +88,12 @@ where /// use cast::{Cast, TxBuilder}; /// use ethers_core::types::Address; /// use ethers_providers::{Http, Provider}; + /// use foundry_common::provider::alloy::get_http_provider; /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; + /// let alloy_provider = get_http_provider("http://localhost:8545"); /// let to = Address::from_str("0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304")?; /// let sig = "function greeting(uint256 i) public returns (string)"; /// let args = vec!["5".to_owned()]; @@ -97,7 +101,7 @@ where /// TxBuilder::new(&provider, Address::zero(), Some(to), Chain::Mainnet, false).await?; /// builder.set_args(sig, args).await?; /// let builder_output = builder.build(); - /// let cast = Cast::new(provider); + /// let cast = Cast::new(provider, alloy_provider); /// let data = cast.call(builder_output, None).await?; /// println!("{}", data); /// # Ok(()) diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index b48a504e4d0d..e7cf2b584fe1 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -24,12 +24,15 @@ pub type TxBuilderPeekOutput<'a> = (&'a AlloyTransactionRequest, &'a Option eyre::Result<()> { -/// # use alloy_primitives::U256; +/// # use alloy_primitives::{Address, U256}; /// # use cast::TxBuilder; /// # use foundry_config::NamedChain; +/// # use std::str::FromStr; /// let provider = ethers_providers::test_provider::MAINNET.provider(); +/// let from = Address::from_str("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").unwrap(); +/// let to = Address::from_str("0xb8c2c29ee19d8307cb7255e1cd9cbde883a267d5").unwrap(); /// let mut builder = -/// TxBuilder::new(&provider, "a.eth", Some("b.eth"), NamedChain::Mainnet, false).await?; +/// TxBuilder::new(&provider, from, Some(to), NamedChain::Mainnet, false).await?; /// builder.gas(Some(U256::from(1))); /// let (tx, _) = builder.build(); /// # Ok(()) From 02f27e54de1553d57ab7d85a4bf6802e2e612a86 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Thu, 15 Feb 2024 16:27:40 -0400 Subject: [PATCH 14/19] fmt --- crates/cast/src/tx.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index e7cf2b584fe1..fd166a88f22b 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -31,8 +31,7 @@ pub type TxBuilderPeekOutput<'a> = (&'a AlloyTransactionRequest, &'a Option Date: Thu, 15 Feb 2024 16:53:13 -0400 Subject: [PATCH 15/19] do not use trait --- crates/cast/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 0db29825d931..c4e5f26ac57a 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -518,8 +518,7 @@ where ) -> Result { let slot = B256::from_str("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc")?; - let value = - TempProvider::get_storage_at(&self.alloy_provider, who, slot.into(), block).await?; + let value = self.alloy_provider.get_storage_at(who, slot.into(), block).await?; let addr = Address::from_word(value.into()); Ok(format!("{addr:?}")) } @@ -544,8 +543,7 @@ where pub async fn admin(&self, who: Address, block: Option) -> Result { let slot = B256::from_str("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103")?; - let value = - TempProvider::get_storage_at(&self.alloy_provider, who, slot.into(), block).await?; + let value = self.alloy_provider.get_storage_at(who, slot.into(), block).await?; let addr = Address::from_word(value.into()); Ok(format!("{addr:?}")) } From a02ff8a00deb545b2ab7965cd18e0df89e323d96 Mon Sep 17 00:00:00 2001 From: Enrique Date: Fri, 16 Feb 2024 11:21:03 -0400 Subject: [PATCH 16/19] Update crates/cast/bin/main.rs Co-authored-by: Matthias Seitz --- crates/cast/bin/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index baa21b6f895d..750c45ab5d0f 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -2,7 +2,6 @@ extern crate tracing; use alloy_primitives::{keccak256, Address, B256}; - use cast::{Cast, SimpleCast, TxBuilder}; use clap::{CommandFactory, Parser}; use clap_complete::generate; From 9034d2b76b0b5436c8e310c0411e957142268eb7 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Fri, 16 Feb 2024 12:04:15 -0400 Subject: [PATCH 17/19] cleanup builder --- crates/cast/bin/cmd/access_list.rs | 4 +- crates/cast/bin/cmd/call.rs | 12 +++--- crates/cast/bin/cmd/estimate.rs | 4 +- crates/cast/bin/cmd/send.rs | 2 +- crates/cast/bin/main.rs | 10 +++-- crates/cast/src/tx.rs | 63 ++++++++---------------------- 6 files changed, 34 insertions(+), 61 deletions(-) diff --git a/crates/cast/bin/cmd/access_list.rs b/crates/cast/bin/cmd/access_list.rs index b6254d2f1718..1c49ac67009b 100644 --- a/crates/cast/bin/cmd/access_list.rs +++ b/crates/cast/bin/cmd/access_list.rs @@ -109,7 +109,7 @@ async fn access_list( where M::Error: 'static, { - let mut builder = TxBuilder::new(&provider, from, to, chain, tx.legacy).await?; + let mut builder = TxBuilder::new(&alloy_provider, from, to, chain, tx.legacy).await?; builder .gas(tx.gas_limit) .gas_price(tx.gas_price) @@ -128,7 +128,7 @@ where let builder_output = builder.peek(); - let cast = Cast::new(&provider, alloy_provider); + let cast = Cast::new(&provider, &alloy_provider); let access_list: String = cast.access_list(builder_output, block, to_json).await?; diff --git a/crates/cast/bin/cmd/call.rs b/crates/cast/bin/cmd/call.rs index 4aa71ea0511e..2b8d51c29c48 100644 --- a/crates/cast/bin/cmd/call.rs +++ b/crates/cast/bin/cmd/call.rs @@ -1,4 +1,5 @@ use alloy_primitives::U256; +use alloy_providers::provider::TempProvider; use alloy_rpc_types::BlockId; use cast::{Cast, TxBuilder}; use clap::Parser; @@ -125,8 +126,7 @@ impl CallArgs { None => None, }; - let mut builder: TxBuilder<'_, Provider> = - TxBuilder::new(&provider, sender, to, chain, tx.legacy).await?; + let mut builder = TxBuilder::new(&alloy_provider, sender, to, chain, tx.legacy).await?; builder .gas(tx.gas_limit) @@ -209,8 +209,8 @@ impl CallArgs { } /// fills the builder from create arg -async fn fill_create( - builder: &mut TxBuilder<'_, Provider>, +async fn fill_create( + builder: &mut TxBuilder<'_, P>, value: Option, code: String, sig: Option, @@ -231,8 +231,8 @@ async fn fill_create( } /// fills the builder from args -async fn fill_tx( - builder: &mut TxBuilder<'_, Provider>, +async fn fill_tx( + builder: &mut TxBuilder<'_, P>, value: Option, sig: Option, args: Vec, diff --git a/crates/cast/bin/cmd/estimate.rs b/crates/cast/bin/cmd/estimate.rs index 271fa07a7ef0..3ae6ad9cc1a7 100644 --- a/crates/cast/bin/cmd/estimate.rs +++ b/crates/cast/bin/cmd/estimate.rs @@ -96,7 +96,7 @@ impl EstimateArgs { None => None, }; - let mut builder = TxBuilder::new(&provider, from, to, chain, false).await?; + let mut builder = TxBuilder::new(&alloy_provider, from, to, chain, false).await?; builder.etherscan_api_key(api_key); match command { @@ -119,7 +119,7 @@ impl EstimateArgs { }; let builder_output = builder.peek(); - let gas = Cast::new(&provider, alloy_provider).estimate(builder_output).await?; + let gas = Cast::new(&provider, &alloy_provider).estimate(builder_output).await?; println!("{gas}"); Ok(()) } diff --git a/crates/cast/bin/cmd/send.rs b/crates/cast/bin/cmd/send.rs index 60b11f902528..0b8f68750dde 100644 --- a/crates/cast/bin/cmd/send.rs +++ b/crates/cast/bin/cmd/send.rs @@ -244,7 +244,7 @@ where { let (sig, params) = args; let params = if !sig.is_empty() { Some((&sig[..], params)) } else { None }; - let mut builder = TxBuilder::new(&provider, from, to, chain, tx.legacy).await?; + let mut builder = TxBuilder::new(&alloy_provider, from, to, chain, tx.legacy).await?; builder .etherscan_api_key(etherscan_api_key) .gas(tx.gas_limit) diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 750c45ab5d0f..8de0c599d9d8 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -2,6 +2,7 @@ extern crate tracing; use alloy_primitives::{keccak256, Address, B256}; +use alloy_providers::provider::TempProvider; use cast::{Cast, SimpleCast, TxBuilder}; use clap::{CommandFactory, Parser}; use clap_complete::generate; @@ -214,8 +215,9 @@ async fn main() -> Result<()> { match erc20 { Some(token) => { let chain = utils::get_chain(config.chain, &provider).await?; - let mut builder: TxBuilder<'_, Provider> = - TxBuilder::new(&provider, Address::ZERO, Some(token), chain, true).await?; + let mut builder = + TxBuilder::new(&alloy_provider, Address::ZERO, Some(token), chain, true) + .await?; builder .set_args( @@ -226,12 +228,12 @@ async fn main() -> Result<()> { let builder_output = builder.build_alloy(); println!( "{}", - Cast::new(provider, alloy_provider).call(builder_output, block).await? + Cast::new(&provider, &alloy_provider).call(builder_output, block).await? ); } None => { let value = - Cast::new(provider, alloy_provider).balance(account_addr, block).await?; + Cast::new(&provider, &alloy_provider).balance(account_addr, block).await?; if ether { println!("{}", SimpleCast::from_wei(&value.to_string(), "eth")?); } else { diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index fd166a88f22b..7871617f16c8 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -1,14 +1,15 @@ use crate::errors::FunctionSignatureError; use alloy_json_abi::Function; use alloy_primitives::{Address, Bytes, U256, U64}; +use alloy_providers::provider::TempProvider; use alloy_rpc_types::request::{TransactionInput, TransactionRequest as AlloyTransactionRequest}; use ethers_core::types::{ transaction::eip2718::TypedTransaction, Eip1559TransactionRequest, TransactionRequest, }; -use ethers_providers::Middleware; use eyre::Result; use foundry_common::{ abi::{encode_function_args, get_func, get_func_etherscan}, + ens::NameOrAddress, types::ToEthers, }; use foundry_config::Chain; @@ -38,17 +39,17 @@ pub type TxBuilderPeekOutput<'a> = (&'a AlloyTransactionRequest, &'a Option { +pub struct TxBuilder<'a, P: TempProvider> { to: Option
, chain: Chain, tx: TypedTransaction, alloy_tx: AlloyTransactionRequest, func: Option, etherscan_api_key: Option, - provider: &'a M, + provider: &'a P, } -impl<'a, M: Middleware> TxBuilder<'a, M> { +impl<'a, P: TempProvider> TxBuilder<'a, P> { /// Create a new TxBuilder /// `provider` - provider to use /// `from` - 'from' field. Could be an ENS name @@ -56,12 +57,12 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { /// `chain` - chain to construct the tx for /// `legacy` - use type 1 transaction pub async fn new( - provider: &'a M, + provider: &'a P, from: Address, to: Option
, chain: impl Into, legacy: bool, - ) -> Result> { + ) -> Result> { let chain = chain.into(); let (mut tx, mut alloy_tx): (TypedTransaction, AlloyTransactionRequest) = if chain @@ -240,7 +241,7 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { &mut self, sig: &str, args: Vec, - ) -> Result<&mut TxBuilder<'a, M>> { + ) -> Result<&mut TxBuilder<'a, P>> { let (data, func) = self.create_args(sig, args).await?; self.tx.set_data(data.clone().into()); self.alloy_tx.input = TransactionInput::new(Bytes::from(data)); @@ -252,7 +253,7 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { pub async fn args( &mut self, value: Option<(&str, Vec)>, - ) -> Result<&mut TxBuilder<'a, M>> { + ) -> Result<&mut TxBuilder<'a, P>> { if let Some((sig, args)) = value { return self.set_args(sig, args).await } @@ -274,12 +275,12 @@ impl<'a, M: Middleware> TxBuilder<'a, M> { } } -async fn resolve_name_args(args: &[String], provider: &M) -> Vec { +async fn resolve_name_args(args: &[String], provider: &P) -> Vec { join_all(args.iter().map(|arg| async { if arg.contains('.') { - let addr = provider.resolve_name(arg).await; + let addr = NameOrAddress::Name(arg.to_string()).resolve(provider).await; match addr { - Ok(addr) => format!("{addr:?}"), + Ok(addr) => addr.to_string(), Err(_) => arg.to_string(), } } else { @@ -293,47 +294,17 @@ async fn resolve_name_args(args: &[String], provider: &M) -> Vec< mod tests { use crate::TxBuilder; use alloy_primitives::{Address, U256}; - use async_trait::async_trait; use ethers_core::types::{transaction::eip2718::TypedTransaction, NameOrAddress}; - use ethers_providers::{JsonRpcClient, Middleware, ProviderError}; use foundry_common::types::ToEthers; use foundry_config::NamedChain; - use serde::{de::DeserializeOwned, Serialize}; const ADDR_1: Address = Address::with_last_byte(1); const ADDR_2: Address = Address::with_last_byte(2); - #[derive(Debug)] - struct MyProvider {} - - #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] - #[cfg_attr(not(target_arch = "wasm32"), async_trait)] - impl JsonRpcClient for MyProvider { - type Error = ProviderError; - - async fn request( - &self, - _method: &str, - _params: T, - ) -> Result { - Err(ProviderError::CustomError("There is no request".to_string())) - } - } - #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] - #[cfg_attr(not(target_arch = "wasm32"), async_trait)] - impl Middleware for MyProvider { - type Error = ProviderError; - type Provider = MyProvider; - type Inner = MyProvider; - - fn inner(&self) -> &Self::Inner { - self - } - } - #[tokio::test(flavor = "multi_thread")] async fn builder_new_non_legacy() -> eyre::Result<()> { - let provider = MyProvider {}; + // Instanciate a local provider although it'll do nothing. + let provider = foundry_common::provider::alloy::get_http_provider("http://localhost:8545"); let builder = TxBuilder::new(&provider, ADDR_1, Some(ADDR_2), NamedChain::Mainnet, false).await?; let (tx, args) = builder.build(); @@ -352,7 +323,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn builder_new_legacy() -> eyre::Result<()> { - let provider = MyProvider {}; + let provider = foundry_common::provider::alloy::get_http_provider("http://localhost:8545"); let builder = TxBuilder::new(&provider, ADDR_1, Some(ADDR_2), NamedChain::Mainnet, true).await?; // don't check anything other than the tx type - the rest is covered in the non-legacy case @@ -368,7 +339,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn builder_fields() -> eyre::Result<()> { - let provider = MyProvider {}; + let provider = foundry_common::provider::alloy::get_http_provider("http://localhost:8545"); let mut builder = TxBuilder::new(&provider, ADDR_1, Some(ADDR_2), NamedChain::Mainnet, false) .await @@ -392,7 +363,7 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn builder_args() -> eyre::Result<()> { - let provider = MyProvider {}; + let provider = foundry_common::provider::alloy::get_http_provider("http://localhost:8545"); let mut builder = TxBuilder::new(&provider, ADDR_1, Some(ADDR_2), NamedChain::Mainnet, false) .await From a030afcc021c03c23c8866d39652cb93a99df60f Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Fri, 16 Feb 2024 12:06:58 -0400 Subject: [PATCH 18/19] clippy --- crates/cast/bin/cmd/call.rs | 4 +--- crates/cast/bin/main.rs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/cast/bin/cmd/call.rs b/crates/cast/bin/cmd/call.rs index 2b8d51c29c48..894e9c1aa99b 100644 --- a/crates/cast/bin/cmd/call.rs +++ b/crates/cast/bin/cmd/call.rs @@ -8,14 +8,12 @@ use foundry_cli::{ opts::{EthereumOpts, TransactionOpts}, utils::{self, handle_traces, parse_ether_value, TraceResult}, }; -use foundry_common::{ens::NameOrAddress, runtime_client::RuntimeClient, types::ToAlloy}; +use foundry_common::{ens::NameOrAddress, types::ToAlloy}; use foundry_compilers::EvmVersion; use foundry_config::{find_project_root_path, Config}; use foundry_evm::{executors::TracingExecutor, opts::EvmOpts}; use std::str::FromStr; -type Provider = ethers_providers::Provider; - /// CLI arguments for `cast call`. #[derive(Debug, Parser)] pub struct CallArgs { diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 8de0c599d9d8..ceadb96d1a20 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -2,19 +2,17 @@ extern crate tracing; use alloy_primitives::{keccak256, Address, B256}; -use alloy_providers::provider::TempProvider; use cast::{Cast, SimpleCast, TxBuilder}; use clap::{CommandFactory, Parser}; use clap_complete::generate; use ethers_core::types::{BlockId, BlockNumber::Latest}; -use ethers_providers::{Middleware, Provider}; +use ethers_providers::Middleware; use eyre::Result; use foundry_cli::{handler, prompt, stdin, utils}; use foundry_common::{ abi::get_event, fmt::format_tokens, fs, - runtime_client::RuntimeClient, selectors::{ decode_calldata, decode_event_topic, decode_function_selector, decode_selectors, import_selectors, parse_signatures, pretty_calldata, ParsedSignatures, SelectorImportData, From f602fec912a679bd93d8ce0ec24031ee9f567747 Mon Sep 17 00:00:00 2001 From: Enrique Ortiz Date: Fri, 16 Feb 2024 12:14:10 -0400 Subject: [PATCH 19/19] fix doc comments --- crates/cast/src/tx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index 7871617f16c8..b20d24563c8b 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -29,7 +29,7 @@ pub type TxBuilderPeekOutput<'a> = (&'a AlloyTransactionRequest, &'a Option