Usage

The main class for generating wallets, fetching address balances, and creating transactions is zpywallet.Wallet. It is the most important class in the library and represents a wallet on a particular blockchain.

You can create a wallet with a randomly-generated mnemonic phrase like this:

from zpywallet.network import BitcoinSegwitMainNet
from zpywallet import Wallet

wallet = Wallet(BitcoinSegwitMainNet, None, "password")

The second argument is the mnemonic phrase you want to use, which allows you to restore a wallet using different parameters. There is an additional keyword argument, derivation_path, which takes a string to use as the custom path. For example: "m/0'. If no path is specified, it uses the default path for the network. ZPyWallet follows BIP44 path conventions, and the number of receiving addresses can also be configured by changing the receive_gap_limit keyword argument to a larger or smaller number.

To save the wallet into a file, use the serialize() method. This returns a byte stream which can be imported using the Wallet.deserialize(data, password) method.

Networks

Blockchains can be imported from zpywallet.network. For example:

from zpywallet.network import BitcoinSegwitMainNet # Segwit-enabled Bitcoin mainnet
from zpywallet.network import BitcoinMainNet # Bitcoin mainnet which makes only legacy addresses and transactions
from zpywallet.network import BitcoinTestNet
from zpywallet.network import EthereumMainNet
# ...

Here are the supported networks:

  • BitcoinMainNet - Bitcoin mainnet, creates legacy addresses and transactions

  • BitcoinSegwitMainNet - Bitcoin mainnet, creates segwit and legacy addresses and transactions

  • BitcoinTestNet - Bitcoin testnet, creates legacy addresses and transactions

  • BitcoinSegwitTestNet - Bitcoin testnet, creates segwit and legacy addresses and transactions

  • LitecoinMainNet - Litecoin mainnet, creates legacy addresses and transactions

  • LitecoinSegwitMainNet - Litecoin mainnet, creates segwit and legacy addresses and transactions

  • LitecoinBTCMainNet - Litecoin mainnet, creates legacy addresses and transactions

  • LitecoinBTCSegwitMainNet - Litecoin mainnet using Bitcoin xpub/xprv, creates segwit and legacy addresses and transactions

  • LitecoinTestNet - Litecoin testnet, creates legacy addresses and transactions

  • LitecoinSegwitTestNet - Litecoin testnet, creates segwit and legacy addresses and transactions

  • DashMainNet - Dash mainnet

  • DashInvertedMainNet - Dash mainnet, with extended public/private bytes swapped

  • DashBTCMainNet - Dash mainnet usign Bitcoin xpub/xprv

  • DashTestNet - Dash testnet

  • DashInvertedTestNet - Dash testnet, with extended public/private bytes swapped

  • DogecoinMainNet - Dogecoin mainnet

  • DogecoinBTCMainNet - Dogecoin mainnet usign Bitcoin xpub/xprv

  • DogecoinTestNet - Dogecoin testnet

  • EthereumMainNet - Ethereum mainnet (does not support smart contracts)

  • BitcoinCashMainNet - Bitcoin Cash mainnet (limited support)

  • BlockcypherTestNet - Blockcypher testnet (limited support)

Bitcoin Signet support is planned for a future release.

In most cases, if there is a BTC variant of a network, you would want to use that, because many wallets incorrectly use Bitcoin’s extended bytes when generating addresses and keys from seed phrases, and for backwards compatibility, you should also use those bytes to continue detecting wallet balances.

There is also an inverted version of Dash’s network because the Dash specifications and implementation differ on which pair is canonical.

Addresses

To generate a random receiving address within the gap limit, you can use the Wallet.random_address() method. ZPyWallet derives receiving addresses from the external .../0/i branch and monitors change addresses from the internal .../1/i branch when change_gap_limit is enabled. It does not automatically increase either gap limit.

To get a list of all the receiving addresses generated by the wallet, use Wallet.addresses().

The type of addresses created depend on the network used by the wallet. For example, legacy networks will create Base58 P2PKH addresses, while Segwit networks will make Bech32 P2WPKH addresses.

Transactions

ZPyWallet has built-in support for fetching transaction history of addresses:

from zpywallet.network import BitcoinSegwitMainNet # Or you can use BitcoinMainNet
from zpywallet import Wallet
from zpywallet import Destination
from zpywallet.address import CryptoClient
from pprint import pprint as pp

wallet = Wallet(...) # Create or restore a wallet here
transactions = wallet.get_transaction_history()
for tx in transactions:
    print(f"Transaction Hash: {tx.txid()}")
    print(f"Timestamp: {tx.timestamp()}")
    print(f"Confirmed: {tx.confirmed()}")
    if tx.confirmed():
      print(f"Height: {tx.height()}")
    print(f"Total Fee: {tx.total_fee()}")
    print(f"Fee Rate: {tx.sat_feerate()}")
    print(f"Inputs: {pp(tx.sat_inputs())}")
    print(f"Outputs: {pp(tx.sat_outputs())}")

utxos = wallet.get_utxos() # Not applicable for Ethereum
for utxo in utxos:
    print(f"Transaction Hash: {utxo.txid()}")
    print(f"Index: {utxo.index()}")
    print(f"Amount: {utxo.amount()}")
    print(f"Address: {utxo.address()}")

# You can also get UTXOs directly from transactions:
if len(transactions) > 0:
    utxo = UTXO(transactions[0], 1) # Get the first UTXO (transaction output)

# You can even get the transaction history of random addresses:
address_client = CryptoClient(
    ['bc1q34aq5drpuwy3wgl9lhup9892qp6svr8ldzyy7c', '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'],
    coin="BTC",
    chain="main",
)

# ...Then you can call get_transaction_history(), get_utxos() and get_balance() like for a wallet

total_balance, confirmed_balance = address_client.get_balance()

# Send coins to an address
# Change output is automatically calculated by the wallet
address1 = "..."
address2 = "..."
destinations = [Destination(address1, 0.1, BitcoinSegwitMainNet), Destination(address2, 0.2, BitcoinSegwitMainNet)] # Amounts are in BTC

# Or specify raw units directly:
destinations = [Destination(address1, 10000000, BitcoinSegwitMainNet, in_standard_units=False)] # 0.1 BTC in sats

# If you want to spend unconfirmed inputs, pass spend_unconfirmed_inputs=True
fee_rate = 1 # sat/vbyte for Segwit network (for legacy networks it is in sat/byte)
transaction = wallet.create_transaction("password", destinations, fee_rate)
wallet.broadcast_transaction(transaction)

Key Generation

Arbitrary private keys can be generated as well:

from zpywallet.network import BitcoinSegwitMainNet
from zpywallet.utils.keys import PrivateKey, PublicKey

priv = PrivateKey.from_random(network=BitcoinSegwitMainNet)
pub = priv.public_key
addr = pub.address() # Specify compressed=False for uncompressed address. Default is compressed.

PrivateKey.from_hex("...", network=BitcoinSegwitMainNet)
PrivateKey.from_int(1, network=BitcoinSegwitMainNet)
wif = priv.to_wif()
hex = priv.to_hex()

message = priv.rfc2440_sign("Sign a message like this")
priv.rfc2440_verify(message) # returns true or false

Indices and Tables