Credit: Prooworld

So you want to build an Ethereum HD wallet?

Warning: This article is not for beginners. It will explore HD wallets, how they’re built, and how to use them in Ethereum.

What exactly is an HD wallet?

Hierarchical Deterministic Wallets (or HD wallets for short) were introduced by BIP 32 and later improved by BIP 44. BIPs (if you’re not familiar with them) stand for Bitcoin Improvement Proposal. Why are we talking about Bitcoin right now? You should take a look at The History of the space for context. Although the Bitcoin and Ethereum networks are incredibly different today, there are still a lot of similarities to be found between the two currencies. Turns out BIP 32 + BIP 44 provided a network agnostic method of generating secure keys in an incredibly flexible manner, a method used by the vast majority of cryptocurrencies.

m / purpose' / coin_type' / account' / change / address_index

How to Build an Ethereum HD Wallet in node.js

Now we know that an HD Wallet is really just a tree of nodes each with a public and private key and each depth height representing a specific function. First we will create a mnemonic, create an address out of it, and then create a raw transaction and broadcast it on the Ropsten Test Net. Time to build one!

Requirements

Master Private Key and Address generation

How do you start a tree? By beginning at the node. Now, HD Wallets are created by a random bit of data called a seed. We will create a mnemonic and convert that mnemonic to a seed. For those unaware as to what a mnemonic is, here is a quote from the bitcoin wiki.

const mnemonic = bip39.generateMnemonic(); //generates string
const seed = bip39.mnemonicToSeed(mnemonic); //creates seed buffer
const root = hdkey.fromMasterSeed(seed);
const masterPrivateKey = root.privateKey.toString('hex');
const addrNode = root.derive("m/44'/60'/0'/0/0"); //line 1
const pubKey = ethUtil.privateToPublic(addrNode._privateKey);
const addr = ethUtil.publicToAddress(pubKey).toString('hex');
const address = ethUtil.toChecksumAddress(addr);
/*
If using ethereumjs-wallet instead do after line 1:
const address = addrNode.getWallet().getChecksumAddressString();
*/

Constructing, Signing, and Broadcasting Transactions

Now that we have our address and the associated private key, let’s have some fun and spend some money!

const params = {
nonce: 0,
to: '0x4584158529818ef77D1142bEeb0b6648BD8eDb2f',
value: '0.1',
gasPrice: 5000000000,
gasLimit: 21000,
chainId: 3
};
const tx = new ethTx(params);//Signing the transaction with the correct private key
tx.sign(addrNode._privateKey);
const serializedTx = tx.serialize()
$ brew tap ethereum/ethereum
$ brew install ethereum
$ geth --testnet --ws
const web3 = new Web3(
new Web3.providers.HttpProvider('http://localhost:8545')
);
//Verify connection is successful
web3.eth.net.isListening()
.then(() => console.log('is connected'))
.catch(e => console.log('Wow. Something went wrong'));
Web3.eth.sendSignedTransaction(
`0x${serializedTx.toString('hex')}`,
(error, result) => {
if (error) { console.log(`Error: ${error}`); }
else { console.log(`Result: ${result}`); }
}
);

Former fold, bitpay Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store