From 64c230a235eb8d5eb78e39042525772008c8a3b8 Mon Sep 17 00:00:00 2001 From: Francesco Dainese Date: Mon, 14 Oct 2024 13:22:06 -0300 Subject: [PATCH 1/3] feat(signer-ledger): EIP712 in `sign_transaction` --- crates/signer-ledger/src/signer.rs | 46 +++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/crates/signer-ledger/src/signer.rs b/crates/signer-ledger/src/signer.rs index 32d32fb972f..281ff0a5f90 100644 --- a/crates/signer-ledger/src/signer.rs +++ b/crates/signer-ledger/src/signer.rs @@ -16,6 +16,9 @@ use alloy_dyn_abi::TypedData; #[cfg(feature = "eip712")] use alloy_sol_types::{Eip712Domain, SolStruct}; +#[cfg(feature = "eip712")] +use alloy_signer::Error; + /// A Ledger Ethereum signer. /// /// This is a simple wrapper around the [Ledger transport](Ledger). @@ -43,7 +46,33 @@ impl alloy_network::TxSigner for LedgerSigner { &self, tx: &mut dyn SignableTransaction, ) -> Result { - sign_transaction_with_chain_id!(self, tx, self.sign_tx_rlp(&tx.encoded_for_signing()).await) + let encoded = tx.encoded_for_signing(); + + match encoded.as_slice() { + // Ledger requires passing EIP712 data to a separate instruction + #[cfg(feature = "eip712")] + [0x19, 0x1, data @ ..] => { + let domain_sep = data + .get(..32) + .ok_or_else(|| { + Error::other("eip712 encoded data did not have a domain separator") + }) + .map(B256::from_slice)?; + + let hash = data[32..] + .get(..32) + .ok_or_else(|| Error::other("eip712 encoded data did not have hash struct")) + .map(B256::from_slice)?; + + sign_transaction_with_chain_id!( + self, + tx, + self.sign_typed_data_with_separator(&hash, &domain_sep).await + ) + } + // Usual flow + encoded => sign_transaction_with_chain_id!(self, tx, self.sign_tx_rlp(encoded).await), + } } } @@ -208,10 +237,10 @@ impl LedgerSigner { } #[cfg(feature = "eip712")] - async fn sign_typed_data_( + async fn sign_typed_data_with_separator( &self, hash_struct: &B256, - domain: &Eip712Domain, + separator: &B256, ) -> Result { // See comment for v1.6.0 requirement // https://github.com/LedgerHQ/app-ethereum/issues/105#issuecomment-765316999 @@ -225,12 +254,21 @@ impl LedgerSigner { } let mut data = Self::path_to_bytes(&self.derivation); - data.extend_from_slice(domain.separator().as_slice()); + data.extend_from_slice(separator.as_slice()); data.extend_from_slice(hash_struct.as_slice()); self.sign_payload(INS::SIGN_ETH_EIP_712, &data).await } + #[cfg(feature = "eip712")] + async fn sign_typed_data_( + &self, + hash_struct: &B256, + domain: &Eip712Domain, + ) -> Result { + self.sign_typed_data_with_separator(hash_struct, &domain.separator()).await + } + /// Helper function for signing either transaction data, personal messages or EIP712 derived /// structs. #[instrument(err, skip_all, fields(command = %command, payload = hex::encode(payload)))] From 5342aafbc7e26bbdcbdd888695254cfa6ba51958 Mon Sep 17 00:00:00 2001 From: Francesco Dainese Date: Fri, 1 Nov 2024 17:31:28 +0100 Subject: [PATCH 2/3] chore: avoid feature-gated import --- crates/signer-ledger/src/signer.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/signer-ledger/src/signer.rs b/crates/signer-ledger/src/signer.rs index 281ff0a5f90..410448333a7 100644 --- a/crates/signer-ledger/src/signer.rs +++ b/crates/signer-ledger/src/signer.rs @@ -16,9 +16,6 @@ use alloy_dyn_abi::TypedData; #[cfg(feature = "eip712")] use alloy_sol_types::{Eip712Domain, SolStruct}; -#[cfg(feature = "eip712")] -use alloy_signer::Error; - /// A Ledger Ethereum signer. /// /// This is a simple wrapper around the [Ledger transport](Ledger). @@ -55,13 +52,13 @@ impl alloy_network::TxSigner for LedgerSigner { let domain_sep = data .get(..32) .ok_or_else(|| { - Error::other("eip712 encoded data did not have a domain separator") + alloy_signer::Error::other("eip712 encoded data did not have a domain separator") }) .map(B256::from_slice)?; let hash = data[32..] .get(..32) - .ok_or_else(|| Error::other("eip712 encoded data did not have hash struct")) + .ok_or_else(|| alloy_signer::Error::other("eip712 encoded data did not have hash struct")) .map(B256::from_slice)?; sign_transaction_with_chain_id!( From fa844eb20eb0ef00d32a5389281a2cb7cc22cf4f Mon Sep 17 00:00:00 2001 From: Francesco Dainese Date: Fri, 1 Nov 2024 20:37:37 +0100 Subject: [PATCH 3/3] chore: fmt --- crates/signer-ledger/src/signer.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/signer-ledger/src/signer.rs b/crates/signer-ledger/src/signer.rs index 410448333a7..a373c96d7c8 100644 --- a/crates/signer-ledger/src/signer.rs +++ b/crates/signer-ledger/src/signer.rs @@ -52,13 +52,17 @@ impl alloy_network::TxSigner for LedgerSigner { let domain_sep = data .get(..32) .ok_or_else(|| { - alloy_signer::Error::other("eip712 encoded data did not have a domain separator") + alloy_signer::Error::other( + "eip712 encoded data did not have a domain separator", + ) }) .map(B256::from_slice)?; let hash = data[32..] .get(..32) - .ok_or_else(|| alloy_signer::Error::other("eip712 encoded data did not have hash struct")) + .ok_or_else(|| { + alloy_signer::Error::other("eip712 encoded data did not have hash struct") + }) .map(B256::from_slice)?; sign_transaction_with_chain_id!(