diff --git a/crates/abi/abi/HEVM.sol b/crates/abi/abi/HEVM.sol index 0528b17462714..3e020e6640e49 100644 --- a/crates/abi/abi/HEVM.sol +++ b/crates/abi/abi/HEVM.sol @@ -2,6 +2,7 @@ struct Log { bytes32[] topics; bytes data; } struct Rpc { string name; string url; } struct DirEntry { string errorMessage; string path; uint64 depth; bool isDir; bool isSymlink; } struct FsMetadata { bool isDir; bool isSymlink; uint256 length; bool readOnly; uint256 modified; uint256 accessed; uint256 created; } +struct Wallet { address addr; uint256 publicKeyX; uint256 publicKeyY; uint256 privateKey; } allowCheatcodes(address) @@ -57,6 +58,12 @@ deriveKey(string,uint32,string)(uint256) deriveKey(string,string,uint32,string)(uint256) rememberKey(uint256)(address) +createWallet(string)(Wallet) +createWallet(uint256)(Wallet) +createWallet(uint256,string)(Wallet) +sign(Wallet,bytes32)(uint8,bytes32,bytes32) +getNonce(Wallet)(uint64) + prank(address) prank(address,address) readCallers()(uint256,address,address) diff --git a/crates/abi/src/bindings/hevm.rs b/crates/abi/src/bindings/hevm.rs index c098519faf3b8..34e50d45ef032 100644 --- a/crates/abi/src/bindings/hevm.rs +++ b/crates/abi/src/bindings/hevm.rs @@ -464,6 +464,94 @@ pub mod hevm { }, ], ), + ( + ::std::borrow::ToOwned::to_owned("createWallet"), + ::std::vec![ + ::ethers_core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("createWallet"), + inputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::String, + internal_type: ::core::option::Option::None, + }, + ], + outputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers_core::abi::ethabi::ParamType::Address, + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ], + ), + internal_type: ::core::option::Option::None, + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers_core::abi::ethabi::StateMutability::NonPayable, + }, + ::ethers_core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("createWallet"), + inputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + internal_type: ::core::option::Option::None, + }, + ], + outputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers_core::abi::ethabi::ParamType::Address, + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ], + ), + internal_type: ::core::option::Option::None, + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers_core::abi::ethabi::StateMutability::NonPayable, + }, + ::ethers_core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("createWallet"), + inputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + internal_type: ::core::option::Option::None, + }, + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::String, + internal_type: ::core::option::Option::None, + }, + ], + outputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers_core::abi::ethabi::ParamType::Address, + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ], + ), + internal_type: ::core::option::Option::None, + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers_core::abi::ethabi::StateMutability::NonPayable, + }, + ], + ), ( ::std::borrow::ToOwned::to_owned("deal"), ::std::vec![ @@ -2074,6 +2162,32 @@ pub mod hevm { ( ::std::borrow::ToOwned::to_owned("getNonce"), ::std::vec![ + ::ethers_core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("getNonce"), + inputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers_core::abi::ethabi::ParamType::Address, + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ], + ), + internal_type: ::core::option::Option::None, + }, + ], + outputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::None, + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers_core::abi::ethabi::StateMutability::NonPayable, + }, ::ethers_core::abi::ethabi::Function { name: ::std::borrow::ToOwned::to_owned("getNonce"), inputs: ::std::vec![ @@ -4375,6 +4489,53 @@ pub mod hevm { constant: ::core::option::Option::None, state_mutability: ::ethers_core::abi::ethabi::StateMutability::NonPayable, }, + ::ethers_core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("sign"), + inputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers_core::abi::ethabi::ParamType::Address, + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ::ethers_core::abi::ethabi::ParamType::Uint(256usize), + ], + ), + internal_type: ::core::option::Option::None, + }, + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::FixedBytes( + 32usize, + ), + internal_type: ::core::option::Option::None, + }, + ], + outputs: ::std::vec![ + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::Uint(8usize), + internal_type: ::core::option::Option::None, + }, + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::FixedBytes( + 32usize, + ), + internal_type: ::core::option::Option::None, + }, + ::ethers_core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers_core::abi::ethabi::ParamType::FixedBytes( + 32usize, + ), + internal_type: ::core::option::Option::None, + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers_core::abi::ethabi::StateMutability::NonPayable, + }, ], ), ( @@ -5119,6 +5280,58 @@ pub mod hevm { .method_hash([152, 104, 0, 52], p0) .expect("method not found (this should never happen)") } + ///Calls the contract's `createWallet` (0x7404f1d2) function + pub fn create_wallet_0( + &self, + p0: ::std::string::String, + ) -> ::ethers_contract::builders::ContractCall< + M, + ( + ::ethers_core::types::Address, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ), + > { + self.0 + .method_hash([116, 4, 241, 210], p0) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `createWallet` (0x7a675bb6) function + pub fn create_wallet_1( + &self, + p0: ::ethers_core::types::U256, + ) -> ::ethers_contract::builders::ContractCall< + M, + ( + ::ethers_core::types::Address, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ), + > { + self.0 + .method_hash([122, 103, 91, 182], p0) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `createWallet` (0xed7c5462) function + pub fn create_wallet_2( + &self, + p0: ::ethers_core::types::U256, + p1: ::std::string::String, + ) -> ::ethers_contract::builders::ContractCall< + M, + ( + ::ethers_core::types::Address, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ), + > { + self.0 + .method_hash([237, 124, 84, 98], (p0, p1)) + .expect("method not found (this should never happen)") + } ///Calls the contract's `deal` (0xc88a5e6d) function pub fn deal( &self, @@ -5784,8 +5997,17 @@ pub mod hevm { .method_hash([235, 199, 58, 180], (p0, p1, p2)) .expect("method not found (this should never happen)") } + ///Calls the contract's `getNonce` (0xa5748aad) function + pub fn get_nonce_0( + &self, + p0: Wallet, + ) -> ::ethers_contract::builders::ContractCall { + self.0 + .method_hash([165, 116, 138, 173], (p0,)) + .expect("method not found (this should never happen)") + } ///Calls the contract's `getNonce` (0x2d0335ab) function - pub fn get_nonce( + pub fn get_nonce_1( &self, p0: ::ethers_core::types::Address, ) -> ::ethers_contract::builders::ContractCall { @@ -6683,7 +6905,7 @@ pub mod hevm { .expect("method not found (this should never happen)") } ///Calls the contract's `sign` (0xe341eaa4) function - pub fn sign( + pub fn sign_0( &self, p0: ::ethers_core::types::U256, p1: [u8; 32], @@ -6692,6 +6914,16 @@ pub mod hevm { .method_hash([227, 65, 234, 164], (p0, p1)) .expect("method not found (this should never happen)") } + ///Calls the contract's `sign` (0xb25c5a25) function + pub fn sign_1( + &self, + p0: Wallet, + p1: [u8; 32], + ) -> ::ethers_contract::builders::ContractCall { + self.0 + .method_hash([178, 92, 90, 37], (p0, p1)) + .expect("method not found (this should never happen)") + } ///Calls the contract's `skip` (0xdd82d13e) function pub fn skip( &self, @@ -7245,6 +7477,48 @@ pub mod hevm { )] #[ethcall(name = "createSelectFork", abi = "createSelectFork(string)")] pub struct CreateSelectFork0Call(pub ::std::string::String); + ///Container type for all input parameters for the `createWallet` function with signature `createWallet(string)` and selector `0x7404f1d2` + #[derive( + Clone, + ::ethers_contract::EthCall, + ::ethers_contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "createWallet", abi = "createWallet(string)")] + pub struct CreateWallet0Call(pub ::std::string::String); + ///Container type for all input parameters for the `createWallet` function with signature `createWallet(uint256)` and selector `0x7a675bb6` + #[derive( + Clone, + ::ethers_contract::EthCall, + ::ethers_contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "createWallet", abi = "createWallet(uint256)")] + pub struct CreateWallet1Call(pub ::ethers_core::types::U256); + ///Container type for all input parameters for the `createWallet` function with signature `createWallet(uint256,string)` and selector `0xed7c5462` + #[derive( + Clone, + ::ethers_contract::EthCall, + ::ethers_contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "createWallet", abi = "createWallet(uint256,string)")] + pub struct CreateWallet2Call( + pub ::ethers_core::types::U256, + pub ::std::string::String, + ); ///Container type for all input parameters for the `deal` function with signature `deal(address,uint256)` and selector `0xc88a5e6d` #[derive( Clone, @@ -8154,6 +8428,19 @@ pub mod hevm { pub [u8; 32], pub ::ethers_core::types::U256, ); + ///Container type for all input parameters for the `getNonce` function with signature `getNonce((address,uint256,uint256,uint256))` and selector `0xa5748aad` + #[derive( + Clone, + ::ethers_contract::EthCall, + ::ethers_contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "getNonce", abi = "getNonce((address,uint256,uint256,uint256))")] + pub struct GetNonce0Call(pub Wallet); ///Container type for all input parameters for the `getNonce` function with signature `getNonce(address)` and selector `0x2d0335ab` #[derive( Clone, @@ -8166,7 +8453,7 @@ pub mod hevm { Hash )] #[ethcall(name = "getNonce", abi = "getNonce(address)")] - pub struct GetNonceCall(pub ::ethers_core::types::Address); + pub struct GetNonce1Call(pub ::ethers_core::types::Address); ///Container type for all input parameters for the `getRecordedLogs` function with signature `getRecordedLogs()` and selector `0x191553a4` #[derive( Clone, @@ -9435,7 +9722,20 @@ pub mod hevm { Hash )] #[ethcall(name = "sign", abi = "sign(uint256,bytes32)")] - pub struct SignCall(pub ::ethers_core::types::U256, pub [u8; 32]); + pub struct Sign0Call(pub ::ethers_core::types::U256, pub [u8; 32]); + ///Container type for all input parameters for the `sign` function with signature `sign((address,uint256,uint256,uint256),bytes32)` and selector `0xb25c5a25` + #[derive( + Clone, + ::ethers_contract::EthCall, + ::ethers_contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "sign", abi = "sign((address,uint256,uint256,uint256),bytes32)")] + pub struct Sign1Call(pub Wallet, pub [u8; 32]); ///Container type for all input parameters for the `skip` function with signature `skip(bool)` and selector `0xdd82d13e` #[derive( Clone, @@ -9835,6 +10135,9 @@ pub mod hevm { CreateSelectFork1(CreateSelectFork1Call), CreateSelectFork2(CreateSelectFork2Call), CreateSelectFork0(CreateSelectFork0Call), + CreateWallet0(CreateWallet0Call), + CreateWallet1(CreateWallet1Call), + CreateWallet2(CreateWallet2Call), Deal(DealCall), DeriveKey0(DeriveKey0Call), DeriveKey1(DeriveKey1Call), @@ -9896,7 +10199,8 @@ pub mod hevm { GetMappingKeyAndParentOf(GetMappingKeyAndParentOfCall), GetMappingLength(GetMappingLengthCall), GetMappingSlotAt(GetMappingSlotAtCall), - GetNonce(GetNonceCall), + GetNonce0(GetNonce0Call), + GetNonce1(GetNonce1Call), GetRecordedLogs(GetRecordedLogsCall), IsPersistent(IsPersistentCall), KeyExists(KeyExistsCall), @@ -9983,7 +10287,8 @@ pub mod hevm { SetEnv(SetEnvCall), SetNonce(SetNonceCall), SetNonceUnsafe(SetNonceUnsafeCall), - Sign(SignCall), + Sign0(Sign0Call), + Sign1(Sign1Call), Skip(SkipCall), Sleep(SleepCall), Snapshot(SnapshotCall), @@ -10112,6 +10417,18 @@ pub mod hevm { ) { return Ok(Self::CreateSelectFork0(decoded)); } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::CreateWallet0(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::CreateWallet1(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::CreateWallet2(decoded)); + } if let Ok(decoded) = ::decode(data) { return Ok(Self::Deal(decoded)); @@ -10365,8 +10682,12 @@ pub mod hevm { return Ok(Self::GetMappingSlotAt(decoded)); } if let Ok(decoded) - = ::decode(data) { - return Ok(Self::GetNonce(decoded)); + = ::decode(data) { + return Ok(Self::GetNonce0(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::GetNonce1(decoded)); } if let Ok(decoded) = ::decode(data) { @@ -10741,8 +11062,12 @@ pub mod hevm { return Ok(Self::SetNonceUnsafe(decoded)); } if let Ok(decoded) - = ::decode(data) { - return Ok(Self::Sign(decoded)); + = ::decode(data) { + return Ok(Self::Sign0(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Sign1(decoded)); } if let Ok(decoded) = ::decode(data) { @@ -10920,6 +11245,15 @@ pub mod hevm { Self::CreateSelectFork0(element) => { ::ethers_core::abi::AbiEncode::encode(element) } + Self::CreateWallet0(element) => { + ::ethers_core::abi::AbiEncode::encode(element) + } + Self::CreateWallet1(element) => { + ::ethers_core::abi::AbiEncode::encode(element) + } + Self::CreateWallet2(element) => { + ::ethers_core::abi::AbiEncode::encode(element) + } Self::Deal(element) => ::ethers_core::abi::AbiEncode::encode(element), Self::DeriveKey0(element) => { ::ethers_core::abi::AbiEncode::encode(element) @@ -11051,7 +11385,12 @@ pub mod hevm { Self::GetMappingSlotAt(element) => { ::ethers_core::abi::AbiEncode::encode(element) } - Self::GetNonce(element) => ::ethers_core::abi::AbiEncode::encode(element), + Self::GetNonce0(element) => { + ::ethers_core::abi::AbiEncode::encode(element) + } + Self::GetNonce1(element) => { + ::ethers_core::abi::AbiEncode::encode(element) + } Self::GetRecordedLogs(element) => { ::ethers_core::abi::AbiEncode::encode(element) } @@ -11272,7 +11611,8 @@ pub mod hevm { Self::SetNonceUnsafe(element) => { ::ethers_core::abi::AbiEncode::encode(element) } - Self::Sign(element) => ::ethers_core::abi::AbiEncode::encode(element), + Self::Sign0(element) => ::ethers_core::abi::AbiEncode::encode(element), + Self::Sign1(element) => ::ethers_core::abi::AbiEncode::encode(element), Self::Skip(element) => ::ethers_core::abi::AbiEncode::encode(element), Self::Sleep(element) => ::ethers_core::abi::AbiEncode::encode(element), Self::Snapshot(element) => ::ethers_core::abi::AbiEncode::encode(element), @@ -11375,6 +11715,9 @@ pub mod hevm { Self::CreateSelectFork1(element) => ::core::fmt::Display::fmt(element, f), Self::CreateSelectFork2(element) => ::core::fmt::Display::fmt(element, f), Self::CreateSelectFork0(element) => ::core::fmt::Display::fmt(element, f), + Self::CreateWallet0(element) => ::core::fmt::Display::fmt(element, f), + Self::CreateWallet1(element) => ::core::fmt::Display::fmt(element, f), + Self::CreateWallet2(element) => ::core::fmt::Display::fmt(element, f), Self::Deal(element) => ::core::fmt::Display::fmt(element, f), Self::DeriveKey0(element) => ::core::fmt::Display::fmt(element, f), Self::DeriveKey1(element) => ::core::fmt::Display::fmt(element, f), @@ -11440,7 +11783,8 @@ pub mod hevm { } Self::GetMappingLength(element) => ::core::fmt::Display::fmt(element, f), Self::GetMappingSlotAt(element) => ::core::fmt::Display::fmt(element, f), - Self::GetNonce(element) => ::core::fmt::Display::fmt(element, f), + Self::GetNonce0(element) => ::core::fmt::Display::fmt(element, f), + Self::GetNonce1(element) => ::core::fmt::Display::fmt(element, f), Self::GetRecordedLogs(element) => ::core::fmt::Display::fmt(element, f), Self::IsPersistent(element) => ::core::fmt::Display::fmt(element, f), Self::KeyExists(element) => ::core::fmt::Display::fmt(element, f), @@ -11539,7 +11883,8 @@ pub mod hevm { Self::SetEnv(element) => ::core::fmt::Display::fmt(element, f), Self::SetNonce(element) => ::core::fmt::Display::fmt(element, f), Self::SetNonceUnsafe(element) => ::core::fmt::Display::fmt(element, f), - Self::Sign(element) => ::core::fmt::Display::fmt(element, f), + Self::Sign0(element) => ::core::fmt::Display::fmt(element, f), + Self::Sign1(element) => ::core::fmt::Display::fmt(element, f), Self::Skip(element) => ::core::fmt::Display::fmt(element, f), Self::Sleep(element) => ::core::fmt::Display::fmt(element, f), Self::Snapshot(element) => ::core::fmt::Display::fmt(element, f), @@ -11685,6 +12030,21 @@ pub mod hevm { Self::CreateSelectFork0(value) } } + impl ::core::convert::From for HEVMCalls { + fn from(value: CreateWallet0Call) -> Self { + Self::CreateWallet0(value) + } + } + impl ::core::convert::From for HEVMCalls { + fn from(value: CreateWallet1Call) -> Self { + Self::CreateWallet1(value) + } + } + impl ::core::convert::From for HEVMCalls { + fn from(value: CreateWallet2Call) -> Self { + Self::CreateWallet2(value) + } + } impl ::core::convert::From for HEVMCalls { fn from(value: DealCall) -> Self { Self::Deal(value) @@ -11990,9 +12350,14 @@ pub mod hevm { Self::GetMappingSlotAt(value) } } - impl ::core::convert::From for HEVMCalls { - fn from(value: GetNonceCall) -> Self { - Self::GetNonce(value) + impl ::core::convert::From for HEVMCalls { + fn from(value: GetNonce0Call) -> Self { + Self::GetNonce0(value) + } + } + impl ::core::convert::From for HEVMCalls { + fn from(value: GetNonce1Call) -> Self { + Self::GetNonce1(value) } } impl ::core::convert::From for HEVMCalls { @@ -12425,9 +12790,14 @@ pub mod hevm { Self::SetNonceUnsafe(value) } } - impl ::core::convert::From for HEVMCalls { - fn from(value: SignCall) -> Self { - Self::Sign(value) + impl ::core::convert::From for HEVMCalls { + fn from(value: Sign0Call) -> Self { + Self::Sign0(value) + } + } + impl ::core::convert::From for HEVMCalls { + fn from(value: Sign1Call) -> Self { + Self::Sign1(value) } } impl ::core::convert::From for HEVMCalls { @@ -12681,6 +13051,63 @@ pub mod hevm { Hash )] pub struct CreateSelectFork0Return(pub ::ethers_core::types::U256); + ///Container type for all return fields from the `createWallet` function with signature `createWallet(string)` and selector `0x7404f1d2` + #[derive( + Clone, + ::ethers_contract::EthAbiType, + ::ethers_contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct CreateWallet0Return( + pub ( + ::ethers_core::types::Address, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ), + ); + ///Container type for all return fields from the `createWallet` function with signature `createWallet(uint256)` and selector `0x7a675bb6` + #[derive( + Clone, + ::ethers_contract::EthAbiType, + ::ethers_contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct CreateWallet1Return( + pub ( + ::ethers_core::types::Address, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ), + ); + ///Container type for all return fields from the `createWallet` function with signature `createWallet(uint256,string)` and selector `0xed7c5462` + #[derive( + Clone, + ::ethers_contract::EthAbiType, + ::ethers_contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct CreateWallet2Return( + pub ( + ::ethers_core::types::Address, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ::ethers_core::types::U256, + ), + ); ///Container type for all return fields from the `deriveKey` function with signature `deriveKey(string,uint32)` and selector `0x6229498b` #[derive( Clone, @@ -13111,6 +13538,18 @@ pub mod hevm { Hash )] pub struct GetLabelReturn(pub ::std::string::String); + ///Container type for all return fields from the `getNonce` function with signature `getNonce((address,uint256,uint256,uint256))` and selector `0xa5748aad` + #[derive( + Clone, + ::ethers_contract::EthAbiType, + ::ethers_contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct GetNonce0Return(pub u64); ///Container type for all return fields from the `getRecordedLogs` function with signature `getRecordedLogs()` and selector `0x191553a4` #[derive( Clone, @@ -13806,7 +14245,19 @@ pub mod hevm { Eq, Hash )] - pub struct SignReturn(pub u8, pub [u8; 32], pub [u8; 32]); + pub struct Sign0Return(pub u8, pub [u8; 32], pub [u8; 32]); + ///Container type for all return fields from the `sign` function with signature `sign((address,uint256,uint256,uint256),bytes32)` and selector `0xb25c5a25` + #[derive( + Clone, + ::ethers_contract::EthAbiType, + ::ethers_contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct Sign1Return(pub u8, pub [u8; 32], pub [u8; 32]); ///Container type for all return fields from the `snapshot` function with signature `snapshot()` and selector `0x9711715a` #[derive( Clone, @@ -13887,4 +14338,21 @@ pub mod hevm { pub name: ::std::string::String, pub url: ::std::string::String, } + ///`Wallet(address,uint256,uint256,uint256)` + #[derive( + Clone, + ::ethers_contract::EthAbiType, + ::ethers_contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct Wallet { + pub addr: ::ethers_core::types::Address, + pub public_key_x: ::ethers_core::types::U256, + pub public_key_y: ::ethers_core::types::U256, + pub private_key: ::ethers_core::types::U256, + } } diff --git a/crates/evm/src/executor/inspector/cheatcodes/env.rs b/crates/evm/src/executor/inspector/cheatcodes/env.rs index 27fa5bdd390a0..bd122387697e2 100644 --- a/crates/evm/src/executor/inspector/cheatcodes/env.rs +++ b/crates/evm/src/executor/inspector/cheatcodes/env.rs @@ -511,7 +511,8 @@ pub fn apply( Ok(Bytes::new()) }, )??, - HEVMCalls::GetNonce(inner) => { + // [function getNonce(address)] returns the current nonce of a given ETH address + HEVMCalls::GetNonce1(inner) => { correct_sender_nonce( b160_to_h160(data.env.tx.caller), &mut data.journaled_state, @@ -527,6 +528,23 @@ pub fn apply( let account = data.journaled_state.state().get(&h160_to_b160(inner.0)).unwrap(); abi::encode(&[Token::Uint(account.info.nonce.into())]).into() } + // [function getNonce(Wallet)] returns the current nonce of the Wallet's ETH address + HEVMCalls::GetNonce0(inner) => { + correct_sender_nonce( + b160_to_h160(data.env.tx.caller), + &mut data.journaled_state, + &mut data.db, + state, + )?; + + // TODO: this is probably not a good long-term solution since it might mess up the gas + // calculations + data.journaled_state.load_account(h160_to_b160(inner.0.addr), data.db)?; + + // we can safely unwrap because `load_account` insert inner.0 to DB. + let account = data.journaled_state.state().get(&h160_to_b160(inner.0.addr)).unwrap(); + abi::encode(&[Token::Uint(account.info.nonce.into())]).into() + } HEVMCalls::ChainId(inner) => { ensure!(inner.0 <= U256::from(u64::MAX), "Chain ID must be less than 2^64 - 1"); data.env.cfg.chain_id = inner.0.into(); diff --git a/crates/evm/src/executor/inspector/cheatcodes/util.rs b/crates/evm/src/executor/inspector/cheatcodes/util.rs index abb9aad05aba6..b3863c0a55c5d 100644 --- a/crates/evm/src/executor/inspector/cheatcodes/util.rs +++ b/crates/evm/src/executor/inspector/cheatcodes/util.rs @@ -12,7 +12,11 @@ use ethers::{ abi::{AbiEncode, Address, ParamType, Token}, core::k256::elliptic_curve::Curve, prelude::{ - k256::{ecdsa::SigningKey, elliptic_curve::bigint::Encoding, Secp256k1}, + k256::{ + ecdsa::SigningKey, + elliptic_curve::{bigint::Encoding, sec1::ToEncodedPoint}, + Secp256k1, + }, LocalWallet, Signer, H160, *, }, signers::{ @@ -23,7 +27,7 @@ use ethers::{ MnemonicBuilder, }, types::{transaction::eip2718::TypedTransaction, NameOrAddress, H256, U256}, - utils, + utils::{self, keccak256}, }; use foundry_common::{fmt::*, RpcUrl}; use revm::{ @@ -120,6 +124,28 @@ fn sign(private_key: U256, digest: H256, chain_id: U256) -> Result { Ok((sig.v, r_bytes, s_bytes).encode().into()) } +/// Using a given private key, return its public ETH address, its public key affine x and y +/// coodinates, and its private key (see the 'Wallet' struct) +/// +/// If 'label' is set to 'Some()', assign that label to the associated ETH address in state +fn create_wallet(private_key: U256, label: Option, state: &mut Cheatcodes) -> Result { + let key = parse_private_key(private_key)?; + let addr = utils::secret_key_to_address(&key); + + let pub_key = key.verifying_key().as_affine().to_encoded_point(false); + let pub_key_x = pub_key.x().ok_or("No x coordinate was found")?; + let pub_key_y = pub_key.y().ok_or("No y coordinate was found")?; + + let pub_key_x = U256::from(pub_key_x.as_slice()); + let pub_key_y = U256::from(pub_key_y.as_slice()); + + if let Some(label) = label { + state.labels.insert(addr, label); + } + + Ok((addr, pub_key_x, pub_key_y, private_key).encode().into()) +} + enum WordlistLang { ChineseSimplified, ChineseTraditional, @@ -222,7 +248,23 @@ pub fn apply( ) -> Option { Some(match call { HEVMCalls::Addr(inner) => addr(inner.0), - HEVMCalls::Sign(inner) => sign(inner.0, inner.1.into(), data.env.cfg.chain_id.into()), + // [function sign(uint256,bytes32)] Used to sign bytes32 digests using the given private key + HEVMCalls::Sign0(inner) => sign(inner.0, inner.1.into(), data.env.cfg.chain_id.into()), + // [function createWallet(string)] Used to derive private key and label the wallet with the + // same string + HEVMCalls::CreateWallet0(inner) => { + create_wallet(U256::from(keccak256(&inner.0)), Some(inner.0.clone()), state) + } + // [function createWallet(uint256)] creates a new wallet with the given private key + HEVMCalls::CreateWallet1(inner) => create_wallet(inner.0, None, state), + // [function createWallet(uint256,string)] creates a new wallet with the given private key + // and labels it with the given string + HEVMCalls::CreateWallet2(inner) => create_wallet(inner.0, Some(inner.1.clone()), state), + // [function sign(uint256,bytes32)] Used to sign bytes32 digests using the given Wallet's + // private key + HEVMCalls::Sign1(inner) => { + sign(inner.0.private_key, inner.1.into(), data.env.cfg.chain_id.into()) + } HEVMCalls::DeriveKey0(inner) => { derive_key::(&inner.0, DEFAULT_DERIVATION_PATH_PREFIX, inner.1) } diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index eda063914a21a..2b35df6db0c8c 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -44,6 +44,14 @@ interface Vm { uint256 created; } + // Returned by 'createWallet'. Used with 'sign' and 'getNonce' + struct Wallet { + address addr; + uint256 publicKeyX; + uint256 publicKeyY; + uint256 privateKey; + } + // Set block.timestamp (newTimestamp) function warp(uint256) external; @@ -90,6 +98,21 @@ interface Vm { // Adds a private key to the local forge wallet and returns the address function rememberKey(uint256) external returns (address); + // Derives a private key from the name, labels the account with that name, and returns the wallet + function createWallet(string calldata) external returns (Wallet memory); + + // Generates a wallet from the private key and returns the wallet + function createWallet(uint256) external returns (Wallet memory); + + // Generates a wallet from the private key, labels the account with that name, and returns the wallet + function createWallet(uint256, string calldata) external returns (Wallet memory); + + // Signs data, (Wallet, digest) => (v, r, s) + function sign(Wallet calldata, bytes32) external returns (uint8, bytes32, bytes32); + + // Get nonce for a Wallet + function getNonce(Wallet calldata) external returns (uint64); + // Performs a foreign function call via terminal, (stringInputs) => (result) function ffi(string[] calldata) external returns (bytes memory); diff --git a/testdata/cheats/Wallet.t.sol b/testdata/cheats/Wallet.t.sol new file mode 100644 index 0000000000000..cccb874bdb0fa --- /dev/null +++ b/testdata/cheats/Wallet.t.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity 0.8.18; + +import "ds-test/test.sol"; +import "./Vm.sol"; + +contract Foo {} + +contract WalletTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + function addressOf(uint256 x, uint256 y) internal pure returns (address) { + return address(uint160(uint256(keccak256(abi.encode(x, y))))); + } + + function bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { + require(min <= max, "min needs to be less than max"); + // If x is between min and max, return x directly. This is to ensure that dictionary values + // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 + if (x >= min && x <= max) return x; + + uint256 size = max - min + 1; + + // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. + // This helps ensure coverage of the min/max values. + if (x <= 3 && size > x) return min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); + + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. + if (x > max) { + uint256 diff = x - max; + uint256 rem = diff % size; + if (rem == 0) return max; + result = min + rem - 1; + } else if (x < min) { + uint256 diff = min - x; + uint256 rem = diff % size; + if (rem == 0) return min; + result = max - rem + 1; + } + } + + function testCreateWalletStringPrivAndLabel() public { + bytes memory privKey = "this is a priv key"; + Vm.Wallet memory wallet = vm.createWallet(string(privKey)); + + // check wallet.addr against recovered address using private key + address expectedAddr = vm.addr(wallet.privateKey); + assertEq(expectedAddr, wallet.addr); + + // check wallet.addr against recovered address using x and y coordinates + expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); + assertEq(expectedAddr, wallet.addr); + + string memory label = vm.getLabel(wallet.addr); + assertEq(label, string(privKey), "labelled address != wallet.addr"); + } + + function testCreateWalletPrivKeyNoLabel(uint256 pkSeed) public { + uint256 pk = bound(pkSeed, 1, Q - 1); + + Vm.Wallet memory wallet = vm.createWallet(pk); + + // check wallet.addr against recovered address using private key + address expectedAddr = vm.addr(wallet.privateKey); + assertEq(expectedAddr, wallet.addr); + + // check wallet.addr against recovered address using x and y coordinates + expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); + assertEq(expectedAddr, wallet.addr); + } + + function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public { + string memory label = "labelled wallet"; + + uint256 pk = bound(pkSeed, 1, Q - 1); + + Vm.Wallet memory wallet = vm.createWallet(pk, label); + + // check wallet.addr against recovered address using private key + address expectedAddr = vm.addr(wallet.privateKey); + assertEq(expectedAddr, wallet.addr); + + // check wallet.addr against recovered address using x and y coordinates + expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); + assertEq(expectedAddr, wallet.addr); + + string memory expectedLabel = vm.getLabel(wallet.addr); + assertEq(expectedLabel, label, "labelled address != wallet.addr"); + } + + function testSignWithWalletDigest(uint256 pkSeed, bytes32 digest) public { + uint256 pk = bound(pkSeed, 1, Q - 1); + + Vm.Wallet memory wallet = vm.createWallet(pk); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wallet, digest); + + address recovered = ecrecover(digest, v, r, s); + assertEq(recovered, wallet.addr); + } + + function testSignWithWalletMessage(uint256 pkSeed, bytes memory message) public { + testSignWithWalletDigest(pkSeed, keccak256(message)); + } + + function testGetNonceWallet(uint256 pkSeed) public { + uint256 pk = bound(pkSeed, 1, Q - 1); + + Vm.Wallet memory wallet = vm.createWallet(pk); + + uint64 nonce1 = vm.getNonce(wallet); + + vm.startPrank(wallet.addr); + new Foo(); + new Foo(); + vm.stopPrank(); + + uint64 nonce2 = vm.getNonce(wallet); + assertEq(nonce1 + 2, nonce2); + } +}