Difference between revisions of "Chain-key Bitcoin"

From Internet Computer Wiki
Jump to: navigation, search
Line 47: Line 47:
 
* <code>get_withdrawal_account</code>: Returns a specific ckBTC account where the owner must transfer ckBTC before being able to retrieve BTC.
 
* <code>get_withdrawal_account</code>: Returns a specific ckBTC account where the owner must transfer ckBTC before being able to retrieve BTC.
 
* <code>retrieve_btc</code>: Instructs the ckBTC minter to burn a certain ckBTC amount and send the corresponding BTC amount to a provided Bitcoin address.
 
* <code>retrieve_btc</code>: Instructs the ckBTC minter to burn a certain ckBTC amount and send the corresponding BTC amount to a provided Bitcoin address.
* <code>retrieve_btc_status</code>: Returns the status of a previous retrieve_btc call.
+
* <code>retrieve_btc_status</code>: Returns the status of a previous <code>retrieve_btc</code> call.
 
* <code>get_events</code>: Returns a set of events at the ckBTC minter.
 
* <code>get_events</code>: Returns a set of events at the ckBTC minter.
  
Line 63: Line 63:
 
==== track_balance(owner: opt principal, subaccount: opt blob) ====
 
==== track_balance(owner: opt principal, subaccount: opt blob) ====
  
The ckBTC minter starts tracking the Bitcoin address derived from the provided principal ID and subaccount using the get_btc_address endpoint. If no principal ID is provided, then the sender’s principal ID is used. If no subaccount is provided, then the default subaccount (all zeros) is used.
+
The ckBTC minter starts tracking the Bitcoin address derived from the provided principal ID and subaccount using the <code>get_btc_address</code> endpoint. If no principal ID is provided, then the sender’s principal ID is used. If no subaccount is provided, then the default subaccount (all zeros) is used.
  
 
The balance of the Bitcoin address is not tracked indefinitely. Tracking is stopped if either at least one new unspent transaction output (UTXO) is discovered or there is no new UTXO within a certain time interval (details about balance tracking are provided below).
 
The balance of the Bitcoin address is not tracked indefinitely. Tracking is stopped if either at least one new unspent transaction output (UTXO) is discovered or there is no new UTXO within a certain time interval (details about balance tracking are provided below).
Line 71: Line 71:
 
==== update_balance(owner: opt principal, subaccount: opt blob) ====
 
==== update_balance(owner: opt principal, subaccount: opt blob) ====
  
Instead of having the ckBTC minter track the balance of a Bitcoin address, the update_balance function can be invoked to instruct the ckBTC minter to check if there are new UTXOs for a particular Bitcoin address.
+
Instead of having the ckBTC minter track the balance of a Bitcoin address, the <code>update_balance</code> function can be invoked to instruct the ckBTC minter to check if there are new UTXOs for a particular Bitcoin address.
  
 
If there is at least one new UTXO, the corresponding ckBTC amount is minted, otherwise an error is returned.
 
If there is at least one new UTXO, the corresponding ckBTC amount is minted, otherwise an error is returned.
  
The ckbTC minter effectively invokes this endpoint itself on a timer when the track_balance function is used.
+
The ckbTC minter effectively invokes this endpoint itself on a timer when the <code>track_balance</code> function is used.
  
 
==== get_withdrawal_account ====
 
==== get_withdrawal_account ====
Line 107: Line 107:
  
 
Note that this endpoint is used for debugging purposes and there is no guarantee that the endpoint will continue to exist in this form.
 
Note that this endpoint is used for debugging purposes and there is no guarantee that the endpoint will continue to exist in this form.
 +
 +
=== Converting BTC to ckBTC ===
 +
 +
In this section, the process to convert BTC to ckBTC is explained, making use of the ckBTC minter and ckBTC ledger endpoints.
 +
 +
The first step is for the user to determine the Bitcoin address where the user is supposed to transfer bitcoin for the minting process by calling the <code>get_btc_address</code> endpoint.
 +
Next, the user transfers the desired BTC amount to this Bitcoin address.
 +
Subsequently, the user calls the <code>track_balance</code> endpoint to inform the ckBTC minter that it is about to receive bitcoin at the given address.
 +
 +
Internally, the tracking works as follows. Since the expected time between Bitcoin blocks is 10 minutes, the ckBTC minter first checks if new unspent transaction outputs (UTXOs) are available for that address with at least the required number of confirmations after <code>10*min_confirmations</code> minutes. If there is at least one new UTXO, tracking stops and the ckBTC minter instructs the ckBTC ledger to mint the same amount of ckBTC tokens into the account derived from the principal ID and the subaccount.
 +
 +
If no new UTXOs are discovered with sufficiently many confirmations, the ckBTC ledger checks if there are new UTXOs with at least one confirmation. If this is not the case, tracking stops as well. Otherwise, the expected time until the first new UTXO reaches the desired number of confirmations is computed, which is 10 minutes times the difference between the desired number of confirmations and the current number of confirmations. The same process then repeats until ckBTC tokens are minted or tracking stops.
 +
 +
It is evident from this description that it’s possible that tracking may stop before ckBTC tokens are minted, for example, if it takes an unusually long time until the transaction appears in a block. In this case, the endpoint can be invoked again.
 +
Alternatively, the user can wait until the transaction has the required number of confirmations and call the <code>update_balance</code> endpoint.
 +
 +
The following figure depicts the conversion flow using the <code>track_balance</code> endpoint.
 +
 +
 +
 +
In this figure, the ckBTC minter discovers the new UTXO after the waiting period by calling <code>get_utxos</code> on the Bitcoin canister. As mentioned above, it is possible that it may take several interactions with the Bitcoin canister until the transaction has received sufficiently many confirmations before the ckBTC minter issues the mint transaction to the ckBTC ledger.

Revision as of 22:08, 3 February 2023

Overview

Chain-key Bitcoin (ckBTC) is a token on the Internet Computer that is backed 1:1 by bitcoin (BTC) such that 1 ckBTC can always be redeemed for 1 BTC and vice versa.

Unlike other tokens pegged to bitcoin, the ckBTC token does not rely on a third-party bridge for the conversion between BTC and ckBTC, making it a substantially more secure alternative to “wrapped” tokens.

While chain-key bitcoin and regular bitcoin have the same value, the advantage of chain-key bitcoin is fast and cheap transfers: A transfer is finalized within a few seconds (a speed-up of roughly three orders of magnitude compared to transfers on the Bitcoin blockchain) and only costs 0.0000001 ckBTC (approximately two orders of magnitude lower than the Bitcoin miner fees).

Architecture

The ckBTC functionality is built upon the Bitcoin integration of the Internet Computer, which makes it possible for canisters to receive, hold, and send bitcoin.

There are two canisters, the ckBTC minter and ckBTC ledger, that together provide the ckBTC functionality. The ckBTC minter mints new ckBTC tokens whenever it receives bitcoin. Likewise, it burns ckBTC tokens whenever an owner of ckBTC tokens requests a withdrawal of bitcoin. The ckBTC ledger is ICRC-1 compliant, updating the balance accounts when ckBTC tokens are transferred and executing the mint and burn operations coming from the ckBTC minter. An overview of the basic architecture is depicted in the following figure.

High-level overview of chain-key Bitcoin.

The figure shows the main flow at a high level of abstraction: Users interact with the ckBTC minter and the ckBTC ledger to convert ckBTC/BTC and transfer ckBTC, respectively. The ckBTC minter interacts with the Bitcoin canister to retrieve information about the Bitcoin network state and send Bitcoin transactions.

Technical Details

ckBTC Ledger

The ckBTC ledger is a canister, controlled by the NNS (specifically, the NNS root canister), running on the pzp6e subnet. Since it is ICRC-1 compliant, it offers all functions defined in the ICRC-1 standard. In particular, it provides the functionality to transfer ckBTC between accounts.

The minting account is the ckBTC minter’s default account, that is, the account derived from the ckBTC minter’s principal ID and the all-zero subaccount.

The initial supply of the ckBTC ledger is 0. ckBTC tokens are minted only when the ckBTC minter receives bitcoin, ensuring that the ckBTC supply managed by the ckBTC ledger is upper bounded by the amount of bitcoin held by the ckBTC minter.

ckBTC Minter

The ckBTC minter is a canister that is controlled by the NNS and running on the pzp6e subnet as well. It has a few important configuration parameters including:

  • retrieve_btc_min_amount: This is the minimum ckBTC amount that can be burned and, correspondingly, the minimum BTC amount that can be withdrawn. The parameter is set to 0.001 BTC, or 100,000 satoshi.
  • max_time_in_queue_nanos: Any BTC retrieval request should be kept in a queue for at most this time. Caching requests rather than handling them right away has the advantage that multiple requests can be served in a single transaction, saving Bitcoin miner fees. The parameter is set to 10 minutes, which corresponds to the expected time between Bitcoin blocks.
  • min_confirmations: The number of confirmations required for the ckBTC minter to accept a Bitcoin transaction. In particular, the ckBTC minter does not mint ckBTC before a transaction transferring BTC to a Bitcoin address managed by the ckBTC minter reaches this number of transactions. The parameter is initially set to 72 but may be reduced over time.

The other parameters are self-explanatory and can be found in the ckBTC minter Candid file.

The ckBTC minter provides the following endpoints:

  • get_btc_address: Returns a specific Bitcoin address that the caller can use to obtain ckBTC by sending BTC to this address.
  • track_balance: Instructs the ckBTC minter to track a certain Bitcoin address until funds are added, which will trigger the minting of the equivalent amount in ckBTC.
  • update_balance: Instructs the ckBTC minter to check the balance of a Bitcoin address and potentially mint ckBTC right away.
  • get_withdrawal_account: Returns a specific ckBTC account where the owner must transfer ckBTC before being able to retrieve BTC.
  • retrieve_btc: Instructs the ckBTC minter to burn a certain ckBTC amount and send the corresponding BTC amount to a provided Bitcoin address.
  • retrieve_btc_status: Returns the status of a previous retrieve_btc call.
  • get_events: Returns a set of events at the ckBTC minter.

The endpoints are discussed in more detail in the following.

get_btc_address(owner: opt principal, subaccount: opt blob)

The provided principal ID and subaccount are concatenated to form the derivation path for the ecdsa_public_key function, which returns the derived public key. If no principal ID is provided, then the sender’s principal ID is used. If no subaccount is provided, then the default subaccount (all zeros) is used.

This public key is encoded as a pay-to-witness-public-key-hash (P2WPKH) Bitcoin address and returned as a text.

Note that the key derivation is not BIP-32 compliant where 31 bits are used for each derivation level. Instead, a single derivation is performed based on the full principal ID and subaccount. Since the derivation is deterministic, a canister can derive this Bitcoin address itself.

track_balance(owner: opt principal, subaccount: opt blob)

The ckBTC minter starts tracking the Bitcoin address derived from the provided principal ID and subaccount using the get_btc_address endpoint. If no principal ID is provided, then the sender’s principal ID is used. If no subaccount is provided, then the default subaccount (all zeros) is used.

The balance of the Bitcoin address is not tracked indefinitely. Tracking is stopped if either at least one new unspent transaction output (UTXO) is discovered or there is no new UTXO within a certain time interval (details about balance tracking are provided below).

If at least one new UTXO is discovered, the same amount of ckBTC tokens are minted and made available to the owner.

update_balance(owner: opt principal, subaccount: opt blob)

Instead of having the ckBTC minter track the balance of a Bitcoin address, the update_balance function can be invoked to instruct the ckBTC minter to check if there are new UTXOs for a particular Bitcoin address.

If there is at least one new UTXO, the corresponding ckBTC amount is minted, otherwise an error is returned.

The ckbTC minter effectively invokes this endpoint itself on a timer when the track_balance function is used.

get_withdrawal_account

The function returns the caller’s withdrawal account, which is the account derived from the ckBTC minter’s principal ID and the subaccount derived from the caller’s principal ID.

A user can only retrieve BTC by first transferring ckBTC to this particular account.

retrieve_btc(address: text, amount: nat64)

The function instructs the ckBTC minter to burn the specified amount. Once the request is picked up from the queue, a Bitcoin transaction is created containing an output that transfers the requested amount (minus fees as discussed below) to the specified Bitcoin address.

Since Bitcoin retrieval is handled asynchronously, the function returns the block index of the transaction burning the ckBTC tokens.

retrieve_btc_status(block_index: nat64)

The status of a BTC retrieval request can be checked using this function. The different possible statuses are:

  • Unknown: There is no information available on the ckBTC minter because there is no retrieval request associated with the given block index or the retrieval request is old and the corresponding information has already been removed.
  • Pending: The BTC retrieval request is queued.
  • Signing: The BTC retrieval request is acquiring all signatures to serve the BTC retrieval request.
  • Sending: The Bitcoin transaction serving the BTC retrieval request is being sent.
  • Submitted: The Bitcoin transaction has been transmitted. The transaction ID is returned.
  • AmountTooLow: The BTC retrieval request could not be served because the Bitcoin miner fees are prohibitively high.
  • Confirmed: The Bitcoin transaction serving the BTC retrieval request is confirmed inside the ckBTC minter, which happens when the transaction has at least the minimum required number of confirmations specified in the min_confirmations parameter above.

get_events(start: nat64, length: nat64)

The ckBTC minter tracks the events that change its internal state. Given a start index and a length parameter, the ckBTC minter returns all events sequentially from the event at the given start index up to the event at index start+length-1.

Note that this endpoint is used for debugging purposes and there is no guarantee that the endpoint will continue to exist in this form.

Converting BTC to ckBTC

In this section, the process to convert BTC to ckBTC is explained, making use of the ckBTC minter and ckBTC ledger endpoints.

The first step is for the user to determine the Bitcoin address where the user is supposed to transfer bitcoin for the minting process by calling the get_btc_address endpoint. Next, the user transfers the desired BTC amount to this Bitcoin address. Subsequently, the user calls the track_balance endpoint to inform the ckBTC minter that it is about to receive bitcoin at the given address.

Internally, the tracking works as follows. Since the expected time between Bitcoin blocks is 10 minutes, the ckBTC minter first checks if new unspent transaction outputs (UTXOs) are available for that address with at least the required number of confirmations after 10*min_confirmations minutes. If there is at least one new UTXO, tracking stops and the ckBTC minter instructs the ckBTC ledger to mint the same amount of ckBTC tokens into the account derived from the principal ID and the subaccount.

If no new UTXOs are discovered with sufficiently many confirmations, the ckBTC ledger checks if there are new UTXOs with at least one confirmation. If this is not the case, tracking stops as well. Otherwise, the expected time until the first new UTXO reaches the desired number of confirmations is computed, which is 10 minutes times the difference between the desired number of confirmations and the current number of confirmations. The same process then repeats until ckBTC tokens are minted or tracking stops.

It is evident from this description that it’s possible that tracking may stop before ckBTC tokens are minted, for example, if it takes an unusually long time until the transaction appears in a block. In this case, the endpoint can be invoked again. Alternatively, the user can wait until the transaction has the required number of confirmations and call the update_balance endpoint.

The following figure depicts the conversion flow using the track_balance endpoint.


In this figure, the ckBTC minter discovers the new UTXO after the waiting period by calling get_utxos on the Bitcoin canister. As mentioned above, it is possible that it may take several interactions with the Bitcoin canister until the transaction has received sufficiently many confirmations before the ckBTC minter issues the mint transaction to the ckBTC ledger.