bitcoin&モナコインでHTLCによるアトミックスワップを行うためのPoCを作成しました。
これにより現在、SymbolやSymbolのコピーチェーン。Ethereumを始めとするEVM互換性のあるチェーンとそれらのERC20,ERC721。さらにBitcoinとBitcoinのコピーチェーンでのアトミックスワップが可能となります。
以下は今回作成したビットコイン系のみのリポジトリ。
それ以外は下記、ふぁーさん作成のAtmicPortで使えます。このあとAtomicPortにもビットコイン系が追加されると思います。なお、HTLCのハッシュ関数はHash256(Sha256の二重掛け)です。理由はSymbolのHTLCに対応するため。
ちなみにEVM互換性のあるチェーンでのHTLCは以下をご覧ください。書きなぐりなので読みにくい。
使い方
基本的にサンプルはsample.ts
にあります。
できることは3つ。それぞれBitcoin testnetとMona testnetで利用可能です。もちろん他のビットコインのコピーチェーンや各メインネットも少し触れば対応可能です。
- トランザクションのロック
- 引き出し
- 期間経過後の返金
準備
import * as bitcoin from 'bitcoinjs-lib';
import { btcSwap } from './btcSwap';
import * as ecc from 'tiny-secp256k1';
import ECPairFactory from 'ecpair';
const ECPair = ECPairFactory(ecc);
const aliceWif = "cNaEjitvA19JZxWAFyCFMsm16TvGEmVAW3AkPnVr8E9vgwdZWMGV"
const bobWif = "cQBwuzEBYQrbWKFZZFpgitRpdDDxUrT1nzvhDWhxMmFtWdRnrCSm"
BTCの場合
import BitCoin from "./bitcoin"
const network = bitcoin.networks.testnet
const swap = new btcSwap(new BitCoin());
const Alice = ECPair.fromWIF(aliceWif, network);
const Bob = ECPair.fromWIF(bobWif, network);
Monaの場合
const coininfo = require('coininfo')
import Mona from "./mona"
const network = coininfo.monacoin.test.toBitcoinJS()
const swap = new btcSwap(new Mona());
const Alice = ECPair.fromWIF(aliceWif, network);
const Bob = ECPair.fromWIF(bobWif, network);
ロック
const amount = 5000;
const fee = 1800;
const lockTime = 2;
swap.lock(lockTime, Alice, Bob, amount, fee)
ロック送金する金額と手数料をビットコインの場合はSatoshi単位で。Monaの場合は * 100000000(1.1Monaなら110000000)
あとロックする期間をブロック単位で指定するだけ。
コンソールにいくつかの大切な情報が表示されるので控える。(以下にあるものは全部必要)
proof: fa86c053566962425bafc51efe57452cdcf3b5766033de95986103376e3*****
secret:19aee0e9f5916cbd2a96e4707ae851b3aecd3a094af1261a10c382fc37a*****
Swap contract (witness script):
aa2019aee0e9f5916cbd2a96e4707ae851b3aecd3a094af1261a10c382fc37ad56b087632103745c9aceb84dcdeddf2c3cdc1edb0b0b5af2f9bf85612d73fa6394758eaee35d67036ae724b17521027efbabf425077cdbceb73f6681c7ebe2ade74a65ea57ebcf0c42364d3822c59068ac
P2WSH swap smart contract address:
tb1qtd8z86gv0e68gdclfrfkuyjk9v6az2m8q2d2fd9zhlv553uqcrqq7x6f47
Transaction hash: 29f8faa916b360e043d4ae5efef824509de945e0147b519fef2f7dde0f967a3d
この中ではproofがロック解除(引き出し)に使用するため公開してはいけない。ほかは問題ない。
引き出し
引き出しはBobによって行う。
ロック時の情報を使う。Proofは非公開なのでAliceしか知らないのは当然だが、WitnessScriptをおいて置かなければいけないのがちょっとイケてない。これは送信者と受信者の公開鍵とロックするブロック高から算出は可能、つまりロック期間さえ分かれば良いかも。(要検討
const txId = "TRANSACTION_HASH"
const contractAddress = "P2WSH_CONTRACT_ADDRESS"
const witnessScript = "SWAP_CONTRACT"
const proof = "PROOF"
const fee = 1700;
swap.withdraw(txId, contractAddress, witnessScript, Bob, proof, fee)
返金
ロック期間を過ぎた場合に送信者への返金。期間を過ぎていなければエラーになる。
const txId = "TRANSACTION_HASH"
const contractAddress = "P2WSH_CONTRACT_ADDRESS"
const witnessScript = "SWAP_CONTRACT"
const fee = 1700;
swap.refund(txId, contractAddress, witnessScript, Alice, fee)
簡単なコア部コード解説
スマコン(と呼ぶのかも分からないが)部のコードは以下。
function swapContractGenerator(receiverPublicKey: Buffer, userRefundPublicKey: Buffer, PAYMENT_HASH: string, timelock: number) {
return bitcoin.script.fromASM(
`
OP_HASH256
${PAYMENT_HASH}
OP_EQUAL
OP_IF
${receiverPublicKey.toString('hex')}
OP_ELSE
${bitcoin.script.number.encode(timelock).toString('hex')}
OP_CHECKLOCKTIMEVERIFY
OP_DROP
${userRefundPublicKey.toString('hex')}
OP_ENDIF
OP_CHECKSIG
`
.trim()
.replace(/\s+/g, ' '),
);
}
※BitCoinScript
https://en.bitcoin.it/wiki/Script
引き出しor返金時にPreImageをInputに加える。PreImageをHash256によりハッシュ化しPAYMENT_HASHを比較。trueなら受取り手の公開鍵をチェックする。
返金の場合は空のPreimageを渡し、falseに向かう。さらにロック期間を超えているかOP_CHECKLOCKTIMEVERIFY
によって比較する。返金の場合は送金者の公開鍵と比較し返金する。
OP_CHECKLOCKTIMEVERIFY
に関する詳細は以下
※HTLCによる以下アトミックスワップのスマコン箇所参考
記事集
タブ開きすぎて嫌なので主に自分用メモ。(だけど誰かの役に立つかもなので
BitCoin Script
https://en.bitcoin.it/wiki/Script
Submarine Swap - On-chain to Off-chain
https://bitcoinjs-guide.bitcoin-studio.com/bitcoinjs-guide/v5/part-three-pay-to-script-hash/submarine_swaps/swap_on2off_p2wsh.html
CLTV
https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.spec.ts
BIP199 HTLC contract support (for AtomicSwap) #945
https://github.com/bitcoinjs/bitcoinjs-lib/issues/945
Mempool API reference
https://mempool.space/testnet/docs/api/rest
Mempool Explorer
https://mempool.space/testnet
Alice
https://mempool.space/testnet/address/tb1qq0en3c8cnrh5pu0tvu6dc8665u4yzc0cvv2rwf
OP_CHECKLOCKTIMEVERIFY
https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki
Mona
faucet
https://faucet.torifuku-kaiou.tokyo/
wallet
https://testnet-monapalette.komikikaku.com/
Explorer
https://testnet.mpchain.info/
Api reference
https://testnet.mpchain.info/doc
UTXO 取得
https://monaledge.com/article/421
※search_raw_transactions
ではなくget_unspent_txouts
があったのでそちらがBetter