-
PHP must be installed on your operating system.
-
You will need to clone the
hd-wallet-derivetool. -
bitPython Bitcoin library. -
web3.pyPython Ethereum library.
-
Create a project directory called
walletandcdinto it. -
Clone the
hd-wallet-derivetool into this folder and install it using the instructions on itsREADME.md. -
Create a symlink called
derivefor thehd-wallet-derive/hd-wallet-derive.phpscript into the top level project directory like so:ln -s hd-wallet-derive/hd-wallet-derive.php deriveThis will clean up the command needed to run the script in the code, to call
./deriveinstead of./hd-wallet-derive/hd-wallet-derive.php.exe. -
Test run the
./derivescript properly, use one of the examples on the repo'sREADME.mdNote: If one gets an error running
./derive, as it happens in Windows machine then use:./hd-wallet-derive/hd-wallet-derive.php.exe -
Create a file called
wallet.py-- universal wallet script. Directory tree forhd-wallet-derive
-
In a separate file,
constants.py, set the following constants:BTC = 'btc'ETH = 'eth'BTCTEST = 'btc-test'
-
In
wallet.py, import all constants:from constants import * -
Use these anytime you reference these strings, both in function calls, and in setting object keys.
-
Generate a new 12 word mnemonic using
hd-wallet-deriveor by using this tool. -
Set this mnemonic as an environment variable by storing it a an
.envfile and importing it into yourwallet.py.
-
Create a function called
derive_walletsthat does the following:-
Use the
subprocesslibrary to create a shell command that calls the./derivescript from Python. Make sure to properly wait for the process. Windows Users may need to prepend thephpcommand in front of./derivelike so:php ./derive. -
The following flags must be passed into the shell command as variables:
- Mnemonic (
--mnemonic) must be set from an environment variable, or default to a test mnemonic - Coin (
--coin) - Numderive (
--numderive) to set number of child keys generated - Format (
--format=json) to parse the output into a JSON object usingjson.loads(output)
- Mnemonic (
-
-
Create a dictionary object called
coinsthat uses thederive_walletsfunction to deriveETHandBTCTESTwallets. -
When done properly, the final object should look something like this (there are only 3 children each in this image):

-
Use
bitandweb3.pyto leverage the keys stored in thecoinsobject by creating three more functions:-
priv_key_to_account:-
This function will convert the
privkeystring in a child key to an account object thatbitorweb3.pycan use to transact. -
This function needs the following parameters:
coin-- the coin type (defined inconstants.py).priv_key-- theprivkeystring will be passed through here.
-
-
You will need to check the coin type, then return one of the following functions based on the library:
- For
ETH, returnAccount.privateKeyToAccount(priv_key)- This function returns an account object from the private key string. You can read more about this object here.
- For
BTCTEST, returnPrivateKeyTestnet(priv_key)- This is a function from the
bitlibarary that converts the private key string into a WIF (Wallet Import Format) object. WIF is a special format bitcoin uses to designate the types of keys it generates. - You can read more about this function here.
- This is a function from the
- For
-
-
create_tx:-
This function will create the raw, unsigned transaction that contains all metadata needed to transact.
-
This function needs the following parameters:
coin-- the coin type (defined inconstants.py).account-- the account object frompriv_key_to_account.to-- the recipient address.amount-- the amount of the coin to send.
-
You will need to check the coin type, then return one of the following functions based on the library:
- For
ETH, return an object containingto,from,value,gas,gasPrice,nonce, andchainID. Make sure to calculate all of these values properly usingweb3.py! - For
BTCTEST, returnPrivateKeyTestnet.prepare_transaction(account.address, [(to, amount, BTC)])
- For
-
-
send_tx:-
This function will call
create_tx, sign the transaction, then send it to the designated network. -
This function needs the following parameters:
coin-- the coin type (defined inconstants.py).account-- the account object frompriv_key_to_account.to-- the recipient address.amount-- the amount of the coin to send.
-
You will need to check the coin, then create a raw_tx object by calling create_tx. Then, you will need to sign the raw_tx using bit or web3.py.
-
Once you've signed the transaction, you will need to send it to the designated blockchain network.
- For
ETH, returnw3.eth.sendRawTransaction(signed.rawTransaction) - For
BTCTEST, returnNetworkAPI.broadcast_tx_testnet(signed)
- For
-
Fund a
BTCTESTaddress using this testnet faucet. -
Use a block explorer to watch transactions on the address.
- btc_acc = priv_key_to_account(BTCTEST,btc_PrivateKey)
- create_tx(BTCTEST,btc_acc,"mtPBiNx19kJ2tgYtD7KJs61jBMo7yvXVaq", 0.0005)
- send_txn(BTCTEST,btc_acc,"mxks7M9hCwKt4f1bNaghbgzBLV4xkmkbo2", 0.0005)
Confirmation on executed transaction(i tried to do another one, but got insufficient fund error)

-
Add one of the
ETHaddresses to the pre-allocated accounts inmtestnet.json -
Initialize using
geth --datadir nodeX init mtestnet.json. -
Add the following middleware to
web3.pyto support the PoA algorithm:from web3.middleware import geth_poa_middleware w3.middleware_onion.inject(geth_poa_middleware, layer=0) -
Due to a bug in
web3.py, send a transaction or two with MyCrypto first, since thew3.eth.generateGasPrice()function does not work with an empty chain. Use one of theETHaddressprivkey, or one of thenodekeystore files. -
Send a transaction from the pre-funded address within the wallet to another, then get the
TxStatusfrom MyCrypto
Due to unresolved issue, my ETH transaction was not working. However, the code is included in multiblockchain.ipy

