传统 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)
}