diff --git a/Cargo.toml b/Cargo.toml
index 5703601..5b52113 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,51 +22,55 @@ path = "src/cached_proxy.rs"
[lib]
name = "dvf_libs"
path = "lib/lib.rs"
-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-tracing = "0.1.34"
-tracing-subscriber = { version = "0.3.11", default-features = true, features = ["env-filter", "fmt"]}
-reqwest = { version = "0.11", features = ["json", "blocking"] }
-tokio = { version = "1", features = ["full"] }
-serde = { version = "1.0.144", features = ["derive"] }
-serde_json = "1.0.85"
-substring = "1.4.5"
-clap = { version = "3.1.6", features = ["derive"]}
+actix-web = "4.7.0"
+alloy = { version = "0.6.4", features = ["full"] }
+alloy-chains = { version = "0.1.47", features = ["serde"] }
+alloy-dyn-abi = { version = "0.8.12", features = ["eip712"] }
+alloy-json-abi = "0.8.12"
+alloy-node-bindings = "0.7.0"
+alloy-rpc-types = "0.6.4"
+alloy-rpc-types-trace = "0.6.4"
+alloy-signer = { version = "0.6.4", features = ["eip712"] }
+alloy-signer-ledger = "0.6.4"
+alloy-signer-local = "0.6.4"
+async-trait = "0.1.69"
+bigint = "1"
+bytes = "1.4.0"
+clap = { version = "3.1.6", features = ["derive"] }
colored = "1.0.0"
+console = "0.15.7"
+dirs-next = "2.0.0"
+dotenv = "0.15.0"
+foundry-block-explorers = "0.9.0"
+foundry-compilers = "0.11.6"
+foundry-compilers-core = "0.12.3"
+hex = "0.4"
+indicatif = "0.17.6"
prettytable-rs = "0.10.0"
+rand = "0.8.5"
regex = "1"
-bigint = "1"
-tiny-keccak = { version = "2.0.0", features = ["sha3", "keccak"] }
-hex = "0.4"
-ethers = { version = "2.0.8", features = ["solc"] }
-ethers-contract = "2.0.8"
-ethers-core = { version = "2.0.8" }
-ethers-etherscan = { version = "2.0.8" }
-ethers-providers = "2.0.8"
-ethers-signers = {version = "2.0.8", features = ["ledger", "yubi", "yubihsm"]}
-ethers-solc = "2.0.8"
+reqwest = { version = "0.11", features = ["json", "blocking"] }
+reth-trie = { git = "https://github.com/paradigmxyz/reth", tag = "v1.1.2"}
+ruint = "1.12.3"
+rustc-hex = "2.1.0"
+scanf = "1.2.1"
semver = { version = "1.0.17", features = ["serde"] }
-toml = "0.7.4"
-dirs-next = "2.0.0"
-zip = "0.6.6"
+serde = { version = "1.0.144", features = ["derive"] }
+serde_json = "1.0.85"
+sha3 = "0.10.8"
+substring = "1.4.5"
tempfile = "3.6.0"
-bytes = "1.4.0"
-async-trait = "0.1.69"
thiserror = "1.0.40"
-sha3 = "0.10.8"
-rustc-hex = "2.1.0"
-indicatif = "0.17.6"
-console = "0.15.7"
-actix-web = "4.7.0"
-scanf = "1.2.1"
-dotenv = "0.15.0"
time = "0.3.36"
-foundry-compilers = "0.11.6"
-alloy = { version = "0.6.4", features = ["full"] }
-alloy-rpc-types = "0.6.4"
-alloy-rpc-types-trace = "0.6.4"
+tiny-keccak = { version = "2.0.0", features = ["sha3", "keccak"] }
+tokio = { version = "1", features = ["full"] }
+toml = "0.7.4"
+tracing = "0.1.34"
+tracing-subscriber = { version = "0.3.11", default-features = true, features = ["env-filter", "fmt"] }
+zip = "0.6.6"
[dev-dependencies]
assert_cmd = "2.0.12"
diff --git a/lib/bytecode_verification/compare_bytecodes.rs b/lib/bytecode_verification/compare_bytecodes.rs
index d53b611..fdcf389 100644
--- a/lib/bytecode_verification/compare_bytecodes.rs
+++ b/lib/bytecode_verification/compare_bytecodes.rs
@@ -1,4 +1,4 @@
-use alloy::dyn_abi::{JsonAbiExt};
+use alloy::dyn_abi::JsonAbiExt;
use foundry_compilers::artifacts::BytecodeHash;
use tracing::{debug, info};
@@ -273,8 +273,8 @@ impl CompareInitCode {
for (arg, value) in project_info.constructor_args.iter_mut().zip(decoded_args) {
let encoded_value = value.abi_encode_packed();
let formatted_value = format!("0x{}", hex::encode(&encoded_value));
-
- let sol_type = value.as_type().expect(format!("Unable to find constructor argument type for {}", arg.name).as_str());
+
+ let sol_type = value.as_type().unwrap_or_else(|| panic!("Unable to find constructor argument type for {}", arg.name));
arg.value = formatted_value;
arg.type_string = sol_type.sol_type_name().to_string()
@@ -289,7 +289,6 @@ impl CompareInitCode {
mod tests {
use crate::types::ConstructorArg;
use alloy::json_abi::{Constructor, Param, StateMutability};
- use ethers::abi::ParamType;
use semver::Version;
use std::collections::HashMap;
@@ -359,18 +358,18 @@ mod tests {
ConstructorArg {
name: "arg1".to_string(),
value: "1".to_string(),
- type_string: "uint256".to_string(),
+ type_string: "address".to_string(),
},
ConstructorArg {
name: "arg2".to_string(),
value: "2".to_string(),
- type_string: "uint128".to_string(),
+ type_string: "address".to_string(),
},
];
let constructor_inputs: Vec = vec![
- Param::parse("uint256 arg1").unwrap(),
- Param::parse("uint128 arg2").unwrap()
+ Param::parse("address arg1").unwrap(),
+ Param::parse("address arg2").unwrap()
];
let constructor = Constructor {
diff --git a/lib/bytecode_verification/parse_json.rs b/lib/bytecode_verification/parse_json.rs
index 95e39f9..3adc442 100644
--- a/lib/bytecode_verification/parse_json.rs
+++ b/lib/bytecode_verification/parse_json.rs
@@ -869,14 +869,12 @@ impl ProjectInfo {
if value["nodeType"] == "FunctionCall" && value["expression"]["name"] == "keccak256" {
if let Some(arguments) = value.get("arguments") {
if !arguments.as_array().unwrap().is_empty() {
- let mut slot = U256::from_str(
- arguments[0]["typeDescriptions"]["typeIdentifier"]
- .as_str()
- .unwrap()
- .replace("t_stringliteral_", "")
- .as_str(),
- )
- .unwrap();
+ let mut hex_wo_prefix = arguments[0]["typeDescriptions"]["typeIdentifier"]
+ .as_str()
+ .unwrap()
+ .replace("t_stringliteral_", "");
+ hex_wo_prefix.insert_str(0, "0x");
+ let mut slot = U256::from_str(hex_wo_prefix.as_str()).unwrap();
if let Some(binary_op) = binary_op {
slot -= U256::from(binary_op);
}
@@ -1399,9 +1397,9 @@ impl ProjectInfo {
Ok(read_dir) => {
for build_info_file in read_dir.flatten() {
let bi: BuildInfo = BuildInfo::read(&build_info_file.path())?;
- if bi.output.contracts.values().flatten().find(|(name, _)| {
- name == &contract_name
- }).is_some() {
+ if bi.output.contracts.values().flatten().any(|(name, _)| {
+ name == contract_name
+ }) {
build_infos.push(bi);
}
}
diff --git a/lib/bytecode_verification/verify_bytecode.rs b/lib/bytecode_verification/verify_bytecode.rs
index da0b39b..d71e359 100644
--- a/lib/bytecode_verification/verify_bytecode.rs
+++ b/lib/bytecode_verification/verify_bytecode.rs
@@ -3,7 +3,7 @@ use std::io::prelude::*;
use std::path::Path;
use colored::Colorize;
-use ethers::abi::Address;
+use alloy::primitives::Address;
use prettytable::Table;
use tracing::debug;
diff --git a/lib/dvf/abstract_wallet.rs b/lib/dvf/abstract_wallet.rs
index 21ddd2f..a2a5730 100644
--- a/lib/dvf/abstract_wallet.rs
+++ b/lib/dvf/abstract_wallet.rs
@@ -1,18 +1,21 @@
use async_trait::async_trait;
-use ethers::signers::{LocalWallet, Signer};
-use ethers::types::Signature;
-use ethers_core::types::transaction::eip2718::TypedTransaction;
-use ethers_core::types::transaction::eip712::Eip712;
-use ethers_core::types::Address;
-use ethers_signers::Ledger;
-use ethers_signers::LedgerError;
-use ethers_signers::WalletError;
+
+use alloy::signers::{Signer, Error as SignerError};
+use alloy::signers::local::{PrivateKeySigner, LocalSignerError};
+use alloy_signer_ledger::{LedgerSigner, LedgerError};
+use alloy::primitives::{Address, PrimitiveSignature as Signature, B256, ChainId};
+use alloy::consensus::SignableTransaction;
+use alloy::network::TxSigner;
+use alloy::dyn_abi::eip712::TypedData;
+use alloy::sol_types::{Eip712Domain, SolStruct};
+
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AbstractError {
LedgerError(LedgerError),
- WalletError(WalletError),
+ WalletError(LocalSignerError),
+ GeneralError(SignerError),
}
impl From for AbstractError {
@@ -21,91 +24,127 @@ impl From for AbstractError {
}
}
-impl From for AbstractError {
- fn from(error: WalletError) -> Self {
+impl From for AbstractError {
+ fn from(error: LocalSignerError) -> Self {
AbstractError::WalletError(error)
}
}
+impl From for AbstractError {
+ fn from(error: SignerError) -> Self {
+ AbstractError::GeneralError(error)
+ }
+}
+
impl std::fmt::Display for AbstractError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AbstractError::LedgerError(e) => write!(f, "{:?}", e),
AbstractError::WalletError(e) => write!(f, "{:?}", e),
+ AbstractError::GeneralError(e) => write!(f, "{:?}", e),
}
}
}
#[derive(Debug)]
pub enum AbstractWallet {
- Ledger(Ledger),
- LocalWallet(LocalWallet),
+ Ledger(LedgerSigner),
+ LocalWallet(PrivateKeySigner),
+}
+
+#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
+#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
+impl TxSigner for AbstractWallet {
+
+ fn address(&self) -> Address {
+ match self {
+ AbstractWallet::Ledger(ledger) => Signer::address(ledger),
+ AbstractWallet::LocalWallet(localwallet) => localwallet.address(),
+ }
+ }
+
+ #[inline]
+ async fn sign_transaction(
+ &self,
+ tx: &mut dyn SignableTransaction,
+ ) -> Result { //@audit how to turn a typed transaction into a signableTx?
+ match self {
+ AbstractWallet::Ledger(ledger) => ledger
+ .sign_transaction(tx)
+ .await,
+ AbstractWallet::LocalWallet(localwallet) => localwallet
+ .sign_transaction(tx)
+ .await,
+ }
+ }
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl Signer for AbstractWallet {
- type Error = AbstractError;
- async fn sign_message>(
+ async fn sign_hash(&self, _hash: &B256) -> Result {
+ Err(alloy_signer::Error::UnsupportedOperation(
+ alloy_signer::UnsupportedSignerOperation::SignHash,
+ ))
+ }
+
+ async fn sign_message(
&self,
- message: S,
- ) -> Result {
+ message: &[u8],
+ ) -> Result {
match self {
AbstractWallet::Ledger(ledger) => ledger
.sign_message(message)
- .await
- .map_err(AbstractError::from),
+ .await,
AbstractWallet::LocalWallet(localwallet) => localwallet
.sign_message(message)
- .await
- .map_err(AbstractError::from),
+ .await,
}
}
- /// Signs the transaction
- async fn sign_transaction(
+ #[inline]
+ async fn sign_typed_data(
&self,
- message: &TypedTransaction,
- ) -> Result {
+ payload: &T,
+ domain: &Eip712Domain,
+ ) -> Result {
match self {
AbstractWallet::Ledger(ledger) => ledger
- .sign_transaction(message)
- .await
- .map_err(AbstractError::from),
+ .sign_typed_data(payload, domain)
+ .await,
+ // .map_err(AbstractError::from),
AbstractWallet::LocalWallet(localwallet) => localwallet
- .sign_transaction(message)
- .await
- .map_err(AbstractError::from),
+ .sign_typed_data(payload, domain)
+ .await,
+ // .map_err(AbstractError::from),
}
}
- async fn sign_typed_data(
- &self,
- payload: &T,
- ) -> Result {
+ #[inline]
+ async fn sign_dynamic_typed_data(&self, payload: &TypedData) -> Result {
match self {
AbstractWallet::Ledger(ledger) => ledger
- .sign_typed_data(payload)
- .await
- .map_err(AbstractError::from),
+ .sign_dynamic_typed_data(payload)
+ .await,
+ // .map_err(AbstractError::from),
AbstractWallet::LocalWallet(localwallet) => localwallet
- .sign_typed_data(payload)
- .await
- .map_err(AbstractError::from),
+ .sign_dynamic_typed_data(payload)
+ .await,
+ // .map_err(AbstractError::from),
}
}
/// Returns the signer's Ethereum Address
fn address(&self) -> Address {
match self {
- AbstractWallet::Ledger(ledger) => ledger.address(),
+ AbstractWallet::Ledger(ledger) => Signer::address(ledger),
AbstractWallet::LocalWallet(localwallet) => localwallet.address(),
}
}
/// Returns the signer's chain id
- fn chain_id(&self) -> u64 {
+ fn chain_id(&self) -> Option {
match self {
AbstractWallet::Ledger(ledger) => ledger.chain_id(),
AbstractWallet::LocalWallet(localwallet) => localwallet.chain_id(),
@@ -113,14 +152,15 @@ impl Signer for AbstractWallet {
}
/// Sets the signer's chain id
- fn with_chain_id>(self, chain_id: T) -> Self {
+ fn set_chain_id(&mut self, chain_id: Option) {
match self {
AbstractWallet::Ledger(ledger) => {
- AbstractWallet::Ledger(ledger.with_chain_id(chain_id))
+ ledger.set_chain_id(chain_id)
}
AbstractWallet::LocalWallet(localwallet) => {
- AbstractWallet::LocalWallet(localwallet.with_chain_id(chain_id))
+ localwallet.set_chain_id(chain_id)
}
}
}
}
+
diff --git a/lib/dvf/config.rs b/lib/dvf/config.rs
index 971ee87..1160f1e 100644
--- a/lib/dvf/config.rs
+++ b/lib/dvf/config.rs
@@ -9,14 +9,14 @@ use std::str::FromStr;
use clap::ArgMatches;
use dirs_next::home_dir;
-use ethers::types::H160;
-use ethers_core::rand::thread_rng;
-use ethers_core::types::Address;
-use ethers_core::types::Chain;
-use ethers_signers::HDPath;
-use ethers_signers::Ledger;
-use ethers_signers::LocalWallet;
-use ethers_signers::Signer;
+
+use alloy::primitives::Address;
+use alloy_chains::NamedChain;
+
+use alloy::signers::Signer;
+use alloy::signers::local::PrivateKeySigner; //LOCALWALLET
+use alloy_signer_ledger::{LedgerSigner, HDPath};
+
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use tempfile::{tempdir, NamedTempFile};
@@ -101,7 +101,7 @@ pub struct DVFConfig {
#[serde(skip_serializing)]
pub active_chain_id: Option,
#[serde(default, skip_serializing)]
- active_chain: Option,
+ active_chain: Option,
}
fn default_max_blocks() -> u64 {
@@ -210,22 +210,22 @@ impl DVFConfig {
pub fn get_abstract_wallet(&self, chain_id: u64) -> Result {
let wallet = match &self.signer {
- None => AbstractWallet::LocalWallet(LocalWallet::new(&mut thread_rng())),
+ None => AbstractWallet::LocalWallet(PrivateKeySigner::random()),
Some(signer) => {
let temp_wallet = match &signer.wallet_type {
DVFWalletType::SecretKey(sk) => AbstractWallet::LocalWallet(
sk.secret_key
- .parse::()
+ .parse::()
.map_err(|_| {
ValidationError::Error("Could not parse private key.".to_string())
})?
- .with_chain_id(chain_id),
+ .with_chain_id(Option::Some(chain_id)),
),
DVFWalletType::Ledger(ledger_config) => {
let rt = tokio::runtime::Runtime::new().unwrap();
AbstractWallet::Ledger(
- rt.block_on(Ledger::new(ledger_config.get_hd_path(), chain_id))?,
+ rt.block_on(LedgerSigner::new(ledger_config.get_hd_path(), Option::Some(chain_id)))?,
)
}
};
@@ -386,12 +386,12 @@ impl DVFConfig {
}
}
- let mut trusted_signers: Vec = vec![];
+ let mut trusted_signers: Vec = vec![];
first_item = true;
println!();
println!("{}", "STEP 3".green());
loop {
- let mut signer = H160::zero();
+ let mut signer = Address::default();
if first_item {
println!(
"Please provide a trusted signer or hit {} to go to the next step.",
@@ -563,7 +563,7 @@ impl DVFConfig {
break;
}
- let mut address = H160::zero();
+ let mut address = Address::default();
if sscanf!(&input, "{}", address).is_ok() {
loop {
println!("Please enter your signing choice:");
@@ -726,7 +726,7 @@ impl DVFConfig {
}
Some(_) => self.active_chain_id = Some(chain_id),
}
- self.active_chain = Chain::try_from(chain_id).ok();
+ self.active_chain = NamedChain::try_from(chain_id).ok();
let rpc_chain_id = web3::get_eth_chain_id(self)?;
if rpc_chain_id != chain_id {
@@ -740,7 +740,7 @@ impl DVFConfig {
Ok(())
}
- pub fn get_chain(&self) -> Chain {
+ pub fn get_chain(&self) -> NamedChain {
self.active_chain.unwrap()
}
diff --git a/lib/dvf/mod.rs b/lib/dvf/mod.rs
index 56e72bb..e470aef 100644
--- a/lib/dvf/mod.rs
+++ b/lib/dvf/mod.rs
@@ -1,4 +1,4 @@
pub mod abstract_wallet;
pub mod config;
pub mod parse;
-pub mod registry;
+pub mod registry;
\ No newline at end of file
diff --git a/lib/dvf/parse.rs b/lib/dvf/parse.rs
index bc702ff..3c15454 100644
--- a/lib/dvf/parse.rs
+++ b/lib/dvf/parse.rs
@@ -8,16 +8,22 @@ use std::num::ParseIntError;
use std::path::Path;
use std::str::FromStr;
+use ruint;
+
use crate::bytecode_verification::parse_json::ProjectInfo;
use crate::utils::pretty::convert_bytes_to_i256;
use crate::utils::pretty::PrettyPrinter;
use clap::ArgMatches;
-use ethers::abi::ethabi::ethereum_types::FromStrRadixErr;
-use ethers::signers::Signer;
-use ethers::solc::error::SolcError;
-use ethers::types::Address;
-use ethers::types::{Bytes, H256, U256};
-use ethers_signers::{LedgerError, WalletError};
+
+use foundry_compilers;
+
+use alloy_signer_ledger::LedgerError;
+use alloy_signer_local::LocalSignerError;
+use alloy::signers::Signer;
+use alloy_dyn_abi;
+use alloy::primitives::{Address, B256, U256, Bytes, PrimitiveSignature};
+
+
use reqwest;
use semver::Version;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -47,6 +53,7 @@ impl From for ValidationError {
match error {
AbstractError::LedgerError(e) => ValidationError::from(e),
AbstractError::WalletError(e) => ValidationError::from(e),
+ AbstractError::GeneralError(e) => ValidationError::from(e),
}
}
}
@@ -57,15 +64,15 @@ impl From for ValidationError {
}
}
-impl From for ValidationError {
- fn from(error: ethers::utils::hex::FromHexError) -> Self {
- ValidationError::Error(format!("Error Decoding Hex: {}", error))
+impl From for ValidationError {
+ fn from(error: alloy_dyn_abi::Error) -> Self {
+ ValidationError::Error(format!("Alloy Dyn Abi Error: {}", error))
}
}
-impl From for ValidationError {
- fn from(error: ethers::abi::Error) -> Self {
- ValidationError::Error(format!("ABI Error: {}", error))
+impl From for ValidationError {
+ fn from(error: ruint::ParseError) -> Self {
+ ValidationError::Error(format!("Uint Parse Error: {}", error))
}
}
@@ -75,20 +82,26 @@ impl From for ValidationError {
}
}
-impl From for ValidationError {
- fn from(error: FromStrRadixErr) -> Self {
- ValidationError::Error(format!("Error converting from hex: {}", error))
+impl From for ValidationError {
+ fn from(error: alloy::signers::Error) -> Self {
+ ValidationError::Error(format!("Signer Error: {}", error))
+ }
+}
+
+impl From for ValidationError {
+ fn from(error: alloy::hex::FromHexError) -> Self {
+ ValidationError::Error(format!("Alloy Hex Parse Error: {}", error))
}
}
-impl From for ValidationError {
- fn from(error: SolcError) -> Self {
- ValidationError::Error(format!("Error in solc: {}", error))
+impl From for ValidationError {
+ fn from(error: hex::FromHexError) -> Self {
+ ValidationError::Error(format!("Hex Parse Error: {}", error))
}
}
-impl From for ValidationError {
- fn from(error: WalletError) -> Self {
+impl From for ValidationError {
+ fn from(error: LocalSignerError) -> Self {
ValidationError::Error(format!("Error in with Local Wallet: {}", error))
}
}
@@ -287,14 +300,14 @@ impl DVFStorageEntry {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DVFEventOccurrence {
- pub topics: Vec,
+ pub topics: Vec,
pub data: Bytes,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DVFEventEntry {
pub sig: String, // Event signature, e.g. "Transfer(address,address,uint256)"
- pub topic0: H256, // Event Topic 0
+ pub topic0: B256, // Event Topic 0
pub occurrences: Vec, // Where the event has legitimately occurred
}
@@ -365,7 +378,7 @@ impl DumpedDVF {
let critical_storage_variables: Vec = vec![];
let critical_events: Vec = vec![];
let constructor_args: Vec = vec![];
- let implementation_address = matches.value_of("implementation").map(|_| Address::zero());
+ let implementation_address = matches.value_of("implementation").map(|_| Address::default());
let implementation_name = matches.value_of("implementation").map(|x| x.to_string());
let dumped = DumpedDVF {
version: CURRENT_VERSION,
@@ -527,13 +540,15 @@ impl CompleteDVF {
match &self.signature {
Some(sig) => match &sig.sig_data {
Some(sig_data) => {
- let signature = ethers::types::Signature::from_str(sig_data).unwrap();
- let sig_message = ethers::types::RecoveryMessage::from(self.get_sig_message()?);
- debug!("sig_message: {}", self.get_sig_message()?);
+ // let signature = PrimitiveSignature::from_str(sig_data).unwrap();
+ let signature: PrimitiveSignature = serde_json::from_str(sig_data).unwrap();
+ let sig_message = self.get_sig_message()?;
debug!("sig_message: {:?}", sig_message);
- let rec_address = signature.recover(sig_message).map_err(|_| {
- ValidationError::Error(String::from("Error. Signature validation failed."))
- })?;
+ let rec_address = signature.recover_address_from_msg(sig_message).map_err(
+ |_| {
+ ValidationError::Error(String::from("Error. Signature validation failed."))
+ }
+ )?;
debug!("Provided Address: {:?}", &sig.signer);
debug!("Recovered address {:?}", rec_address);
if sig.signer != rec_address {
@@ -653,11 +668,12 @@ impl CompleteDVF {
// Chain ID should not matter here
let wallet = config.get_abstract_wallet(1)?;
let rt = tokio::runtime::Runtime::new().unwrap();
- rt.block_on(wallet.sign_message(to_be_signed_data))?
+ rt.block_on(wallet.sign_message(to_be_signed_data.as_bytes()))?
}
};
if let Some(sig) = self.signature.as_mut() {
- sig.sig_data = Some("0x".to_string() + &signature.to_string());
+ let signature_str = serde_json::to_string(&signature).unwrap();
+ sig.sig_data = Some(signature_str);
};
Ok(())
}
diff --git a/lib/dvf/registry.rs b/lib/dvf/registry.rs
index d4aca0f..0966114 100644
--- a/lib/dvf/registry.rs
+++ b/lib/dvf/registry.rs
@@ -4,7 +4,7 @@ use std::fs;
use std::path::Path;
use std::path::PathBuf;
-use ethers_core::types::Address;
+use alloy::primitives::Address;
use tracing::debug;
use crate::dvf::config::DVFConfig;
diff --git a/lib/state/contract_state.rs b/lib/state/contract_state.rs
index 066fac7..973d3f2 100644
--- a/lib/state/contract_state.rs
+++ b/lib/state/contract_state.rs
@@ -172,10 +172,8 @@ impl<'a> ContractState<'a> {
}
if log.op == "CALL" || log.op == "STATICCALL" {
- let mut address_bytes = [0u8; 32];
- stack[stack.len() - 2].to_big_endian(&mut address_bytes);
- let mut a = Address::from([0; 20]);
- a.assign_from_slice(&address_bytes[12..]);
+ let address_bytes = stack[stack.len() - 2].to_be_bytes::<32>();
+ let a = Address::from_slice(&address_bytes[12..]);
depth_to_address.insert(log.depth + 1, a);
}
@@ -212,7 +210,7 @@ impl<'a> ContractState<'a> {
if length_in_bytes > U256::from(32_u64)
&& length_in_bytes < U256::from(usize::MAX / 2)
{
- let usize_str_length = length_in_bytes.as_usize() * 2 + 2;
+ let usize_str_length = usize::try_from(length_in_bytes).unwrap() * 2 + 2;
assert!(sha3_input.len() == usize_str_length);
key = Some(sha3_input[2..usize_str_length - 64].to_string());
index = U256::from_str_radix(&sha3_input[usize_str_length - 64..], 16)?;
@@ -294,7 +292,7 @@ impl<'a> ContractState<'a> {
}
for unused_part in unused_parts {
- let crit_var = DVFStorageEntry {
+ let crit_var: DVFStorageEntry = DVFStorageEntry {
slot: unused_part.slot,
offset: unused_part.offset,
var_name: String::from("unknown"),
@@ -448,7 +446,7 @@ impl<'a> ContractState<'a> {
)?);
}
let mut current_slot = match self.is_dynamic_array(&state_variable.var_type) {
- true => U256::from(hash_u256(&state_variable.slot)),
+ true => U256::from_be_slice(hash_u256(&state_variable.slot).as_slice()),
false => state_variable.slot,
};
for i in 0..num {
@@ -468,7 +466,7 @@ impl<'a> ContractState<'a> {
current_offset = 0;
// Check if we need to skip one slot
} else if current_offset + base_num_bytes + base_num_bytes > 32 {
- current_slot = current_slot.add(U256::one());
+ current_slot = current_slot.add(U256::from(1));
current_offset = 0;
} else {
current_offset += base_num_bytes;
@@ -581,19 +579,19 @@ impl<'a> ContractState<'a> {
snapshot,
table,
)?);
- let mut string_length = U256::from_big_endian(&snapshot.get_slot(
+ let mut string_length = U256::from_be_slice(&snapshot.get_slot(
&length_var.slot,
length_var.offset,
32,
));
// We skip the -1 as we round down anyway
- string_length /= U256([2, 0, 0, 0]);
- let mut string_index = U256::zero();
- let mut current_slot = U256::from(hash_u256(&state_variable.slot));
+ string_length /= U256::from_limbs([2, 0, 0, 0]);
+ let mut string_index = U256::ZERO;
+ let mut current_slot = U256::from_be_slice(hash_u256(&state_variable.slot).as_slice());
let mut raw_string: Vec = vec![];
- let u256_32 = U256([32, 0, 0, 0]);
+ let u256_32 = U256::from_limbs([32, 0, 0, 0]);
loop {
- let value_length = cmp::min(string_length.as_usize(), 32);
+ let value_length = cmp::min(string_length.as_limbs()[0] as usize, 32); //@note take the least significant limbs
let value =
snapshot.get_slot_and_mark(¤t_slot, 32 - value_length, value_length);
raw_string.extend_from_slice(&value);
@@ -613,8 +611,8 @@ impl<'a> ContractState<'a> {
break;
}
string_length -= u256_32;
- string_index += U256::one();
- current_slot += U256::one();
+ string_index += U256::from(1);
+ current_slot += U256::from(1);
}
let mut full_string = String::new();
if Self::is_string(&state_variable.var_type) {
diff --git a/lib/utils/pretty.rs b/lib/utils/pretty.rs
index c42530e..ed02c2b 100644
--- a/lib/utils/pretty.rs
+++ b/lib/utils/pretty.rs
@@ -2,12 +2,10 @@ use std::collections::HashMap;
use std::ops::BitAnd;
use std::str::FromStr;
-use ethers::abi::ethabi::param_type::Writer;
-use ethers::abi::Log;
-use ethers::abi::Token;
-use ethers::abi::{Event, ParamType};
-use ethers::types::{Address, Sign, I256, U256};
-use ethers_etherscan::Client;
+use alloy::json_abi::Event;
+use alloy::primitives::{Address, U256, I256, Sign};
+
+use alloy_dyn_abi::{DecodedEvent, DynSolValue};
use prettytable::Table;
use serde::Deserialize;
use tracing::debug;
@@ -37,7 +35,6 @@ pub struct ResolvedAddress {
#[derive(Debug)]
pub struct PrettyPrinter {
ns: HashMap,
- client: Option,
}
const KNOWN_ADDRS: &str = include_str!("../../addresses/known.json");
@@ -64,30 +61,30 @@ impl PrettyPrinter {
ns.extend(registry.collect_name_resolution(chain_id));
}
debug!("Name Resolution has {} entries.", ns.keys().len());
- PrettyPrinter { ns, client: None }
+ PrettyPrinter { ns }
}
- // Based on: https://docs.rs/ethabi/latest/src/ethabi/signature.rs.html
- // and https://docs.rs/ethabi/latest/src/ethabi/event.rs.html
pub fn event_to_string(event: &Event) -> String {
- let name = &event.name;
- let params: Vec = event.inputs.iter().map(|p| p.kind.clone()).collect();
- let types = params
- .iter()
- .map(Writer::write)
- .collect::>()
- .join(",");
- format!("{name}({types})")
+ event.signature()
}
- pub fn pretty_event_params(&self, log: &Log, newlines: bool) -> String {
+ pub fn pretty_event_params(&self, abi_event: &Event, decoded_event: &DecodedEvent, newlines: bool) -> String {
let mut decoded_params: Vec = vec![];
- for param in &log.params {
+ let mut next_index = 0;
+ let mut next_body = 0;
+ for param in &abi_event.inputs {
+ let current_val: &DynSolValue = if param.indexed {
+ next_index += 1;
+ &decoded_event.indexed[next_index - 1]
+ } else {
+ next_body += 1;
+ &decoded_event.body[next_body - 1]
+ };
decoded_params.push(format!(
"{} = {}",
¶m.name,
Self::insert_newline_every_n_chars(
- &self.pretty_token(¶m.value),
+ &self.pretty_token(current_val),
CHARS_PER_LINE,
param.name.len() + 4
),
@@ -100,35 +97,36 @@ impl PrettyPrinter {
}
}
- pub fn pretty_event(&self, event: &Event, log: &Log, newlines: bool) -> String {
- let name = &event.name;
- let params = self.pretty_event_params(log, newlines);
- format!("{name}{params}")
- }
-
- pub fn pretty_token(&self, token: &Token) -> String {
- match token {
- Token::Address(addr) => self.pretty_address(addr, false, false),
- Token::FixedBytes(fbytes) => format!("0x{}", hex::encode(fbytes)),
- Token::Bytes(bytes) => format!("0x{}", hex::encode(bytes)),
- Token::Int(int) => Self::pretty_int(&I256::from_raw(*int)),
- Token::Uint(uint) => Self::pretty_uint(uint),
- Token::Bool(b) => Self::pretty_bool(*b),
- Token::String(s) => s.clone(),
- Token::FixedArray(arr) | Token::Array(arr) => {
+ pub fn pretty_token(&self, dyn_val: &DynSolValue) -> String {
+ match dyn_val {
+ DynSolValue::Address(addr) => self.pretty_address(addr, false, false),
+ DynSolValue::FixedBytes(fbytes, _num_bytes) => format!("0x{}", hex::encode(fbytes)),
+ DynSolValue::Bytes(bytes) => format!("0x{}", hex::encode(bytes)),
+ DynSolValue::Int(int, _num_bits) => Self::pretty_int(int),
+ DynSolValue::Uint(uint, _num_bits) => Self::pretty_uint(uint),
+ DynSolValue::Bool(b) => Self::pretty_bool(*b),
+ DynSolValue::String(s) => s.clone(),
+ DynSolValue::FixedArray(arr) | DynSolValue::Array(arr) => {
let decoded: Vec = arr.iter().map(|a| self.pretty_token(a)).collect();
format!("[{}]", decoded.join(", "))
}
- Token::Tuple(arr) => {
+ DynSolValue::Tuple(arr) => {
let decoded: Vec = arr.iter().map(|a| self.pretty_token(a)).collect();
format!("({})", decoded.join(", "))
}
+ DynSolValue::Function(func) => {
+ format!("function {:?}", func)
+ }
+ DynSolValue::CustomStruct { name: _name, prop_names: _prop_name, tuple } => {
+ let decoded: Vec = tuple.iter().map(|a| self.pretty_token(a)).collect();
+ format!("({})", decoded.join(", "))
+ }
}
}
fn pretty_uint(u256: &U256) -> String {
// TODO Timestamps
- if u256 == &U256::max_value() {
+ if u256 == &U256::MAX {
return String::from("uint256 Max Value");
}
let u256_str = u256.to_string();
@@ -179,11 +177,11 @@ impl PrettyPrinter {
match resolved.address_type {
AddressType::Contract | AddressType::Token | AddressType::Registry => {
if long {
- if let Some(client) = self.client.as_ref() {
- format!("{}\nLink:\n{}", resolved.name, client.address_url(*a))
- } else {
- resolved.name.clone()
- }
+ format!(
+ "{}\nLink:\nhttps://etherscan.io/address/{:?}",
+ resolved.name,
+ a,
+ )
} else {
resolved.name.clone()
}
@@ -244,11 +242,10 @@ impl PrettyPrinter {
let i256 = convert_bytes_to_i256(value, var_type);
return Self::pretty_int(&i256);
} else if ContractState::is_uint(var_type) {
- let u256 = U256::from_big_endian(value);
+ let u256 = U256::from_be_slice(value);
return Self::pretty_uint(&u256);
} else if ContractState::is_address(var_type) {
- let mut a = Address::zero();
- a.assign_from_slice(&value[value.len() - 20..]);
+ let a = Address::from_slice(&value[value.len() - 20..]);
return self.pretty_address(&a, long, leave_empty);
} else if ContractState::is_bool(var_type) {
let last_byte: u8 = *value.last().unwrap();
@@ -372,10 +369,10 @@ pub fn convert_bytes_to_i256(bytes: &[u8], var_type: &str) -> I256 {
for i in 0..num_used_bytes {
full_bytes[i + num_unused_bytes] = bytes[bytes.len() - num_used_bytes + i];
}
- let u256 = U256::from_big_endian(&full_bytes);
+ let u256 = U256::from_be_slice(&full_bytes);
I256::from_raw(u256)
} else {
- let u256 = U256::from_big_endian(bytes);
+ let u256 = U256::from_be_slice(bytes);
I256::from_raw(u256)
}
}
@@ -387,46 +384,44 @@ mod tests {
#[test]
fn test_convert_bytes_to_i256() {
let b = vec![0xff];
- assert_eq!(I256::minus_one(), convert_bytes_to_i256(&b, "t_int8"));
+ assert_eq!(I256::MINUS_ONE, convert_bytes_to_i256(&b, "t_int8"));
let b2 = vec![0xff, 0xff];
- assert_eq!(I256::minus_one(), convert_bytes_to_i256(&b2, "t_int16"));
+ assert_eq!(I256::MINUS_ONE, convert_bytes_to_i256(&b2, "t_int16"));
let b3 = vec![0xff, 0xfe];
assert_eq!(
- I256::minus_one() + I256::minus_one(),
+ I256::MINUS_ONE + I256::MINUS_ONE,
convert_bytes_to_i256(&b3, "t_int16")
);
let b4 = vec![0, 0xff, 0xfe];
assert_eq!(
- I256::minus_one() + I256::minus_one(),
+ I256::MINUS_ONE + I256::MINUS_ONE,
convert_bytes_to_i256(&b4, "t_int16")
);
let b5 = vec![0x00];
- assert_eq!(I256::zero(), convert_bytes_to_i256(&b5, "t_int8"));
+ assert_eq!(I256::ZERO, convert_bytes_to_i256(&b5, "t_int8"));
let b6 = vec![0x00, 0x00];
- assert_eq!(I256::zero(), convert_bytes_to_i256(&b6, "t_int16"));
+ assert_eq!(I256::ZERO, convert_bytes_to_i256(&b6, "t_int16"));
let b7 = vec![0x00, 0x01];
- assert_eq!(I256::one(), convert_bytes_to_i256(&b7, "t_int16"));
+ assert_eq!(I256::ONE, convert_bytes_to_i256(&b7, "t_int16"));
let b8 = vec![0, 0x00, 0x02];
assert_eq!(
- I256::one() + I256::one(),
+ I256::ONE + I256::ONE,
convert_bytes_to_i256(&b8, "t_int16")
);
let b9 = vec![0u8; 32];
- assert_eq!(I256::zero(), convert_bytes_to_i256(&b9, "t_int256"));
+ assert_eq!(I256::ZERO, convert_bytes_to_i256(&b9, "t_int256"));
for i in vec![
- I256::zero(),
- I256::one(),
- I256::minus_one(),
- I256::max_value(),
- I256::min_value(),
+ I256::ZERO,
+ I256::ONE,
+ I256::MINUS_ONE,
+ I256::MAX,
+ I256::MAX,
] {
- let mut bytes = [0u8; 32];
- i.to_big_endian(&mut bytes);
+ let bytes: [u8; 32] = i.to_be_bytes();
assert_eq!(i, convert_bytes_to_i256(&bytes.to_vec(), "t_int256"));
}
- for i in vec![I256::zero(), I256::one(), I256::minus_one()] {
- let mut bytes = [0u8; 32];
- i.to_big_endian(&mut bytes);
+ for i in vec![I256::ZERO, I256::ONE, I256::MINUS_ONE] {
+ let bytes: [u8; 32] = i.to_be_bytes();
assert_eq!(i, convert_bytes_to_i256(&bytes.to_vec(), "t_int128"));
}
let b10 = vec![0x80];
diff --git a/lib/web3.rs b/lib/web3.rs
index 04404e4..f70ed5d 100644
--- a/lib/web3.rs
+++ b/lib/web3.rs
@@ -1,5 +1,5 @@
use std::cmp::Ordering;
-use std::collections::{BTreeMap, HashMap, HashSet};
+use std::collections::{HashMap, HashSet};
use std::fmt;
use std::io::Read;
use std::str::FromStr;
@@ -17,14 +17,68 @@ use tracing::{debug, info};
use crate::dvf::config::DVFConfig;
use crate::dvf::parse::ValidationError;
-use alloy::primitives::{Address, B256, U256};
+use alloy::primitives::{Address, B256, U256, Bytes};
use alloy_rpc_types_trace::parity::{Action, TraceOutput, LocalizedTransactionTrace};
-use alloy_rpc_types_trace::geth::{CallFrame, DefaultFrame, DiffMode};
-use alloy::rpc::types::{TransactionReceipt, Log, Block, Transaction};
+use alloy_rpc_types_trace::geth::{CallFrame, DefaultFrame, StructLog, DiffMode};
+use alloy::rpc::types::{TransactionReceipt, Log, Block, Transaction, EIP1186AccountProofResponse};
+
+use reth_trie::root;
const NUM_STORAGE_QUERIES: u64 = 32;
const LARGE_BLOCK_RANGE: u64 = 100000;
+mod pathological_rpc_deserde {
+ use serde::{self, Deserialize};
+
+ pub fn deserialize<'de, D>(deserializer: D) -> Result
+ where
+ D: super::Deserializer<'de>,
+ {
+ let s = String::deserialize(deserializer)?;
+ u64::from_str_radix(s.trim_start_matches("0x"), 16).map_err(serde::de::Error::custom)
+ }
+}
+
+// @note Some rpc returns gas in hex string
+// Copy pasted the alloy DefaultFrame with customized deserde impl
+#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct IntermediateDefaultFrame {
+ /// Whether the transaction failed
+ pub failed: bool,
+ /// How much gas was used.
+ #[serde(deserialize_with = "pathological_rpc_deserde::deserialize")]
+ pub gas: u64,
+ /// Output of the transaction
+ pub return_value: Bytes,
+ /// Recorded traces of the transaction
+ pub struct_logs: Vec,
+}
+
+impl From for TraceWithAddress {
+
+ fn from(x: IntermediateTraceWithAddress) -> Self {
+ let df = DefaultFrame {
+ failed: x.trace.failed,
+ gas: x.trace.gas,
+ return_value: x.trace.return_value,
+ struct_logs: x.trace.struct_logs,
+ };
+ TraceWithAddress {
+ trace: df,
+ address: x.address,
+ tx_id: x.tx_id,
+ }
+ }
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct IntermediateTraceWithAddress {
+ pub trace: IntermediateDefaultFrame,
+ pub address: Address,
+ pub tx_id: String,
+}
+
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TraceWithAddress {
pub trace: DefaultFrame,
@@ -155,7 +209,7 @@ fn extract_create_call_frame(
) -> Result {
if call_frame.typ.starts_with("CREATE")
&& call_frame.error.is_none()
- && call_frame.to.as_ref().and_then(|to| Some(to)) == Some(address)
+ && call_frame.to.as_ref() == Some(address)
{
return Ok(call_frame.clone());
}
@@ -241,7 +295,7 @@ fn extract_create_addresses_from_call_frame(
is_first: bool,
) -> Result<(), ValidationError> {
if !is_first && call_frame.typ.starts_with("CREATE") {
- let rec = call_frame.to.as_ref().and_then(|to| Some(to));
+ let rec = call_frame.to.as_ref();
match rec {
Some(addr) => addresses.push(*addr),
None => {
@@ -521,6 +575,28 @@ pub fn get_block_number_for_tx(
))
}
+// Not every rpc supports eth_getAccount.
+// So we have to retrieve the account by querying an empty storage proof
+pub fn get_eth_account_at_block(config: &DVFConfig, account: &Address, block: u64) -> Result {
+ let block_hex = format!("{:#x}", block);
+ let request_body = json!({
+ "jsonrpc": "2.0",
+ "method": "eth_getProof",
+ "params": [
+ account,
+ [], // slots
+ block_hex,
+ ],
+ "id": 1
+ });
+
+ let result = send_blocking_web3_post(config, &request_body)?;
+
+ let proof_resp: EIP1186AccountProofResponse = serde_json::from_value(result)?;
+
+ Ok(proof_resp.storage_hash)
+}
+
fn get_deployment_tx_from_blockscout(
config: &DVFConfig,
address: &Address,
@@ -743,7 +819,7 @@ pub fn get_all_txs_for_contract(
// Ignores reverting executions
fn call_frame_contains(call_frame: &CallFrame, address: &Address) -> bool {
if call_frame.error.is_none()
- && call_frame.to.as_ref().and_then(|to| Some(to)) == Some(address)
+ && call_frame.to.as_ref() == Some(address)
{
return true;
}
@@ -1262,9 +1338,16 @@ impl StorageSnapshot {
// And diffs for all txs
if let Ok(all_diffs) = get_many_diff_traces(config, &tx_hashes) {
// And compute snapshot from there
- Self::snapshot_from_diff_traces(&all_diffs, address)
+ let snapshot = Self::snapshot_from_diff_traces(&all_diffs, address);
+ // verify snapshot with account storage merkle root
+ Self::validate_snapshot_with_mpt_root(config, &snapshot, address, init_block_num);
+ snapshot
+
} else {
- Self::snapshot_from_tx_ids(config, address, &tx_hashes)?
+ let snapshot = Self::snapshot_from_tx_ids(config, address, &tx_hashes)?;
+ // verify snapshot with account storage merkle root
+ Self::validate_snapshot_with_mpt_root(config, &snapshot, address, init_block_num);
+ snapshot
}
};
debug!("Storage Snapshot: {:?}", snapshot);
@@ -1275,6 +1358,25 @@ impl StorageSnapshot {
})
}
+ // Reconstruct and verify the account storage root
+ pub fn validate_snapshot_with_mpt_root(config: &DVFConfig, snapshot: &HashMap, address: &Address, block_num: u64) {
+ // retrieve account info from rpc
+ let account_storage_root = get_eth_account_at_block(config, address, block_num).unwrap();
+
+ // snapshot type casting
+ let snapshot: HashMap = snapshot
+ .iter()
+ .map(
+ |(k, v)|
+ (B256::from(*k), U256::from_be_slice(v.as_slice()))
+ )
+ .collect();
+
+ let reconstructed_root = root::storage_root_unhashed(snapshot);
+
+ assert_eq!(reconstructed_root, account_storage_root);
+ }
+
fn init_unused_parts(snapshot: &HashMap) -> HashMap {
let mut unused_parts: HashMap = HashMap::new();
for slot in snapshot.keys() {
@@ -1703,6 +1805,7 @@ impl StorageSnapshot {
#[cfg(test)]
mod tests {
use std::str::FromStr;
+ use reth_trie::root;
use super::*;
use env_logger;
@@ -1780,22 +1883,57 @@ mod tests {
);
}
+ #[test]
+ fn test_validate_snapshot_with_merkle_root() {
+ init();
+ let address = Address::from_str("0x27dab51C2c5B6AF23DF64143c61ffCFa36F35E6d").unwrap();
+ let mut config = match DVFConfig::from_env(None) {
+ Ok(config) => config,
+ Err(err) => {
+ println!("{}", err);
+ assert!(false);
+ return;
+ }
+ };
+ config.set_chain_id(1).unwrap();
+
+ let init_block_num = get_eth_block_number(&config).unwrap() - 1;
+
+ let account_storage_root = get_eth_account_at_block(&config, &address, init_block_num).unwrap();
+
+ let snapshot: HashMap, [u8; 32]> = get_eth_storage_snapshot(&config, &address, init_block_num).unwrap();
+ let snapshot: HashMap = snapshot
+ .into_iter()
+ .map(
+ |(k, v)|
+ (B256::from(k), U256::from_be_slice(v.as_slice()))
+ )
+ .collect();
+
+ let reconstructed_root = root::storage_root_unhashed(snapshot);
+
+ println!("expected: {:?}", account_storage_root);
+ println!("reconstructed: {:?}", reconstructed_root);
+
+ assert_eq!(account_storage_root, reconstructed_root);
+ }
+
#[test]
fn test_snapshot_get() {
init();
let slots: Vec = vec![
U256::from_str_radix(
- "0x0000000000000000000000000000000000000000000000000000000000000002",
+ "0000000000000000000000000000000000000000000000000000000000000002",
16,
)
.unwrap(),
U256::from_str_radix(
- "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
16,
)
.unwrap(),
U256::from_str_radix(
- "0x000000000000000000000000000000000000000000000000000000000000000a",
+ "000000000000000000000000000000000000000000000000000000000000000a",
16,
)
.unwrap(),
@@ -1819,7 +1957,7 @@ mod tests {
assert_eq!(
snapshot.get_slot(
&U256::from_str_radix(
- "0x0000000000000000000000000000000000000000000000000000000000000123",
+ "0000000000000000000000000000000000000000000000000000000000000123",
16
)
.unwrap(),
@@ -1831,7 +1969,7 @@ mod tests {
assert_eq!(
snapshot.get_slot(
&U256::from_str_radix(
- "0x0000000000000000000000000000000000000000000000000000000000000123",
+ "0000000000000000000000000000000000000000000000000000000000000123",
16
)
.unwrap(),
@@ -1843,7 +1981,7 @@ mod tests {
assert_eq!(
snapshot.get_slot(
&U256::from_str_radix(
- "0x0000000000000000000000000000000000000000000000000000000000000123",
+ "0000000000000000000000000000000000000000000000000000000000000123",
16
)
.unwrap(),
diff --git a/src/cached_proxy.rs b/src/cached_proxy.rs
index 5989be8..7a3169c 100644
--- a/src/cached_proxy.rs
+++ b/src/cached_proxy.rs
@@ -1,6 +1,6 @@
use actix_web::{web, web::get, web::post, App, HttpRequest, HttpServer, Responder};
use clap::{Arg, Command};
-use ethers::utils::keccak256;
+use alloy::primitives::keccak256;
use reqwest::{header::HeaderMap, Url};
use serde_json::Value;
use std::fs::{create_dir_all, File};
diff --git a/src/dvf.rs b/src/dvf.rs
index 6b696d3..4150ce2 100644
--- a/src/dvf.rs
+++ b/src/dvf.rs
@@ -4,6 +4,7 @@ use std::path::{Path, PathBuf};
use std::process::exit;
use std::str::FromStr;
+use alloy_dyn_abi::EventExt;
use clap::{value_parser, Arg, ArgAction, ArgMatches, Command, SubCommand};
use colored::Colorize;
use console::style;
@@ -17,8 +18,8 @@ use dvf_libs::state::contract_state::ContractState;
use dvf_libs::state::forge_inspect::{self, StateVariable, TypeDescription};
use dvf_libs::utils::pretty::PrettyPrinter;
use dvf_libs::web3;
-use ethers::abi::{Event, RawLog};
-use ethers::types::{Address, H256};
+use alloy::json_abi::Event;
+use alloy::primitives::{Address, B256};
use indicatif::ProgressBar;
use prettytable::{row, Table};
use scanf::sscanf;
@@ -206,13 +207,14 @@ fn validate_dvf(
#[allow(clippy::needless_range_loop)]
for i in 0..seen_events.len() {
- if seen_events[i].topics != critical_event.occurrences[i].topics {
+ let log_inner = &seen_events[i].inner;
+ if log_inner.topics() != critical_event.occurrences[i].topics {
return Err(ValidationError::Invalid(format!(
"Mismatching topics for event occurrence {} of {}.",
i, critical_event.sig
)));
}
- if seen_events[i].data != critical_event.occurrences[i].data {
+ if log_inner.data.data != critical_event.occurrences[i].data {
return Err(ValidationError::Invalid(format!(
"Mismatching data for event occurrence {} of {}.",
i, critical_event.sig
@@ -290,7 +292,7 @@ fn is_valid_path(val: &str) -> Result<(), String> {
fn is_valid_address(val: &str) -> Result<(), String> {
match Address::from_str(val) {
Ok(a) => {
- if a != Address::zero() {
+ if a != Address::ZERO {
Ok(())
} else {
Err(String::from("Zero is not a valid address."))
@@ -992,11 +994,11 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
let all_events = match &imp_project_info {
None => project_info.events.clone(),
Some(imp_project) => {
- let mut set_of_sigs: HashSet = HashSet::new();
+ let mut set_of_sigs: HashSet = HashSet::new();
let mut res: Vec = vec![];
for eventlist in [&project_info.events, &imp_project.events] {
for event in eventlist {
- let sig = event.signature();
+ let sig = event.selector();
if set_of_sigs.contains(&sig) {
info!(
"Warning. Event {} omitted, as it is already known.",
@@ -1019,16 +1021,17 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
for abi_event in &all_events {
let sig = PrettyPrinter::event_to_string(abi_event);
debug!("Found the following event: {}", sig);
- let topic0 = abi_event.signature();
+ let topic0 = abi_event.selector();
debug!("Topic0: {:?}", topic0);
let mut table_head = false;
// Collect Occurrences
let mut occurrences: Vec = vec![];
for seen_event in &seen_events {
- if seen_event.topics.first() == Some(&topic0) {
- let decoded_log = abi_event.parse_log(RawLog::from(seen_event.clone()))?;
- let pretty_event = pretty_printer.pretty_event_params(&decoded_log, true);
+ if seen_event.topic0() == Some(&topic0) {
+ let log_inner = &seen_event.inner;
+ let decoded_event = abi_event.decode_log(log_inner, true)?;
+ let pretty_event = pretty_printer.pretty_event_params(abi_event, &decoded_event, true);
// Add Event Name to table
if !table_head {
@@ -1039,8 +1042,8 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
event_table.add_row(row![format!("- {}", pretty_event)]);
let occurrence = parse::DVFEventOccurrence {
- topics: seen_event.topics.clone(),
- data: seen_event.data.clone(),
+ topics: log_inner.data.topics().to_vec(),
+ data: log_inner.data.data.clone(),
};
occurrences.push(occurrence);
covered_events += 1;
@@ -1061,20 +1064,21 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
seen_events.len(),
covered_events
);
- let used_topics_0: HashSet =
- all_events.iter().map(|e| e.signature()).collect();
- let all_topics_0: HashSet = seen_events
+ let used_topics_0: HashSet =
+ all_events.iter().map(|e| e.selector()).collect();
+ let all_topics_0: HashSet = seen_events
.iter()
- .map(|e| *e.topics.first().unwrap())
+ .map(|e| *e.topic0().unwrap())
.collect();
for unused_topic in all_topics_0.difference(&used_topics_0) {
// Collect Occurrences
let mut occurrences: Vec = vec![];
for seen_event in &seen_events {
- if seen_event.topics.first() == Some(unused_topic) {
+ let log_inner = &seen_event.inner;
+ if seen_event.topic0() == Some(unused_topic) {
let occurrence = parse::DVFEventOccurrence {
- topics: seen_event.topics.clone(),
- data: seen_event.data.clone(),
+ topics: log_inner.data.topics().to_vec(),
+ data: log_inner.data.data.clone(),
};
occurrences.push(occurrence);
}
@@ -1361,14 +1365,15 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
let num_shared = std::cmp::min(seen_events.len(), critical_event.occurrences.len());
#[allow(clippy::needless_range_loop)]
for i in 0..num_shared {
- if seen_events[i].topics != critical_event.occurrences[i].topics {
+ let log_innner = &seen_events[i].inner;
+ if log_innner.topics() != critical_event.occurrences[i].topics {
println!(
"Mismatching topics for event occurrence {} of {}.",
i, critical_event.sig
);
replace_events = true;
}
- if seen_events[i].data != critical_event.occurrences[i].data {
+ if log_innner.data.data != critical_event.occurrences[i].data {
println!(
"Mismatching data for event occurrence {} of {}.",
i, critical_event.sig
@@ -1380,9 +1385,10 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
// Collect Occurrences
let mut occurrences: Vec = vec![];
for seen_event in &seen_events {
+ let log_inner = &seen_event.inner;
let occurrence = parse::DVFEventOccurrence {
- topics: seen_event.topics.clone(),
- data: seen_event.data.clone(),
+ topics: log_inner.data.topics().to_vec(),
+ data: log_inner.data.data.clone(),
};
occurrences.push(occurrence);
}
diff --git a/src/fetch.rs b/src/fetch.rs
index 2af1527..e612dbe 100644
--- a/src/fetch.rs
+++ b/src/fetch.rs
@@ -13,11 +13,11 @@ use clap::ArgMatches;
use clap::{App, Arg, ArgAction};
use dvf_libs::dvf::config::DVFConfig;
use dvf_libs::dvf::parse::{ValidationError, CURRENT_VERSION};
-use ethers_core::abi::Address;
-use ethers_etherscan::contract::SourceCodeEntry;
-use ethers_etherscan::errors::EtherscanError;
-use ethers_etherscan::Client;
-use ethers_solc::artifacts::Settings;
+use alloy::primitives::Address;
+use foundry_block_explorers::contract::{SourceCodeEntry, SourceCodeMetadata};
+use foundry_block_explorers::Client;
+use foundry_block_explorers::errors::EtherscanError;
+use foundry_compilers::artifacts::Settings;
use semver::Version;
use tokio::runtime::Runtime;
use toml::Table;
@@ -355,17 +355,17 @@ fn fetch(matches: &ArgMatches) -> Result<(), ValidationError> {
// Write sources
// Check what kind of Etherscan Response we have (Single file, Multi file, ...)
match &metadata.items[0].source_code {
- ethers_etherscan::contract::SourceCodeMetadata::SourceCode(source_str) => {
+ SourceCodeMetadata::SourceCode(source_str) => {
let sol_path = foundry_path
.join("src")
.join(&metadata.items[0].contract_name)
.with_extension("sol");
fs::write(sol_path, source_str).expect("Unable to write file");
}
- ethers_etherscan::contract::SourceCodeMetadata::Sources(sources) => {
+ SourceCodeMetadata::Sources(sources) => {
parse_sources(sources, foundry_path);
}
- ethers_etherscan::contract::SourceCodeMetadata::Metadata {
+ SourceCodeMetadata::Metadata {
sources, settings, ..
} => {
// Parse settings
diff --git a/tests/test_bytecode_only_e2e.rs b/tests/test_bytecode_only_e2e.rs
index afd1918..3430862 100644
--- a/tests/test_bytecode_only_e2e.rs
+++ b/tests/test_bytecode_only_e2e.rs
@@ -4,12 +4,12 @@ mod tests {
use assert_cmd::Command;
use dvf_libs::dvf::config::DVFConfig;
use dvf_libs::utils::pretty::ResolvedAddress;
- use ethers::types::Address;
use std::collections::HashMap;
- use std::str::FromStr;
use std::thread::sleep;
use std::time::Duration;
use tempfile::TempDir;
+ use std::str::FromStr;
+ use alloy::primitives::Address;
#[test]
fn test_invalid_bytecode() {
diff --git a/tests/test_decoding.rs b/tests/test_decoding.rs
index 74781c8..b166d32 100644
--- a/tests/test_decoding.rs
+++ b/tests/test_decoding.rs
@@ -10,7 +10,7 @@ mod tests {
use dvf_libs::state::contract_state::ContractState;
use dvf_libs::state::forge_inspect;
use dvf_libs::utils::pretty::PrettyPrinter;
- use dvf_libs::web3::{StorageSnapshot, TraceWithAddress};
+ use dvf_libs::web3::{StorageSnapshot, TraceWithAddress, IntermediateTraceWithAddress};
use prettytable::Table;
fn generate_results(
@@ -58,7 +58,8 @@ mod tests {
let path = format!("./tests/data/trace_{}.json", contract_name);
println!("Reading {}", path);
let trace_str = fs::read_to_string(&path).unwrap();
- let trace_w_a: TraceWithAddress = serde_json::from_str(&trace_str).unwrap();
+ let trace_w_a: IntermediateTraceWithAddress = serde_json::from_str(&trace_str).unwrap();
+ let trace_w_a: TraceWithAddress = trace_w_a.into();
let empty_config = DVFConfig::default();
let mut snapshot =
diff --git a/tests/test_end_to_end.rs b/tests/test_end_to_end.rs
index 83e5b1e..d6e9416 100644
--- a/tests/test_end_to_end.rs
+++ b/tests/test_end_to_end.rs
@@ -4,7 +4,6 @@ mod tests {
use assert_cmd::Command;
use dvf_libs::dvf::config::DVFConfig;
use dvf_libs::dvf::parse::CompleteDVF;
- use ethers_core::utils::{Anvil, AnvilInstance};
use std::fs::metadata;
use std::fs::File;
use std::fs::OpenOptions;
@@ -16,6 +15,7 @@ mod tests {
use std::thread::sleep;
use std::time::Duration;
use tempfile::NamedTempFile;
+ use alloy_node_bindings::{AnvilInstance, Anvil};
#[derive(PartialEq, Clone)]
enum LocalClientType {