サブマリンスワップは、オフチェーンのコインとオンチェーンのコインを交換するためのプロトコル。LN上のコインとオンチェーンのコインを交換したい場合、LNの支払いを入手するために必要なプリイメージと、オンチェーンの資金を受け取るために必要なプリイメージに同じプリイメージを使用することで、LNでの支払いを通じて入手したプリイメージを使って、オンチェーンの資金を請求できるようになり、オンチェーン/オフチェーン間で資金をスワップできるようにする。
このサブマリンスワップでは、
- 対象のプリイメージのハッシュによって設定されたHTLCトランザクションの発行
- 有効期限内にLN支払いをすることで、1のトランザクションのUTXOからオンチェーン資金を入手するトランザクション
という2つのオンチェーントランザクションが必要になる。
Papa Swap
このオンチェーントランザクションの数を1つにするスワッププロトコルがPapa Swap↓
https://github.com/supertestnet/papa-swap
名前にあるPapaは、冷戦時代の潜水艦のパパ級に由来したもので、これには機密解除された世界最速の潜水艦であるソ連のK-222が含まれており、パパ級=最速の潜水艦=最速のサブマリンスワップという理由で名付けられたらしい。
Papa Swapのフロー
Papa Swapは、事前署名されたトランザクションチェーンを利用することで、スワップで発生するオンチェーントランザクションを削減する仕組みを実現している↓
sequenceDiagram participant User as L1ユーザー participant LN as ライトニングネットワーク participant SP as スワップサービス participant BTC as オンチェーン(L1) User->>SP: スワップリクエスト(金額指定)を送信 SP->>User: 手数料支払い用のインボイスを発行 User->>LN: 手数料インボイスへの支払い<br/>※ DoS攻撃を防ぎ、サービスの運営コストを<br/>カバーするための最小限の信頼要素 LN->>SP: 手数料を受信 Note over SP: プリイメージ(秘密値)を生成 Note over SP: スワップ用のコントラクトとTx0〜Tx4(後述)<br/>スワップ用インボイスを生成 SP->>User: スワップ用インボイス、プリイメージから生成した公開鍵、<br/>スワップ用コントラクトおよび各Tx、さらにTx3とTx4の署名を送信 User->>User:各Txおよびそのコントラクトが正しいか検証 User->>User:Tx3, Tx4の署名を検証 User->>User:インボイスのペイメントハッシュとコントラクト内の<br/>ハッシュロックのハッシュ値が一致するかチェック Note over User: Tx1とTx2の署名を生成 User->>SP:Tx1とTx2の署名を送信 SP->>SP: 受け取ったデータと署名を検証 SP->>BTC:スワップ用のTx0をブロードキャス BTC-->>User: スワップ用のUTXOを確認 User->>LN:スワップ用のインボイスへの支払い LN->>SP: インボイスへの支払いを受信 SP-->>User: LN決済によりプリイメージを学習 Note over User: スワップ完了!<br/>プリイメージを入手したことで<br/>スワップ用Txをいつでも使用可能に
スワップサービスは、手数料をLNで受け取った後、まずランダムなプリイメージp
を生成し、スワップ用のコントラクトとして以下のTaprootアウトプットをセットアップする。
ここで重要になるのが、LNで支払いを受け取る際に知ることができるプリイメージp
を秘密鍵として扱い、その公開鍵pG
をTaprootのkey-pathに組み込むこと。これにより、LN支払い完了と同時にユーザーはkey-pathの完全な秘密鍵(ユーザーの秘密鍵 + p)を導出でき、追加のオンチェーントランザクションなしで資金を管理できるようになる。なお、プリイメージと公開鍵の秘密鍵が同じであることは保証できないので、一致しない場合のリカバリーは後述のトランザクションチェーンで担保される。
- key-path:ユーザーの公開鍵+
pG
をkey-pathの公開鍵とする - script-path:以下の2つのアンロック条件を設定したTapscriptをセットアップする
- ファーストブランチ:ユーザーとスワップサービス両者の署名を必要とする
- セカンドブランチ:プリイメージの提供とユーザーとスワップサービス両者の署名を必要とする
※ 従来のサブマリンスワップでは、プリイメージを知っていればユーザー側の署名のみでアンロックできたのが、ここではすべて両者の署名を必要とするよう制限される。
このTaprootアウトプットへスワップ用の資金を送金するトランザクションをTx0とする。続いて、このトランザクションを起点として子トランザクションチェーンTx1〜Tx4を生成する。各トランザクションの役割は、
- Tx1:Tx0のアウトプットを全く同じコントラクト宛に送信するトランザクションで、払い戻しに使用するタイムロックのトリガーとなる。
- Tx2:Tx1のアウトプットを使用し資金をスワップサービスに払い戻すトランザクション。Tx1の承認から2016ブロックの相対的タイムロックが設定されており、タイムロックの期限が切れたらTx2をブロードキャスト可能になる。(Tx1のコントラクトには
OP_CSV
はないので、nSequenceに2016ブロックのタイムロック値を設定した上で事前署名が行われる) - Tx3:Tx0のアウトプットを使用するトランザクションで、ユーザーはプリイメージを使っていればこのトランザクションでスワップ資金を入手できる。
- Tx4:Tx1のアウトプットを使用するトランザクションで、ユーザーはプリイメージを使っていればこのトランザクションでスワップ資金を入手できる。
※ Tx1とTx2はTapscriptのファーストブランチでアンロックするトランザクションで、Tx3とTx4はセカンドブランチでアンロックするトランザクション。
まず、正常ケースでは、スワップはTx0のトランザクションのみで完了する。プリイメージを入手したユーザーはTx0のUTXOをkey-pathを使っていつでもスワップしたオンチェーンのコインを使用できる。その他のTx1〜Tx4は、以下のような異常ケースが起きた場合に使われる。
- スワップサービスがTx0をブロードキャストしたけど、ユーザーがLNでスワップ用の資金を支払わなかった場合。スワップサービスはTx1をブロードキャストし、その後2016ブロック待ってからTx2をブロードキャストし資金を回収する。
- ユーザーがLN支払いで入手したプリイメージがkey-pathの秘密鍵ではなかった(一致しない)場合。ユーザーは、Tx3をブロードキャストすることでスワップ資金を入手する。
- ユーザーがLN支払いをしたにも関わらず、スワップサービスがTx1をブロードキャストし払い戻しをトリガーした場合。ユーザーは、Tx4をブロードキャストすることで、スワップ資金を退避させる。
これらのトランザクションチェーンに対する事前署名によって、どちらかに不正があったとしても資金が回収できるようになっている。
このように払い戻しのトリガーをスワップ用トランザクション(Tx0)から引き剥がして子トランザクションに移動し、プリイメージでユーザーの公開鍵を調整してTaprootの内部鍵にすることで、サブマリンスワップで必要だったオンチェーンのスワップ資金回収用のトランザクションが登場しなくて済むようにしたのがPapa Swap。
正常にスワップが行われる限り、
- トランザクションは1つで済み、
- Taprootを利用することで、スワップした資金を使用する際のオンチェーンコストも削減され、
- サブマリンスワップのようにHTLCのコントラクトが公開されることがなく、Taprootにより単純な支払いと区別もつかなくなり、プライバシーもより向上する
というメリットがある。
Nostrの利用
Papa Swapを実装するにあたっては、NWC(Nostr Wallet Connect)を使用して、スワップリクエストをNostr経由で受け取り、インボイスを発行して後続のプロセスを実行する方法が推奨されてる。