How to Create a Zcash Sapling-Compatible Multisig Transaction
Jorge Valdeiglesias
October 24th, 2018

Using bitgo-utxo-lib to build a Zcash Sapling-compatible multisig transparent transaction


The next Zcash major network upgrade, Sapling, is scheduled to go live on October 28th.

We are not going to explain the benefits of the new version since there is plenty of coverage on the internet already (you can read all about it in our blog post: BitGo Ready for Zcash Sapling). Instead, this article is going to show you how to use it!

To do so, we are going to use bitgo-utxo-lib, an open source library used to build transactions for UTXO (unspent transaction output) coins, including Zcash, Bitcoin, Bitcoin Gold, Bitcoin Cash, Dash, and Litecoin.

Moreover, since at BitGo we support multisig wallets based on their security features, I’m going to show you how to spend ZEC (Zcash currency) from a multisig address after Zcash Sapling network upgrade.

If you are familiar with Zcash you should notice that this tutorial builds a transparent transaction, not a shielded one since these are more complex and not yet widely supported. One of Sapling’s goals is to change this by improving the performance of proof building and validation.

Prerequisites

The only piece of software you are going to need for this tutorial is npm. The rest is just plain JavaScript.

Zcash was forked from Bitcoin Core code (not a chain fork!) and the two share many concepts. This tutorial is targeted at developers familiar with either coin.

If you want to build a transaction yourself rather than following the example, you will need:

  • A multisig address, including the redeemscript and enough private keys to unlock the funds (in this example we will use 2 out of 3 signatures). There is a great answer in StackOverflow by Alex Melville, a fellow BitGo software engineer, on how to get these parameters from a bitcoin full node. You just have to do the same but in a Zcash one (commands are the same).
  • A transaction funding the multisig address. This includes the transaction id, unspent index, and value of such transaction.
  • A Zcash address to send the funds to.

Project setup

First, let’s create a new folder, initialize a default npm project, and add bitgo-utxo-lib to the project dependencies. To do so, open a terminal window and run:

How to Create a Zcash Sapling-Compatible Multisig Transaction 1

Start coding

Now that we have the project set up, open index.js file and import bitgo-utxo-lib by adding the following line at the top:

How to Create a Zcash Sapling-Compatible Multisig Transaction 2

The next step is to instantiate the transaction builder object and configure it to craft transactions following the Zcash Sapling protocol.

bitgo-utxo-lib uses network objects to specify which protocol to use. These encapsulate blockchain specific parameters like bip32 version byte, wif prefix, consensusBranchId (Zcash specific), and more… You can see all network specific parameters in the network file in GitHub.

Add the following lines to the script:

How to Create a Zcash Sapling-Compatible Multisig Transaction 3

Now that we have a builder, let’s set up the basic fields required by a Sapling transaction: version and group id.

Sapling version number is 4 and it succeeds Overwinter (version 3). Previous to that we had version 1 for the Sprout release.

Group id is a field introduced in the Overwinter upgrade as a network upgrade mechanism for transaction parsing.

How to Create a Zcash Sapling-Compatible Multisig Transaction 4

For Sapling, the id changed from 0x03C48270 (Overwinter) to 0x892F2085.

You set these fields in the builder as follows:

How to Create a Zcash Sapling-Compatible Multisig Transaction 5

There are two other optional, but popular, fields worth mentioning:

Lock time: Defines the block height after which the transaction can be included in a block by a miner. Zero means it can be immediately added to the blockchain. Expiry height: Defines the block height after which the transaction will be removed from the mempool if they have not been mined. Zero means there is no expiration time.

How to Create a Zcash Sapling-Compatible Multisig Transaction 6

In this example, we disabled the lock time, meaning the transaction can be picked by a miner as soon as it shows up in the mempool but it can only be included in a block before the blockchain reaches block 289507.

Inputs and Outputs

In the UTXO model, a transaction is made from inputs and outputs.

From the new transaction perspective, inputs are the outputs of a funding transaction which have to be unspent (not referenced by any other transaction in the blockchain).

We have multiple ways to prepare and add inputs using the builder; in this example, we will directly reference the transaction id and output index with the unspent ZEC we will use:

How to Create a Zcash Sapling-Compatible Multisig Transaction 7

Now, the outputs of a transaction are the different destinations we want the funds in the input to go. In this case, we will transfer most of the funds to a single address. To do so you only need the destination address and value.

How to Create a Zcash Sapling-Compatible Multisig Transaction 8

The total amount available in our input transaction is 2 ZEC (200000000 zatoshis), but as you can see, we are only transferring 199999000 zatoshis. This is because we need to pay a fee to the miners and the remaining 1000 zatoshis are used for that.

Signing

Now that we have our builder with the Zcash Sapling parameters, the inputs to use and the outputs to send the funds to, we have to sign the transaction in order to unlock the funds.

Since the funds used by this transaction are in a 2-of-3 multisig address, we require 2 signatures to unlock the funds.

When we create a multisig address with the 3 public keys of the joint owners' account, we are given a redeemscript. In our example, this looks like:

How to Create a Zcash Sapling-Compatible Multisig Transaction 9

We can decode the raw hex using bitgo-utxo-lib like this:

How to Create a Zcash Sapling-Compatible Multisig Transaction 10

The script is executed every time we try to move funds out of this address and what it’s saying is that to unlock the funds, it needs at least 2 (OP2) out of 3 (OP3 ) ECDSA signatures to match (OP_CHECKMULTISIG) one of the public keys (021… 03c… 02f… ). The combination of the signatures with the public keys proves the transaction was created by the real owner of the address in question.

We will need one last parameter, hashType, in order to tell the builder how to sign the transaction. In this example, we are using the default value, SIGHASHALL, which means that every output and input in the transaction will be signed. Other hash types like SIGHASHNONE sign the input but leave the outputs unsigned so miners can later change the destination address. We obviously don’t want the latter.

The Zcash protocol requires us to sign the transaction with the value of the inputs. In other words:

How to Create a Zcash Sapling-Compatible Multisig Transaction 11

This extra bit of information helps offline signing devices to calculate the exact amount being spent and transaction fees without having to pull the inputs transaction from the network. This helps with the implementation of lightweight, air-gapped wallets. In our example, the amount is in the constant inputValueToSign.

Add the following lines to the script in order to sign the transaction output at index 0:

How to Create a Zcash Sapling-Compatible Multisig Transaction 12

If we had more outputs, like a change address, we would have to sign those as well by repeating builder.sign step with a different index.

Final Step

Once the transaction builder has the version, group id, inputs, outputs, and signatures, we are ready to build our Zcash Sapling transaction hex by adding the following lines:

How to Create a Zcash Sapling-Compatible Multisig Transaction 13

The build function generates the script signature for each input depending on the script type provided.

In the command line window run:

How to Create a Zcash Sapling-Compatible Multisig Transaction 14

You should see the following transaction hex as output:

How to Create a Zcash Sapling-Compatible Multisig Transaction 15

If you got the same transaction hex, then congrats! You built your first Zcash Sapling compatible transaction.

Finally, to broadcast it into the Zcash network, we have to find a node to do it for us. I used https://explorer.testnet.z.cash/tx/send since it is updated with the latest Sapling compatible software.

How to Create a Zcash Sapling-Compatible Multisig Transaction 16

Once we hit the “Send transaction” button, our transaction will go to the mempool and wait for a miner to pick it up. This particular transaction can be seen here: https://explorer.testnet.z.cash/tx/20ec1ae4eb2082499c0014a520c13266b18dd134d65274de4f3adca701c9042f

Note that if you try to broadcast this very same transaction you will get the message:

How to Create a Zcash Sapling-Compatible Multisig Transaction 17

This is because the expiry height value has been passed already. If you try to change it for a valid one and broadcast it, you will get:

How to Create a Zcash Sapling-Compatible Multisig Transaction 18

And that’s because the funds in the input used in this example have been used already when doing this tutorial.

Conclusion

We’ve seen how to spend the funds from a Zcash multisig address by manually building a Sapling compatible transaction with bitgo-utxo-lib and broadcasting it using a public node.

Most part of this tutorial works for other cryptocurrencies like Bitcoin, you just have to change the network and make sure you are using the right parameters. For instance, version group id and expiry height only apply for Zcash, other coins don’t use these.

You can find the full example in GitHub gist: https://gist.github.com/argjv/289c80dbe89c43179f6f543ed94283ea#file-zecsaplingmultisig-js

How to Create a Zcash Sapling-Compatible Multisig Transaction 19

Prev
May 15th, 2018
Building the Infrastructure for Institutional Digital Currency Investing
Next
April 17th, 2018
BitGo Adds Support for ERC20 Tokens
Get Started With Us...

For more information on our solutions, start a conversation today!