Zcash Cold Wallet
In this article
I'll be talking about Zcash Cold Wallet, a command line interface tool developed by hhanh00 for creating Zcash wallets and signing Zcash shielded transactions offline.
Spoiler: Epic Fail
I was writing this article while I was testing this software for the first time. But the last step failed on me. I guess i should have tested the software befere started writing this article. But since it was already almost finished, I'll publish it anyways. Enjoy.
What is a Cold Wallet?
Cold Wallet
In a nutshell, a cold wallet, in the context of cryptocurrencies, is a wallet in which both the private keys, and the transaction signing are made completly offline, with no internet or network connectivity.
You can read more here
How it works?
The ideia of a offline wallet for signing transactions is that you need to have two devices (PCs, laptops, smarthpones, etc...):
- One is connected to the internet
- A "watch-only" wallet is installed on this machine, this wallet can only see your transactions and wallet balance, it cannot directly spend any $ZEC, it can only prepare transactions to be signed and then broadcast the signed transaction.
- The other is said to be "air gapped", with no connection to the internet.
- This one is used for signing pre-constructed transactions using you private key. The prepared transaction should transfered to this offline machine in a secure way, like a USB thumb drive.
Let's do it!
First things first
Zcash Cold Wallet is an experimental software and should be used for testing purposes only!
The provided binaries releases are configure to use testnet only!
But since I wanted to try this for real, I compiled it myself, enabling Mainnet support.
Compiling Zcash Cold Wallet from source
It's fairly easy to compilte Zcash Cold Wallet from source, first make sure to have rust installed and updated.
Then clone the git repository into your pc:
$ git clone https://github.com/hhanh00/zcash-cold-wallet.git
Then change directory into zcash-cold-wallet and build it with mainnet support:
$ cd zcash-cold-wallet$ cargo build --features mainnet --release
The compiled binary should be located in ./target/release/zcash-coldwallet.
Generating a wallet
For this article we'll be generating a new wallet. For this, in your offline computer your should run the following command:
$ ./zcash-coldwallet generate
The command line tool will give an output similitar to this:
seed phrase: inject deliver keep trophy giggle blanket reflect plunge draw civil educate wrestle doll town field duty satisfy stick amateur giggle print wrestle million speakspending key: secret-extended-key-main1q085vl69qqqqpq8y026kjcw6du4d8kr92tsly6xz8y44uaupyf3tu88ejx8z3ju9887d533pthes44dt6fq3dqvhv894shvhmraag8skff7vendku82q2f0jyzvfpkfw6x8eexerg22wxnteajzmm2gnu05qw2vj8uhazvq28twsjvmuh3zxxwuxcg3gsj8wyvhs6wq6tzqqpfcml2s26a3jq6nh0rkw2fh48qc37caxgnw66n6y6x5x5xfl32ul325wcp6gc5jdvlgx82xgfderivation path: m/32'/133'/0'viewing key: zxviews1q085vl69qqqqpq8y026kjcw6du4d8kr92tsly6xz8y44uaupyf3tu88ejx8z3ju989xwlll7nmk7uevuqczf9x376y4zym3zes68rrl5emcjd0h2zyrac8ayqeh6lj2qswalua3lk7hvp2qyz2l23qv7zzkhexveh0929mqp8twsjvmuh3zxxwuxcg3gsj8wyvhs6wq6tzqqpfcml2s26a3jq6nh0rkw2fh48qc37caxgnw66n6y6x5x5xfl32ul325wcp6gc5jdvlg8mtrdnpayment address: zs1l7kehq8zl5p8d6r02zm3hm4r77sk8psdtjqh9x9nldj2caj9mpgawpaj3fh045kwgvm3xq63hzk
This output contains:
- The seed for the newly generated wallet.
- Spensing key for the generated sapling address.
- Derivation path.
- Viewing key for the generated sapling address.
- The Sapling address.
WARNING: Zcash Cold Wallet does not store this information! It's up to you to write it down and keep safe!
Initializing the watch-only wallet
Now that you safely generated your wallet offline, it's time to initialize a watch-only wallet in your online pc.
This will initialize the wallet databse:
$ ./zcash-coldwallet init-db
After that you should import your viewing key into the wallet:
$ ./zcash-coldwallet init-account zxviews1q085vl69qqqqpq8y026kjcw6du4d8kr92tsly6xz8y44uaupyf3tu88ejx8z3ju989xwlll7nmk7uevuqczf9x376y4zym3zes68rrl5emcjd0h2zyrac8ayqeh6lj2qswalua3lk7hvp2qyz2l23qv7zzkhexveh0929mqp8twsjvmuh3zxxwuxcg3gsj8wyvhs6wq6tzqqpfcml2s26a3jq6nh0rkw2fh48qc37caxgnw66n6y6x5x5xfl32ul325wcp6gc5jdvlg8mtrdn 2023-02-27
In the above example I've initialized my wallet with the optional birthday in the format of YYYY-MM-DD
The last step to get the watch-only wallet up and running is to sync the wallet:
$ ./zcash-coldwallet sync
When the sync finishes you'll get the output:
Starting height: 1998747Synced to 1998778Scan completed
Awesome! now we have a configured and synched watch-only wallet.
I sent a few zats to the generated address for testing. To check the wallet balance, sync it again with the previus command and the run the command get-balance:
$ ./zcash-coldwallet get-balance
This command will output your wallet balance:
Balance: 0.02
Ok, everything looking good. Now I'll prepare a transaction for sending this amout to another addres.
To prepare a transaction you'ill run the following command: ./zcash-coldwallet prepare-tx <destination-address> <amount> <json-file>
Where:
- <destination-address> is the address you want to send ZEC to.
- <amount> The amount to send expressed in ZEC minues the default fee, e.g.: for sending 0.2 ZEC, subtract 0.00001 to get the amount of 0.01999.
- <json-file> The filename that will be written with the prepared transaction.
$ ./zcash-coldwallet prepare-tx zs1katzmlgsvdry02d8fpu8xnvfwechpk2ucy5fn7cyuv8y5pqxx0yfzvp4h6gctfee7jxkzsutf0h 0.01999 tx.json
A file called tx.json was created in my working directory, containing the prepared transaction to be sign on my offline computer.
Signing the transaction
Using a USB flash drive
or any other secure airgapped media, transfer the tx.json file from your online computer to your offline computer.
You will also need to download and transafer the sapling params to your offline computer.
On your offline computer sign the transaction using your spending private key using the command ./zcash-coldwallet sign <secret-extended-key> <json-file> <raw-transaction>
Where:
- <secret-extended-key> is your secret spending key.
- <json-file> the prepared transaction json file.
- <raw-transaction> the filename for the signed raw transaction.
It should look something like:
$ ./zcash-coldwallet sign secret-extended-key-main1q085vl69qqqqpq8y026kjcw6du4d8kr92tsly6xz8y44uaupyf3tu88ejx8z3ju9887d533pthes44dt6fq3dqvhv894shvhmraag8skff7vendku82q2f0jyzvfpkfw6x8eexerg22wxnteajzmm2gnu05qw2vj8uhazvq28twsjvmuh3zxxwuxcg3gsj8wyvhs6wq6tzqqpfcml2s26a3jq6nh0rkw2fh48qc37caxgnw66n6y6x5x5xfl32ul325wcp6gc5jdvlgx82xgf tx.json tx.raw
And we'll get the output:
Payment of 0.01999 ZEC to zs1katzmlgsvdry02d8fpu8xnvfwechpk2ucy5fn7cyuv8y5pqxx0yfzvp4h6gctfee7jxkzsutf0h
Nice! our transaction was sined using zk-snarks!
Broadcasting the transaction
Using a securre airgap method,
like an USB flash drive, we'll transfer the signed tx.raw transaction file from our offline computer to our online computer.
the last step to complete our transfer is to broadcast it to the Zcash network wi the command:
$ ./zcash-coldwallet submit tx.raw
Fail! this command should have returned the transaction id of the transaction, but instead I got the message error:
Error: Failed to submit transaction. Error code -26, Error Message 16: bad-sapling-bundle-authorization
I don't know if this is a error on my end,
or because the Zcash Cold Wallet repo hasn't been updated for two years, But I decided to still post this article, because I think this tool is so cool, I'd love to see it working. Maybe if this article gets some relevance, the developer will keep maintaining the code, and in the future we could have the safest way to hold our ZEC.
Conclusion ... at least for now
It's a bummer I coudn't make it work, and It's funny how it worked until the very last step. But I guess it's worth to shred my experience.
If I can get this to work, I'll definitely edit this post showing!
That's it. If you stuck aroud until here, my very thank you, I hope you enjoyed.
