fix: make chain_id mandatory (#286)

* chore: update deps (#352)

* chore(deps): bump elliptic-curve from 0.10.4 to 0.10.5

Bumps [elliptic-curve](https://github.com/RustCrypto/traits) from 0.10.4 to 0.10.5.
- [Release notes](https://github.com/RustCrypto/traits/releases)
- [Commits](https://github.com/RustCrypto/traits/compare/elliptic-curve-v0.10.4...elliptic-curve-v0.10.5)

---
updated-dependencies:
- dependency-name: elliptic-curve
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: bump deps

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(core): make chain id mandatory

* fix(signers): make chain id mandatory

* test: make chain id mandatory

* test: add missing chain id

* fix: add missing chain id

* chore(wallet): set chain_id by default to 1

* ci: run CI on master

* fix(yubi): add missing chain id

* chore: skip ganache test with celo features

* ci: run only on push to master

* fix: add missing chain id

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Georgios Konstantopoulos 2021-07-29 23:22:25 +03:00 committed by GitHub
parent e7f603f69c
commit 9dca606eaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 123 additions and 123 deletions

View File

@ -1,4 +1,8 @@
on: pull_request
on:
push:
branches:
- master
pull_request:
name: Tests
@ -10,7 +14,7 @@ env:
jobs:
tests:
name: Check
name: ethereum tests
runs-on: ubuntu-latest
steps:
- name: Checkout sources
@ -51,7 +55,7 @@ jobs:
cargo test
feature-tests:
name: Check
name: celo tests
runs-on: ubuntu-latest
steps:
- name: Checkout sources
@ -95,7 +99,7 @@ jobs:
cargo test --all-features
lint:
name: Check
name: lints
runs-on: ubuntu-latest
steps:
- name: Checkout sources

3
Cargo.lock generated
View File

@ -830,7 +830,6 @@ dependencies = [
"ethers-core",
"ethers-providers",
"ethers-signers",
"futures-executor",
"futures-util",
"hex",
"rand 0.8.4",
@ -889,7 +888,6 @@ dependencies = [
"futures-util",
"hex",
"rand 0.8.4",
"serde_json",
"sha2 0.9.5",
"tempfile",
"thiserror",
@ -1002,7 +1000,6 @@ dependencies = [
"futures-core",
"futures-task",
"futures-util",
"num_cpus",
]
[[package]]

View File

@ -8,7 +8,7 @@ use ethers_contract::{Contract, ContractFactory, EthEvent};
use ethers_core::utils::{GanacheInstance, Solc};
use ethers_middleware::signer::SignerMiddleware;
use ethers_providers::{Http, Middleware, Provider};
use ethers_signers::LocalWallet;
use ethers_signers::{LocalWallet, Signer};
use std::{convert::TryFrom, sync::Arc, time::Duration};
// Note: The `EthEvent` derive macro implements the necessary conversion between `Tokens` and
@ -40,6 +40,7 @@ pub fn connect(ganache: &GanacheInstance, idx: usize) -> Arc<HttpWallet> {
.unwrap()
.interval(Duration::from_millis(10u64));
let wallet: LocalWallet = ganache.keys()[idx].clone().into();
let wallet = wallet.with_chain_id(1u64);
Arc::new(SignerMiddleware::new(provider, wallet))
}

View File

@ -97,12 +97,11 @@ mod eth_tests {
let contract = deploy(client.clone(), abi, bytecode).await;
// make a call with `client`
let _tx_hash = *contract
let func = contract
.method::<_, H256>("setValue", "hi".to_owned())
.unwrap()
.send()
.await
.unwrap();
let tx = func.send().await.unwrap();
let _receipt = tx.await.unwrap();
// and we can fetch the events
let logs: Vec<ValueChanged> = contract
@ -504,8 +503,8 @@ mod celo_tests {
use super::*;
use ethers::{
middleware::signer::SignerMiddleware,
providers::{Http, Provider},
signers::LocalWallet,
providers::{Http, Middleware, Provider},
signers::{LocalWallet, Signer},
types::BlockNumber,
};
use std::{convert::TryFrom, sync::Arc, time::Duration};
@ -518,12 +517,13 @@ mod celo_tests {
let provider = Provider::<Http>::try_from("https://alfajores-forno.celo-testnet.org")
.unwrap()
.interval(Duration::from_millis(6000));
let chain_id = provider.get_chainid().await.unwrap().as_u64();
// Funded with https://celo.org/developers/faucet
let wallet = "d652abb81e8c686edba621a895531b1f291289b63b5ef09a94f686a5ecdd5db1"
.parse::<LocalWallet>()
.unwrap()
.set_chain_id(44787u64);
.with_chain_id(chain_id);
let client = SignerMiddleware::new(provider, wallet);
let client = Arc::new(client);

View File

@ -45,6 +45,7 @@ serde_json = { version = "1.0.64", default-features = false }
bincode = { version = "1.3.3", default-features = false }
once_cell = { version = "1.8.0" }
hex-literal = "0.3.3"
futures-util = { version = "0.3.16", default-features = false }
[features]
celo = [] # celo support extends the transaction format with extra fields

View File

@ -7,15 +7,14 @@ use crate::{
use rlp::RlpStream;
use serde::{Deserialize, Serialize};
const BASE_NUM_TX_FIELDS: usize = 9;
// Number of tx fields before signing
#[cfg(not(feature = "celo"))]
const UNSIGNED_TX_FIELDS: usize = 6;
const NUM_TX_FIELDS: usize = BASE_NUM_TX_FIELDS;
// Celo has 3 additional fields
#[cfg(feature = "celo")]
const UNSIGNED_TX_FIELDS: usize = 9;
// Unsigned fields + signature [r s v]
const SIGNED_TX_FIELDS: usize = UNSIGNED_TX_FIELDS + 3;
const NUM_TX_FIELDS: usize = BASE_NUM_TX_FIELDS + 3;
/// Parameters for sending a transaction
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Debug)]
@ -130,52 +129,34 @@ impl TransactionRequest {
}
/// Hashes the transaction's data with the provided chain id
pub fn sighash<T: Into<U64>>(&self, chain_id: Option<T>) -> H256 {
pub fn sighash<T: Into<U64>>(&self, chain_id: T) -> H256 {
keccak256(self.rlp(chain_id).as_ref()).into()
}
/// Gets the unsigned transaction's RLP encoding
pub fn rlp<T: Into<U64>>(&self, chain_id: Option<T>) -> Bytes {
pub fn rlp<T: Into<U64>>(&self, chain_id: T) -> Bytes {
let mut rlp = RlpStream::new();
// "If [..] CHAIN_ID is available, then when computing the hash of a
// transaction for the purposes of signing, instead of hashing only
// six rlp encoded elements (nonce, gasprice, startgas, to, value, data),
// you SHOULD hash nine rlp encoded elements
// (nonce, gasprice, startgas, to, value, data, chainid, 0, 0)"
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#specification
let num_els = if chain_id.is_some() {
UNSIGNED_TX_FIELDS + 3
} else {
UNSIGNED_TX_FIELDS
};
rlp.begin_list(num_els);
rlp.begin_list(NUM_TX_FIELDS);
self.rlp_base(&mut rlp);
// Only hash the 3 extra fields when preparing the
// data to sign if chain_id is present
if let Some(chain_id) = chain_id {
rlp.append(&chain_id.into());
rlp.append(&0u8);
rlp.append(&0u8);
}
rlp.append(&chain_id.into());
rlp.append(&0u8);
rlp.append(&0u8);
rlp.out().freeze().into()
}
/// Produces the RLP encoding of the transaction with the provided signature
pub fn rlp_signed(&self, signature: &Signature) -> Bytes {
let mut rlp = RlpStream::new();
// construct the RLP body
rlp.begin_list(SIGNED_TX_FIELDS);
rlp.begin_list(NUM_TX_FIELDS);
self.rlp_base(&mut rlp);
// append the signature
rlp.append(&signature.v);
rlp.append(&signature.r);
rlp.append(&signature.s);
rlp.out().freeze().into()
}
@ -326,7 +307,7 @@ impl Transaction {
pub fn rlp(&self) -> Bytes {
let mut rlp = RlpStream::new();
rlp.begin_list(SIGNED_TX_FIELDS);
rlp.begin_list(NUM_TX_FIELDS);
rlp.append(&self.nonce);
rlp.append(&self.gas_price);
rlp.append(&self.gas);

View File

@ -36,7 +36,6 @@ tokio = { version = "1.5" }
[dev-dependencies]
ethers = { version = "0.4.0", path = "../ethers" }
futures-executor = { version = "0.3.14", features = ["thread-pool"] }
hex = { version = "0.4.3", default-features = false, features = ["std"] }
rand = { version = "0.8.4", default-features = false }
tokio = { version = "1.5", default-features = false, features = ["rt", "macros", "time"] }

View File

@ -21,7 +21,7 @@
//! ```no_run
//! use ethers::{
//! providers::{Provider, Http},
//! signers::LocalWallet,
//! signers::{LocalWallet, Signer},
//! middleware::{
//! gas_escalator::{GasEscalatorMiddleware, GeometricGasPrice, Frequency},
//! gas_oracle::{GasOracleMiddleware, GasNow, GasCategory},

View File

@ -343,7 +343,7 @@ mod tests {
let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
.parse::<LocalWallet>()
.unwrap()
.set_chain_id(chain_id);
.with_chain_id(chain_id);
let client = SignerMiddleware::new(provider, key);
let tx = client.sign_transaction(tx).await.unwrap();
@ -365,7 +365,7 @@ mod tests {
// new SignerMiddleware
let provider = Provider::try_from("http://localhost:8545").unwrap();
let key = LocalWallet::new(&mut rand::thread_rng());
let key = LocalWallet::new(&mut rand::thread_rng()).with_chain_id(1u32);
let client = SignerMiddleware::new(provider, key);
// an address that is not the signer address

View File

@ -4,7 +4,7 @@ use ethers_middleware::{
signer::SignerMiddleware,
};
use ethers_providers::{Middleware, Provider, Ws};
use ethers_signers::LocalWallet;
use ethers_signers::{LocalWallet, Signer};
use std::time::Duration;
#[tokio::test]

View File

@ -4,7 +4,7 @@ async fn nonce_manager() {
use ethers_core::types::*;
use ethers_middleware::{nonce_manager::NonceManagerMiddleware, signer::SignerMiddleware};
use ethers_providers::{Http, Middleware, Provider};
use ethers_signers::LocalWallet;
use ethers_signers::{LocalWallet, Signer};
use std::convert::TryFrom;
use std::time::Duration;
@ -12,10 +12,12 @@ async fn nonce_manager() {
Provider::<Http>::try_from("https://rinkeby.infura.io/v3/fd8b88b56aa84f6da87b60f5441d6778")
.unwrap()
.interval(Duration::from_millis(2000u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64();
let wallet = "59c37cb6b16fa2de30675f034c8008f890f4b2696c729d6267946d29736d73e4"
.parse::<LocalWallet>()
.unwrap();
.unwrap()
.with_chain_id(chain_id);
let address = wallet.address();
let provider = SignerMiddleware::new(provider, wallet);

View File

@ -2,7 +2,7 @@ use ethers_providers::{Http, Middleware, Provider};
use ethers_core::types::TransactionRequest;
use ethers_middleware::signer::SignerMiddleware;
use ethers_signers::LocalWallet;
use ethers_signers::{LocalWallet, Signer};
use std::{convert::TryFrom, time::Duration};
#[tokio::test]
@ -20,6 +20,8 @@ async fn send_eth() {
let provider = Provider::<Http>::try_from(ganache.endpoint())
.unwrap()
.interval(Duration::from_millis(10u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64();
let wallet = wallet.with_chain_id(chain_id);
let provider = SignerMiddleware::new(provider, wallet);
// craft the transaction
@ -48,13 +50,14 @@ async fn test_send_transaction() {
let provider = Provider::<Http>::try_from("https://alfajores-forno.celo-testnet.org")
.unwrap()
.interval(Duration::from_millis(3000u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64();
// Funded with https://celo.org/developers/faucet
// Please do not drain this account :)
let wallet = "d652abb81e8c686edba621a895531b1f291289b63b5ef09a94f686a5ecdd5db1"
.parse::<LocalWallet>()
.unwrap()
.set_chain_id(44787u64);
.with_chain_id(chain_id);
let client = SignerMiddleware::new(provider, wallet);
let balance_before = client.get_balance(client.address(), None).await.unwrap();
@ -71,6 +74,7 @@ async fn test_send_transaction() {
}
#[tokio::test]
#[cfg(not(feature = "celo"))]
async fn send_transaction_handles_tx_from_field() {
use ethers_core::utils::Ganache;

View File

@ -8,7 +8,7 @@ mod tests {
signer::SignerMiddleware,
};
use ethers_providers::{Http, Middleware, Provider};
use ethers_signers::LocalWallet;
use ethers_signers::{LocalWallet, Signer};
use std::convert::TryFrom;
#[tokio::test]
@ -58,6 +58,8 @@ mod tests {
// the base provider
let provider = Arc::new(Provider::<Http>::try_from(ganache.endpoint()).unwrap());
let chain_id = provider.get_chainid().await.unwrap().as_u64();
let signer = signer.with_chain_id(chain_id);
// the Gas Price escalator middleware is the first middleware above the provider,
// so that it receives the transaction last, after all the other middleware

View File

@ -8,7 +8,7 @@ use ethers_middleware::{
SignerMiddleware,
};
use ethers_providers::{Http, Middleware, Provider};
use ethers_signers::LocalWallet;
use ethers_signers::{LocalWallet, Signer};
use rand::Rng;
use std::{convert::TryFrom, sync::Arc, time::Duration};
@ -26,6 +26,8 @@ async fn ds_proxy_transformer() {
let provider = Provider::<Http>::try_from(ganache.endpoint())
.unwrap()
.interval(Duration::from_millis(10u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64();
let wallet = wallet.with_chain_id(chain_id);
let signer_middleware = SignerMiddleware::new(provider.clone(), wallet);
let wallet_addr = signer_middleware.address();
let provider = Arc::new(signer_middleware.clone());
@ -111,6 +113,8 @@ async fn ds_proxy_code() {
let provider = Provider::<Http>::try_from(ganache.endpoint())
.unwrap()
.interval(Duration::from_millis(10u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64();
let wallet = wallet.with_chain_id(chain_id);
let signer_middleware = SignerMiddleware::new(provider.clone(), wallet);
let wallet_addr = signer_middleware.address();
let provider = Arc::new(signer_middleware.clone());

View File

@ -6,7 +6,7 @@ mod eth_tests {
use super::*;
use ethers::{
middleware::SignerMiddleware,
signers::LocalWallet,
signers::{LocalWallet, Signer},
types::{BlockId, TransactionRequest, H256},
utils::Ganache,
};
@ -86,9 +86,11 @@ mod eth_tests {
"https://rinkeby.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27",
)
.unwrap();
let chain_id = provider.get_chainid().await.unwrap();
let wallet = "59c37cb6b16fa2de30675f034c8008f890f4b2696c729d6267946d29736d73e4"
.parse::<LocalWallet>()
.unwrap();
.unwrap()
.with_chain_id(chain_id.as_u64());
let address = wallet.address();
let provider = SignerMiddleware::new(provider, wallet);
generic_pending_txs_test(provider, address).await;
@ -102,9 +104,11 @@ mod eth_tests {
Provider::connect("wss://rinkeby.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27")
.await
.unwrap();
let chain_id = provider.get_chainid().await.unwrap();
let wallet = "ff7f80c6e9941865266ed1f481263d780169f1d98269c51167d20c630a5fdc8a"
.parse::<LocalWallet>()
.unwrap();
.unwrap()
.with_chain_id(chain_id.as_64());
let address = wallet.address();
let provider = SignerMiddleware::new(provider, wallet);
generic_pending_txs_test(provider, address).await;

View File

@ -35,7 +35,6 @@ yubihsm = { version = "0.39.0", features = ["secp256k1", "usb", "mockhsm"] }
tempfile = "3.2.0"
tokio = { version = "1.5", default-features = false, features = ["macros"] }
serde_json = { version = "1.0.64", default-features = false }
[features]
celo = ["ethers-core/celo"]

View File

@ -24,10 +24,8 @@ use super::types::*;
pub struct LedgerEthereum {
transport: Mutex<Ledger>,
derivation: DerivationType,
pub chain_id: Option<u64>,
/// The ledger's address, instantiated at runtime
pub address: Address,
pub(crate) chain_id: u64,
pub(crate) address: Address,
}
impl LedgerEthereum {
@ -38,14 +36,11 @@ impl LedgerEthereum {
/// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
/// use ethers::signers::{Ledger, HDPath};
///
/// let ledger = Ledger::new(HDPath::LedgerLive(0), Some(1)).await?;
/// let ledger = Ledger::new(HDPath::LedgerLive(0), 1).await?;
/// # Ok(())
/// # }
/// ```
pub async fn new(
derivation: DerivationType,
chain_id: Option<u64>,
) -> Result<Self, LedgerError> {
pub async fn new(derivation: DerivationType, chain_id: u64) -> Result<Self, LedgerError> {
let transport = Ledger::init().await?;
let address = Self::get_address_with_path_transport(&transport, &derivation).await?;
@ -123,13 +118,9 @@ impl LedgerEthereum {
}
/// Signs an Ethereum transaction (requires confirmation on the ledger)
pub async fn sign_tx(
&self,
tx: &TransactionRequest,
chain_id: Option<u64>,
) -> Result<Signature, LedgerError> {
pub async fn sign_tx(&self, tx: &TransactionRequest) -> Result<Signature, LedgerError> {
let mut payload = Self::path_to_bytes(&self.derivation);
payload.extend_from_slice(tx.rlp(chain_id).as_ref());
payload.extend_from_slice(tx.rlp(self.chain_id).as_ref());
self.sign_payload(INS::SIGN, payload).await
}
@ -216,7 +207,7 @@ mod tests {
// Replace this with your ETH addresses.
async fn test_get_address() {
// Instantiate it with the default ledger derivation path
let ledger = LedgerEthereum::new(DerivationType::LedgerLive(0), None)
let ledger = LedgerEthereum::new(DerivationType::LedgerLive(0), 1)
.await
.unwrap();
assert_eq!(
@ -235,7 +226,7 @@ mod tests {
#[tokio::test]
#[ignore]
async fn test_sign_tx() {
let ledger = LedgerEthereum::new(DerivationType::LedgerLive(0), None)
let ledger = LedgerEthereum::new(DerivationType::LedgerLive(0), 1)
.await
.unwrap();
@ -257,7 +248,7 @@ mod tests {
#[tokio::test]
#[ignore]
async fn test_version() {
let ledger = LedgerEthereum::new(DerivationType::LedgerLive(0), None)
let ledger = LedgerEthereum::new(DerivationType::LedgerLive(0), 1)
.await
.unwrap();
@ -268,7 +259,7 @@ mod tests {
#[tokio::test]
#[ignore]
async fn test_sign_message() {
let ledger = LedgerEthereum::new(DerivationType::Legacy(0), None)
let ledger = LedgerEthereum::new(DerivationType::Legacy(0), 1)
.await
.unwrap();
let message = "hello world";

View File

@ -24,11 +24,20 @@ impl Signer for LedgerEthereum {
&self,
message: &TransactionRequest,
) -> Result<Signature, Self::Error> {
self.sign_tx(message, self.chain_id).await
self.sign_tx(message).await
}
/// Returns the signer's Ethereum Address
fn address(&self) -> Address {
self.address
}
fn with_chain_id<T: Into<u64>>(mut self, chain_id: T) -> Self {
self.chain_id = chain_id.into();
self
}
fn chain_id(&self) -> u64 {
self.chain_id
}
}

View File

@ -67,15 +67,8 @@ use ethers_core::types::{Address, Signature, TransactionRequest};
use std::error::Error;
/// Applies [EIP155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md)
pub fn to_eip155_v<T: Into<u8>>(recovery_id: T, chain_id: Option<u64>) -> u64 {
let standard_v: u8 = recovery_id.into();
if let Some(chain_id) = chain_id {
// When signing with a chain ID, add chain replay protection.
(standard_v as u64) + 35 + chain_id * 2
} else {
// Otherwise, convert to 'Electrum' notation.
(standard_v as u64) + 27
}
pub fn to_eip155_v<T: Into<u8>>(recovery_id: T, chain_id: u64) -> u64 {
(recovery_id.into() as u64) + 35 + chain_id * 2
}
/// Trait for signing transactions and messages
@ -98,4 +91,10 @@ pub trait Signer: std::fmt::Debug + Send + Sync {
/// Returns the signer's Ethereum Address
fn address(&self) -> Address;
/// Returns the signer's chain id
fn chain_id(&self) -> u64;
/// Sets the signer's chain id
fn with_chain_id<T: Into<u64>>(self, chain_id: T) -> Self;
}

View File

@ -183,7 +183,7 @@ impl<W: Wordlist> MnemonicBuilder<W> {
Ok(Wallet::<SigningKey> {
signer,
address,
chain_id: None,
chain_id: 1,
})
}
}

View File

@ -43,7 +43,7 @@ use std::fmt;
///
/// // Optionally, the wallet's chain id can be set, in order to use EIP-155
/// // replay protection with different chains
/// let wallet = wallet.set_chain_id(1337u64);
/// let wallet = wallet.with_chain_id(1337u64);
///
/// // The wallet can be used to sign messages
/// let message = b"hello";
@ -60,8 +60,8 @@ pub struct Wallet<D: DigestSigner<Sha256Proxy, RecoverableSignature>> {
pub(crate) signer: D,
/// The wallet's address
pub(crate) address: Address,
/// The wallet's chain id (for EIP-155), signs w/o replay protection if left unset
pub(crate) chain_id: Option<u64>,
/// The wallet's chain id (for EIP-155)
pub(crate) chain_id: u64,
}
#[async_trait]
@ -75,25 +75,44 @@ impl<D: Sync + Send + DigestSigner<Sha256Proxy, RecoverableSignature>> Signer fo
let message = message.as_ref();
let message_hash = hash_message(message);
Ok(self.sign_hash_with_eip155(message_hash, None))
Ok(self.sign_hash(message_hash, false))
}
async fn sign_transaction(&self, tx: &TransactionRequest) -> Result<Signature, Self::Error> {
let sighash = tx.sighash(self.chain_id);
Ok(self.sign_hash_with_eip155(sighash, self.chain_id))
Ok(self.sign_hash(sighash, true))
}
fn address(&self) -> Address {
self.address
}
/// Gets the wallet's chain id
///
/// # Panics
///
/// If the chain id has not already been set.
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: DigestSigner<Sha256Proxy, RecoverableSignature>> Wallet<D> {
fn sign_hash_with_eip155(&self, hash: H256, chain_id: Option<u64>) -> Signature {
fn sign_hash(&self, hash: H256, eip155: bool) -> Signature {
let recoverable_sig: RecoverableSignature =
self.signer.sign_digest(Sha256Proxy::from(hash));
let v = to_eip155_v(recoverable_sig.recovery_id(), chain_id);
let v = if eip155 {
to_eip155_v(recoverable_sig.recovery_id(), self.chain_id)
} else {
u8::from(recoverable_sig.recovery_id()) as u64 + 27
};
let r_bytes: FieldBytes<Secp256k1> = recoverable_sig.r().into();
let s_bytes: FieldBytes<Secp256k1> = recoverable_sig.s().into();
@ -103,26 +122,10 @@ impl<D: DigestSigner<Sha256Proxy, RecoverableSignature>> Wallet<D> {
Signature { r, s, v }
}
/// Sets the wallet's chain_id, used in conjunction with EIP-155 signing
pub fn set_chain_id<T: Into<u64>>(mut self, chain_id: T) -> Self {
self.chain_id = Some(chain_id.into());
self
}
/// Gets the wallet's signer
pub fn signer(&self) -> &D {
&self.signer
}
/// Gets the wallet's chain id
pub fn chain_id(&self) -> Option<u64> {
self.chain_id
}
/// Returns the wallet's address
pub fn address(&self) -> Address {
self.address
}
}
// do not log the signer

View File

@ -66,7 +66,7 @@ impl Wallet<SigningKey> {
Ok(Self {
signer,
address,
chain_id: None,
chain_id: 1,
})
}
@ -82,7 +82,7 @@ impl Wallet<SigningKey> {
Ok(Self {
signer,
address,
chain_id: None,
chain_id: 1,
})
}
@ -93,7 +93,7 @@ impl Wallet<SigningKey> {
Self {
signer,
address,
chain_id: None,
chain_id: 1,
}
}
}
@ -113,7 +113,7 @@ impl From<SigningKey> for Wallet<SigningKey> {
Self {
signer,
address,
chain_id: None,
chain_id: 1,
}
}
}
@ -129,7 +129,7 @@ impl From<K256SecretKey> for Wallet<SigningKey> {
Self {
signer,
address,
chain_id: None,
chain_id: 1,
}
}
}
@ -224,10 +224,10 @@ mod tests {
"4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
.parse()
.unwrap();
let wallet = wallet.set_chain_id(chain_id);
let wallet = wallet.with_chain_id(chain_id);
let sig = wallet.sign_transaction(&tx).await.unwrap();
let sighash = tx.sighash(Some(chain_id));
let sighash = tx.sighash(chain_id);
assert!(sig.verify(sighash, wallet.address).is_ok());
}

View File

@ -58,7 +58,7 @@ impl From<YubiSigner<Secp256k1>> for Wallet<YubiSigner<Secp256k1>> {
Self {
signer,
address,
chain_id: None,
chain_id: 1,
}
}
}

View File

@ -9,7 +9,7 @@ async fn main() -> anyhow::Result<()> {
// the wallet's index. Alternatively, you may use Legacy with the wallet's
// index or supply the full HD path string. You may also provide the chain_id
// (here: mainnet) for EIP155 support.
let ledger = Ledger::new(HDPath::LedgerLive(0), Some(1)).await?;
let ledger = Ledger::new(HDPath::LedgerLive(0), 1).await?;
let client = SignerMiddleware::new(provider, ledger);
// Create and broadcast a transaction (ENS enabled!)