Design of Approve Cell

Design of Approve Cell

背景

在 SUDT 的相关开发中,我们遇到了一个与用户体验紧密相关的问题。那就是,用户如何在没有某 SUDT 的 ACP cell 的时候接收该 SUDT?

一种解决方案是,用户需要自行创建一个该 SUDT 的 ACP cell(anyone-can-pay cell),而用户实际上无法在链上提前得知有人将要给 ta 发送一个新的 SUDT,目前只能通过链下通知的方式,告知用户创建需要 ACP cell。另外一种解决方案是,发送方需要在发送 SUDT 时赠送给对方一个该 SUDT 的 ACP cell。这两种解决方案在一定程度上会造成接收方无法便捷地接收代币,发送方需要额外付出转账成本的问题。

为了解决这一问题,我们设计了一个 Approve Cell 的方式,当发送方给一个没有该 SUDT ACP cell 的用户发送 SUDT 时,可以将 SUDT 转至一个 Approve Cell,然后等待接收方前来认领。这样就可以实现接收方在没有提前创建该 SUDT 的 ACP cell 的情况下,从链上获取到发送方的代币发送信息,进而再决定要不要创建一个 ACP cell 来接收该部分资产。

解决方案

发送方将需要转账的 SUDT 转移至一个 Approve Cell,在 Approve Cell 的 lock args 中添加发送方和接收方的信息,接收方在链上读取到相关的授权信息后,即可按照规则进行解锁。

// 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
  • Apprvoe cell 设置有 approval 周期(限制发送方无法在 approval 周期内撤销 Approve Cell,这个会写死在approve_cell_lock_script 内)

Approve Cell 的解锁逻辑

Approve Cell 的 lock script 有两种解锁方式:

  • 接收方接收。接收方按照 Approve Cell 的规则解锁 Approve Cell,解锁方式根据签名规则分成两种:
    • 接收方提供 lock args,并使用默认的 secp256k1_blake160 作为 code_hash,组装成 lock script,并进行签名,且组装成的 lock script 经对比与 Approve Cell 中的 receiver_lock_hash 一致。
    • 接收方直接提供与 receiver_lock_hash 一致的 cell 作为 input cell,并进行签名。
  • 发送方撤回。发送方创建的 Approve Cell 在链上存在时间超过 approve 周期未被接收方领取时,发送方可以通过提供与 sender_lock_hash 一致的 cell 作为 input cell,并进行签名,实现撤回。

交易结构示例

创建 Approve Cell

1. 发送方给没有该 UDT ACP Cell 的用户发送 UDT 时,将会创建一个 Approve Cell

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 解锁逻辑1: 接收方申领

接收方使用官方 secp256k1_blake160 lock 进行接收(适用于 CKB 短地址)

接收方提供 lock args,并使用默认的 secp256k1_blake160 作为 code_hash,组装成 lock script,并进行签名,且组装成的 lock script 经对比与 Approve Cell 中的 receiver_lock_hash 一致。

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>

接收方使用其他 lock script 进行接收

接收方直接提供与 receiver_lock_hash 一致的 cell 作为 input 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

	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 解锁逻辑2: 发送方撤回

发送方创建的 Approve Cell 在链上存在时间超过 approval 周期未被接收方领取时,发送方撤回 Approve Cell。

撤回时发送方需要在 input cells 中加入一个 lock script 与 Approve Cell args 中的 sender_lock_hash 一致的 cell,根据用户持有各种 cells 的不同情况,会衍生出多种多样的交易组装方式,为了方便前端筛选合适 cell 组装交易,我们可以优先考虑以下两种情况:

  • 如果发送方还有该 SUDT 的 cell (我们假设 SUDT cell 通常采用的都是 ACP lock),则将其作为 input cell,进行签名
  • 如果发送方没有该 SUDT 的 cell,而有与 sender_lock_hash 一致的 CKB Normal Cell,则将其作为 input cell,进行签名

发送方还有该 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

发送方没有该 SUDT 的 cell,但还有 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
2 Likes