ethers-rs/ethers-signers/src/wallet/mod.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

177 lines
5.8 KiB
Rust
Raw Normal View History

mod mnemonic;
pub use mnemonic::{MnemonicBuilder, MnemonicBuilderError};
mod private_key;
pub use private_key::WalletError;
#[cfg(all(feature = "yubihsm", not(target_arch = "wasm32")))]
mod yubi;
2020-12-24 10:38:27 +00:00
use crate::{to_eip155_v, Signer};
use ethers_core::{
k256::{
ecdsa::{signature::hazmat::PrehashSigner, RecoveryId, Signature as RecoverableSignature},
elliptic_curve::FieldBytes,
Secp256k1,
},
derive-eip712: initial implementation of eip712 derive macro (#481) * derive-eip712: initial implementation of eip712 derive macro This commit provides an initial implementation for a derive macro to encode typed data according to EIP-712, https://eips.ethereum.org/EIPS/eip-712 Additionally, this commit introduces a new signer trait method: async fn sign_typed_data<T: Eip712 + Send + Sync>( &self, payload: &T, ) -> Result<Signature, Self::Error>; And implements the new method for each of the signers (wallet, ledger, aws). Additionally, these changes include using `WalletError` for the Wallet signer error type At the moment, derive does not recurse the primary type to find nested Eip712 structs. This is something that is noted in the source and currently responds with an error regarding custom types. A subsequent PR should be opened once this issue becomes needed. For the moment, the current implementation should satisfy non-nested, basic struct types. * rename to ethers-derive-eip712; move to ethers-core * refactor of derive-eip712 macro; use ParamType and EthAbiToken * macro updates; add byte array checker for paramtype; use literal constant for domain type hash * replace std::convert::Infallible with WalletError as Wallet signer error type * update workspace members and dev dependencies for examples folder * add example for eip712 and test against contract * remove extraneous backward slash in '\x19\x01' prefix; example tests pass * update unreleased change log * remove print statements * use parse_macro_input macro; remove dead code; handle nest struct not implemented error * move eip712 example to solidity-contract tests folder; update cargo workspace dependencies * allow optional EIP712Domain parameter when encoding eip712 struct and signing typed data * add documentation for eip712 feature * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Sebastian Martinez <me@sebastinez.dev> * add error enum for Eip712Error; use sign_payload for ledger signer * add EIP712WithDomain type for providing a wrapper around custom setting of the domain * make LedgerWallet sign_payload public * use optional feature gated dependencies for eip712; add default method for encode_eip712 * add default domain_separator method, pre-compute separator hash * move derive-eip712 deps to dev deps * remove invalid sign payload parameter, add await on async method * remove deprecated comment * debugging 'bad key handle' error for ledger signer try using 'sign_message' * await sign digest for aws signer * remove extra space, fix fmt warning * fix test, fmt errors * use gt 0.6.0 pragma compiler version * enable ABIEncoderV2 for solidity test contract * chore: make test constructor public Co-authored-by: Sebastian Martinez <me@sebastinez.dev> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
2021-10-08 15:22:51 +00:00
types::{
transaction::{eip2718::TypedTransaction, eip712::Eip712},
Use EIP155 for all signers with empty transaction `chain_id` (#1198) * remove error when signing with a different chain - a chain_id mismatch between the signer and the transaction is valid since the behavior is the same between two signers with different chain ids - a specified chain_id should be signed regardless of the chain_id of the signer - refactor `sign_hash` to no longer take an `eip155` flag - it now _just_ signs hashes. EIP155 is specific to transactions, so we now normalize the `v` value in `sign_transaction_sync` * use signer chain_id for tx in trezor signer - use the trezor signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * use signer chain_id for tx in ledger signer - use the ledger signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * prefer transaction chain_id in aws signer - uses the signer chain_id if the transaction chain_id doesn't exist - refactor `sign_digest_with_eip155` to take an input chain_id, so the signer chain_id is not used every time. If we want to enforce transaction and signer chain ids to be consistent, this should be undone * add private key signing test for an empty chain_id * Apply suggestions from code review Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2022-05-02 18:51:25 +00:00
Address, Signature, H256, U256,
derive-eip712: initial implementation of eip712 derive macro (#481) * derive-eip712: initial implementation of eip712 derive macro This commit provides an initial implementation for a derive macro to encode typed data according to EIP-712, https://eips.ethereum.org/EIPS/eip-712 Additionally, this commit introduces a new signer trait method: async fn sign_typed_data<T: Eip712 + Send + Sync>( &self, payload: &T, ) -> Result<Signature, Self::Error>; And implements the new method for each of the signers (wallet, ledger, aws). Additionally, these changes include using `WalletError` for the Wallet signer error type At the moment, derive does not recurse the primary type to find nested Eip712 structs. This is something that is noted in the source and currently responds with an error regarding custom types. A subsequent PR should be opened once this issue becomes needed. For the moment, the current implementation should satisfy non-nested, basic struct types. * rename to ethers-derive-eip712; move to ethers-core * refactor of derive-eip712 macro; use ParamType and EthAbiToken * macro updates; add byte array checker for paramtype; use literal constant for domain type hash * replace std::convert::Infallible with WalletError as Wallet signer error type * update workspace members and dev dependencies for examples folder * add example for eip712 and test against contract * remove extraneous backward slash in '\x19\x01' prefix; example tests pass * update unreleased change log * remove print statements * use parse_macro_input macro; remove dead code; handle nest struct not implemented error * move eip712 example to solidity-contract tests folder; update cargo workspace dependencies * allow optional EIP712Domain parameter when encoding eip712 struct and signing typed data * add documentation for eip712 feature * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Sebastian Martinez <me@sebastinez.dev> * add error enum for Eip712Error; use sign_payload for ledger signer * add EIP712WithDomain type for providing a wrapper around custom setting of the domain * make LedgerWallet sign_payload public * use optional feature gated dependencies for eip712; add default method for encode_eip712 * add default domain_separator method, pre-compute separator hash * move derive-eip712 deps to dev deps * remove invalid sign payload parameter, add await on async method * remove deprecated comment * debugging 'bad key handle' error for ledger signer try using 'sign_message' * await sign digest for aws signer * remove extra space, fix fmt warning * fix test, fmt errors * use gt 0.6.0 pragma compiler version * enable ABIEncoderV2 for solidity test contract * chore: make test constructor public Co-authored-by: Sebastian Martinez <me@sebastinez.dev> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
2021-10-08 15:22:51 +00:00
},
utils::hash_message,
};
use async_trait::async_trait;
use std::fmt;
/// An Ethereum private-public key pair which can be used for signing messages.
///
/// # Examples
///
/// ## Signing and Verifying a message
///
/// The wallet can be used to produce ECDSA [`Signature`] objects, which can be
/// then verified. Note that this uses [`hash_message`] under the hood which will
/// prefix the message being hashed with the `Ethereum Signed Message` domain separator.
///
/// ```
/// use ethers_core::rand::thread_rng;
/// use ethers_signers::{LocalWallet, Signer};
///
/// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
/// let wallet = LocalWallet::new(&mut thread_rng());
///
/// // Optionally, the wallet's chain id can be set, in order to use EIP-155
/// // replay protection with different chains
/// let wallet = wallet.with_chain_id(1337u64);
///
/// // The wallet can be used to sign messages
/// let message = b"hello";
/// let signature = wallet.sign_message(message).await?;
/// assert_eq!(signature.recover(&message[..]).unwrap(), wallet.address());
2022-08-08 17:30:13 +00:00
///
/// // LocalWallet is clonable:
/// let wallet_clone = wallet.clone();
/// let signature2 = wallet_clone.sign_message(message).await?;
/// assert_eq!(signature, signature2);
/// # Ok(())
/// # }
/// ```
///
/// [`Signature`]: ethers_core::types::Signature
/// [`hash_message`]: fn@ethers_core::utils::hash_message
2022-08-08 17:30:13 +00:00
#[derive(Clone)]
pub struct Wallet<D: PrehashSigner<(RecoverableSignature, RecoveryId)>> {
/// The Wallet's private Key
pub(crate) signer: D,
/// The wallet's address
pub(crate) address: Address,
/// The wallet's chain id (for EIP-155)
pub(crate) chain_id: u64,
}
impl<D: PrehashSigner<(RecoverableSignature, RecoveryId)>> Wallet<D> {
/// Construct a new wallet with an external Signer
pub fn new_with_signer(signer: D, address: Address, chain_id: u64) -> Self {
Wallet { signer, address, chain_id }
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<D: Sync + Send + PrehashSigner<(RecoverableSignature, RecoveryId)>> Signer for Wallet<D> {
derive-eip712: initial implementation of eip712 derive macro (#481) * derive-eip712: initial implementation of eip712 derive macro This commit provides an initial implementation for a derive macro to encode typed data according to EIP-712, https://eips.ethereum.org/EIPS/eip-712 Additionally, this commit introduces a new signer trait method: async fn sign_typed_data<T: Eip712 + Send + Sync>( &self, payload: &T, ) -> Result<Signature, Self::Error>; And implements the new method for each of the signers (wallet, ledger, aws). Additionally, these changes include using `WalletError` for the Wallet signer error type At the moment, derive does not recurse the primary type to find nested Eip712 structs. This is something that is noted in the source and currently responds with an error regarding custom types. A subsequent PR should be opened once this issue becomes needed. For the moment, the current implementation should satisfy non-nested, basic struct types. * rename to ethers-derive-eip712; move to ethers-core * refactor of derive-eip712 macro; use ParamType and EthAbiToken * macro updates; add byte array checker for paramtype; use literal constant for domain type hash * replace std::convert::Infallible with WalletError as Wallet signer error type * update workspace members and dev dependencies for examples folder * add example for eip712 and test against contract * remove extraneous backward slash in '\x19\x01' prefix; example tests pass * update unreleased change log * remove print statements * use parse_macro_input macro; remove dead code; handle nest struct not implemented error * move eip712 example to solidity-contract tests folder; update cargo workspace dependencies * allow optional EIP712Domain parameter when encoding eip712 struct and signing typed data * add documentation for eip712 feature * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Sebastian Martinez <me@sebastinez.dev> * add error enum for Eip712Error; use sign_payload for ledger signer * add EIP712WithDomain type for providing a wrapper around custom setting of the domain * make LedgerWallet sign_payload public * use optional feature gated dependencies for eip712; add default method for encode_eip712 * add default domain_separator method, pre-compute separator hash * move derive-eip712 deps to dev deps * remove invalid sign payload parameter, add await on async method * remove deprecated comment * debugging 'bad key handle' error for ledger signer try using 'sign_message' * await sign digest for aws signer * remove extra space, fix fmt warning * fix test, fmt errors * use gt 0.6.0 pragma compiler version * enable ABIEncoderV2 for solidity test contract * chore: make test constructor public Co-authored-by: Sebastian Martinez <me@sebastinez.dev> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
2021-10-08 15:22:51 +00:00
type Error = WalletError;
async fn sign_message<S: Send + Sync + AsRef<[u8]>>(
&self,
message: S,
) -> Result<Signature, Self::Error> {
let message = message.as_ref();
let message_hash = hash_message(message);
self.sign_hash(message_hash)
}
feat: typed txs provider / middleware changes (part 3) (#357) * feat(providers): add eth_feeHistory api * add access list * feat: fill transactions with access list / default sender info * feat: add helpers for operating on the txs enum * feat: send_transaction takes TypedTransaction now * fix(contract): temp wrap all contract txs as Legacy txs * feat(middleware): use TypedTransaction in Transformer * feat(signers): use TypedTransaction in Wallet/Ledger * feat(core): add helpers for setting typed tx fields * feat(signer): use typed transactions * fix(middleware): adjust nonce/gas/escalators for TypedTxs The GPO and the Escalators will throw an error if they are provided an EIP1559 transaction * fix(providers): ensure the correct account's nonce is filled * fix: add .into() to txs until we make the fn call more generic * Revert "fix: add .into() to txs until we make the fn call more generic" This reverts commit 04dc34b26d0e3f418ed3fc69ea35ad538b83dd50. * feat: generalize send_transaction interface * fix: only set the nonce manually in the Signer middleware * fix(transformer): fill the transaction after transformation * chore: fix compilation errors & lints * fix(signer): set the correct account's nonce * feat: make trace_call / call take TypedTransaction * fix: set sender to transaction in signer * chore: ethgasstation broke * chore: cargo fmt / lints * Fix(signer): pass the chain id * fix: final tx encoding fixes 1. Normalize v values for eip1559/2730 2. Make access lists mandatory for 1559 3. do not double-rlp on rlp_signed * fix: set access list only if available * test: check 1559 / 2930 txs * fix: do not prepend a 0 for Legacy txs & test * chore: code review comments * chore: fix aws signer signature
2021-08-09 00:31:11 +00:00
async fn sign_transaction(&self, tx: &TypedTransaction) -> Result<Signature, Self::Error> {
Use EIP155 for all signers with empty transaction `chain_id` (#1198) * remove error when signing with a different chain - a chain_id mismatch between the signer and the transaction is valid since the behavior is the same between two signers with different chain ids - a specified chain_id should be signed regardless of the chain_id of the signer - refactor `sign_hash` to no longer take an `eip155` flag - it now _just_ signs hashes. EIP155 is specific to transactions, so we now normalize the `v` value in `sign_transaction_sync` * use signer chain_id for tx in trezor signer - use the trezor signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * use signer chain_id for tx in ledger signer - use the ledger signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * prefer transaction chain_id in aws signer - uses the signer chain_id if the transaction chain_id doesn't exist - refactor `sign_digest_with_eip155` to take an input chain_id, so the signer chain_id is not used every time. If we want to enforce transaction and signer chain ids to be consistent, this should be undone * add private key signing test for an empty chain_id * Apply suggestions from code review Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2022-05-02 18:51:25 +00:00
let mut tx_with_chain = tx.clone();
if tx_with_chain.chain_id().is_none() {
Use EIP155 for all signers with empty transaction `chain_id` (#1198) * remove error when signing with a different chain - a chain_id mismatch between the signer and the transaction is valid since the behavior is the same between two signers with different chain ids - a specified chain_id should be signed regardless of the chain_id of the signer - refactor `sign_hash` to no longer take an `eip155` flag - it now _just_ signs hashes. EIP155 is specific to transactions, so we now normalize the `v` value in `sign_transaction_sync` * use signer chain_id for tx in trezor signer - use the trezor signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * use signer chain_id for tx in ledger signer - use the ledger signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * prefer transaction chain_id in aws signer - uses the signer chain_id if the transaction chain_id doesn't exist - refactor `sign_digest_with_eip155` to take an input chain_id, so the signer chain_id is not used every time. If we want to enforce transaction and signer chain ids to be consistent, this should be undone * add private key signing test for an empty chain_id * Apply suggestions from code review Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2022-05-02 18:51:25 +00:00
// in the case we don't have a chain_id, let's use the signer chain id instead
tx_with_chain.set_chain_id(self.chain_id);
}
self.sign_transaction_sync(&tx_with_chain)
}
derive-eip712: initial implementation of eip712 derive macro (#481) * derive-eip712: initial implementation of eip712 derive macro This commit provides an initial implementation for a derive macro to encode typed data according to EIP-712, https://eips.ethereum.org/EIPS/eip-712 Additionally, this commit introduces a new signer trait method: async fn sign_typed_data<T: Eip712 + Send + Sync>( &self, payload: &T, ) -> Result<Signature, Self::Error>; And implements the new method for each of the signers (wallet, ledger, aws). Additionally, these changes include using `WalletError` for the Wallet signer error type At the moment, derive does not recurse the primary type to find nested Eip712 structs. This is something that is noted in the source and currently responds with an error regarding custom types. A subsequent PR should be opened once this issue becomes needed. For the moment, the current implementation should satisfy non-nested, basic struct types. * rename to ethers-derive-eip712; move to ethers-core * refactor of derive-eip712 macro; use ParamType and EthAbiToken * macro updates; add byte array checker for paramtype; use literal constant for domain type hash * replace std::convert::Infallible with WalletError as Wallet signer error type * update workspace members and dev dependencies for examples folder * add example for eip712 and test against contract * remove extraneous backward slash in '\x19\x01' prefix; example tests pass * update unreleased change log * remove print statements * use parse_macro_input macro; remove dead code; handle nest struct not implemented error * move eip712 example to solidity-contract tests folder; update cargo workspace dependencies * allow optional EIP712Domain parameter when encoding eip712 struct and signing typed data * add documentation for eip712 feature * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Sebastian Martinez <me@sebastinez.dev> * add error enum for Eip712Error; use sign_payload for ledger signer * add EIP712WithDomain type for providing a wrapper around custom setting of the domain * make LedgerWallet sign_payload public * use optional feature gated dependencies for eip712; add default method for encode_eip712 * add default domain_separator method, pre-compute separator hash * move derive-eip712 deps to dev deps * remove invalid sign payload parameter, add await on async method * remove deprecated comment * debugging 'bad key handle' error for ledger signer try using 'sign_message' * await sign digest for aws signer * remove extra space, fix fmt warning * fix test, fmt errors * use gt 0.6.0 pragma compiler version * enable ABIEncoderV2 for solidity test contract * chore: make test constructor public Co-authored-by: Sebastian Martinez <me@sebastinez.dev> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
2021-10-08 15:22:51 +00:00
async fn sign_typed_data<T: Eip712 + Send + Sync>(
&self,
payload: &T,
derive-eip712: initial implementation of eip712 derive macro (#481) * derive-eip712: initial implementation of eip712 derive macro This commit provides an initial implementation for a derive macro to encode typed data according to EIP-712, https://eips.ethereum.org/EIPS/eip-712 Additionally, this commit introduces a new signer trait method: async fn sign_typed_data<T: Eip712 + Send + Sync>( &self, payload: &T, ) -> Result<Signature, Self::Error>; And implements the new method for each of the signers (wallet, ledger, aws). Additionally, these changes include using `WalletError` for the Wallet signer error type At the moment, derive does not recurse the primary type to find nested Eip712 structs. This is something that is noted in the source and currently responds with an error regarding custom types. A subsequent PR should be opened once this issue becomes needed. For the moment, the current implementation should satisfy non-nested, basic struct types. * rename to ethers-derive-eip712; move to ethers-core * refactor of derive-eip712 macro; use ParamType and EthAbiToken * macro updates; add byte array checker for paramtype; use literal constant for domain type hash * replace std::convert::Infallible with WalletError as Wallet signer error type * update workspace members and dev dependencies for examples folder * add example for eip712 and test against contract * remove extraneous backward slash in '\x19\x01' prefix; example tests pass * update unreleased change log * remove print statements * use parse_macro_input macro; remove dead code; handle nest struct not implemented error * move eip712 example to solidity-contract tests folder; update cargo workspace dependencies * allow optional EIP712Domain parameter when encoding eip712 struct and signing typed data * add documentation for eip712 feature * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Sebastian Martinez <me@sebastinez.dev> * add error enum for Eip712Error; use sign_payload for ledger signer * add EIP712WithDomain type for providing a wrapper around custom setting of the domain * make LedgerWallet sign_payload public * use optional feature gated dependencies for eip712; add default method for encode_eip712 * add default domain_separator method, pre-compute separator hash * move derive-eip712 deps to dev deps * remove invalid sign payload parameter, add await on async method * remove deprecated comment * debugging 'bad key handle' error for ledger signer try using 'sign_message' * await sign digest for aws signer * remove extra space, fix fmt warning * fix test, fmt errors * use gt 0.6.0 pragma compiler version * enable ABIEncoderV2 for solidity test contract * chore: make test constructor public Co-authored-by: Sebastian Martinez <me@sebastinez.dev> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
2021-10-08 15:22:51 +00:00
) -> Result<Signature, Self::Error> {
let encoded =
payload.encode_eip712().map_err(|e| Self::Error::Eip712Error(e.to_string()))?;
derive-eip712: initial implementation of eip712 derive macro (#481) * derive-eip712: initial implementation of eip712 derive macro This commit provides an initial implementation for a derive macro to encode typed data according to EIP-712, https://eips.ethereum.org/EIPS/eip-712 Additionally, this commit introduces a new signer trait method: async fn sign_typed_data<T: Eip712 + Send + Sync>( &self, payload: &T, ) -> Result<Signature, Self::Error>; And implements the new method for each of the signers (wallet, ledger, aws). Additionally, these changes include using `WalletError` for the Wallet signer error type At the moment, derive does not recurse the primary type to find nested Eip712 structs. This is something that is noted in the source and currently responds with an error regarding custom types. A subsequent PR should be opened once this issue becomes needed. For the moment, the current implementation should satisfy non-nested, basic struct types. * rename to ethers-derive-eip712; move to ethers-core * refactor of derive-eip712 macro; use ParamType and EthAbiToken * macro updates; add byte array checker for paramtype; use literal constant for domain type hash * replace std::convert::Infallible with WalletError as Wallet signer error type * update workspace members and dev dependencies for examples folder * add example for eip712 and test against contract * remove extraneous backward slash in '\x19\x01' prefix; example tests pass * update unreleased change log * remove print statements * use parse_macro_input macro; remove dead code; handle nest struct not implemented error * move eip712 example to solidity-contract tests folder; update cargo workspace dependencies * allow optional EIP712Domain parameter when encoding eip712 struct and signing typed data * add documentation for eip712 feature * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Sebastian Martinez <me@sebastinez.dev> * add error enum for Eip712Error; use sign_payload for ledger signer * add EIP712WithDomain type for providing a wrapper around custom setting of the domain * make LedgerWallet sign_payload public * use optional feature gated dependencies for eip712; add default method for encode_eip712 * add default domain_separator method, pre-compute separator hash * move derive-eip712 deps to dev deps * remove invalid sign payload parameter, add await on async method * remove deprecated comment * debugging 'bad key handle' error for ledger signer try using 'sign_message' * await sign digest for aws signer * remove extra space, fix fmt warning * fix test, fmt errors * use gt 0.6.0 pragma compiler version * enable ABIEncoderV2 for solidity test contract * chore: make test constructor public Co-authored-by: Sebastian Martinez <me@sebastinez.dev> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
2021-10-08 15:22:51 +00:00
self.sign_hash(H256::from(encoded))
derive-eip712: initial implementation of eip712 derive macro (#481) * derive-eip712: initial implementation of eip712 derive macro This commit provides an initial implementation for a derive macro to encode typed data according to EIP-712, https://eips.ethereum.org/EIPS/eip-712 Additionally, this commit introduces a new signer trait method: async fn sign_typed_data<T: Eip712 + Send + Sync>( &self, payload: &T, ) -> Result<Signature, Self::Error>; And implements the new method for each of the signers (wallet, ledger, aws). Additionally, these changes include using `WalletError` for the Wallet signer error type At the moment, derive does not recurse the primary type to find nested Eip712 structs. This is something that is noted in the source and currently responds with an error regarding custom types. A subsequent PR should be opened once this issue becomes needed. For the moment, the current implementation should satisfy non-nested, basic struct types. * rename to ethers-derive-eip712; move to ethers-core * refactor of derive-eip712 macro; use ParamType and EthAbiToken * macro updates; add byte array checker for paramtype; use literal constant for domain type hash * replace std::convert::Infallible with WalletError as Wallet signer error type * update workspace members and dev dependencies for examples folder * add example for eip712 and test against contract * remove extraneous backward slash in '\x19\x01' prefix; example tests pass * update unreleased change log * remove print statements * use parse_macro_input macro; remove dead code; handle nest struct not implemented error * move eip712 example to solidity-contract tests folder; update cargo workspace dependencies * allow optional EIP712Domain parameter when encoding eip712 struct and signing typed data * add documentation for eip712 feature * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Sebastian Martinez <me@sebastinez.dev> * add error enum for Eip712Error; use sign_payload for ledger signer * add EIP712WithDomain type for providing a wrapper around custom setting of the domain * make LedgerWallet sign_payload public * use optional feature gated dependencies for eip712; add default method for encode_eip712 * add default domain_separator method, pre-compute separator hash * move derive-eip712 deps to dev deps * remove invalid sign payload parameter, add await on async method * remove deprecated comment * debugging 'bad key handle' error for ledger signer try using 'sign_message' * await sign digest for aws signer * remove extra space, fix fmt warning * fix test, fmt errors * use gt 0.6.0 pragma compiler version * enable ABIEncoderV2 for solidity test contract * chore: make test constructor public Co-authored-by: Sebastian Martinez <me@sebastinez.dev> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
2021-10-08 15:22:51 +00:00
}
fn address(&self) -> Address {
self.address
}
/// Gets the wallet's chain id
fn chain_id(&self) -> u64 {
self.chain_id
}
/// Sets the wallet's chain_id, used in conjunction with EIP-155 signing
fn with_chain_id<T: Into<u64>>(mut self, chain_id: T) -> Self {
self.chain_id = chain_id.into();
self
}
}
impl<D: PrehashSigner<(RecoverableSignature, RecoveryId)>> Wallet<D> {
Use EIP155 for all signers with empty transaction `chain_id` (#1198) * remove error when signing with a different chain - a chain_id mismatch between the signer and the transaction is valid since the behavior is the same between two signers with different chain ids - a specified chain_id should be signed regardless of the chain_id of the signer - refactor `sign_hash` to no longer take an `eip155` flag - it now _just_ signs hashes. EIP155 is specific to transactions, so we now normalize the `v` value in `sign_transaction_sync` * use signer chain_id for tx in trezor signer - use the trezor signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * use signer chain_id for tx in ledger signer - use the ledger signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * prefer transaction chain_id in aws signer - uses the signer chain_id if the transaction chain_id doesn't exist - refactor `sign_digest_with_eip155` to take an input chain_id, so the signer chain_id is not used every time. If we want to enforce transaction and signer chain ids to be consistent, this should be undone * add private key signing test for an empty chain_id * Apply suggestions from code review Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2022-05-02 18:51:25 +00:00
/// Synchronously signs the provided transaction, normalizing the signature `v` value with
/// EIP-155 using the transaction's `chain_id`, or the signer's `chain_id` if the transaction
/// does not specify one.
pub fn sign_transaction_sync(&self, tx: &TypedTransaction) -> Result<Signature, WalletError> {
// rlp (for sighash) must have the same chain id as v in the signature
Use EIP155 for all signers with empty transaction `chain_id` (#1198) * remove error when signing with a different chain - a chain_id mismatch between the signer and the transaction is valid since the behavior is the same between two signers with different chain ids - a specified chain_id should be signed regardless of the chain_id of the signer - refactor `sign_hash` to no longer take an `eip155` flag - it now _just_ signs hashes. EIP155 is specific to transactions, so we now normalize the `v` value in `sign_transaction_sync` * use signer chain_id for tx in trezor signer - use the trezor signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * use signer chain_id for tx in ledger signer - use the ledger signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * prefer transaction chain_id in aws signer - uses the signer chain_id if the transaction chain_id doesn't exist - refactor `sign_digest_with_eip155` to take an input chain_id, so the signer chain_id is not used every time. If we want to enforce transaction and signer chain ids to be consistent, this should be undone * add private key signing test for an empty chain_id * Apply suggestions from code review Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2022-05-02 18:51:25 +00:00
let chain_id = tx.chain_id().map(|id| id.as_u64()).unwrap_or(self.chain_id);
let mut tx = tx.clone();
tx.set_chain_id(chain_id);
let sighash = tx.sighash();
let mut sig = self.sign_hash(sighash)?;
Use EIP155 for all signers with empty transaction `chain_id` (#1198) * remove error when signing with a different chain - a chain_id mismatch between the signer and the transaction is valid since the behavior is the same between two signers with different chain ids - a specified chain_id should be signed regardless of the chain_id of the signer - refactor `sign_hash` to no longer take an `eip155` flag - it now _just_ signs hashes. EIP155 is specific to transactions, so we now normalize the `v` value in `sign_transaction_sync` * use signer chain_id for tx in trezor signer - use the trezor signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * use signer chain_id for tx in ledger signer - use the ledger signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * prefer transaction chain_id in aws signer - uses the signer chain_id if the transaction chain_id doesn't exist - refactor `sign_digest_with_eip155` to take an input chain_id, so the signer chain_id is not used every time. If we want to enforce transaction and signer chain ids to be consistent, this should be undone * add private key signing test for an empty chain_id * Apply suggestions from code review Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2022-05-02 18:51:25 +00:00
// sign_hash sets `v` to recid + 27, so we need to subtract 27 before normalizing
sig.v = to_eip155_v(sig.v as u8 - 27, chain_id);
Ok(sig)
2021-08-18 13:02:57 +00:00
}
Use EIP155 for all signers with empty transaction `chain_id` (#1198) * remove error when signing with a different chain - a chain_id mismatch between the signer and the transaction is valid since the behavior is the same between two signers with different chain ids - a specified chain_id should be signed regardless of the chain_id of the signer - refactor `sign_hash` to no longer take an `eip155` flag - it now _just_ signs hashes. EIP155 is specific to transactions, so we now normalize the `v` value in `sign_transaction_sync` * use signer chain_id for tx in trezor signer - use the trezor signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * use signer chain_id for tx in ledger signer - use the ledger signer's chain_id if the transaction's chain_id doesn't exist - sets the chain_id in both `sign_tx` and the Signer implementation's `sign_transaction` * prefer transaction chain_id in aws signer - uses the signer chain_id if the transaction chain_id doesn't exist - refactor `sign_digest_with_eip155` to take an input chain_id, so the signer chain_id is not used every time. If we want to enforce transaction and signer chain ids to be consistent, this should be undone * add private key signing test for an empty chain_id * Apply suggestions from code review Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> * Update ethers-signers/src/ledger/mod.rs Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2022-05-02 18:51:25 +00:00
/// Signs the provided hash.
pub fn sign_hash(&self, hash: H256) -> Result<Signature, WalletError> {
let (recoverable_sig, recovery_id) = self.signer.sign_prehash(hash.as_ref())?;
let v = u8::from(recovery_id) as u64 + 27;
let r_bytes: FieldBytes<Secp256k1> = recoverable_sig.r().into();
let s_bytes: FieldBytes<Secp256k1> = recoverable_sig.s().into();
let r = U256::from_big_endian(r_bytes.as_slice());
let s = U256::from_big_endian(s_bytes.as_slice());
Ok(Signature { r, s, v })
}
/// Gets the wallet's signer
pub fn signer(&self) -> &D {
&self.signer
}
}
// do not log the signer
impl<D: PrehashSigner<(RecoverableSignature, RecoveryId)>> fmt::Debug for Wallet<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Wallet")
.field("address", &self.address)
.field("chain_Id", &self.chain_id)
.finish()
}
}