サブマリンスワップのコントラクト
サブマリンスワップとはオンチェーンとオフチェーンのコインをトラストレスに交換する仕組みです。このサブマリンスワップは、もともとブロックチェーン間のコインを交換するためのアトミックスワップから生まれました。今回はビットコインのL1とL2のコインを交換するためのサブマリンスワップについて、そのコントラクト内容を見ていきます。Submarine Swapsを解説している動画も分かりやすいので、興味のある方は見てみてください。
以下の説明では、メイカーをサービスプロパイダー、テイカーをユーザーとして読み替えることができます。
スワップイン
スワップインは、L1のコインをL2へ交換します。
スワップインのスクリプトは以下です(実際のコードはこちら)。テイカーが以下のスクリプトアドレスへL1のコインを送金します。メイカーはそれを確認したらテイカーへL2上でコインを送金します。テイカーはプリイメジを公開することでL2のコインを着金させることができ、それと同時にメイカーはプリイメジを知ることができるので、以下のスクリプトのOP_IF節を使ってL1のコインを受け取ります。もし、テイカーが以下のスクリプトアドレスへL1コインを送金してもメイカーがL2上でコインを送金しなかった場合(または送金したけどテイカーが着金しなかった場合)、{timeoutBlockHeight}で指定したブロック高が経過すればテイカーはコインの払い戻しをすることができます。Diamond Handsのスワップサービスでは、このブロック高を40ブロックとしています。
OP_HASH160
OP_PUSHBYTES_20 {preimageHash}
OP_EQUAL
OP_IF
OP_PUSHBYTES_33 {claimPublicKey}
OP_ELSE
OP_PUSHBYTES_3 {timeoutBlockHeight}
OP_CLTV
OP_DROP
OP_PUSHBYTES_33 {refundPublicKey}
OP_ENDIF
OP_CHECKSIG
スワップアウト
スワップアウトは、L2のコインをL1へ交換します。
スワップアウトのスクリプトは以下です(実際のコードはこちら)。メイカーが以下のスクリプトアドレスへコインを送金します。次に、テイカーがL2上でメイカーへコインを送金します。メイカーはプリイメジを公開してL2上のコインを着金させます。テイカーは公開されたプリイメジを使って、以下のスクリプトのOP_IF節を通してコインを引き出します。
OP_SIZE
OP_PUSHBYTES_1 20
OP_EQUAL
OP_IF
OP_HASH160
OP_PUSHBYTES_20 {preimageHash}
OP_EQUALVERIFY
OP_PUSHBYTES_33 {claimPublicKey}
OP_ELSE
OP_DROP
OP_PUSHBYTES_3 {timeoutBlockHeight}
OP_CLTV
OP_DROP
OP_PUSHBYTES_33 {refundPublicKey}
OP_ENDIF
OP_CHECKSIG
スクリプトの差異について
上記のスワップインとスワップアウトのスクリプトは少しだけ差異があることに気づきます。スワップインではプリイメジのハッシュ化を先頭で行っているのに対し、スワップアウトではOP_IF節の中で行っています。スワップインのスクリプトは必ずハッシュ化を行う必要があります。スワップアウトの場合、プリイメジを提供しなければハッシュ化は実行されないので、コンピュータリソース的には優しいですね。イーサリアムの場合、すべての実行コードに消費コストが割り当ててありますが、ビットコインの場合はすべて等しく、消費コストは実行コードのバイト数に従います。ビットコインではどのコードを組み込むかはあまり意識するインセンティブにはなりません。
また、スワップインとアウトのスクリプトが異なっているので、オンチェーン解析をするとどちらのスワップが行われたかを知ることができます。これはプライバシーを下げることになります。スワップインとアウトはテイカーのメイカーが入れ替われば同じ取引をしていることになるので、1つのスクリプトでも良さそうな気がします。なぜ差異があるのか疑問が残ります。
スワップインの改良
サブマリンスワップの考案者であるAlex氏は、スワップインが失敗した時、タイムアウトを待たずして即時に資金回収できるようにするとツイートしていました。
タイムアウトは、プリイメジを公開してL2での送金が完了したのち、L1のコインをすぐに払い戻しされないようにするために設けています。
タイムアウトの設定なしに資金をどのように払い戻しさせるのでしょうか?P2TRのKey-pathにマルチシグアドレス(Musig2)を追加して払い戻しを協調的にする条件を追加することもできそうです。Musigを使わない場合はScript-pathにマルチシグアドレスの条件を追加でも可能です。
スワップインでのプリイメジはテイカーが作りますが、L2での着金ができなかった場合、メイカーが生成したシークレットを公開することで、そのシークレットで払い戻しをする条件を追加したりするのかもしれません。メイカーはL2での送金が成功・ペンディング・失敗の状態を知っているので、失敗した時にシークレットを公開すれば良さそうです。
Diamond handsのスワップサービスでもスワップインが失敗した場合、タイムアウトになるまでテイカーは待たないといけません。資金が盗まれることはないですが、ちょっと不安になるので、取引が失敗した際はすぐに払い戻しできるようにすると良いかもしれません。