NIP-57
翻訳 commit=c30971f
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に送信されるべきものである。
(訳注)
lnurl-payエンドポイント
は、(1)のlnurl-payリクエストURLのこと。 callback
は(1)で取得したJSONに含まれる。
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を完了するために支払いを行うべきインボイス。
(訳注)
インボイスはライトニングインボイスのこと。
(リクエスト処理の例: 原文参照)
別表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.」とあるので存在しない場合がある。

zapリクエスト
は
zapレシート
の
description
タグに含まれる

zapレシート
の description
タグには、インボイスのdescriptionが含まれる
zapレシート
は、インボイスのdescriptionが zapリクエスト
を含む場合に限り作成する
プロトコルの流れの(6)で作ったインボイス(
BOLT-11)には、description(
d
タグ)として
zapレシート
が含まれている
invoiceAmount
はライトニングインボイスに含まれる金額のこと。 bolt11
タグにはライトニングインボイスが含まれている。
(special thanks:

)
別表G: "zap"タグ (zap分配)
イベントが1つ以上の zap
タグを含む場合、クライアントはプロフィールのフィールドの代わりにそのタグの値に基づいてlnurl-payリクエストを導出するべきである(SHOULD)。
このタグの2番めの引数は受取人の公開鍵の16進数文字列で、3番目の引数(任意)は受取人のメタデータ(kind 0)をダウンロードするためのリレーとする。
4番目の引数(任意)は各受取人に割り当てる重みを指定する。クライアントはすべての重みを取得して合計を求め、受取人ごとの(重みの)割合を計算すべきである。重みが指定されていなければ、クライアントはzapをすべての受取人に均等に分配すべき。重みが一部のみ指定されている場合、重みが指定されていない受取人にはzapを届けるべきでない(重み=0とみなす)。
(zapタグの例: 原文参照)
クライアントは投稿の中にzap分配設定を表示してもよい(MAY)。
今後の展望
対象のユーザへの zapリクエスト
を暗号化することによって、zapをよりプライベートな方向に拡張できるが、簡単のためこの初期草案では対象外としている。
以下、訳注
シーケンス図 (by

)
実装に関するTips
仕様について
投稿に対する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等のスマートフォン向けのウォレットで読み取り、あるいは開くことができるようになります。
ウォレットを乗り換えるとLNURLが変わるので、古いZapについては検証が失敗するようになってしまいます
LNURLをパースしてLNURLサーバに問い合わせて kind:9735
の署名に使われるpubkeyを取得しているため、LNURLが変われば署名に使われる pubkey
も変わる
アイデアとしては以下のようなものがあります
Zapレシートの表示する前に警告を表示する
Zapレシートのpubkeyをユーザが信頼するか、ミュートするかどうかを選ばせる
過去に特定のpubkeyから多数のZapを受け取っていた場合、信頼するかどうかをユーザに選ばせる
Alby等の一部のウォレットはブラウザ拡張経由の送金に対応しています→
WebLNNostr Wallet Connectを使うと、ウォレットアプリの画面に移ることなくZapできます→
NIP-47
関連項目: