Skip to content

Commit d9d40d6

Browse files
committed
fetchinvoice: allow user to specify bip353 name corresponding to how they got offer.
Changelog-Added: JSON-RPC: `fetchinvoice` BIP 353 name support (`bip353`). Signed-off-by: Rusty Russell <[email protected]>
1 parent dce81fb commit d9d40d6

File tree

9 files changed

+723
-650
lines changed

9 files changed

+723
-650
lines changed

Diff for: .msggen.json

+5
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,7 @@
15471547
},
15481548
"FetchinvoiceRequest": {
15491549
"FetchInvoice.amount_msat": 2,
1550+
"FetchInvoice.bip353": 10,
15501551
"FetchInvoice.offer": 1,
15511552
"FetchInvoice.payer_metadata": 9,
15521553
"FetchInvoice.payer_note": 8,
@@ -6774,6 +6775,10 @@
67746775
"added": "pre-v0.10.1",
67756776
"deprecated": null
67766777
},
6778+
"FetchInvoice.bip353": {
6779+
"added": "v25.02",
6780+
"deprecated": null
6781+
},
67776782
"FetchInvoice.changes": {
67786783
"added": "pre-v0.10.1",
67796784
"deprecated": null

Diff for: cln-grpc/proto/node.proto

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: cln-grpc/src/convert.rs

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: cln-rpc/src/model.rs

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: contrib/msggen/msggen/schema.json

+7
Original file line numberDiff line numberDiff line change
@@ -13124,6 +13124,13 @@
1312413124
],
1312513125
"added": "v24.11"
1312613126
},
13127+
"bip353": {
13128+
"type": "string",
13129+
"description": [
13130+
"BIP353 string (optionally with \u20bf) indicating where we fetched the offer from"
13131+
],
13132+
"added": "v25.02"
13133+
},
1312713134
"dev_reply_path": {
1312813135
"hidden": true
1312913136
},

Diff for: contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py

+650-650
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: doc/schemas/lightning-fetchinvoice.json

+7
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@
6969
],
7070
"added": "v24.11"
7171
},
72+
"bip353": {
73+
"type": "string",
74+
"description": [
75+
"BIP353 string (optionally with ₿) indicating where we fetched the offer from"
76+
],
77+
"added": "v25.02"
78+
},
7279
"dev_reply_path": {
7380
"hidden": true
7481
},

Diff for: plugins/fetchinvoice.c

+34
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <common/onion_message.h>
1919
#include <common/overflows.h>
2020
#include <common/route.h>
21+
#include <common/utils.h>
2122
#include <errno.h>
2223
#include <plugins/establish_onion_path.h>
2324
#include <plugins/fetchinvoice.h>
@@ -823,6 +824,7 @@ struct command_result *json_fetchinvoice(struct command *cmd,
823824
struct out_req *req;
824825
struct tlv_invoice_request *invreq;
825826
struct sent *sent = tal(cmd, struct sent);
827+
const char *bip353;
826828
u32 *timeout;
827829
u64 *quantity;
828830
u32 *recurrence_counter, *recurrence_start;
@@ -837,6 +839,7 @@ struct command_result *json_fetchinvoice(struct command *cmd,
837839
p_opt_def("timeout", param_number, &timeout, 60),
838840
p_opt("payer_note", param_string, &payer_note),
839841
p_opt("payer_metadata", param_bin_from_hex, &payer_metadata),
842+
p_opt("bip353", param_string, &bip353),
840843
p_opt("dev_path_use_scidd", param_dev_scidd, &sent->dev_path_use_scidd),
841844
p_opt("dev_reply_path", param_dev_reply_path, &sent->dev_reply_path),
842845
NULL))
@@ -1018,6 +1021,37 @@ struct command_result *json_fetchinvoice(struct command *cmd,
10181021
}
10191022
}
10201023

1024+
/* BOLT #12:
1025+
* - if it received the offer from which it constructed this
1026+
* `invoice_request` using BIP 353 resolution:
1027+
* - MUST include `invreq_bip_353_name` with,
1028+
* - `name` set to the post-₿, pre-@ part of the BIP 353 HRN,
1029+
* - `domain` set to the post-@ part of the BIP 353 HRN.
1030+
*/
1031+
if (bip353) {
1032+
char *at;
1033+
if (!utf8_check(bip353, strlen(bip353)))
1034+
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
1035+
"invalid UTF-8 for bip353");
1036+
at = strchr(bip353, '@');
1037+
if (!at)
1038+
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
1039+
"missing @ for bip353");
1040+
1041+
/* Strip ₿ if present (0xE2 0x82 0xBF) */
1042+
if (strstarts(bip353, "₿"))
1043+
bip353 += strlen("₿");
1044+
invreq->invreq_bip_353_name
1045+
= tal(invreq, struct tlv_invoice_request_invreq_bip_353_name);
1046+
/* Not nul-terminated! */
1047+
invreq->invreq_bip_353_name->name
1048+
= tal_dup_arr(invreq->invreq_bip_353_name, u8,
1049+
(const u8 *)bip353, at - bip353, 0);
1050+
invreq->invreq_bip_353_name->domain
1051+
= tal_dup_arr(invreq->invreq_bip_353_name, u8,
1052+
(const u8 *)at + 1, strlen(at + 1), 0);
1053+
}
1054+
10211055
/* We derive transient payer_id from invreq_metadata */
10221056
invreq->invreq_payer_id = tal(invreq, struct pubkey);
10231057
if (!payer_key(invreq->invreq_metadata,

Diff for: tests/test_pay.py

+15
Original file line numberDiff line numberDiff line change
@@ -4544,6 +4544,21 @@ def test_fetchinvoice(node_factory, bitcoind):
45444544
# We've done 3 onion calls: sleep now to avoid hitting ratelimit!
45454545
time.sleep(1)
45464546

4547+
# Test bip353.
4548+
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12'], 'bip353': '₿[email protected]'})['invoice']
4549+
assert l1.rpc.decode(inv1)['invreq_bip_353_name'] == {'name': 'rusty',
4550+
'domain': 'blockstream.com'}
4551+
# Without ₿ works too.
4552+
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12'], 'bip353': '[email protected]'})['invoice']
4553+
assert l1.rpc.decode(inv1)['invreq_bip_353_name'] == {'name': 'rusty',
4554+
'domain': 'blockstream.com'}
4555+
# Needs @
4556+
with pytest.raises(RpcError, match="missing @"):
4557+
l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12'], 'bip353': 'rustyblockstream.com'})
4558+
4559+
# We've done 3 onion calls: sleep now to avoid hitting ratelimit!
4560+
time.sleep(1)
4561+
45474562
# If we remove plugin, it can no longer give us an invoice.
45484563
l3.rpc.plugin_stop(plugin)
45494564

0 commit comments

Comments
 (0)