组合资产合约设计与Taproot

CKB目前有xUDT和Spore/DOB两大类资产类型。
两者都有一些扩展功能,但是远不能实现一些复杂的资产。
比如组合资产,例如将两种xUDT组合在一起,或者将xUDT和Spore组合在一起等等。

在讨论具体的解决方案之前,我们先明确一下ckb种两类script(typescript和lockscript)的定位。
lockscript用来决定资产的ownership,对应的就是BTC中的lockscript。而在ETH中对应的是secp256k1+keccak的固定算法,没有可编程性。
typescript用来决定资产的类型,对应的就是ETH中的智能合约,而在BTC中没有对应物。

如果我们想把已有的资产组合起来,并赋予它们额外的业务逻辑。按照ETH的思路,只要我们把已有的资产都transfer给一个智能合约,智能合约就会像机器人一样自主的根据合约代码去操作这些资产。

那么在CKB中如何将资产tranfer给一个typescript呢?
默认情况下,CKB中资产的ownership是由lockscript描述的,换另外一个lockscript就表示资产transfer了。

对于原生资产ckb来说,因为cell里的typescript结构是空着的,所以只要填一个typescript就可以了。这也是现有资产协议,比如xUDT的铸造过程。

但是如果是一个xUDT资产,它的typescript结构已经被占用了,怎么再关联到另外一个typescript?
我们只要把这个cell从一个普通的lockscript换成一个proxylock,这个proxylock指向一个typescript就可以了。

我们先尝试一个非常简单的场景来作为示例。
把一个普通lock锁定的xUDT转给一个什么都不做的typescript(叫Echo),然后再转回普通的lock。

转入交易大概结构如下:

inputs:
    Type: xUDT  -  arg
    Lock: userlock
    Data: amount(100)
outputs:
  --Type: Echo  -  userlockhash
    Lock: userlock
  --Type: xUDT  -  arg
    Lock: lock2typeProxy  -  typehash
    Data: amount(100)

转出的交易结构就是刚好反过来,就不再赘述了。

这里的lock2typeProxy 是一个lockscript,但是它不像普通的lock一样去检查签名,而是在交易里查找是否存在某个cell它的typescript的hash刚好跟自己的arg是一样的。有则返回成功,否则返回失败。

可能有人会觉得这里没有实质的lock,资产会不会不安全。其实就像前面类比的ETH的情况,就是把资产托管给合约了,比如AA钱包。ETH的合约也是没有对应的私钥的,安全完全看合约代码。

Echo是一个typescript,但是它没什么逻辑,只是为了保证资产要原路转回,所以在arg中保存了转入的资产原来的userlock的hash。然后执行的时候需要检查自身所在的cell的lock是否跟这个lockhash是一致的,以保证只有原来的user才能赎回资产。

lock2typeProxy 的 arg就是Echo这个typescript的hash。

除了多出来的type为Echo的cell,其实这个cell不放在转入交易里,单独创建也是可以的。
其实我们做的事情就是把xUDT原来普通的userlock,换成了lock2typeProxy - typehash 这样一个特殊的lock。

其中的typehash又是 Echo - userlockhash 这个type的hash。
结合在一起lock2typeProxy(hash(Echo(hash(userlock)))),就是普通userlock在Echo这样一个合约里的对应lock。

认识到这一点之后,资产进入Echo合约之后,不转出的情况下也可以把资产转给另外一个人,只要把资产转给lock2typeProxy(hash(Echo (hash(otheruserlock))))这个lock就可以了。
当然解锁要带上多出来的type为Echo的cell。

熟悉BTC的同学应该到这里能看到,这个思路其实跟P2SH(pay to script hash)是一样的。
都是将所有权转给一个script的hash,解锁的时候要带上scripthash对应的script原文。
其他一切不变,钱包也可以正常支持,只要集成一下lock的对应关系即可:
userlock ↔ lock2typeProxy(hash(Echo(hash(userlock))))

既然标题提到了Taproot,除了前面提到的P2SH,还有一个重要技术是MAST。这个会在下面组合资产的例子中体现。

同样设置一个简单的场景:把特定数量的token和一个spore组合在一起,transfer的时候也要一起,除非销毁这个组合资产。

组合交易的大概结构如下:

inputs:
  --Type: xUDT --  arg
    Lock: userlock
    Data: amount(100)
  --Type: Spore -- arg
    Lock: userlock
    Data: content
outputs:
  --Type: Compose --  xUDThash, Sporehash, 100, userlockhash
    Lock: userlock
  --Type: xUDT -- arg
    Lock: lock2typeProxy -- typehash
    Data: amount(100)
  --Type: Spore - arg
    Lock: lock2typeProxy -- typehash
    Data: content

这里Compose这个Typescript的逻辑是:input和output里必须有且只能有1个对应Sporehash的spore cell,还有对应xUDThash的xUDT cell,amount必须是100,最后的userlockhash,要跟本cell的userlock对的上。

拆开的交易其实就是组合交易反过来,同样也可以在不拆开的情况下做transfer,只要提前计算出接收用户的lock在Compose合约里对应的lock就可以了。

这个例子要强调的是:
Compose合约的逻辑非常简单,只是约束了组合后的资产要遵循的一些约束,没有对原有资产进行任何干涉。原因是原有资产的typescript(这里就是xUDT和Spore),也在同时起作用,约束了原有资产各自的行为逻辑。

在cell model里,script是做校验的而不是做计算的,所以script可组合性非常好。想象写代码的时候,函数前面那一大堆参数合法性校验,新增一个校验规则基本上不用动原来的代码,哪怕有重复的也没关系。

所以Compose的参数里要放xUDThash和Sporehash,不只是要对资产类型进行约束这么简单。更深层的含义是,xUDT和Spore形成一个组合资产,这个资产的Typescript可以看作是Compose(xUDT, Spore)这样一个组合形态。

这就跟Taproot里的MAST对应起来。
钱包要支持的特殊类型的lock,也跟BTC的P2TR类似。
更复杂的合约会对应更复杂的Typescript组合,也对应着更复杂的lock构造规则。

5 Likes

好文!cell的设计确实表现出强大的可组合性,将来哪些应用可以用到您提到这个组合设计,或者满足哪类需求?grok给出的回答:
CKB 的组合设计(lock2typeProxy 和 Compose 等机制)适用于需要资产绑定、条件控制、可编程性和跨资产协作的场景,具体应用包括 DeFi 衍生品、NFT 增强、游戏经济、身份管理、托管服务等。它满足了原子性、可编程性、安全性和兼容性等核心需求,展现了与比特币 Taproot/MAST 类似的优雅性,同时凭借 cell 模型的灵活性提供了更广阔的创新空间。未来,随着标准化合约和生态工具的完善,这种设计有望在 CKB 生态中催生丰富的应用场景。

1 Like

对。还有一个关键的区别是,ckb 中这个“合约” (也就是上面的 Echo type script) 是可以带状态的 (Echo 所在 cell 的 data),状态可以按照一定的规则变化,状态变化可以带来合约逻辑的变化。所以说 cell model 是 stateful verification model.

1 Like

在cell model里,script是做校验的而不是做计算的,所以script可组合性非常好。想象写代码的时候,函数前面那一大堆参数合法性校验,新增一个校验规则基本上不用动原来的代码,哪怕有重复的也没关系。

:+1:, 加上下面这个总结

状态可以按照一定的规则变化,状态变化可以带来合约逻辑的变化。所以说 cell model 是 stateful verification model.

很有启发性