diff --git a/Cargo.lock b/Cargo.lock index fe6cfa8cb615f..63ab6aeda08c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -815,6 +815,7 @@ version = "0.2.0" dependencies = [ "async-trait", "chrono", + "const-hex", "ethers-contract", "ethers-core", "ethers-etherscan", @@ -827,11 +828,9 @@ dependencies = [ "foundry-evm", "foundry-utils", "futures", - "hex", "rayon", "rusoto_core", "rusoto_kms", - "rustc-hex", "serde", "serde_json", "thiserror", @@ -1205,6 +1204,18 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "const-hex" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "268f52aae268980d03dd9544c1ea591965b2735b038d6998d6e4ab37c8c24445" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "serde", +] + [[package]] name = "const-oid" version = "0.9.5" @@ -2325,6 +2336,7 @@ name = "forge" version = "0.2.0" dependencies = [ "comfy-table", + "const-hex", "ethers", "eyre", "foundry-common", @@ -2332,7 +2344,6 @@ dependencies = [ "foundry-evm", "foundry-utils", "glob", - "hex", "once_cell", "parking_lot", "proptest", @@ -2444,6 +2455,7 @@ dependencies = [ "clap_complete_fig", "color-eyre", "comfy-table", + "const-hex", "criterion", "dialoguer", "dotenvy", @@ -2461,7 +2473,6 @@ dependencies = [ "foundry-utils", "futures", "globset", - "hex", "indicatif", "itertools", "once_cell", @@ -2473,7 +2484,6 @@ dependencies = [ "regex", "reqwest", "rpassword", - "rustc-hex", "semver 1.0.18", "serde", "serde_json", @@ -2583,6 +2593,7 @@ version = "0.2.0" dependencies = [ "auto_impl", "bytes", + "const-hex", "ethers", "eyre", "foundry-abi", @@ -2592,7 +2603,6 @@ dependencies = [ "foundry-utils", "futures", "hashbrown 0.13.2", - "hex", "itertools", "jsonpath_lib", "once_cell", @@ -2635,6 +2645,7 @@ dependencies = [ name = "foundry-utils" version = "0.2.0" dependencies = [ + "const-hex", "dunce", "ethers-addressbook", "ethers-contract", @@ -2647,13 +2658,11 @@ dependencies = [ "foundry-common", "futures", "glob", - "hex", "once_cell", "pretty_assertions", "rand 0.8.5", "reqwest", "rlp", - "rustc-hex", "serde", "serde_json", "tokio", @@ -7092,12 +7101,12 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" name = "ui" version = "0.2.0" dependencies = [ + "const-hex", "crossterm 0.26.1", "ethers", "eyre", "forge", "foundry-common", - "hex", "revm", "tui", ] diff --git a/Cargo.toml b/Cargo.toml index ca461e348805d..6d27a103b7fd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,6 +119,7 @@ ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-featu ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false } chrono = { version = "0.4", default-features = false, features = ["clock", "std"] } +hex = { package = "const-hex", version = "1.6", features = ["hex"] } solang-parser = "=0.3.1" #[patch."https://github.com/gakonst/ethers-rs"] diff --git a/cast/Cargo.toml b/cast/Cargo.toml index f38c2da42d81b..414ff90b4b580 100644 --- a/cast/Cargo.toml +++ b/cast/Cargo.toml @@ -20,11 +20,10 @@ ethers-providers = { workspace = true } ethers-signers = { workspace = true } futures = "0.3" eyre = "0.6" -rustc-hex = "2" serde = "1" serde_json = "1" chrono.workspace = true -hex = "0.4" +hex.workspace = true rayon = "1" # aws diff --git a/cast/src/lib.rs b/cast/src/lib.rs index 5770e71e29824..0e0e6ebf1688f 100644 --- a/cast/src/lib.rs +++ b/cast/src/lib.rs @@ -28,7 +28,6 @@ pub use rusoto_core::{ request::HttpClient as AwsHttpClient, Client as AwsClient, }; pub use rusoto_kms::KmsClient; -use rustc_hex::{FromHexIter, ToHex}; use std::{ path::PathBuf, str::FromStr, @@ -915,8 +914,7 @@ impl SimpleCast { /// } /// ``` pub fn from_utf8(s: &str) -> String { - let s: String = s.as_bytes().to_hex(); - format!("0x{s}") + hex::encode_prefixed(s) } /// Converts hex data into text data @@ -935,13 +933,11 @@ impl SimpleCast { /// } /// ``` pub fn to_ascii(hex: &str) -> Result { - let hex_trimmed = hex.trim_start_matches("0x"); - let iter = FromHexIter::new(hex_trimmed); - let mut ascii = String::new(); - for letter in iter.collect::>() { - ascii.push(letter? as char); + let bytes = hex::decode(hex)?; + if !bytes.iter().all(u8::is_ascii) { + return Err(eyre::eyre!("Invalid ASCII bytes")) } - Ok(ascii) + Ok(String::from_utf8(bytes).unwrap()) } /// Converts fixed point number into specified number of decimals @@ -1457,7 +1453,7 @@ impl SimpleCast { } }; let calldata = match encode_args(&func, args) { - Ok(res) => res.to_hex::(), + Ok(res) => hex::encode(res), Err(e) => eyre::bail!("Could not ABI encode the function and arguments. Did you pass in the right types?\nError\n{}", e), }; let encoded = &calldata[8..]; @@ -1482,7 +1478,7 @@ impl SimpleCast { pub fn calldata_encode(sig: impl AsRef, args: &[impl AsRef]) -> Result { let func = HumanReadableParser::parse_function(sig.as_ref())?; let calldata = encode_args(&func, args)?; - Ok(format!("0x{}", calldata.to_hex::())) + Ok(hex::encode_prefixed(calldata)) } /// Generates an interface in solidity from either a local file ABI or a verified contract on @@ -1609,8 +1605,7 @@ impl SimpleCast { } } - let namehash: String = node.to_hex(); - Ok(format!("0x{namehash}")) + Ok(hex::encode_prefixed(node)) } /// Keccak-256 hashes arbitrary data diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 3787eb4e8dbda..b23523ae4d0a7 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -60,12 +60,11 @@ tempfile = "3" # misc eyre = "0.6" color-eyre = "0.6" -rustc-hex = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" regex = { version = "1", default-features = false } rpassword = "7" -hex = "0.4" +hex = { workspace = true, features = ["serde"] } itertools = "0.10" proptest = "1" semver = "1" diff --git a/cli/src/cast.rs b/cli/src/cast.rs index dbe64932bc819..b97c8a4471b8f 100644 --- a/cli/src/cast.rs +++ b/cli/src/cast.rs @@ -22,7 +22,6 @@ use foundry_common::{ }, }; use foundry_config::Config; -use rustc_hex::ToHex; use std::time::Instant; #[tokio::main] @@ -83,21 +82,9 @@ async fn main() -> eyre::Result<()> { Subcommands::ToHexdata { input } => { let value = stdin::unwrap_line(input)?; let output = match value { - s if s.starts_with('@') => { - let var = std::env::var(&s[1..])?; - var.as_bytes().to_hex() - } - s if s.starts_with('/') => { - let input = fs::read(s)?; - input.to_hex() - } - s => { - let mut output = String::new(); - for s in s.split(':') { - output.push_str(&s.trim_start_matches("0x").to_lowercase()) - } - output - } + s if s.starts_with('@') => hex::encode(std::env::var(&s[1..])?), + s if s.starts_with('/') => hex::encode(fs::read(s)?), + s => s.split(':').map(|s| s.trim_start_matches("0x").to_lowercase()).collect(), }; println!("0x{output}"); } diff --git a/cli/src/cmd/forge/create.rs b/cli/src/cmd/forge/create.rs index 362931b353f73..edc7a02cbb9c1 100644 --- a/cli/src/cmd/forge/create.rs +++ b/cli/src/cmd/forge/create.rs @@ -18,7 +18,6 @@ use ethers::{ }; use eyre::Context; use foundry_common::{abi::parse_tokens, compile, estimate_eip1559_fees}; -use rustc_hex::ToHex; use serde_json::json; use std::{path::PathBuf, sync::Arc}; @@ -263,10 +262,9 @@ impl CreateArgs { let code = Vec::new(); let encoded_args = abi .constructor() - .ok_or(eyre::eyre!("could not find constructor"))? - .encode_input(code, &args)? - .to_hex::(); - constructor_args = Some(encoded_args); + .ok_or_else(|| eyre::eyre!("could not find constructor"))? + .encode_input(code, &args)?; + constructor_args = Some(hex::encode(encoded_args)); } self.verify_preflight_check(constructor_args.clone(), chain).await?; diff --git a/cli/src/cmd/forge/verify/etherscan/mod.rs b/cli/src/cmd/forge/verify/etherscan/mod.rs index ae44302660dde..7948f48b58198 100644 --- a/cli/src/cmd/forge/verify/etherscan/mod.rs +++ b/cli/src/cmd/forge/verify/etherscan/mod.rs @@ -24,7 +24,6 @@ use foundry_utils::Retry; use futures::FutureExt; use once_cell::sync::Lazy; use regex::Regex; -use rustc_hex::ToHex; use semver::{BuildMetadata, Version}; use std::{ fmt::Debug, @@ -432,8 +431,8 @@ impl EtherscanVerificationProvider { let encoded_args = encode_args( &func, &read_constructor_args_file(constructor_args_path.to_path_buf())?, - )? - .to_hex::(); + )?; + let encoded_args = hex::encode(encoded_args); return Ok(Some(encoded_args[8..].into())) } diff --git a/evm/Cargo.toml b/evm/Cargo.toml index ca9ce3f736757..e553f274aed19 100644 --- a/evm/Cargo.toml +++ b/evm/Cargo.toml @@ -19,7 +19,7 @@ ethers = { workspace = true, features = ["ethers-solc"] } # Encoding/decoding serde_json = "1" serde = "1" -hex = "0.4" +hex.workspace = true jsonpath_lib = "0.3" # Error handling diff --git a/evm/src/executor/inspector/cheatcodes/ext.rs b/evm/src/executor/inspector/cheatcodes/ext.rs index 862235fefe286..ee4707019de58 100644 --- a/evm/src/executor/inspector/cheatcodes/ext.rs +++ b/evm/src/executor/inspector/cheatcodes/ext.rs @@ -7,10 +7,9 @@ use ethers::{ }; use foundry_common::{fmt::*, fs, get_artifact_path}; use foundry_config::fs_permissions::FsAccessKind; -use hex::FromHex; use serde::Deserialize; use serde_json::Value; -use std::{collections::BTreeMap, env, path::Path, process::Command, str::FromStr}; +use std::{collections::BTreeMap, env, path::Path, process::Command}; /// Invokes a `Command` with the given args and returns the abi encoded response /// @@ -211,22 +210,18 @@ fn value_to_token(value: &Value) -> Result { Err(fmt_err!("Unsupported value: {number:?}")) } Value::String(string) => { - if let Some(val) = string.strip_prefix("0x") { - // If it can decoded as an address, it's an address - if let Ok(addr) = H160::from_str(string) { - Ok(Token::Address(addr)) - } else if hex::decode(val).is_ok() { - // if length == 32 bytes, then encode as Bytes32, else Bytes - Ok(if val.len() == 64 { - Token::FixedBytes(Vec::from_hex(val).unwrap()) - } else { - Token::Bytes(Vec::from_hex(val).unwrap()) - }) - } else { - // If incorrect length, pad 0 at the beginning - let arr = format!("0{val}"); - Ok(Token::Bytes(Vec::from_hex(arr).unwrap())) + if let Some(mut val) = string.strip_prefix("0x") { + let s; + if val.len() % 2 != 0 { + s = format!("0{}", val); + val = &s[..]; } + let bytes = hex::decode(val)?; + Ok(match bytes.len() { + 20 => Token::Address(Address::from_slice(&bytes)), + 32 => Token::FixedBytes(bytes), + _ => Token::Bytes(bytes), + }) } else { Ok(Token::String(string.to_owned())) } diff --git a/forge/Cargo.toml b/forge/Cargo.toml index d194a68252a3b..0893b45d3ad5a 100644 --- a/forge/Cargo.toml +++ b/forge/Cargo.toml @@ -16,7 +16,7 @@ ethers = { workspace = true, features = ["solc-full"] } comfy-table = "6" eyre = "0.6" glob = "0.3" -hex = "0.4" +hex.workspace = true once_cell = "1" parking_lot = "0.12" proptest = "1" diff --git a/ui/Cargo.toml b/ui/Cargo.toml index 3d0c3a024e33c..cc115b096a1e2 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -15,6 +15,6 @@ ethers = { workspace = true } crossterm = "0.26" eyre = "0.6" -hex = "0.4" +hex.workspace = true revm = { version = "3", features = ["std", "serde"] } tui = { version = "0.19", default-features = false, features = ["crossterm"] } diff --git a/utils/Cargo.toml b/utils/Cargo.toml index c98ebc65b9fa8..790cbe103c116 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -19,12 +19,11 @@ ethers-solc = { workspace = true } eyre = { version = "0.6", default-features = false } futures = "0.3" glob = "0.3" -hex = "0.4" +hex.workspace = true once_cell = "1" rand = "0.8" reqwest = { version = "0.11", default-features = false, features = ["json", "rustls"] } rlp = "0.5" -rustc-hex = { version = "2", default-features = false } serde = "1" serde_json = { version = "1", default-features = false } tokio = { version = "1", features = ["rt-multi-thread", "macros"] }