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:
parent
79862ffda5
commit
2640757d8a
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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..])
|
|
||||||
}
|
|
|
@ -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(())
|
||||||
|
}
|
Loading…
Reference in New Issue