HD Key
WalletD features BIP32 compliant HD keys to facilitate Hierarchical Deterministic (HD) wallets. In this section, we'll guide you on how to use WalletD to access BIP39 mnemonics.
Imports needed for this section
use walletd::walletd_hd_key::prelude::*;
use walletd::walletd_hd_key::slip44::{Coin, Symbol};
Master HD Key from a Seed
You can create a new master HDKey from a Seed and also derive a child HDKey.
Here's how you can import a master hd key based on a seed hex:
Example
let seed_hex = "a2fd9c0522d84d52ee4c8533dc02d4b69b4df9b6255e1af20c9f1d4d691689f2a38637eb1ec778972bf845c32d5ae83c7536999b5666397ac32021b21e0accee";
let seed = Seed::from_str(seed_hex)?;
// creating a new master key for a testnet network based on the above seed
let master_hd_key = HDKey::new_master(seed, HDNetworkType::TestNet)?;
// the master hd key should have a depth of 0
println!("master hd key depth {}", master_hd_key.depth());
Setting a network type on the HDKey is required, you should select HDNetworkType::TestNet
during development and testing purposes and to avoid using real funds and HDNetworkType::MainNet
for production level code with caution.
Be sure to be consistent with HDNetworkType when connecting to the blockchain, make sure to use a compatible blockchain for the specified network type category.
HD Key Serialization, WIF
The Wallet Import Format (WIF) is a standard way to encode private keys. The extended public key and extended private key can also be serialized using a standard serialized format.
How to display these key formats for an HDKey:
Example
// use the to_wif method
println!("wif of master hd key {}", master_hd_key.to_wif().unwrap());
// can display the serialized for mat of the extended private and public keys
println!(
"master hd key extended public key: {}",
master_hd_key.extended_public_key_serialized()?
);
println!(
"master hd key extended private key: {}",
master_hd_key.extended_private_key_serialized()?
);
Specify Derivation Path
You flexibly specify the derivation path using the HDPathBuilder. The default HDPathBuilder which can be accessed through HDPath::builder()
does not specify the purpose, or coin type, and uses the hardened indices for the purpose, coin type, and account indices.
Example
let default_deriv_path = HDPath::builder().build().to_string();
// without specifying the purpose, the default derivation path is "m
assert_eq!(default_deriv_path, "m");
println!("default derivation path: {}", default_deriv_path);
// can flexibly specify the derivation path using the HDPathBuilder
let account_deriv_path = HDPath::builder()
.purpose_index(HDPurpose::BIP44.to_shortform_num())
.coin_type_index(Coin::from(Symbol::ETH).id())
.account_index(0)
.no_change_index()
.no_address_index()
.build().to_string();
// checking this is what we are expecting
assert_eq!(account_deriv_path, "m/44'/60'/0'");
Derive Child HD Key
Can derive a child key from the master key or a parent key using the HDKey::derive
method.
Example
let eth_first_account_key = master_hd_key.derive(account_deriv_path.to_string())?;
// the master seed should be the same for a child HD Key and it's parent HD Key
assert_eq!(
eth_first_account_key.master_seed(),
master_hd_key.master_seed()
);
println!(
"eth_first_account_key depth {}",
eth_first_account_key.depth()
);
assert_eq!(eth_first_account_key.depth(), 3);
Can also use a string directly to represent the derivation path, '
or h
can be used to denote a hardened index.
Example
let account_deriv_path = HDPath::builder()
.purpose_index(HDPurpose::BIP44.to_shortform_num())
.coin_type_index(Coin::from(Symbol::ETH).id())
.account_index(0)
.no_change_index()
.no_address_index()
.build().to_string();
let compare_account_key = master_hd_key.derive("m/44h/60h/0h".to_string())?;
assert_eq!(eth_first_account_key, compare_account_key);
let address_key1 = master_hd_key.derive("m/44h/60h/0h/0/0".to_string())?;
let address_key2 = eth_first_account_key.derive("m/44'/60'/0'/0/0".to_string())?;
assert_eq!(address_key1, address_key2);
A shortcut way to get a derived HDKey directly from a master seed, with a specified HDNetworkType and a derivation path is to use the HDKey::new
method.
Example
let custom_key_path = HDPath::builder()
.purpose_index(HDPurpose::BIP84.to_shortform_num())
.coin_type_index(Coin::Testnet.id())
.account_index(0)
.change_index(1)
.address_index(0)
.hardened_address()
.build()
.to_string();
assert_eq!(custom_key_path, "m/84'/1'/0'/1/0'");
let derived_key = HDKey::new(
seed,
HDNetworkType::TestNet,
custom_key_path,
)?;
println!("derived_key: {:?}", derived_key);
println!("derived_key depth: {}", derived_key.depth());
println!("derived_key wif: {}", derived_key.to_wif()?);
println!(
"derived_key public key: {}",
derived_key.extended_public_key_serialized()?
);
println!(
"derived_key private key: {}",
derived_key.extended_private_key_serialized()?
);
// Can also just display the bytes in the extended private and public keys as a hex
println!(
"derived_key public key hex: {:x}",
derived_key.extended_public_key()?);
println!(
"derived_key private key hex: {:x}",
derived_key.extended_private_key()?);