Splitting Notes
As we saw earlier, notes must be fully spent. Usually, this is not an issue because we receive the change from the same transaction.
INFO
The change comes from our spending transaction. Whereas in real life, the payee receives the note and then returns the change in a separate transaction.
However, if we want to make several transactions in a row, having to wait for the change becomes a problem. The transaction needs to be mined and often the wallet waits a few blocks[1] before it makes incoming notes available for spending.
TIP
You can configure the number of confirmations in zcash-warp
. We set it to 1. A typical value is 3 for mobile wallets.
By "pre-splitting" your wallet notes, you make smaller denominations. This is similar to keeping for small bills/coins rather than holding a large note.
Multi-pay
There is no automated way to split notes in zcash-warp
[2]. So we will do it manually by making a transaction that pays ourselves multiple times.
The input of the multi-pay command is a JSON object.
The JSON object for the basic transaction in the previous section is
{
"recipients": [
{
"address": "zregtestsapling154t4hyfhzjn7pdtyfs9znamk872krs239jzgmr5fnp98u8gqmhndc28c3el0k95d7reus097upc",
"amount": 100000000,
"pools": 7,
"memo": null,
"memo_bytes": null
}
],
"src_pools": 7,
"sender_pay_fees": true,
"use_change": true,
"height": 103,
"expiration": 203
}
Most of the data is easily recognizable. There are a few new fields.
memo
andmemo_bytes
specify the memo of the note. Only one of these fields should be populated. Usememo
if it is a text andmemo_bytes
if it should be arbitrary binary data.height
is the current block height. It must be one of the synchronization point.
INFO
Warp Sync works in leaps and bounds. When you sync up to the current block height, it may stop at a few intermediate points, but it will not include every block.
You can list the sync points with the command checkpoint list
or simply use the current block height with last-height
.
Expiration height is the block # at which the transaction should expire. A value of 50 to 100 blocks after the height
is usual.
To split the 5.25 ZEC for the first wallet, we first edit the JSON object and replace the destination address with the account #1 Orchard address (address 1 4
) and duplicate it 5 times.
{
"recipients": [
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"pools": 7,
"memo": null,
"memo_bytes": null
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"pools": 7,
"memo": null,
"memo_bytes": null
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"pools": 7,
"memo": null,
"memo_bytes": null
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"pools": 7,
"memo": null,
"memo_bytes": null
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"pools": 7,
"memo": null,
"memo_bytes": null
}
],
"src_pools": 7,
"sender_pay_fees": true,
"use_change": true,
"height": 103,
"expiration": 203
}
Then we use multi-pay
to make a transaction with that JSON.
WARNING
The JSON object has to be on one line. Use a JSON minifier to compactify.
zcash-warp〉multi-pay 1 '{"recipients":[{"address":"uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk","amount":100000000,"pools":7,"memo":null,"memo_bytes":null},{"address":"uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk","amount":100000000,"pools":7,"memo":null,"memo_bytes":null},{"address":"uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk","amount":100000000,"pools":7,"memo":null,"memo_bytes":null},{"address":"uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk","amount":100000000,"pools":7,"memo":null,"memo_bytes":null},{"address":"uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk","amount":100000000,"pools":7,"memo":null,"memo_bytes":null}],"src_pools":7,"sender_pay_fees":true,"use_change":true,"height":103,"expiration":203}'
We get the following transaction:
{
"height": 103,
"recipients": [
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"change": false
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"change": false
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"change": false
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"change": false
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 100000000,
"change": false
},
{
"address": "uregtest1qae0mnr0p9jenge23nc47f359kwkyqvq0kl3qfgyqmk5k37jcvqlzafype9r99yxwfhs38q3w0a2qgam489deht2fguv6hg6g5m0c5vk",
"amount": 24935000,
"change": true
}
],
"transparent_ins": 0,
"sapling_net": 0,
"orchard_net": 30000,
"fee": 30000,
"privacy_level": 3,
"num_inputs": [
0,
0,
1
],
"num_outputs": [
0,
0,
6
],
"data": null,
"keys": null
}
This is an Orchard to Orchard transaction based on the num_inputs
and num_outputs
. There are 6 outputs: 5 x 1 ZEC + change. The Orchard Logical Actions is MAX(1, 6) = 6. We pay 6 x 5000 = 30000 of fees. Fees are always public, and we see they came from the Orchard pool since orchard_net
= 30000.
As usual, let's submit the transaction, mine and sync.
zcash-warp〉broadcast-latest 09/23/2024 05:26:03 PM
$ ./src/zcash-cli --datadir=regtest_dir generate 1
zcash-warp〉sync 09/23/2024 05:26:58 PM
Balance
Looking at the balance, not much has changed. We just have slightly less because we had to pay the transaction fees.
zcash-warp〉balance 1 09/23/2024 05:32:42 PM
Balance: BalanceT { transparent: 0, sapling: 0, orchard: 524935000 }
However, the wallet has 6 notes.
[
{
"id_note": 4,
"height": 104,
"confirmations": 1,
"timestamp": 1727076805,
"value": 100000000,
"orchard": true,
"excluded": false
},
{
"id_note": 5,
"height": 104,
"confirmations": 1,
"timestamp": 1727076805,
"value": 100000000,
"orchard": true,
"excluded": false
},
{
"id_note": 6,
"height": 104,
"confirmations": 1,
"timestamp": 1727076805,
"value": 100000000,
"orchard": true,
"excluded": false
},
{
"id_note": 7,
"height": 104,
"confirmations": 1,
"timestamp": 1727076805,
"value": 100000000,
"orchard": true,
"excluded": false
},
{
"id_note": 8,
"height": 104,
"confirmations": 1,
"timestamp": 1727076805,
"value": 100000000,
"orchard": true,
"excluded": false
},
{
"id_note": 9,
"height": 104,
"confirmations": 1,
"timestamp": 1727076805,
"value": 24935000,
"orchard": true,
"excluded": false
}
]
Let's diversify our wallet by having some transparent, sapling and orchard notes.