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 transactionsBitcoinSegwitMainNet- Bitcoin mainnet, creates segwit and legacy addresses and transactionsBitcoinTestNet- Bitcoin testnet, creates legacy addresses and transactionsBitcoinSegwitTestNet- Bitcoin testnet, creates segwit and legacy addresses and transactionsLitecoinMainNet- Litecoin mainnet, creates legacy addresses and transactionsLitecoinSegwitMainNet- Litecoin mainnet, creates segwit and legacy addresses and transactionsLitecoinBTCMainNet- Litecoin mainnet, creates legacy addresses and transactionsLitecoinBTCSegwitMainNet- Litecoin mainnet using Bitcoin xpub/xprv, creates segwit and legacy addresses and transactionsLitecoinTestNet- Litecoin testnet, creates legacy addresses and transactionsLitecoinSegwitTestNet- Litecoin testnet, creates segwit and legacy addresses and transactionsDashMainNet- Dash mainnetDashInvertedMainNet- Dash mainnet, with extended public/private bytes swappedDashBTCMainNet- Dash mainnet usign Bitcoin xpub/xprvDashTestNet- Dash testnetDashInvertedTestNet- Dash testnet, with extended public/private bytes swappedDogecoinMainNet- Dogecoin mainnetDogecoinBTCMainNet- Dogecoin mainnet usign Bitcoin xpub/xprvDogecoinTestNet- Dogecoin testnetEthereumMainNet- 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