docs: add example for mnemonic (#258)

* cleanup: use helper secret_to_address function from ethers-core

* docs: add example for mnemonic
This commit is contained in:
Georgios Konstantopoulos 2021-04-05 11:24:06 +03:00 committed by GitHub
parent 79862ffda5
commit 2640757d8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 25 deletions

View File

@ -1,10 +1,14 @@
//! Specific helper functions for creating/loading a mnemonic private key following BIP-39 //! Specific helper functions for creating/loading a mnemonic private key following BIP-39
//! specifications //! specifications
use crate::{wallet::util::key_to_address, Wallet, WalletError}; use crate::{Wallet, WalletError};
use coins_bip32::path::DerivationPath; use coins_bip32::path::DerivationPath;
use coins_bip39::{Mnemonic, Wordlist}; use coins_bip39::{Mnemonic, Wordlist};
use ethers_core::{k256::ecdsa::SigningKey, types::PathOrString, utils::to_checksum}; use ethers_core::{
k256::ecdsa::SigningKey,
types::PathOrString,
utils::{secret_key_to_address, to_checksum},
};
use rand::Rng; use rand::Rng;
use std::{fs::File, io::Write, marker::PhantomData, path::PathBuf, str::FromStr}; use std::{fs::File, io::Write, marker::PhantomData, path::PathBuf, str::FromStr};
use thiserror::Error; use thiserror::Error;
@ -174,7 +178,7 @@ impl<W: Wordlist> MnemonicBuilder<W> {
mnemonic.derive_key(&self.derivation_path, self.password.as_deref())?; mnemonic.derive_key(&self.derivation_path, self.password.as_deref())?;
let key: &SigningKey = derived_priv_key.as_ref(); let key: &SigningKey = derived_priv_key.as_ref();
let signer = SigningKey::from_bytes(&key.to_bytes())?; let signer = SigningKey::from_bytes(&key.to_bytes())?;
let address = key_to_address(&signer); let address = secret_key_to_address(&signer);
Ok(Wallet::<SigningKey> { Ok(Wallet::<SigningKey> {
signer, signer,

View File

@ -6,8 +6,6 @@ pub use mnemonic::{MnemonicBuilder, MnemonicBuilderError};
mod private_key; mod private_key;
pub use private_key::WalletError; pub use private_key::WalletError;
mod util;
#[cfg(feature = "yubihsm")] #[cfg(feature = "yubihsm")]
mod yubi; mod yubi;

View File

@ -1,13 +1,14 @@
//! Specific helper functions for loading an offline K256 Private Key stored on disk //! Specific helper functions for loading an offline K256 Private Key stored on disk
use super::Wallet; use super::Wallet;
use crate::wallet::{mnemonic::MnemonicBuilderError, util::key_to_address}; use crate::wallet::mnemonic::MnemonicBuilderError;
use coins_bip32::Bip32Error; use coins_bip32::Bip32Error;
use coins_bip39::MnemonicError; use coins_bip39::MnemonicError;
use eth_keystore::KeystoreError; use eth_keystore::KeystoreError;
use ethers_core::{ use ethers_core::{
k256::ecdsa::{self, SigningKey}, k256::ecdsa::{self, SigningKey},
rand::{CryptoRng, Rng}, rand::{CryptoRng, Rng},
utils::secret_key_to_address,
}; };
use std::{path::Path, str::FromStr}; use std::{path::Path, str::FromStr};
use thiserror::Error; use thiserror::Error;
@ -60,7 +61,7 @@ impl Wallet<SigningKey> {
{ {
let (secret, _) = eth_keystore::new(dir, rng, password)?; let (secret, _) = eth_keystore::new(dir, rng, password)?;
let signer = SigningKey::from_bytes(secret.as_slice())?; let signer = SigningKey::from_bytes(secret.as_slice())?;
let address = key_to_address(&signer); let address = secret_key_to_address(&signer);
Ok(Self { Ok(Self {
signer, signer,
address, address,
@ -76,7 +77,7 @@ impl Wallet<SigningKey> {
{ {
let secret = eth_keystore::decrypt_key(keypath, password)?; let secret = eth_keystore::decrypt_key(keypath, password)?;
let signer = SigningKey::from_bytes(secret.as_slice())?; let signer = SigningKey::from_bytes(secret.as_slice())?;
let address = key_to_address(&signer); let address = secret_key_to_address(&signer);
Ok(Self { Ok(Self {
signer, signer,
address, address,
@ -87,7 +88,7 @@ impl Wallet<SigningKey> {
/// Creates a new random keypair seeded with the provided RNG /// Creates a new random keypair seeded with the provided RNG
pub fn new<R: Rng + CryptoRng>(rng: &mut R) -> Self { pub fn new<R: Rng + CryptoRng>(rng: &mut R) -> Self {
let signer = SigningKey::random(rng); let signer = SigningKey::random(rng);
let address = key_to_address(&signer); let address = secret_key_to_address(&signer);
Self { Self {
signer, signer,
address, address,
@ -106,7 +107,7 @@ impl PartialEq for Wallet<SigningKey> {
impl From<SigningKey> for Wallet<SigningKey> { impl From<SigningKey> for Wallet<SigningKey> {
fn from(signer: SigningKey) -> Self { fn from(signer: SigningKey) -> Self {
let address = key_to_address(&signer); let address = secret_key_to_address(&signer);
Self { Self {
signer, signer,
@ -122,7 +123,7 @@ impl From<K256SecretKey> for Wallet<SigningKey> {
fn from(key: K256SecretKey) -> Self { fn from(key: K256SecretKey) -> Self {
let signer = SigningKey::from_bytes(&*key.to_bytes()) let signer = SigningKey::from_bytes(&*key.to_bytes())
.expect("private key should always be convertible to signing key"); .expect("private key should always be convertible to signing key");
let address = key_to_address(&signer); let address = secret_key_to_address(&signer);
Self { Self {
signer, signer,

View File

@ -1,14 +0,0 @@
use ethers_core::{
k256::{ecdsa::SigningKey, EncodedPoint as K256PublicKey},
types::Address,
utils::keccak256,
};
pub fn key_to_address(secret_key: &SigningKey) -> Address {
// TODO: Can we do this in a better way?
let uncompressed_pub_key = K256PublicKey::from(&secret_key.verify_key()).decompress();
let public_key = uncompressed_pub_key.unwrap().to_bytes();
debug_assert_eq!(public_key[0], 0x04);
let hash = keccak256(&public_key[1..]);
Address::from_slice(&hash[12..])
}

View File

@ -0,0 +1,32 @@
use ethers::signers::{coins_bip39::English, MnemonicBuilder};
fn main() -> anyhow::Result<()> {
let phrase = "work man father plunge mystery proud hollow address reunion sauce theory bonus";
let index = 0u32;
let password = "TREZOR123";
// Access mnemonic phrase with password
// Child key at derivation path: m/44'/60'/0'/0/{index}
let wallet = MnemonicBuilder::<English>::default()
.phrase(phrase)
.index(index)?
// Use this if your mnemonic is encrypted
.password(password)
.build()?;
dbg!(&wallet);
// Generate a random wallet (24 word phrase) at custom derivation path
let mut rng = rand::thread_rng();
let wallet = MnemonicBuilder::<English>::default()
.word_count(24)
.derivation_path("m/44'/60'/0'/2/1")?
// Optionally add this if you want the generated mnemonic to be written
// to a file
// .write_to(path)
.build_random(&mut rng)?;
dbg!(&wallet);
Ok(())
}