Background
For some scenarios, such as stablecoin with regulatory compliance, token issuer needs to have the privilege to protect the users’ assets from malicious attack under specific critical circumstance, including fraud, money laundering and so on. The sUDT protocol only defines the fundamental functionalities of UDT, but not includes the regulation parts. So we need to figure out a way to extend the sUDT standard to meet such purpose.
There are at least two main ways to realize these features. On the one hand, we could create a new xUDT protocol which is the superset of sUDT with the same data structure definition and more functionalities. On the other hand, we could create a new xAcp lock, which allows the issuer directly take over specific assets if necessary.
The UDT standard is one of the most fundamental protocols in the application layer of blockchain. A reasonable UDT proposal has to cover the consideration of technology, user experience, and application universality. This post discusses the two possible solution to the regulation UDT preliminarily, and gives the pros and cons.
xUDT as a new Typescript
xUDT is almost the same as sUDT standard except it needs some transfer constrain cells in deps
during the token transfer process.
deps:
status cell
blacklist cell
...
inputs:
xUDT cell
outputs:
xUDT cell
The xUDT Typescript will not only verify the token amount consistency but also verify input and output cells following the address rules.
xUDT cell structure & transfer rules
The data structure of xUDT cell is similar to that of sUDT, with a slight change in type args
.
// xUDT cell
Capacity:
Data:
uint128 amount
Type:
code_hash = xUDT
hash_type = type
args = issuer_lock_hash_160bit | regulation_byte
Lock:
any
The variable regulation_byte
is an one-byte parameter with the following definition.
regulation_byte: 0b 0 0 0 0 0 0 0 0
| | | └- Global control
| | └--- Blacklist
| └----- Whitelist
| Reserved
└--------------- 1: Definition / 0: Usage
The issuer firstly deploy some regulation cells to define the global control cell
, blacklist cell
, and the whitelist cell
. Later, all the transfer transactions must include such cells as deps
to match the rules. Here follows the creation of the global control cell
and the blacklist cell
.
# create a global control cell
input:
ordinary cell:
lock: issuer_lock
output:
xUDT cell:
data:
uint128 amount = 0 // the amount must equals to zero
control_params: {
"transfer":"enable",
"mint":"enable",
"burn":"enable",
...
}
Type:
code_hash = xUDT
hash_type = type
args = issuer_lock_hash_160bit | regulation_byte = 0b10000001
lock:
any
# create a blacklist cell
input:
ordinary cell:
lock: issuer_lock
output:
xUDT cell:
data:
uint128 amount = 0 // the amount must equals to zero
blacklist_data
Type:
code_hash = xUDT
hash_type = type
args = issuer_lock_hash_160bit | regulation_byte = 0b10000010
lock:
any
# transfer
deps:
global cell
blacklist cell
script code cell
input:
xUDT cell:
data:
uint128 amount
Type:
code_hash = xUDT
hash_type = type
args = issuer_lock_hash_160bit | regulation_byte = 0b00000011
lock:
any
output:
xUDT cell:
data:
uint128 amount
Type:
code_hash = xUDT
hash_type = type
args = issuer_lock_hash_160bit | regulation_byte = 0b00000011
lock:
any
User experience & application immigration
For the token issuer, they need to create the right regulation cells before their tokens could be accepted by the end users. But it won’t be a big obstacle. For the end users, they just use their own lock script (address) to hold the token, same as sUDT.
The wallet and exchange developers have to add the new xUDT transfer support, which is a bit more work on transaction generator. Another good news is the ckb-indexer has already supported the prefix indexing mode, which could handle the xUDT typescript well.
If this xUDT standard could be accepted as the default standard. It’s better to upgrade the current sUDT script to the new xUDT script by typeid
method directly, instead of deploying a new xUDT script. Because the xUDT is backward compatible, if you done’t need the regulation features, just leave the regulation_byte
empty.
Drawbacks of xUDT
It cannot support the directly control to the user’s assets, because the constrains only work during the transfer process. The illegal assets can be froze, but can not be slashed or confiscated. The users’ cell is always controlled by themselves, even it may be bannd by the issuer.
xAcp as a new Lockscript
Acp lock(a.k.a. anyone can pay lock) is used to assist sUDT cell to provide a better udt transfer user experience. It is reasonable to modify the Acp lock to add issuer privileges to control the users assets under some critical circumstance.
xAcp rules
Compared with xUDT scheme, xACP is much easier to be implemented. What we need to do is 1) delegate the ownership to the token minter, 2) make sure the token transfer among the same xAcp locks. To achieve this, we need to add an additional byte/marker to the Acp lock args to identify its regulation features.
sUDT cell:
data:
uint128 amount
type:
sUDT type
lock:
code_hash = xAcp code hash
args = user_pkhash160 | <2 bytes minimum> | 1 byte regulation_byte = 0xFF
When the regulation_byte
presents, the xAcp code will enforce the extra ownership and transfer logics mentioned above.
User experience & application immigration
We could upgrade the Acp lock to make it support xAcp features. So the users won’t realize what really happens. And the same as the suffixal minimal transfer amount bytes
, applications like wallets will automatically handle the regulation byte during the transaction assembly period. Both the minimum
and regulation byte
are absent in the acp address.
Drawbacks of xAcp
The most important drawback of xAcp is obvious, that the users cannot change their locks. Which means most of the dApp interactions cannot be processed, because most of them require the assets to use some specific dApp related locks. Like the DEX, it uses a order lock
to manage exchange orders.
The second drawback or a notable feature of xAcp is that the issuer has to mint the tokens to an xAcp address first. If the issuer accidentally mints the tokens to a normal address, then that portion of tokens won’t follow the regulation rules until they are transfered to an xAcp address with regulation byte
enabled.