Build
Connected Chains
Bitcoin

On Bitcoin the gateway is implemented as an TSS MPC account. The private key securing the account is split into fragments and distributed among ZetaChain observer-signer validators.

Bitcoin gateway supports:

  • depositing BTC to a universal app or an account on ZetaChain
  • depositing BTC and calling a universal app

To deposit BTC into ZetaChain's Universal EVM (and optionally call a smart contract), the Bitcoin transaction must conform to this specifications:

  1. The Bitcoin transaction must have at least 2 outputs.

  2. The first output must be addressed to the TSS Bitcoin address.

  3. The second output must be a memo output, i.e. OP_RETURN PUSH_x [DATA]. This output must be less than 80 bytes.

  4. The memo [DATA] is an array of bytes that encodes the recipient address of this deposit into ZRC-20 or the smart contract on ZetaChain's EVM that will be invoked by this transaction.

  5. If the purpose of this Bitcoin transaction is to only deposit BTC into the BTC ZRC-20 on ZetaChain's EVM, then the [DATA] should be exactly 20 bytes long, consists of an Ethereum-style address.

  6. If the purpose of this Bitcoin transaction is to deposit BTC and also use the deposited amount to call a smart contract on ZetaChain's EVM, then the [DATA] field must consists of a smart contract address, and a binary message that will be forwarded to the said smart contract:

    [DATA] = [ZetaChain's EVM contract address (20B)] - [arbitrary binary message]

Here's (opens in a new tab) an example Bitcoin transaction on Bitcoin Testnet that deposits 0.0005 tBTC (50000 sats) into the address (0x)6da30bfa65e85a16b05bce3846339ed2bc746316.

Note the three outputs:

  1. sending the intended amount (50000sats) to the current TSS Bitcoin address tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur.
  2. the memo output, encoding the recipient address on ZetaChain's EVM (0x)6a146da30bfa65e85a16b05bce3846339ed2bc746316.
  3. change sent back to the user.

If you're using ZetaChain's Hardhat smart contract template (opens in a new tab), you can use the send-btc task to transfer BTC:

npx hardhat send-btc --recipient tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur --amount 0.0005 --memo 6a146da30bfa65e85a16b05bce3846339ed2bc746316

Where recipient is the TSS Bitcoin address, amount is the amount of tBTC to transfer, and memo is the recipient address on ZetaChain's EVM.

In order to test with Bitcoin, you will need to use a wallet that allows setting an OP_RETURN and memos in a binary format. Please see our wallet suggestions here.

If invalid information is sent (i. e. invalid address), the assets may be lost and not recoverable.

In summary, a ZetaChain's EVM BTC transaction would look like this:

  1. A user sends 1 BTC on Bitcoin network to the Bitcoin TSS address , adding a memo (via OP_RETURN) in the tx saying (colloquially) “deposit to 0x1337”.
  2. Upon receiving this tx, the ZetaCore state machine calls the deposit (0x1337, 1e8) to mint and credit 0x1337 with 1 zBTC minus fees.
  3. If 0x1337 is an Externally Owned Account (EOA), that's it. If it’s a contract, ZetaCore will call the onCrossChainMessage function sending the message that was specified in the OP_RETURN memo.

The TSS address holds the BTC, where ownerships are tracked inside this BTC ZRC-20 contract.

Unlike EVM-based chains, each deposited Bitcoin output incurs a fee when it is spent. To address this, both the depositor and the withdrawer share the cost of the spend. This fee is charged in advance as a deposit fee.

The Bitcoin deposit fee is calculated with the following formula:

depositFee == (txFee / txVsize) * 68vB * 2
  • txFee is the deposit transaction's fee. This can be calculated by formula: totalInputValue - totalOutputValue
  • txVsize is the deposit transaction's size in vByte. This can be retrieved from RPC GetRawTransaction (ZetaChain's implementation).