Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Zallet is a full-node Zcash wallet written in Rust. It is being built as a replacement for the zcashd wallet.

Security Warnings

Zallet is currently under development and has not been fully reviewed.

Current phase: Alpha release

Zallet is currently in alpha. What this means is:

  • Breaking changes may occur at any time, requiring you to delete and recreate your Zallet wallet.
  • Many JSON-RPC methods that will be ported from zcashd have not yet been implemented.
  • We will be rapidly making changes as we release new alpha versions.

We encourage everyone to test out Zallet during the alpha period and provide feedback, either by opening issues on GitHub or contacting us in the #wallet-dev channel of the Zcash R&D Discord.

Future phase: Beta release

After alpha testing will come the beta phase. At this point, all of the JSON-RPC methods that we intend to support will exist. Users will be expected to migrate to the provided JSON-RPC methods; semantic differences will need to be taken into account.

Installation

There are multiple ways to install the zallet binary. The table below has a summary of the simplest options:

EnvironmentCLI command
DebianDebian packages
UbuntuDebian packages

Help from new packagers is very welcome. However, please note that Zallet is currently ALPHA software, and is rapidly changing. If you create a Zallet package before the 1.0.0 production release, please ensure you mark it as alpha software and regularly update it.

Pre-compiled binaries

WARNING: This approach does not have automatic updates.

Executable binaries are available for download on the GitHub Releases page.

Build from source using Rust

WARNING: This approach does not have automatic updates.

To build Zallet from source, you will first need to install Rust and Cargo. Follow the instructions on the Rust installation page. Zallet currently requires at least Rust version 1.85.

WARNING: The following does not yet work because Zallet cannot be published to crates.io while it has unpublished dependencies. This will be fixed during the alpha phase. In the meantime, follow the instructions to install the latest development version.

Once you have installed Rust, the following command can be used to build and install Zallet:

cargo install zallet

This will automatically download Zallet from crates.io, build it, and install it in Cargo's global binary directory (~/.cargo/bin/ by default).

To update, run cargo install zallet again. It will check if there is a newer version, and re-install Zallet if a new version is found. You will need to shut down and restart any running Zallet instances to apply the new version.

To uninstall, run the command cargo uninstall zallet. This will only uninstall the binary, and will not alter any existing wallet datadir.

Installing the latest development version

If you want to run the latest unpublished changes, then you can instead install Zallet directly from the main branch of its code repository:

cargo install --git https://github.com/zcash/wallet.git

Debian binary packages setup

The Electric Coin Company operates a package repository for 64-bit Debian-based distributions. If you'd like to try out the binary packages, you can set it up on your system and install Zallet from there.

First install the following dependency so you can talk to our repository using HTTPS:

sudo apt-get update && sudo apt-get install apt-transport-https wget gnupg2

Next add the Zcash master signing key to apt's trusted keyring:

wget -qO - https://apt.z.cash/zcash.asc | gpg --import
gpg --export B1C9095EAA1848DBB54D9DDA1D05FDC66B372CFE | sudo apt-key add -
Key fingerprint = B1C9 095E AA18 48DB B54D 9DDA 1D05 FDC6 6B37 2CFE

Add the repository to your Bullseye sources:

echo "deb [arch=amd64] https://apt.z.cash/ bullseye main" | sudo tee /etc/apt/sources.list.d/zcash.list

Or add the repository to your Bookworm sources:

echo "deb [arch=amd64] https://apt.z.cash/ bookworm main" | sudo tee /etc/apt/sources.list.d/zcash.list

Update the cache of sources and install Zcash:

sudo apt update && sudo apt install zallet

Troubleshooting

Missing Public Key Error

If you see:

The following signatures couldn't be verified because the public key is not available: NO_PUBKEY B1C9095EAA1848DB

Get the new key directly from the z.cash site:

wget -qO - https://apt.z.cash/zcash.asc | gpg --import
gpg --export B1C9095EAA1848DBB54D9DDA1D05FDC66B372CFE | sudo apt-key add -

to retrieve the new key and resolve this error.

Revoked Key error

If you see something similar to:

The following signatures were invalid: REVKEYSIG AEFD26F966E279CD

Remove the key marked as revoked:

sudo apt-key del AEFD26F966E279CD

Then retrieve the updated key:

wget -qO - https://apt.z.cash/zcash.asc | gpg --import
gpg --export B1C9095EAA1848DBB54D9DDA1D05FDC66B372CFE | sudo apt-key add -

Then update the list again:

sudo apt update

Expired Key error

If you see something similar to:

The following signatures were invalid: KEYEXPIRED 1539886450

Remove the old signing key:

sudo apt-key del 1539886450

Remove the list item from local apt:

sudo rm /etc/apt/sources.list.d/zcash.list

Update the repository list:

sudo apt update

Then start again at the beginning of this document.

Setting up a Zallet wallet

WARNING: This process is currently unstable, very manual, and subject to change as we make Zallet easier to use.

Create a config file

Zallet by default uses $HOME/.zallet as its data directory. You can override this with the -d/--datadir flag.

Once you have picked a datadir for Zallet, create a zallet.toml file in it. You currently need at least the following:

[builder.limits]

[consensus]
network = "main"

[database]

[external]

[features]
as_of_version = "0.0.0"

[features.deprecated]

[features.experimental]

[indexer]
validator_user = ".."
validator_password = ".."

[keystore]

[note_management]

[rpc]
bind = ["127.0.0.1:SOMEPORT"]

In particular, you currently need to configure the [indexer] section to point at your full node's JSON-RPC endpoint. The relevant config options in that section are:

  • validator_address (if not running on localhost at the default port)
  • validator_cookie_auth = true and validator_cookie_path (if using cookie auth)
  • validator_user and validator_password (if using basic auth)

If you have an existing zcash.conf, you can use it as a starting point:

$ zallet migrate-zcash-conf --datadir /path/to/zcashd/datadir -o /path/to/zallet/datadir/zallet.toml

Reference

Initialize the wallet encryption

Zallet uses age encryption to encrypt all key material internally. Currently you can use two kinds of age identities, which you can generate with rage:

  • A plain identity file directly on disk:

    $ rage-keygen -o /path/to/zallet/datadir/encryption-identity.txt
    Public key: age1...
    
  • A passphrase-encrypted identity file:

    $ rage -p -o /path/to/zallet/datadir/encryption-identity.txt <(rage-keygen)
    Public key: age1...
    Using an autogenerated passphrase:
        drip-lecture-engine-wood-play-business-blame-kitchen-month-combine
    

(age plugins will also be supported but currently are tricky to set up.)

Once you have created your identity file, initialize your Zallet wallet:

$ zallet -d /path/to/zallet/datadir init-wallet-encryption

Reference

Generate a mnemonic phrase

$ zallet -d /path/to/zallet/datadir generate-mnemonic

Reference

Each time you run this, a new BIP 39 mnemonic will be added to the wallet. Be careful to only run it multiple times if you want multiple independent roots of spend authority!

Start Zallet

$ zallet -d /path/to/zallet/datadir start

Reference

Command-line tool

The zallet command-line tool is used to create and maintain wallet datadirs, as well as run wallets themselves. After you have installed zallet, you can run the zallet help command in your terminal to view the available commands.

The following sections provide in-depth information on the different commands available.

The start command

zallet start starts a Zallet wallet!

The command takes no arguments (beyond the top-level flags on zallet itself). When run, Zallet will connect to the backing full node (which must be running), start syncing, and begin listening for JSON-RPC connections.

You can shut down a running Zallet wallet with Ctrl+C if zallet is in the foreground, or (on Unix systems) by sending it the signal SIGINT or SIGTERM.

The example-config command

zallet example-config generates an example configuration TOML file that can be used to run Zallet.

The command takes one flag that is currently required: -o/--output PATH which specifies where the generated config file should be written. The value - will write the config to stdout.

For the Zallet alpha releases, the command also currently takes another required flag --this-is-alpha-code-and-you-will-need-to-recreate-the-example-later.

The generated config file contains every available config option, along with their documentation:

$ zallet example-config -o -
# Default configuration for Zallet.
#
# This file is generated as an example using Zallet's current defaults. It can
# be used as a skeleton for custom configs.
#
# Fields that are required to be set are uncommented, and set to an example
# value. Every other field is commented out, and set to the current default
# value that Zallet will use for it (or `UNSET` if the field has no default).
#
# Leaving a field commented out means that Zallet will always use the latest
# default value, even if it changes in future. Uncommenting a field but keeping
# it set to the current default value means that Zallet will treat it as a
# user-configured value going forward.


#
# Settings that affect transactions created by Zallet.
#
[builder]

# Whether to spend unconfirmed transparent change when sending transactions.
#
# Does not affect unconfirmed shielded change, which cannot be spent.
#spend_zeroconf_change = true

...

The migrate-zcash-conf command

Available on crate feature zcashd-import only.

zallet migrate-zcash-conf migrates a zcashd configuration file (zcash.conf) to an equivalent Zallet configuration file (zallet.toml).

The command requires at least one of the following two flag:

  • --path: A path to a zcashd configuration file.
  • --zcashd-datadir: A path to a zcashd datadir. If this is provided, then --path can be relative (or omitted, in which case the default filename zcash.conf will be used).

For the Zallet alpha releases, the command also currently takes another required flag --this-is-alpha-code-and-you-will-need-to-redo-the-migration-later.

When run, Zallet will parse the zcashd config file, and migrate its various options to equivalent Zallet config options. Non-wallet options will be ignored, and wallet options that cannot be migrated will cause a warning to be printed to stdout.

The migrate-zcashd-wallet command

Available on crate feature zcashd-import only.

zallet migrate-zcashd-wallet migrates a zcashd wallet file (wallet.dat) to a Zallet wallet (wallet.db).

zallet init-wallet-encryption must be run before this command. In addition, the db_dump utility (provided either by global installation or a local source-based zcashd installation) must be available. Note that you specifically need the db_dump utility built for BDB version 6.2.23 for greatest reliability.

The command requires at least one of the following two flag:

  • --path: A path to a zcashd wallet file.
  • --zcashd-datadir: A path to a zcashd datadir. If this is provided, then --path can be relative (or omitted, in which case the default filename wallet.dat will be used).

Additional CLI arguments:

  • --zcashd-install-dir: A path to a local zcashd installation directory, for source-based builds of zcashd. This is used to find the installed version of the db_dump utility, which is required for operation. If not specified, Zallet will attempt to find db_dump on the system path; however, it is recommended to use a db_dump provided via local zcashd installation to ensure version compatibility with the wallet.dat file.
  • --allow-multiple-wallet-imports: An optional flag that must be set if a user wants to import keys and transactions from multiple wallet.dat files (not required for the first wallet.dat import.)
  • --buffer-wallet-transactions: If set, Zallet will eagerly fetch transaction data from the chain as part of wallet migration instead of via ordinary chain sync. This may speed up wallet recovery, but requires all wallet transactions to be buffered in-memory which may cause out-of-memory errors for large wallets.
  • --allow-warnings: If set, Zallet will ignore errors in parsing transactions extracted from the wallet.dat file. This can enable the import of key data from wallets that have been used on consensus forks of the Zcash chain.

For the Zallet alpha releases, the command also currently takes another required flag --this-is-alpha-code-and-you-will-need-to-redo-the-migration-later.

When run, Zallet will parse the zcashd wallet file, connect to the backing full node (to obtain necessary chain information for setting up wallet birthdays), create Zallet accounts corresponding to the structure of the zcashd wallet, and store the key material in the Zallet wallet. Parsing is performed using the db_dump command-line utility, which must either be present in the zcutil/bin directory of a zcashd source installation (as specified via the --zcashd-install-dir argument), or avaliable on the system $PATH.

The init-wallet-encryption command

zallet init-wallet-encryption prepares a Zallet wallet for storing key material securely.

The command currently takes no arguments (beyond the top-level flags on zallet itself). When run, Zallet will use the age encryption identity stored in a wallet's datadir to initialize the wallet's encryption keys. The encryption identity file name (or path) can be set with the keystore.encryption_identity config option.

WARNING: For the first Zallet alpha release (0.1.0-alpha.1), zallet requires the encryption identity file to already exist. You can generate one with rage.

Identity kinds

Zallet supports several kinds of age identities, and how zallet init-wallet-encryption interacts with the user depends on what kind is used:

Plain (unencrypted) age identity file

In this case, zallet init-wallet-encryption will run successfully without any user interaction.

The ability to spend funds in Zallet is directly tied to the capability to read the age identity file on disk. If Zallet is running, funds can be spent at any time.

Passphrase-encrypted identity file

In this case, zallet init-wallet-encryption will ask the user for the passphrase, decrypt the identity, and then use it to initialize the wallet's encryption keys.

Starting Zallet requires the capability to read the identity file on disk, but spending funds additionally requires the passphrase. Zallet can be temporarily unlocked using the JSON-RPC method walletpassphrase, and locked with walletlock.

WARNING: it is currently difficult to use zallet rpc for unlocking a Zallet wallet: zallet rpc walletpassphrase PASSPHRASE will leak your passphrase into your terminal's history.

Plugin identity file

age plugins will eventually be supported by zallet init-wallet-encryption, but currently are tricky to set up and require manual database editing.

Starting Zallet requires the capability to read the plugin identity file on disk. Then, each time a JSON-RPC method is called that requires access to specific key material, the plugin will be called to decrypt it, and Zallet will keep the key material in memory only as long as required to perform the operation. This can be used to control spend authority with an external device like a YubiKey (with age-plugin-yubikey) or a KMS.

The generate-mnemonic command

zallet generate-mnemonic generates a new BIP 39 mnemonic and stores it in a Zallet wallet.

The command takes no arguments (beyond the top-level flags on zallet itself). When run, Zallet will generate a mnemonic, add it to the wallet, and print out its ZIP 32 seed fingerprint (which you will use to identify it in other Zallet commands and RPCs).

$ zallet generate-mnemonic
Seed fingerprint: zip32seedfp1qhrfsdsqlj7xuvw3ncu76u98c2pxfyq2c24zdm5jr3pr6ms6dswss6dvur

Each time you run zallet generate-mnemonic, a new mnemonic will be added to the wallet. Be careful to only run it multiple times if you want multiple independent roots of spend authority!

The import-mnemonic command

zallet import-mnemonic enables a BIP 39 mnemonic to be imported into a Zallet wallet.

The command takes no arguments (beyond the top-level flags on zallet itself). When run, Zallet will ask you to enter the mnemonic. It is recommended to paste the mnemonic in from e.g. a password manager, as what you type will not be printed to the screen and thus it is possible to make mistakes.

$ zallet import-mnemonic
Enter mnemonic:

Once the mnemonic has been provided, press Enter. Zallet will import the mnemonic, and print out its ZIP 32 seed fingerprint (which you will use to identify it in other Zallet commands and RPCs).

$ zallet import-mnemonic
Enter mnemonic:
Seed fingerprint: zip32seedfp1qhrfsdsqlj7xuvw3ncu76u98c2pxfyq2c24zdm5jr3pr6ms6dswss6dvur

The export-mnemonic command

zallet export-mnemonic enables a BIP 39 mnemonic to be exported from a Zallet wallet.

The command takes the UUID of the account for which the mnemonic should be exported. You can obtain this from a running Zallet wallet with zallet rpc z_listaccounts.

The mnemonic is encrypted to the same age identity that the wallet uses to internally encrypt key material. You can then use a tool like [rage] to decrypt the resulting file.

$ zallet export-mnemonic --armor 514ab5f4-62bd-4d8c-94b5-23fa8d8d38c2 >mnemonic.age
$ echo mnemonic.age
-----BEGIN AGE ENCRYPTED FILE-----
...
-----END AGE ENCRYPTED FILE-----
$ rage -d -i path/to/encrypted-identity.txt mnemonic.age
some seed phrase ...

rage

The rpc command

Available on crate feature rpc-cli only.

zallet rpc lets you communicate with a Zallet wallet's JSON-RPC interface from a command-line shell.

  • zallet rpc help will print a list of all JSON-RPC methods supported by Zallet.
  • zallet rpc help <method> will print out a description of <method>.
  • zallet rpc <method> will call that JSON-RPC method. Parameters can be provided via additional CLI arguments (zallet rpc <method> <param>).

Comparison to zcash-cli

The zcashd full node came bundled with a zcash-cli binary, which served an equivalent purpose to zallet rpc. There are some differences between the two, which we summarise below:

zcash-cli functionalityzallet rpc equivalent
zcash-cli -conf=<file>zallet --config <file> rpc
zcash-cli -datadir=<dir>zallet --datadir <dir> rpc
zcash-cli -stdinNot implemented
zcash-cli -rpcconnect=<ip>rpc.bind setting in config file
zcash-cli -rpcport=<port>rpc.bind setting in config file
zcash-cli -rpcwaitNot implemented
zcash-cli -rpcuser=<user>Not implemented
zcash-cli -rpcpassword=<pw>Not implemented
zcash-cli -rpcclienttimeout=<n>zallet rpc --timeout <n>
Hostname, domain, or IP addressOnly IP address
zcash-cli <method> [<param> ..]zallet rpc <method> [<param> ..]

For parameter parsing, zallet rpc is (as of the alpha releases) both more and less flexible than zcash-cli:

  • It is more flexible because zcash-cli implements type-checking on method parameters, which means that it cannot be used with Zallet JSON-RPC methods where the parameters have changed. zallet rpc currently lacks this, which means that:

    • zallet rpc will work against both zcashd and zallet processes, which can be useful during the migration phase.
    • As the alpha and beta phases of Zallet progress, we can easily make changes to RPC methods as necessary.
  • It is less flexible because parameters need to be valid JSON:

    • Strings need to be quoted in order to parse as JSON strings.
    • Parameters that contain strings need to be externally quoted.
zcash-cli parameterzallet rpc parameter
nullnull
truetrue
4242
string'"string"'
[42][42]
["string"]'["string"]'
{"key": <value>}'{"key": <value>}'

Command-line repair tools

The zallet command-line tool comes bundled with a few commands that are specifically for investigating and repairing broken wallet states:

The repair truncate-wallet command

If a Zallet wallet gets into an inconsistent state due to a reorg that it cannot handle automatically, zallet start will shut down. If you encounter this situation, you can use zallet repair truncate-wallet to roll back the state of the wallet to before the reorg point, and then start the wallet again to catch back up to the current chain tip.

The command takes one argument: the maximum height that the wallet should know about after truncation. Due to how Zallet represents its state internally, there may be heights that the wallet cannot roll back to, in which case a lower height may be used. The actual height used by zallet repair truncate-wallet is printed to standard output:

$ zallet repair truncate-wallet 3000000
2999500

Migrating from zcashd

TODO: Document how to migrate from zcashd to Zallet.

JSON-RPC altered semantics

Zallet implements a subset of the zcashd JSON-RPC wallet methods. While we have endeavoured to preserve semantics where possible, for some methods it was necessary to make changes in order for the methods to be usable with Zallet's wallet architecture. This page documents the semantic differences between the zcashd and Zallet wallet methods.

Changed RPC methods

z_listaccounts

Changes to response:

  • New account_uuid field.

z_getnewaccount

Changes to parameters:

  • New account_name required parameter.
  • New seedfp optional parameter.
    • This is required if the wallet has more than one seed.

z_getaddressforaccount

Changes to parameters:

  • account parameter can be a UUID.

Changes to response:

  • New account_uuid field.
  • account field in response is not present if the account parameter is a UUID.
  • The returned address is now time-based if no transparent receiver is present and no explicit index is requested.
  • Returns an error if an empty list of receiver types is provided along with a previously-generated diversifier index, and the previously-generated address did not use the default set of receiver types.

listaddresses

Changes to response:

  • imported_watchonly includes addresses derived from imported Unified Viewing Keys.
  • Transparent addresses for which we have BIP 44 derivation information are now listed in a new derived_transparent field (an array of objects) instead of the transparent field.

getrawtransaction

Changes to parameters:

  • blockhash must be null if set; single-block lookups are not currently supported.

Changes to response:

  • vjoinsplit, joinSplitPubKey, and joinSplitSig fields are always omitted.

z_viewtransaction

Changes to response:

  • Some top-level fields from gettransaction have been added:
    • status
    • confirmations
    • blockhash, blockindex, blocktime
    • version
    • expiryheight, which is now always included (instead of only when a transaction has been mined).
    • fee, which is now included even if the transaction does not spend any value from any account in the wallet, but can also be omitted if the transparent inputs for a transaction cannot be found.
    • generated
  • New account_uuid field on inputs and outputs (if relevant).
  • New accounts top-level field, containing a map from UUIDs of involved accounts to the effect the transaction has on them.
  • Information about all transparent inputs and outputs (which are always visible to the wallet) are now included. This causes the following semantic changes:
    • pool field on both inputs and outputs can be "transparent".
    • New fields tIn and tOutPrev on inputs.
    • New field tOut on outputs.
    • address field on outputs: in zcashd, this was omitted only if the output was received on an account-internal address; it is now also omitted if it is a transparent output to a script that doesn't have an address encoding. Use walletInternal if you need to identify change outputs.
    • memo field on outputs is omitted if pool = "transparent".
    • memoStr field on outputs is no longer only omitted if memo does not contain valid UTF-8.

z_listunspent

Changes to response:

  • For each output in the response array:
    • The amount field has been renamed to value for consistency with z_viewtransaction. The amount field may be reintroduced under a deprecation flag in the future if there is user demand.
    • A valueZat field has been added for consistency with z_viewtransaction
    • An account_uuid field identifying the account that received the output has been added.
    • The account field has been removed and there is no plan to reintroduce it; use the account_uuid field instead.
    • An is_watch_only field has been added.
    • The spendable field has been removed; use is_watch_only instead. The spendable field may be reintroduced under a deprecation flag in the future if there is user demand.
    • The change field has been removed, as determining whether an output qualifies as change involves a bunch of annoying subtleties and the meaning of this field has varied between Sapling and Orchard.
    • A walletInternal field has been added.
    • Transparent outputs are now included in the response array. The pool field for such outputs is set to the string "transparent".
    • The memo field is now omitted for transparent outputs.

z_sendmany

Changes to parameters:

  • fee must be null if set; ZIP 317 fees are always used.
  • If the minconf field is omitted, the default ZIP 315 confirmation policy (3 confirmations for trusted notes, 10 confirmations for untrusted notes) is used.

Changes to response:

  • New txids array field in response.
  • txid field is omitted if txids has length greater than 1.

Omitted RPC methods

The following RPC methods from zcashd have intentionally not been implemented in Zallet, either due to being long-deprecated in zcashd, or because other RPC methods have been updated to replace them.

Omitted RPC methodUse this instead
createrawtransactionTo-be-implemented methods for working with PCZTs
fundrawtransactionTo-be-implemented methods for working with PCZTs
getnewaddressz_getnewaccount, z_getaddressforaccount
getrawchangeaddress
keypoolrefill
importpubkey
importwallet
settxfee
signrawtransactionTo-be-implemented methods for working with PCZTs
z_importwallet
z_getbalancez_getbalanceforaccount, z_getbalanceforviewingkey, getbalance
z_getmigrationstatus
z_getnewaddressz_getnewaccount, z_getaddressforaccount
z_listaddresseslistaddresses