diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index 49611dcca071c..89a7fedb67882 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -62,3 +62,4 @@ tracing.workspace = true walkdir.workspace = true proptest.workspace = true serde.workspace = true + diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 59c5bab3cb457..d3a7f653b86e9 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -9760,6 +9760,26 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "signTypedData", + "description": "Signs Human-Readable Typed Data with `privateKey` using the secp256k1 curve.", + "declaration": "function signTypedData(string calldata jsonData, uint256 privateKey) external pure returns (uint8 v, bytes32 r, bytes32 s);", + "visibility": "external", + "mutability": "pure", + "signature": "signTypedData(string,uint256)", + "selector": "0x85f00b0d", + "selectorBytes": [ + 133, + 240, + 11, + 13 + ] + }, + "group": "crypto", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "sign_0", diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 00f3b8004a96c..977aa9d315248 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -2651,6 +2651,10 @@ interface Vm { #[cheatcode(group = Crypto)] function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + /// Signs Human-Readable Typed Data with `privateKey` using the secp256k1 curve. + #[cheatcode(group = Crypto)] + function signTypedData(string calldata jsonData, uint256 privateKey) external pure returns (uint8 v, bytes32 r,bytes32 s); + /// Signs `digest` with `privateKey` using the secp256k1 curve. /// /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the diff --git a/crates/cheatcodes/src/crypto.rs b/crates/cheatcodes/src/crypto.rs index 8ef7e96aeff3b..8e6d5bd390a57 100644 --- a/crates/cheatcodes/src/crypto.rs +++ b/crates/cheatcodes/src/crypto.rs @@ -1,6 +1,7 @@ //! Implementations of [`Crypto`](spec::Group::Crypto) Cheatcodes. use crate::{Cheatcode, Cheatcodes, Result, Vm::*}; +use alloy_dyn_abi::eip712::TypedData; use alloy_primitives::{keccak256, Address, B256, U256}; use alloy_signer::{Signer, SignerSync}; use alloy_signer_local::{ @@ -51,6 +52,16 @@ impl Cheatcode for sign_0Call { } } +impl Cheatcode for signTypedDataCall { + fn apply(&self, _state: &mut Cheatcodes) -> Result { + let Self { jsonData, privateKey } = self; + let typed_data: TypedData = serde_json::from_str(jsonData)?; + let digest = typed_data.eip712_signing_hash()?; + let sig = sign(privateKey, &digest)?; + Ok(encode_full_sig(sig)) + } +} + impl Cheatcode for signCompact_0Call { fn apply(&self, _state: &mut Cheatcodes) -> Result { let Self { wallet, digest } = self; diff --git a/crates/evm/traces/src/decoder/mod.rs b/crates/evm/traces/src/decoder/mod.rs index 2e22ca7cdc358..c91d066789b29 100644 --- a/crates/evm/traces/src/decoder/mod.rs +++ b/crates/evm/traces/src/decoder/mod.rs @@ -457,11 +457,12 @@ impl CallTraceDecoder { Some(decoded.iter().map(format_token).collect()) } - "signDelegation" | "signAndAttachDelegation" => { + "signDelegation" | "signAndAttachDelegation" | "signTypedData" => { let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..], false).ok()?; // Redact private key and replace in trace for // signAndAttachDelegation(address implementation, uint256 privateKey) // signDelegation(address implementation, uint256 privateKey) + // signTypedData(string jsonData, uint256 privateKey) decoded[1] = DynSolValue::String("".to_string()); Some(decoded.iter().map(format_token).collect()) } diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index adf6733ba9424..c9d9d0033f582 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -481,6 +481,7 @@ interface Vm { function signDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation); function signDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation); function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s); + function signTypedData(string calldata jsonData, uint256 privateKey) external pure returns (uint8 v, bytes32 r, bytes32 s); function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);