Skip to content

bhatt11z/Multi-Blockchain-Wallet-in-Python

Repository files navigation

Multi-Blockchain Wallet in Python

Dependencies

  • PHP must be installed on your operating system.

  • You will need to clone the hd-wallet-derive tool.

  • bit Python Bitcoin library.

  • web3.py Python Ethereum library.

Instructions

  • Create a project directory called wallet and cd into it.

  • Clone the hd-wallet-derive tool into this folder and install it using the instructions on its README.md.

  • Create a symlink called derive for the hd-wallet-derive/hd-wallet-derive.php script into the top level project directory like so: ln -s hd-wallet-derive/hd-wallet-derive.php derive

    This will clean up the command needed to run the script in the code, to call ./derive instead of ./hd-wallet-derive/hd-wallet-derive.php.exe.

  • Test run the ./derive script properly, use one of the examples on the repo's README.md

    Note: 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 for hd-wallet-derive image

2. Setup constants

  • 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.

3. Generate a Mnemonic

  • Generate a new 12 word mnemonic using hd-wallet-derive or by using this tool.

  • Set this mnemonic as an environment variable by storing it a an .env file and importing it into your wallet.py.

4. Derive the wallet keys

  • Create a function called derive_wallets that does the following:

    • Use the subprocess library to create a shell command that calls the ./derive script from Python. Make sure to properly wait for the process. Windows Users may need to prepend the php command in front of ./derive like 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 using json.loads(output)
  • Create a dictionary object called coins that uses the derive_wallets function to derive ETH and BTCTEST wallets.

  • When done properly, the final object should look something like this (there are only 3 children each in this image): image

5. Linking the transaction signing libraries

  • Use bit and web3.py to leverage the keys stored in the coins object by creating three more functions:

    • priv_key_to_account:

      • This function will convert the privkey string in a child key to an account object that bit or web3.py can use to transact.

      • This function needs the following parameters:

        • coin -- the coin type (defined in constants.py).
        • priv_key -- the privkey string 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, return Account.privateKeyToAccount(priv_key)
        • This function returns an account object from the private key string. You can read more about this object here.
      • For BTCTEST, return PrivateKeyTestnet(priv_key)
        • This is a function from the bit libarary 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.
  • 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 in constants.py).
      • account -- the account object from priv_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 containing to, from, value, gas, gasPrice, nonce, and chainID. Make sure to calculate all of these values properly using web3.py!
      • For BTCTEST, return PrivateKeyTestnet.prepare_transaction(account.address, [(to, amount, BTC)])
  • 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 in constants.py).
      • account -- the account object from priv_key_to_account.
      • to -- the recipient address.
      • amount -- the amount of the coin to send.

image image

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, return w3.eth.sendRawTransaction(signed.rawTransaction)
    • For BTCTEST, return NetworkAPI.broadcast_tx_testnet(signed)

Bitcoin Testnet transaction

Bitcoin transaction

  • btc_acc = priv_key_to_account(BTCTEST,btc_PrivateKey)
  • create_tx(BTCTEST,btc_acc,"mtPBiNx19kJ2tgYtD7KJs61jBMo7yvXVaq", 0.0005)

Send BTC transaction

  • send_txn(BTCTEST,btc_acc,"mxks7M9hCwKt4f1bNaghbgzBLV4xkmkbo2", 0.0005)

Confirmation on executed transaction(i tried to do another one, but got insufficient fund error) image

ETH Transaction - Local PoA

  • Add one of the ETH addresses to the pre-allocated accounts in mtestnet.json

  • Initialize using geth --datadir nodeX init mtestnet.json.

  • Add the following middleware to web3.py to 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 the w3.eth.generateGasPrice() function does not work with an empty chain. Use one of the ETH address privkey, or one of the node keystore files.

  • Send a transaction from the pre-funded address within the wallet to another, then get the TxStatus from MyCrypto

Due to unresolved issue, my ETH transaction was not working. However, the code is included in multiblockchain.ipy

About

Developed a wallet that can hold multiple crypto currencies simultaneously.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published