Introduction
What is RGB++?
The RGB++ Protocol is a simple protocol that enhances Bitcoin Layer 1 programmability by establishing a binding between Bitcoin UTXOs and Turing-complete CKB Scripts. This binding creates a powerful bridge between Bitcoin’s security and CKB’s programmability.
At its core, RGB++ Protocol uses a specific Bitcoin UTXO as a single-use seal - a cryptographic commitment that can only be used once, leveraging Bitcoin’s inherent UTXO properties. This UTXO, along with its corresponding CKB cells, serves as the cryptographic proof, or the commitment, of ownership for RGB++ assets. When a single-use seal is consumed, the ownership of the RGB++ asset is guaranteed to be transferred to the new UTXO or the wallet controlling it.
The protocol employs CKB Cells to represent RGB++ asset ownership relationships, establishing an isomorphic binding with Bitcoin UTXOs. In this architecture, CKB serves dual roles: as a public database for assets and as an off-chain pre-settlement layer.
With RGB++ Protocol, users can seamlessly issue Layer 2 assets on CKB and transfer them between Bitcoin and CKB networks, combining Bitcoin’s security with CKB’s programmability.
For more detailed information, please refer to the RGB++ Protocol Light Paper or its Chinese version.
Resources
Protocol Overview
- RGB++ Protocol Light Paper (English)
- RGB++ Protocol Light Paper (中文)
Infrastructure
- RGB++ Explorer - Block explorer for RGB++ transactions and assets
- btc-assets-api - API service for BTC/RGB++ asset management and transaction processing
Core Components
RGB++ Script
Core contracts that implement the RGB++ protocol, including the RGB++ lock script for asset ownership and BTC time lock for cross-chain security.
CKB Bitcoin SPV
Light client implementation that enables CKB to verify Bitcoin transactions, providing a secure bridge between Bitcoin and CKB networks.
Development Tools
Community Resources
Core Concepts
Single-Use Seal
Single-use seals are a cryptographic mechanism that locks a seal on a message, ensuring that the message can only be read or used once. The RGB++ protocol leverages Bitcoin UTXOs’ inherent single-use property to implement this sealing mechanism.
Through the use of single-use seals, the RGB++ protocol creates assets that are cryptographically bound to specific Bitcoin UTXOs. The ownership of these corresponding UTXOs directly establishes ownership of the RGB++ issued assets. To transfer a RGB++ asset, the holder must spend their corresponding UTXO, which effectively consumes the single-use seal and ensures the asset can only be transferred once.
For a comprehensive explanation of single-use seals, please refer to this technical article.
Typical Transaction Flow
As defined by the protocol, each RGB++ transaction generates a pair of corresponding transactions: one on the Bitcoin and one on the CKB.
The following is a typical transaction flow:
1. Off-chain pre-computation
Let’s assume btc_utxo#1
is the single-use seal that will be consumed in this RGB++ transaction, while btc_utxo#2
will serve as the new single-use seal after the transaction completes.
In parallel, the CKB cell(s) that are isomorphically bound to btc_utxo#1
are selected as inputs for the CKB transaction CKB_TX_B
. The output(s) of CKB_TX_B
will maintain the latest state of the RGB++ asset.
It’s important to note that during the off-chain pre-computation phase, the Bitcoin transaction has not yet been submitted, so the transaction id component of btc_utxo#2
is not yet available. In this case, a placeholder value is used as a temporary substitute.
The commitment is computed using the following formula:
commitment = hash(CKB_TX_B | btc_utxo#1 | btc_utxo#2)
In practice, the btc_utxo#1
and btc_utxo#2
are encoded within the RGB++ Script arguments of CKB_TX_B
, establishing a secure binding between Bitcoin UTXOs and CKB cells.
For detailed implementation, please refer to the RGB++ Script.
2. Bitcoin Transaction Submission
In this phase, the actual Bitcoin transaction Bitcoin_TX_A
is submitted. The transaction’s input consumes btc_utxo#1
, while its two outputs serve distinct purposes: the first output uses an OP_RETURN
script to store the commitment calculated in the previous phase, and the second output creates btc_utxo#2
.
3. CKB Transaction Submission
In this phase, the CKB transaction CKB_TX_B
is submitted, with the RGB++ asset’s latest state recorded in CKB_TX_B.output.data
field.
Consequently, btc_utxo#2
becomes the new single-use seal required for initiating the next state change, while CKB_TX_B.output
represents the current state of the RGB++ asset.
4. On-chain Verification
In this phase, the following checks are performed:
- UTXOs related to Bitcoin validations are spent only once;
- A lightweight client on CKB confirms the existence of this Bitcoin transaction on the Bitcoin blockchain;
- The Bitcoin transaction is submitted as a witness in the CKB transaction;
- CKB ensures that the Bitcoin transaction has spent the correct UTXO;
- CKB validates that the Bitcoin transaction commits to the correct commitment;
- Finally, CKB confirms that the state transition on CKB complies with the predefined contract rules.
Core Components
RGB++ Scripts
As described in the Typical Transaction Flow section, isomorphic binding requires that RGB++ transactions must be submitted on the Bitcoin chain, and that users utilize single-use seals on Bitcoin to describe operations on RGB++ cells. The transaction process follows these steps: first, the user constructs the CKB raw transaction and the RGB++ commitment; then, submits Bitcoin transaction that contains the commitment; and finally, submits the final CKB transaction.
The ownership of Bitcoin UTXOs is encoded in the lock script of RGB++ Cells, specified by the combination of the Bitcoin transaction ID and output index.
Regarding the commitment calculation, it encompasses the first N
consecutive inputs and outputs, where N
must include all inputs and outputs with non-null Type
scripts. Any additional inputs and outputs with null Type
scripts that follow these first N
elements can be included in the CKB transaction without affecting the commitment. This design allows for flexible transaction fee adjustments while maintaining the integrity of the commitment.
The protocol implements two key contracts:
RGBPP_lock
: A specialized contract that manages the unlocking mechanism for RGB++ Cells, ensuring secure and controlled access to the assets.1 2 3 4 5
RGBPP_lock: code_hash: RGBPP_lock args: out_index | %bitcoin_tx%
- The combination of
out_index
andbitcoin_tx
uniquely identifies the Bitcoin UTXO that owns this Cell.
- The combination of
BTC_TIME_lock
: A time-based locking contract that enforces a predetermined block confirmation period when assets are transferred from Bitcoin Layer 1 to Layer 2, providing additional security for cross-layer transactions.1 2
BTC_TIME_lock: args: lock_script | after | %new_bitcoin_tx%
lock_script
is the owner of the cell once the time lock is unlocked;after
enforces a minimum block confirmation threshold that must be met before thenew_bitcoin_tx
can be unlocked.
Both the RGBPP_lock
and BTC_TIME_lock
contracts require access to Bitcoin light client data, which is identified by the associated contract’s type_hash
. To eliminate hardcoded dependencies and enhance configurability, the protocol introduces the concept of Config Cell as a flexible solution for managing these configuration parameters. The following is the structure of the Config Cell:
|
|
During contract deployment, the transaction outputs must include both the contract code cell and its corresponding config cell to ensure proper initialization. The following is an example of the deployment transaction:
|
|
The configuration cell is loaded using the following steps:
load_script
finds the current contract’stype_hash
- It then locates the cell dep with a matching
type_hash
and anout_point.index
of 1 - The data of this cell dep is loaded to obtain the global configuration
During the RGBPP_Lock
unlocking process, the SPV cells are consulted to verify the existence of the corresponding Bitcoin transaction, while the commitment is recalculated and validated against the commitment stored in the Bitcoin transaction’s OP_RETURN
field, along with additional security checks.
The following figure demonstrates the unlocking process.
The BTC_TIME_lock
unlocking process is straightforward, as its behavior is explicitly expressed by the arguments in its lock script.
For a comprehensive understanding of the protocol design, please refer to the RGB++ Script Standard or its Chinese version. The complete implementation can be found in the RGB++ Script repository.
SPV Service
Within the programmable layer of RGB++, a Bitcoin SPV light client maintains a synchronized record of Bitcoin block headers, enabling smart contracts to access and verify Bitcoin blockchain data, including historical transaction records, block difficulty, network hash rate, current block height, timestamps, and detailed transaction information, thereby providing a secure and efficient bridge between Bitcoin and CKB networks.
SPV Service on CKB does the following:
- Prove if a header belongs to the Bitcoin chain
- Prove if a transaction is in a Bitcoin block
To achieve this, CKB Bitcoin SPV Service does the following:
- Synchronizes Bitcoin headers to to Bitcoin SPV clients running on the CKB chain
- Generate proofs for Bitcoin transactions so that they can be verified on CKB
Given on-chain verification comes with resource constraints, such as the inability to afford 100 MiB of storage or 30 seconds of computation on CKB, the MMR is introduced to address this issue by only saving the MMR root of Bitcoin headers on CKB. MMR provides a compact representation of the entire header chain with efficient verification capabilities, making it ideal for resource-constrained environments.
Also, Merkle proof is used to verify that a transaction - or specifically, its hash - was included in a given block.
For detailed technical design, please refer to the CKB Bitcoin SPV Design.
SPV Type Script
A Bitcoin SPV on CKB consists of cells that are managed by the CKB Bitcoin SPV Type Script and identified by the script arguments. A Bitcoin SPV instance is a collection of cells. It contains two types of cells: SPV info cell and SPV client cell:
SPV Client Cell
- A cell is identified as an SPV client cell if its type script matches the SPV type script.
- SPV client cells store the Bitcoin state. Each Bitcoin SPV instance includes a minimum of three SPV client cells.
Client Cell: Type Script: code hash: "..." hash type: "type" args: "typeid + clients count + flags" Data: - id - btc tip block hash - btc headers mmr root - target adjust info
SPV Info Cell
- The SPV info cell stores the basic information of the current Bitcoin SPV instance, such as
tip_client_id
. - Each Bitcoin SPV instance contains only one SPV info cell.
Info Cell: Type Script: code hash: "..." hash type: "type" args: "typeid + clients count + flags" Data: - tip client cell id
- The SPV info cell stores the basic information of the current Bitcoin SPV instance, such as
The SPV cells are initialized in a single transaction, resulting in one SPV info cell and a minimum of three SPV client cells. The cells must be arranged consecutively, with the SPV info cell positioned first, followed by the SPV client cells in ascending order of their IDs. Upon initialization, all client cells must contain identical data.
The SPV client cell with an ID matching the tip_client_id
in the SPV info cell contains the most recent data, while the next cell in sequence holds the oldest data. This arrangement forms a ring structure where the sequence wraps around from the last cell back to the first cell. During updates, new data is written to the cell currently holding the oldest data, and the tip_client_id
in the SPV info cell is updated to point to this newly updated cell, effectively marking it as the new “latest data” holder.
RGB++ SDK
本质上来说,RGB++ SDK 的核心是对 RGB++ 资产所有权的验证和记录。普通的 BTC 交易,私钥签名后,全网的 BTC 节点验证通过后,这笔交易就完成了。而 RGB++ 由于存在 isomorphic binding,绑定的 UTXO 和 CKB Cell 的消费和生成需要保证原子性,它依赖 btc-assets-api 和 SPV Service 将 BTC 上的 RGB++ 资产交易的信息被忠实地同步到 CKB 上,同时需要将由此带来的 RGB++ 资产的所有权变化记录在 CKB Cell 中。
不妨将 RGB++ SDK 理解成一个在 RGB++ 协议语义下的钱包,它可以同时管理 BTC 和 CKB 上的资产,进而方便地操作 RGB++ 资产。同时,在基础的 BTC/CKB 私钥验签之外,借助 SPV Service 和 RGB++ 合约,RGB++ SDK 将和 RGB++ 资产的验签的流程从 BTC 链延伸至 CKB 链,从这一角度来说,RGB++ SDK 又提供了 RGB++ 资产验签器的功能。
At its core, the RGB++ SDK is focused on verifying and recording RGB++ asset ownership. In a regular BTC transaction, once the transaction is signed with a private key and broadcast to the network, it is considered complete after being validated and confirmed by most BTC nodes.
However, with RGB++’s isomorphic binding, the consumption and generation of bound UTXOs and CKB Cells must maintain atomicity. It relies on btc-assets-api and SPV Service to faithfully synchronize RGB++ asset transaction information from BTC to CKB, while recording the resulting ownership changes in CKB Cells.
That’s where the RGB++ SDK comes in. It can be understood as a wallet operating within the RGB++ protocol semantics, capable of managing assets on both BTC and CKB chains, thereby facilitating RGB++ asset operations. Beyond basic BTC/CKB private key signature verification, the RGB++ SDK extends the signature verification process for RGB++ assets from the BTC chain to the CKB chain through the SPV Service and RGB++ contracts. From this perspective, the RGB++ SDK also provides the functionality of an RGB++ asset signature verifier.
At the implementation level, the RGB++ SDK extensively utilizes ccc, the standard CKB JavaScript/TypeScript SDK, for core functionalities such as transaction assembly, signing, and submission.
The following are the two SDK repositories:
- Actively developed (recommended): https://github.com/ckb-devrel/ccc/tree/rgbpp-sdk (TypeScript)
- Continuously maintained: https://github.com/RGBPlusPlus/rgbpp-sdk (TypeScript)
btc-assets-api
This is a service that retrieves BTC/RGB++ information/assets and processes transactions with these assets.
Basically, it does the following:
- Blockchain Information Retrieval: Access to Bitcoin chain data including blocks, headers, transactions, addresses, and RGB++ assets. This functionality is provided by the SPV service.
- Transaction Handling.
- Transaction Queue Management: Automated processing of RGB++ asset workflows through scheduled cron jobs.
The btc-assets-api requires an access token for authentication. Testnet users can generate a token directly via the /token/generate
API endpoint. The public testnet endpoint can be found in the btc-assets-api repository.
Mainnet access is restricted to whitelisted users. Please contact us to request an access token.
Quick Start
Before you start, refer to the btc-assets-api section to apply for an access token.
UDT
In CKB, custom tokens are implemented as User-Defined Tokens (UDTs). The CKB core team has established a minimal standard for UDTs called xUDT (extensible UDT). In this section, we demonstrate the RGB++ protocol by issuing a RGB++ token using the pre-deployed xUDT Script.
For a comprehensive guide on issuing fungible tokens on CKB, please refer to the tutorial: Create a Fungible Token. The following discussion will focus on the RGB++-specific aspects of the token issuance process.
The complete implementation is available in the RGB++ SDK repository.
Issuance
Let’s walk through the issuance process step by step.
The process begins by selecting a UTXO (or automatically creating one with the dust limit value of 546 satoshis if not provided) to serve as the initial single-use seal.
Subsequently, we create a CKB cell with its lock script set to the RGB++ lock script, using the UTXO as its argument. This configuration represents the user’s intent to issue a RGB++ xUDT token, which will only be fulfilled after the initial UTXO is spent.
Next, a partial CKB transaction is constructed using the CKB cell and xUDT script information. Based on this, the commitment is calculated and the Bitcoin transaction is assembled, which is then submitted to the network.
The Bitcoin transaction’s confirmation status is periodically checked through the SPV service. Upon confirmation, we acquire the new single-use seal - a UTXO also with the dust limit value of 546 satoshis - which represents ownership of the issued RGB++ xUDT token. The transaction ID of this UTXO is used to replace the placeholder value in the RGB++ lock script, enabling the assembly of the final CKB transaction.
The final CKB transaction is then submitted to the network, completing the token issuance process.
The following is the code for the issuance process.
|
|
For practical examples of RGB++ xUDT issuance, please refer to these transactions:
Transfer on BTC
The process of transferring RGB++ xUDT tokens on Bitcoin follows a similar pattern to the issuance process. Key points to note:
- The unique ID of issued xUDT token, obtained during issuance, is used to construct the xUDT script that identifies the token.
- The partial CKB transaction assembly is simplified through ccc: by providing the xUDT script, ccc automatically handles the input construction.
The following is the code for the transfer process.
|
|
For practical examples of RGB++ xUDT transfer, please refer to these transactions:
Leap to CKB
The process of leaping xUDT from Bitcoin to CKB follows almost the same pattern as the regular transfer process, with one key distinction: after the leap, the lock script changes from RGBPP_Lock
to BTC_TIME_lock
.
The following is the code for the leap process.
|
|
For practical examples of RGB++ xUDT leap, please refer to these transactions:
Unlocking the BTC_TIME_lock
This process is relatively straightforward. We wait for the required number of confirmations (default is 6) before unlocking the BTC_TIME_lock
. After unlocking, the xUDT becomes a standard CKB asset, with its ownership logic governed by the lock script specified in the BTC_TIME_lock
arguments. Notably, this process does not require any Bitcoin transaction.
The following is the code for the unlock process.
|
|
For a practical example of unlocking the BTC_TIME_lock, please refer to this transaction:
Glossary
UTXO
A Bitcoin Unspent Transaction Output. It is defined by a transaction hash and a vout index which, collectively, constitute an outpoint.
CKB Cell
Cells are the primary state units in CKB, within them users can include arbitrary states. All data on Nervos CKB is stored in Cells.
A Cell has 4 fields: capacity
, data
, type
and lock
.
For a detailed explanation of the Cell Model, please refer to this document.
Isomorphic Binding
A one-to-one mapping mechanism in RGB++ that links Bitcoin UTXOs to CKB Cells, enabling ownership synchronization through Bitcoin’s UTXO locks while maintaining state in CKB’s Cell data and type fields. This binding allows for Turing-complete Bitcoin UTXO transactions validated by CKB Cells.
CKB Script
A Script in CKB is a binary executable that can be executed on-chain. It is a program that runs on a virtual machine powered by the RISC-V instruction set, called the CKB-VM, and can perform arbitrary logic to guard and protect your Cells. You can think of it as smart contract.
There’re two main types of Scripts:
- Lock Script: A required Script controlling the ownership and access to a Cell, ensuring only authorized users can spend/consume the Cell.
- Type Script: An optional Script dictating how a Cell can be used or modified in a transaction.
xUDT Script
Extensible UDT(xUDT) is the User-Defined-Token(fungible token) Script implementation on CKB. You can think of it as the ERC-20 smart contract on Ethereum.
SPV
Simple Payment Verification (SPV) allows a transaction receiver to confirm that the sender has control of the source funds of the payment they are offering, without needing to download the entire blockchain. This is achieved using Merkle proofs.
Refer to the Bitcoin whitepaper for more details.
MMR
A Merkle Mountain Range (MMR) is a binary hash tree data structure designed to allow efficient appending of new leaves while maintaining the integrity of the existing nodes.
A MMR proof can be utilized to verify whether a specific item is included in the MMR root.
Merkle Root
A merkle root is created by hashing together pairs of TXIDs to get a short and unique fingerprint for all the transactions in a block.
This merkle root is placed in a block header to prevent the contents of the block from being tampered with later on.
OP_RETURN
The OP_RETURN
standard locking script just contains the OP_RETURN
opcode followed by one or more data pushes.
|
|
The standard OP_RETURN
script has a maximum size limit of 83 bytes. However, there is an ongoing discussion and corresponding pull request to relax these standardness restrictions.
For more information, please refer to: