From 4d377409faf5e681f88b5b3a2de640c9f9631ae9 Mon Sep 17 00:00:00 2001 From: Sabnock <24715302+Sabnock01@users.noreply.github.com> Date: Sat, 7 Sep 2024 08:33:15 -0500 Subject: [PATCH] feat: add `codehash` and `storage-root` to `cast` (#8828) * feat: add codehash and storage-root to cast * fix: use eth_getProof * fix: nits --- crates/cast/bin/args.rs | 42 ++++++++++++++++++++++++++ crates/cast/bin/main.rs | 12 ++++++++ crates/cast/src/lib.rs | 66 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/crates/cast/bin/args.rs b/crates/cast/bin/args.rs index 727458505968..fdb6a113354a 100644 --- a/crates/cast/bin/args.rs +++ b/crates/cast/bin/args.rs @@ -831,6 +831,48 @@ pub enum CastSubcommand { rpc: RpcOpts, }, + /// Get the codehash for an account. + #[command()] + Codehash { + /// The block height to query at. + /// + /// Can also be the tags earliest, finalized, safe, latest, or pending. + #[arg(long, short = 'B')] + block: Option, + + /// The address to get the codehash for. + #[arg(value_parser = NameOrAddress::from_str)] + who: NameOrAddress, + + /// The storage slot numbers (hex or decimal). + #[arg(value_parser = parse_slot)] + slots: Vec, + + #[command(flatten)] + rpc: RpcOpts, + }, + + /// Get the storage root for an account. + #[command(visible_alias = "sr")] + StorageRoot { + /// The block height to query at. + /// + /// Can also be the tags earliest, finalized, safe, latest, or pending. + #[arg(long, short = 'B')] + block: Option, + + /// The address to get the storage root for. + #[arg(value_parser = NameOrAddress::from_str)] + who: NameOrAddress, + + /// The storage slot numbers (hex or decimal). + #[arg(value_parser = parse_slot)] + slots: Vec, + + #[command(flatten)] + rpc: RpcOpts, + }, + /// Get the source code of a contract from Etherscan. #[command(visible_aliases = &["et", "src"])] EtherscanSource { diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 28009dbdcfcc..27a052fe6ccc 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -362,6 +362,18 @@ async fn main_args(args: CastArgs) -> Result<()> { let who = who.resolve(&provider).await?; println!("{}", Cast::new(provider).nonce(who, block).await?); } + CastSubcommand::Codehash { block, who, slots, rpc } => { + let config = Config::from(&rpc); + let provider = utils::get_provider(&config)?; + let who = who.resolve(&provider).await?; + println!("{}", Cast::new(provider).codehash(who, slots, block).await?); + } + CastSubcommand::StorageRoot { block, who, slots, rpc } => { + let config = Config::from(&rpc); + let provider = utils::get_provider(&config)?; + let who = who.resolve(&provider).await?; + println!("{}", Cast::new(provider).storage_root(who, slots, block).await?); + } CastSubcommand::Proof { address, slots, rpc, block } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 03355213de57..73ab5b28bda1 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -494,6 +494,72 @@ where Ok(self.provider.get_transaction_count(who).block_id(block.unwrap_or_default()).await?) } + /// #Example + /// + /// ``` + /// use alloy_primitives::{Address, FixedBytes}; + /// use alloy_provider::{network::AnyNetwork, ProviderBuilder, RootProvider}; + /// use cast::Cast; + /// use std::str::FromStr; + /// + /// # async fn foo() -> eyre::Result<()> { + /// let provider = + /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// let cast = Cast::new(provider); + /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?; + /// let slots = vec![FixedBytes::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")?]; + /// let codehash = cast.codehash(addr, slots, None).await?; + /// println!("{}", codehash); + /// # Ok(()) + /// # } + pub async fn codehash( + &self, + who: Address, + slots: Vec, + block: Option, + ) -> Result { + Ok(self + .provider + .get_proof(who, slots) + .block_id(block.unwrap_or_default()) + .await? + .code_hash + .to_string()) + } + + /// #Example + /// + /// ``` + /// use alloy_primitives::{Address, FixedBytes}; + /// use alloy_provider::{network::AnyNetwork, ProviderBuilder, RootProvider}; + /// use cast::Cast; + /// use std::str::FromStr; + /// + /// # async fn foo() -> eyre::Result<()> { + /// let provider = + /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; + /// let cast = Cast::new(provider); + /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?; + /// let slots = vec![FixedBytes::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")?]; + /// let storage_root = cast.storage_root(addr, slots, None).await?; + /// println!("{}", storage_root); + /// # Ok(()) + /// # } + pub async fn storage_root( + &self, + who: Address, + slots: Vec, + block: Option, + ) -> Result { + Ok(self + .provider + .get_proof(who, slots) + .block_id(block.unwrap_or_default()) + .await? + .storage_hash + .to_string()) + } + /// # Example /// /// ```