Background
In the development of SUDT, we have encountered a problem that is closely related to the user experience which is how to receive a SUDT when there is no ACP cell has been created for that SUDT?
One solution is that the receiver needs to create an ACP cell (anyone-can-pay cell) for the SUDT, and the receiver cannot actually know in advance that someone is going to send a new SUDT to him/her, for now the receiver can only be notified via a off-chain notification that an ACP cell is needed. The other solution is that the sender needs to give the receiver an ACP cell of the SUDT when sending the SUDT. These two solutions will leads to the problem that the receiver cannot receive the token conveniently or the sender needs to pay additional costs.
To solve this problem, we design an Approve Cell approach. When the sender sends a SUDT to a receiver who does not have an ACP cell for the SUDT, it can transfer the SUDT to an Approve Cell and then wait for the receiver to claim it. The receiver can get transfer information from the chain and then decide whether to create an ACP cell to receive the asset, so that the receiver can receive the SUDT without creating the ACP cell in advance and the sender don’t need to pay the additional costs.
Solutions
The sender transfers the SUDT that needs to be transferred to an Approve Cell, adds the sender’s and receiver’s information to the Approve Cell’s lock args, and the receiver can follow the rules to unlock it once read the relevant authorization information on the chain.
// Structure of Approve Cell
capacity: uint128 // 8 bytes
lock script:
code_hash: <approve_cell_lock_script> // 32 bytes
hash_type: type // 1 byte
args: <receiver_lock_hash>, <sender_lock_hash> // 20 bytes + 20 bytes
type script: <sudt_type_script> // 65 bytes
data:{
sudt_amount // 16 bytes
}
// Total: 162 bytes
- Approve Cell has a
approve period
(restrict the sender from undoing the Approve Cell within theapprove period
, this would written in the approve_cell_lock_script).
Unlock Logic of Approve Cell
Approve Cell’s lock script has two methods of unlocking:
-
Receiver claimed. The receiver unlocks the Approve Cell according to the rules of the Approve Cell, which can be separated into two ways according to the signature rules.
- The receiver provides a lock args and uses the default secp256k1_blake160 as lock code_hash to assemble and sign the lock script, which is identical to the
receiver_lock_hash
in the Approve Cell. - The receiver directly provides a input cell that is identical to the
receiver_lock_hash
and signs it.
- The receiver provides a lock args and uses the default secp256k1_blake160 as lock code_hash to assemble and sign the lock script, which is identical to the
-
Sender withdrew. If the Approve Cell created by the sender has been on the chain for longer than the
approve period
and has not been claimed by the receiver, the sender can withdraw by providing a cell identical tosender_lock_hash
as a input cell and signing it to withdraw the Approve Cell.
Examples of transaction structures
Create an Approve Cell
When the sender sends a SUDT to a receiver who does not have this SUDT’s ACP Cell, an Approve Cell will be created.
Inputs:
SUDT Cell:
Capacity: 142 CKBytes
Lock: <sender_lock_script>
Type: <sudt_type_script>
Data:
sudt_amount: 1000 UDT
CKB Normal Cell:
Capacity: 1000 CKBytes
Lock: <sender_lock_script>
Outputs:
Approve Cell:
Capacity: 162 CKBytes
Lock:
code_hash: <approve_cell_lock_script>
hash_type: type
args: <receiver_lock_hash>, <sender_lock_hash>
Type: <sudt_type_script>
Data:
sudt_amount: 100 UDT // approve amount of UDT
SUDT Cell:
Capacity: 142 CKBytes
Lock: <sender_lock_script>
Type: <sudt_type_script>
Data:
sudt_amount: 900 UDT
CKB Normal Cell:
Capacity: (838-fee) CKBytes
Lock: <sender_lock_script>
Witnesses
<valid signature for sender_sudt_cell_lock_hash>
<valid signature for sender_ckb_normal_cell_lock_hash>
Approve Cell Unlock Logic 1: Receiver claimed
The receiver uses the official secp256k1_blake160 lock to claim (suitable for short CKB address)
The receiver provides the lock args and assembles the lock script with the default secp256k1_blake160 as the code_hash and signs it. The assembled lock script is the same as the receiver_lock_hash
in the Approve Cell.
Inputs:
Approve Cell:
Capacity: 162 CKBytes
Lock:
code_hash: <approve_cell_lock_script>
hash_type: type
args: <receiver_lock_hash>, <sender_lock_hash>
Type: <sudt_type_script>
Data:
sudt_amount: 100 UDT
Anyone SUDT Cell:
Capacity: 142 CKBytes
Lock: <anyone_lock_script>
Type: <sudt_type_script>
Data:
sudt_amount: 200 UDT
Outputs:
Anyone SUDT Cell:
Capacity: 142 CKBytes
Lock: <anyone_lock_script>
Type: <sudt_type_script>
Data:
sudt_amount: 300 UDT
CKB Normal Cell:
Capacity: 162 CKBytes
Lock: <sender_lock_script>
Witnesses:
<valid signature for secp256k1_blake160 + receiver lock script> // need a identifier, marked as receiver
<valid signature for anyone_lock_script>
The receiver uses other lock script to claim
The receiver directly provides a cell identical to receiver_lock_hash
in the Approve Cell as an input cell and signs it.
Inputs:
Approve Cell:
Capacity: 162 CKBytes
Lock:
code_hash: <approve_cell_lock_script>
hash_type: type
args: <receiver_lock_hash>, <sender_lock_hash>
Type: <sudt_type_script>
Data:
sudt_amount: 100 UDT
SUDT Cell:
Capacity: 142 CKBytes
Lock: <receiver_lock_script> // equals to the receiver_lock_hash in the args part of Approve Cell
Type: <sudt_type_script>
Data:
sudt_amount: 200 UDT
Outputs:
SUDT Cell:
Capacity: 142 CKBytes
Lock: <receiver_lock_script>
Type: <sudt_type_script>
Data:
sudt_amount: 300 UDT
CKB Normal Cell: // send CKB back to the sender
Capacity: 162 CKBytes
Lock: <sender_lock_script>
Witnesses:
<000...000>
<valid signature for receiver_lock_hash> need a identifier, marked as receiver
Approve Cell Unlock Logic 2: Sender Withdrew
The sender withdraws the Approve Cell if the cell created by the sender has been on chain for longer than the approval period
and has not been claimed by the receiver.
When withdrawing, the sender needs to add a lock script to the input cells that is identical to the sender_lock_hash
in the Approve Cell lock args, and depending on the different situations in which the user has different cells, there are various ways to assemble the transaction, and in order to facilitate the front end developer to filter the appropriate cell, we can give priority to the following two situations:
-
If the sender has this SUDT cell (we assume all SUDT cells using the ACP lock), it will be used as an input cell for signing.
-
If the sender does not have this SUDT cell but has a CKB Normal Cell whose lock script corresponds to the
sender_lock_hash
in Approve Cell, it will be used as an input cell for signing.
Sender has this SUDT cell
Inputs:
Approve Cell:
Capacity: 162 CKBytes
Lock:
code_hash: <approve_cell_lock_script>
hash_type: type
args: <receiver_lock_hash>, <sender_lock_hash>
Type: <sudt_type_script>
Data:
sudt_amount: 100 UDT
USDT Cell: // sender can use a SUDT Cell to unlock the Approve Cell
Capacity: 142 CKBytes
Lock: <sender_lock_script> // equals to the sender_lock_hash in the args part of Approve Cell
Type: <sudt_type_script> // equals to the type script of Apporve Cell
Data:
sudt_amount: 900 UDT
Outputs:
SUDT Cell:
Capacity: 142 CKBytes
Lock: <sender_lock_script>
Type: <sudt_type_script>
Data:
sudt_amount: 1000 UDT
CKB Normal Cell:
Capacity: 162 CKBytes
Lock: <sender_lock_script>
Witnesses:
<000...000>
<valid signature for sender_lock_hash> need a identifier, marked as sender
Sender does not have this SUDT cell, but has a suitable CKB Normal Cell
Inputs:
Approve Cell:
Capacity: 162 CKBytes
Lock:
code_hash: <approve_cell_lock_script>
hash_type: type
args: <receiver_lock_hash>, <sender_lock_hash>
Type: <sudt_type_script>
Data:
sudt_amount: 100 UDT
CKB Normal Cell: // sender can use a CKB Normal Cell to unlock the Approve Cell
Capacity: XX CKBytes
Lock: <sender_lock_script> // equals to the sender_lock_hash in the args part of Approve Cell
Outputs:
SUDT Cell:
Capacity: 142 CKBytes
Lock: <sender_lock_script>
Type: <sudt_type_script>
Data:
sudt_amount: 100 UDT
Sender CKB Normal Cell:
Capacity: XX+20 CKBytes
Lock: <sender_lock_script>
Witnesses:
<000...000>
<valid signature for sender_lock_hash> need a identifier, marked as sender