设计了下 CKB 和其他链怎么用 HTLC 做 atomic swap

传统 atomic swap 一般是两个链上同时放 hash time lock contract,正常情况走 redeem 分支,异常用 refund 分支 revert 的。BTC 需要用到 OP_CHECKLOCKTIMEVERIFY
ETH 用 全局变量 block.timestamp

这两个 CKB 都没有,不过看到 input.since 好像类似 BTC 的 nLockTime 可以用上。所以找猫画虎设计了下 atomic swap 方案,等我有空实现一下。

整体上类似 BTC 在 OP_CHECKLOCKTIMEVERIFY 之前的老方案,下面简称“原方案”。下面方案中,和“原方案”类似,也是 BTC 那边 initiate, CKB(altcoin) 这边 participate 。因此 tx1 tx2 和原方案相同,略去不写。之后的步骤伪代码如下:

Tx3:

tx3: {
 input_cell: a previous cell of user A,
 witness:    A_signature(SECP256K1_BLAKE160_SIGHASH_ALL),
 output_cell: {
    lock: {
        args = (hashed_secret, B_Addr, A_Addr, 24h),
        code_hash = hash_of_elf(
            function check_target_addr(addr) -> bool {
                let output_lock = ckb_load_cell_by_field(source: output_cell, field: lock)
                output_lock.code_hash == SECP256K1_BLAKE160_SIGHASH_ALL && 
                  output_lock.args == addr
            }
            function check_sig (signed_message, addr) -> bool {
                // 一般情况 witness[0] 是 tx sender 对 raw tx 和 其他 witness 的签名,这里先简化成只对 raw tx 签名,好像也没啥问题
                let pubkey = recover_pubkey(blake160(ckb_load_tx_hash()), signed_message)
                hash(pubkey) == addr
            }
            function check_redeem(B_addr) -> bool {
                let secret = load_witnress(index: 1)
                check_target_addr(B_addr) && hash(secret) == hashed_secret
            }
            function check_refund(A_addr, locktime) -> bool {
                // Lock scripts can use information of output cells, which is more powerful than Bitcoin,
                // so here we don't require B to sign the TX2/TX4 similar to https://en.bitcoin.it/wiki/Atomic_swap#Solution_using_revealing_secrets_of_contract
                if ckb_load_input_by_field(field: since) != {relative: locktime/*24h*/} {
                    false
                } else {
                    // normal sig check. 
                    let signed_message = load_witness(index: 1)
                    check_sig(signed_message, A_addr)
                }    
            }
            function main() -> int32 {
	            let (hashed_secret, B_addr, A_addr, locktime) = ckb_load_script();
	            let (is_redeem, other_args) = ckb_load_witness();
	            let is_success = if is_redeem {    
	                check_redeem(B_addr, other_args /*hashed_secret here*/)
	            } else {
	                check_refund(A_addr, other_args /*locktime here*/)
	            }
	            if is_success ? 0 else 1
	        }    
        ),
    }
 }

TX4: 如上面注释所说,CKB 的 Script 可以比 BTC 的 Script access 到更多信息,更强大一些,因此可以直接在 TX3 的 Lock Script 判断 time lock 和 output address,实际上就使得原方案的 TX4 没必要了。因此 CKB 的 Atomic Swap 实际上可以不做原方案的 TX4。

Redeem TX: 类似原方案,见下:

redeem_tx: {
    input: {tx3}
    output: {
        lock: B_addr
    },
    witness: (true, the_revealed_secret)
}

Refund TX:

refund_tx: {
   input: {tx3, since: {relative: 24h}}
   output: {
     lock: any_addr_A_likes
   },
   witness: (false, A_signature_of_raw_tx_without_other_witness)
 }
5 Likes

CKB 实际上是用一种统一的方式支持了 BTC 所有的 timelock。基于 BTC 的方案做是比较自然的。

ps. CKB (以及 BTC) 这么设计的原因是为了交易的确定性。Ethereum 上 EVM 本身是确定性的,但是编程模型因为直接引入了 block.timestamp 这样的东西却使得交易结果是不确定的。

1 Like