generated at
NIP-57

>Lightning Zaps

hr
翻訳 commit=c30971f

このNIPは、ユーザ間のLightning Network上での支払いを記録する2つの新しいイベントを定義する。
kind 9734 zapリクエスト で、支払人による 受取人のライトニングウォレットまたはライトニングインボイスへの送金リクエストを表す。
kind 9735 zapレシート で、 zapリクエスト に応じて発行されたインボイスへの支払いが受取人のライトニングウォレットによって確認されたことを表す。

Nostr上にライトニング支払いのレシートを残すことで、クライアントはネットワーク上の実体からのライトニング支払いを表示できる。これは楽しみのために、またはスパムの抑止力として利用できる。

プロトコルの流れ
1. クライアントは、zap対象のイベントに含まれる zap タグ(別表G参照)より、または受取人のプロフィールのlud06, lud16フィールドをlnurl仕様に従ってデコードすることにより、受取人のlnurl-payリクエストURLを割り出す。クライアントはそのURLにGETリクエストを送り、レスポンスをパースしなければならない(MUST)。(レスポンスに) allowNostr が存在して true であり、さらに nostrPubkey が存在して値がBIP 340のhex形式の有効な公開鍵であれば、クライアントはこの情報をレスポンスの callback , minSendable , maxSendable の値とともにユーザに関連付けるべきである。
(訳注)
lnurl-payリクエストURLとの通信については、LUD-06の(3)を参照。
lud06 フィールド(LNURLアドレス)のデコード仕様はLUD-01を参照。
lud16 フィールド(Internet Identifier)の仕様はLUD-16を参照。
nostrPubkey はBIP-340へのリンクがあるが、通常のnostr公開鍵と同じ形式

2. クライアントは各投稿上またはユーザのプロフィール上にライトニングzapボタンを表示してもよい。もしユーザのlnurl-payリクエストエンドポイントがNostrをサポートしているなら、クライアントは通常のlnurlインボイスの代わりに zapレシート をリクエストするためにこのNIPを使うべきである(SHOULD)。
(訳注)
(1)で allowNostr フィールドが true であるならば、Nostrをサポートしていることを意味する。
lnurl-payリクエストエンドポイント は、(1)のlnurl-payリクエストURLのこと。
lnurlインボイスは単にライトニングインボイスと解釈してよい。lud06で発行されたインボイスのことを指していると思われる。
「代わりに」とあるが、後述の callback の応答としてはライトニングインボイスが返り、zapレシートはリレーに送信される。

3. あるユーザ(「支払人」)が他のユーザ(「受取人」)にzapを送りたいという意思を示したら、クライアントは別表Aで説明された通りに zapリクエスト イベントを生成し、署名を行うべきである。

4. zapリクエスト は(リレーに)送信するのではなく、受取人のlnurl-payエンドポイントからGETリクエストで取得した callback URLに送信されるべきものである。
(訳注)
このステップはLUD-06の(4)に相当する。LUD-06#65a0212f1246d7000044ddb3
lnurl-payエンドポイント は、(1)のlnurl-payリクエストURLのこと。 callback は(1)で取得したJSONに含まれる。
callback URLの呼び出しは別表Bを参照 → NIP-57#646050e32b313000005be09f

5. 受取人のlnurlサーバはこの zapリクエスト を受け取り、検証する。zapをサポートするためにlnurlサーバを正しく設定する方法については別表Cを参照。 nostr クエリパラメータ(の内容)を検証する方法の詳細については別表Dを参照。

6. zapリクエスト が有効なら、(lnurl)サーバはdescriptionとしてその zapリクエスト noteのみを含むdescription hash invoiceを取得する。それ以外のlnurlメタデータは含めない。これはLUD-06に従うレスポンスとして(クライアントに)返される。
(訳注)
このステップはLUD-06の(6)と(7)に相当する。LNURLサーバはライトニングインボイスを作成してクライアントに返す。そのライトニングインボイスの h タグには zapリクエスト のハッシュ値を含めるようにすべきということを言っている。元になっている仕様LUD-06では(3)の metadata のハッシュ値を h タグに含めるように定めているが、それは含めないようにする。
言葉について
description hash invoice はライトニングインボイス( lnbc1... , BOLT-11)のことと理解して良い。
description hash はライトニングインボイスの h フィールドのこと。 zapリクエスト のSHA-256ハッシュ値を含める。 d タグには何も含めない。
LUD-06に従うレスポンス LUD-06の(6)の pr こと。

7. インボイスを受け取ったら、クライアントはそれに対して(自分で)支払いを行うか、それを支払い機能を持つアプリに渡してよい(MAY)。

8. インボイスに対し支払いが行われたら、受取人のlnurlサーバは別表Eに記載のとおりに zapレシート を生成し、 zapリクエスト に指定されているリレー( relays )に送信しなければならない(MUST)。

9. クライアントは投稿・プロフィール上の zapレシート を取得してもよい(MAY)が、このとき別表Fに記載の方法で正当性を確認しなければならない(MUST)。 zapリクエスト が空でない content を含むならば、zapのコメントとして表示してよい。一般にクライアントはユーザの zapリクエスト を表示すべきで、 zapレシート は「...によって承認されたzap」という表示のために使えるが、これは任意。

参考情報と例
※JSONやコードの例については 原文 を参照してください

別表A: Zapリクエストイベント
zapリクエスト はkind 9734 のイベントで、リレーにではなく(zap)受取人のlnurl-payの callback URLに送信する。
このイベントの content には、支払いにあわせて送信するメッセージを含めてもよい(MAY)。
このイベントには次のタグを含めなければならない(MUST):
relays : 受取人のウォレットが zapレシート を送るべきリレーのリスト
amount : 支払人が送信しようとしている金額(millisats(satsの1/1000)単位)。推奨されているが必須ではない
lnurl : 受取人のlnurl-pay URL。 lnurl から始まるbech32形式で指定。推奨されているが必須ではない
p : 受取人のhex形式の公開鍵

さらに、イベントには以下のタグを含めてもよい(MAY):
e : hex形式のイベントIDの。個人ではなくイベントに対してzapする場合、これを含めなければならない(MUST)。
a : パラメータつき上書き可能イベントを特定する「座標」。NIP-23の長文投稿のようなへのzapに使う
(訳注) ["a", "<kind>:<pubkey>:<dタグ>", "<relay url>"] という形式

(イベント例: 原文参照)

別表B: ZapリクエストのHTTPリクエスト
署名された zapリクエスト イベントは(リレーに)送信するのではなく、受取人の(lnurl-payの) callback URLにHTTP GETリクエストによって送信する。 callback URLは受取人のlnurl-payエンドポイントから提供される。
このリクエストは次のクエリパラメータを含むべきである:
amount : 支払人が送信しようとしている金額(millisats単位)
nostr : zapリクエスト イベントをJSONエンコード・URIエンコードしたもの
lnurl : 受取人のlnurl-pay URLを lnurl から始まるbech32形式にエンコードしたもの

このリクエストに対し、(受取人のLNURLサーバは) pr フィールドを含むJSONレスポンスを返すべきである。 pr フィールドはzapを完了するために支払いを行うべきインボイス。

(訳注)
callback の呼び出しはLUD-06#65a01a001246d7000044dd6aも参照
インボイスはライトニングインボイスのこと。

(リクエスト処理の例: 原文参照)

別表C: LNURLサーバの設定
lnurlサーバがzapインボイスをサポートしていることをクライアントに知らせるため、追加設定が必要:
1. lnurl-pay静的エンドポイント /.well-known/lnurlp/<user> (のレスポンス)に nostrPubkey を追加する。 nostrPubkey は、lnurlサーバが zapレシート イベントに署名する際に使う秘密鍵に対応する公開鍵。クライアントはこれを zapレシート の検証に用いる
2. allowsNostr フィールドを追加し、値を true に設定する

別表D: LNURLサーバによるZapリクエスト検証
クライアントが zapリクエスト イベントをサーバのlnurl-payコールバックURLに送信する際、そのイベントをJSON・URIエンコードした結果を値とする nostr クエリパラメータが含まれているはず。もし nostr クエリパラメータが存在するならば、以下の方法で zapリクエスト を検証しなければならない:

1. 正当な署名を持たなければならない(MUST)
2. タグを持たなければならない(MUST)
3. ただ1つの p タグを持たなければならない(MUST)
4. 0個か1個の e タグを持たなければならない(MUST)
5. zapレシート の送信先リレーを指定する relays タグを持つべき
(訳注) 「べき」という文末だが、別表AではMUSTとされている。
6. amount タグを持つ場合、その値は amount クエリパラメータの値と一致していなければならない(MUST)
7. a タグを持つ場合、それは妥当なイベント座標でなければならない(MUST)
8. P タグが0個〜1個なければならない(MUST)。存在する場合、 zapレシート pubkey と等しくなければならない(MUST)。

このイベントは後でインボイスに支払いが行われた際に使うため、保存しておかなければならない(MUST)。

別表E: Zapレシートイベント
zapレシート は、 zapリクエスト から生成されたインボイスに対し支払いが行われた際に、ライトニングノードが作成する。 zapレシート は、インボイスのdescriptionが zapリクエスト を含む場合に限り作成する。

支払いを受けたら、次のステップを実行する:

1. インボイスのdescriptionを取得する。これはdescription hash invoiceを生成するタイミングでどこかに保存しておく必要がある。参照実装であるCLN (core lightning) では自動的に保存される
(訳注) インボイスのdescription zapリクエスト のこと。
(訳注) description hash bolt11 インボイス はライトニングインボイスのこと。 生成するタイミング は(6)。別表Dも参照。
2. bolt11 descriptionをJSON形式のNostrイベントとしてパースする。これを別表Dに示した仕様に基づいて検証すべきである(SHOULD)。
(訳注) bolt11 description はE1の インボイスのdescription zapリクエスト のこと。
3. 以下に示す仕様を満たす、kind 9735 のNostrイベントを作成し、 zapリクエスト relays タグで指定されたリレーに送信する

zapレシート イベントは以下を満たすべきである:
content は空であるべき(SHOULD)
created_at には、冪等性のためインボイスの paid_at の値を設定すべき(SHOULD)
tags には zapリクエスト と同じ p タグ(zapの受取人)、 zapリクエスト e タグ(任意)、 zapリクエスト a タグ(任意)、 zapリクエスト の公開鍵(zapの支払人)を含めた P タグを含めなければならない(MUST)。
description hash bolt11インボイスを含む bolt11 タグを持たなければならない(MUST)
JSONエンコードされたZapリクエストを含む description タグを持たなければならない(MUST)
description のSHA256ハッシュ値はbolt11インボイスのdescription hashと一致していなければならない(MUST)
(訳注)bolt11インボイス(=ライトニングインボイス)の h タグには zapリクエスト のSHA-256ハッシュ値が含まれているはず。
bolt11インボイスのpayment hashと突合するための preimage タグを含めてもよい(MAY)。これは支払証明ではなく、インボイスが本物かどうかあるいは支払い済みかどうかを証明する方法はない。決済の正当性に関しては、 zapレシート の作成者を信用することになる
(訳注) payment hash はライトニングインボイスの p フィールドのこと。BOLT-11を参照。

zapレシート は支払証明ではなく、あるNostrユーザがインボイスを取得したことの証明でしかない。 zapレシート の存在はそのインボイスに支払いが行われたことを示唆するが、悪意ある実装のもとでは正しいとは限らない。


zapをサポートするlnurlサーバの参照実装はこちら

(zapレシートの例: 原文参照)

別表F: Zapレシートの検証
クライアントはNIP-01のフィルタを使い、イベントと公開鍵に関連付けられた zapレシート を取得できる(例: {"kinds": [9735], "#e": [...]} )。Zapは次の手順にしたがって検証されなければならない(MUST)。
zapレシート イベントの公開鍵は、受取人のLNURLプロバイダの(プロトコルフローの手順1で取得した) nostrPubkey と同じでなければならない(MUST)。
zapレシート bolt11 タグに含まれる invoiceAmount は(存在する場合には) zapリクエスト amount タグと等しくなければならない(MUST)。
zapリクエスト lnurl タグは(存在する場合には)受取人の lnurl と等しいべきである(SHOULD)。
(訳注)
「存在する場合には」がどこに掛かっているのかについて
Appendix Aにおいてzap リクエストamount, lnurlタグが「This is recommended, but optional.」とあるので存在しない場合がある。 tanakei
zapリクエスト zapレシート description タグに含まれる syusui_s
zapレシート description タグには、インボイスのdescriptionが含まれる
zapレシート は、インボイスのdescriptionが zapリクエスト を含む場合に限り作成する
プロトコルの流れの(6)で作ったインボイス(BOLT-11)には、description( d タグ)として zapレシート が含まれている
invoiceAmount はライトニングインボイスに含まれる金額のこと。 bolt11 タグにはライトニングインボイスが含まれている。
(special thanks: syusui_s)

別表G: "zap"タグ (zap分配)
イベントが1つ以上の zap タグを含む場合、クライアントはプロフィールのフィールドの代わりにそのタグの値に基づいてlnurl-payリクエストを導出するべきである(SHOULD)。
このタグの2番めの引数は受取人の公開鍵の16進数文字列で、3番目の引数(任意)は受取人のメタデータ(kind 0)をダウンロードするためのリレーとする。
4番目の引数(任意)は各受取人に割り当てる重みを指定する。クライアントはすべての重みを取得して合計を求め、受取人ごとの(重みの)割合を計算すべきである。重みが指定されていなければ、クライアントはzapをすべての受取人に均等に分配すべき。重みが一部のみ指定されている場合、重みが指定されていない受取人にはzapを届けるべきでない(重み=0とみなす)。

(zapタグの例: 原文参照)

クライアントは投稿の中にzap分配設定を表示してもよい(MAY)。

今後の展望
対象のユーザへの zapリクエスト を暗号化することによって、zapをよりプライベートな方向に拡張できるが、簡単のためこの初期草案では対象外としている。

hr
以下、訳注

シーケンス図 (by tanakei)

実装に関するTips
仕様について
LUD-06をはじめに読むと、この仕様の理解が進みます
投稿に対するZapを取得するには
{ "kinds":[9735], "#e":[投稿のID] }
ユーザに対するZapの一覧を取得するには
{ "kinds":[9735], "#p":[受取人のpubkey], "limit": 50 }
Zapの完了を検知するには
{ "kinds":[9735], "#e":[投稿のID], "#p":[受取人のpubkey], since: 現在時刻 }
ユーザにライトニングインボイスを提示して、ユーザにより支払いがされると、Zapレシートが送られる
Zapレシートのbolt11タグにそのライトニングインボイスが含まれていれば完了と見做せる
Zapレシートの検証
ライトニングインボイス(BOLT-11)のパースが必要です。別表Fにしたがって、 amount を検証しなくてはいけません。
ウォレットをリンクから開く方法、QRコードを表示する方法
lightning:lnbc10n1...... のように lightning: を先頭につけて、 <a> タグの href に含める、QRコードにする
インボイスをWallet of Satoshi等のスマートフォン向けのウォレットで読み取り、あるいは開くことができるようになります。
lightnig:... BOLT-11の仕様で定義されています。
ウォレットを乗り換えるとLNURLが変わるので、古いZapについては検証が失敗するようになってしまいます
LNURLをパースしてLNURLサーバに問い合わせて kind:9735 の署名に使われるpubkeyを取得しているため、LNURLが変われば署名に使われる pubkey も変わる
アイデアとしては以下のようなものがあります
Zapレシートの表示する前に警告を表示する
Zapレシートのpubkeyをユーザが信頼するか、ミュートするかどうかを選ばせる
過去に特定のpubkeyから多数のZapを受け取っていた場合、信頼するかどうかをユーザに選ばせる
Alby等の一部のウォレットはブラウザ拡張経由の送金に対応しています→WebLN
Nostr Wallet Connectを使うと、ウォレットアプリの画面に移ることなくZapできます→NIP-47

関連項目: