mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 07:34:24 +01:00
bolt12: use spec field names, update decode API.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
fdb3d9186a
commit
ef2f4a0648
@@ -272,6 +272,7 @@
|
||||
"CreateInvoice.bolt12": 3,
|
||||
"CreateInvoice.description": 7,
|
||||
"CreateInvoice.expires_at": 8,
|
||||
"CreateInvoice.invreq_payer_note": 15,
|
||||
"CreateInvoice.label": 1,
|
||||
"CreateInvoice.local_offer_id": 13,
|
||||
"CreateInvoice.paid_at": 11,
|
||||
@@ -336,6 +337,7 @@
|
||||
"DelInvoice.bolt12": 3,
|
||||
"DelInvoice.description": 5,
|
||||
"DelInvoice.expires_at": 8,
|
||||
"DelInvoice.invreq_payer_note": 11,
|
||||
"DelInvoice.label": 1,
|
||||
"DelInvoice.local_offer_id": 9,
|
||||
"DelInvoice.payer_note": 10,
|
||||
@@ -630,6 +632,7 @@
|
||||
"ListInvoices.invoices[].bolt12": 8,
|
||||
"ListInvoices.invoices[].description": 2,
|
||||
"ListInvoices.invoices[].expires_at": 5,
|
||||
"ListInvoices.invoices[].invreq_payer_note": 15,
|
||||
"ListInvoices.invoices[].label": 1,
|
||||
"ListInvoices.invoices[].local_offer_id": 9,
|
||||
"ListInvoices.invoices[].paid_at": 13,
|
||||
|
||||
6
cln-grpc/proto/node.proto
generated
6
cln-grpc/proto/node.proto
generated
@@ -481,7 +481,7 @@ message CreateinvoiceResponse {
|
||||
optional uint64 paid_at = 11;
|
||||
optional bytes payment_preimage = 12;
|
||||
optional bytes local_offer_id = 13;
|
||||
optional string payer_note = 14;
|
||||
optional string invreq_payer_note = 15;
|
||||
}
|
||||
|
||||
message DatastoreRequest {
|
||||
@@ -571,7 +571,7 @@ message DelinvoiceResponse {
|
||||
DelinvoiceStatus status = 7;
|
||||
uint64 expires_at = 8;
|
||||
optional bytes local_offer_id = 9;
|
||||
optional string payer_note = 10;
|
||||
optional string invreq_payer_note = 11;
|
||||
}
|
||||
|
||||
message InvoiceRequest {
|
||||
@@ -640,7 +640,7 @@ message ListinvoicesInvoices {
|
||||
optional string bolt11 = 7;
|
||||
optional string bolt12 = 8;
|
||||
optional bytes local_offer_id = 9;
|
||||
optional string payer_note = 10;
|
||||
optional string invreq_payer_note = 15;
|
||||
optional uint64 pay_index = 11;
|
||||
optional Amount amount_received_msat = 12;
|
||||
optional uint64 paid_at = 13;
|
||||
|
||||
6
cln-grpc/src/convert.rs
generated
6
cln-grpc/src/convert.rs
generated
@@ -348,7 +348,7 @@ impl From<responses::CreateinvoiceResponse> for pb::CreateinvoiceResponse {
|
||||
paid_at: c.paid_at, // Rule #2 for type u64?
|
||||
payment_preimage: c.payment_preimage.map(|v| v.to_vec()), // Rule #2 for type secret?
|
||||
local_offer_id: c.local_offer_id.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex?
|
||||
payer_note: c.payer_note, // Rule #2 for type string?
|
||||
invreq_payer_note: c.invreq_payer_note, // Rule #2 for type string?
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,7 +408,7 @@ impl From<responses::DelinvoiceResponse> for pb::DelinvoiceResponse {
|
||||
status: c.status as i32,
|
||||
expires_at: c.expires_at, // Rule #2 for type u64
|
||||
local_offer_id: c.local_offer_id.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex?
|
||||
payer_note: c.payer_note, // Rule #2 for type string?
|
||||
invreq_payer_note: c.invreq_payer_note, // Rule #2 for type string?
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -464,7 +464,7 @@ impl From<responses::ListinvoicesInvoices> for pb::ListinvoicesInvoices {
|
||||
bolt11: c.bolt11, // Rule #2 for type string?
|
||||
bolt12: c.bolt12, // Rule #2 for type string?
|
||||
local_offer_id: c.local_offer_id.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex?
|
||||
payer_note: c.payer_note, // Rule #2 for type string?
|
||||
invreq_payer_note: c.invreq_payer_note, // Rule #2 for type string?
|
||||
pay_index: c.pay_index, // Rule #2 for type u64?
|
||||
amount_received_msat: c.amount_received_msat.map(|f| f.into()), // Rule #2 for type msat?
|
||||
paid_at: c.paid_at, // Rule #2 for type u64?
|
||||
|
||||
12
cln-rpc/src/model.rs
generated
12
cln-rpc/src/model.rs
generated
@@ -2258,8 +2258,8 @@ pub mod responses {
|
||||
pub payment_preimage: Option<Secret>,
|
||||
#[serde(alias = "local_offer_id", skip_serializing_if = "Option::is_none")]
|
||||
pub local_offer_id: Option<String>,
|
||||
#[serde(alias = "payer_note", skip_serializing_if = "Option::is_none")]
|
||||
pub payer_note: Option<String>,
|
||||
#[serde(alias = "invreq_payer_note", skip_serializing_if = "Option::is_none")]
|
||||
pub invreq_payer_note: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<Response> for CreateinvoiceResponse {
|
||||
@@ -2396,8 +2396,8 @@ pub mod responses {
|
||||
pub expires_at: u64,
|
||||
#[serde(alias = "local_offer_id", skip_serializing_if = "Option::is_none")]
|
||||
pub local_offer_id: Option<String>,
|
||||
#[serde(alias = "payer_note", skip_serializing_if = "Option::is_none")]
|
||||
pub payer_note: Option<String>,
|
||||
#[serde(alias = "invreq_payer_note", skip_serializing_if = "Option::is_none")]
|
||||
pub invreq_payer_note: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<Response> for DelinvoiceResponse {
|
||||
@@ -2516,8 +2516,8 @@ pub mod responses {
|
||||
pub bolt12: Option<String>,
|
||||
#[serde(alias = "local_offer_id", skip_serializing_if = "Option::is_none")]
|
||||
pub local_offer_id: Option<String>,
|
||||
#[serde(alias = "payer_note", skip_serializing_if = "Option::is_none")]
|
||||
pub payer_note: Option<String>,
|
||||
#[serde(alias = "invreq_payer_note", skip_serializing_if = "Option::is_none")]
|
||||
pub invreq_payer_note: Option<String>,
|
||||
#[serde(alias = "pay_index", skip_serializing_if = "Option::is_none")]
|
||||
pub pay_index: Option<u64>,
|
||||
#[serde(alias = "amount_received_msat", skip_serializing_if = "Option::is_none")]
|
||||
|
||||
@@ -339,7 +339,7 @@ def createinvoice2py(m):
|
||||
"paid_at": m.paid_at, # PrimitiveField in generate_composite
|
||||
"payment_preimage": hexlify(m.payment_preimage), # PrimitiveField in generate_composite
|
||||
"local_offer_id": hexlify(m.local_offer_id), # PrimitiveField in generate_composite
|
||||
"payer_note": m.payer_note, # PrimitiveField in generate_composite
|
||||
"invreq_payer_note": m.invreq_payer_note, # PrimitiveField in generate_composite
|
||||
})
|
||||
|
||||
|
||||
@@ -384,7 +384,7 @@ def delinvoice2py(m):
|
||||
"status": str(m.status), # EnumField in generate_composite
|
||||
"expires_at": m.expires_at, # PrimitiveField in generate_composite
|
||||
"local_offer_id": hexlify(m.local_offer_id), # PrimitiveField in generate_composite
|
||||
"payer_note": m.payer_note, # PrimitiveField in generate_composite
|
||||
"invreq_payer_note": m.invreq_payer_note, # PrimitiveField in generate_composite
|
||||
})
|
||||
|
||||
|
||||
@@ -428,7 +428,7 @@ def listinvoices_invoices2py(m):
|
||||
"bolt11": m.bolt11, # PrimitiveField in generate_composite
|
||||
"bolt12": m.bolt12, # PrimitiveField in generate_composite
|
||||
"local_offer_id": hexlify(m.local_offer_id), # PrimitiveField in generate_composite
|
||||
"payer_note": m.payer_note, # PrimitiveField in generate_composite
|
||||
"invreq_payer_note": m.invreq_payer_note, # PrimitiveField in generate_composite
|
||||
"pay_index": m.pay_index, # PrimitiveField in generate_composite
|
||||
"amount_received_msat": amount2msat(m.amount_received_msat), # PrimitiveField in generate_composite
|
||||
"paid_at": m.paid_at, # PrimitiveField in generate_composite
|
||||
|
||||
468
contrib/pyln-testing/pyln/testing/node_pb2.py
generated
468
contrib/pyln-testing/pyln/testing/node_pb2.py
generated
File diff suppressed because one or more lines are too long
@@ -46,7 +46,7 @@ On success, an object is returned, containing:
|
||||
- **paid\_at** (u64, optional): UNIX timestamp of when invoice was paid (**status** *paid* only)
|
||||
- **payment\_preimage** (secret, optional): the proof of payment: SHA256 of this **payment_hash** (always 64 characters)
|
||||
- **local\_offer\_id** (hex, optional): the *id* of our offer which created this invoice (**experimental-offers** only). (always 64 characters)
|
||||
- **payer\_note** (string, optional): the optional *payer_note* from invoice_request which created this invoice (**experimental-offers** only).
|
||||
- **invreq\_payer\_note** (string, optional): the optional *invreq_payer_note* from invoice_request which created this invoice (**experimental-offers** only).
|
||||
|
||||
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
||||
|
||||
@@ -75,4 +75,4 @@ RESOURCES
|
||||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:9fc2c7cb6e5980774a768dd9ddfe81e254c084554c159e6b07e92e703dc10595)
|
||||
[comment]: # ( SHA256STAMP:3acf2924a8670605f70a7976cf4909b60addf4b1aeebc9b9a104151cffa2c984)
|
||||
|
||||
@@ -29,127 +29,202 @@ On success, an object is returned, containing:
|
||||
|
||||
If **type** is "bolt12 offer", and **valid** is *true*:
|
||||
|
||||
- **offer\_id** (hex): the id of this offer (merkle hash of non-signature fields) (always 64 characters)
|
||||
- **node\_id** (pubkey): public key of the offering node
|
||||
- **description** (string): the description of the purpose of the offer
|
||||
- **signature** (bip340sig, optional): BIP-340 signature of the *node_id* on this offer
|
||||
- **chains** (array of hexs, optional): which blockchains this offer is for (missing implies bitcoin mainnet only):
|
||||
- **offer\_id** (hex): the id we use to identify this offer (always 64 characters)
|
||||
- **offer\_description** (string): the description of the purpose of the offer
|
||||
- **offer\_node\_id** (pubkey): public key of the offering node
|
||||
- **offer\_chains** (array of hexs, optional): which blockchains this offer is for (missing implies bitcoin mainnet only):
|
||||
- the genesis blockhash (always 64 characters)
|
||||
- **currency** (string, optional): ISO 4217 code of the currency (missing implies Bitcoin) (always 3 characters)
|
||||
- **minor\_unit** (u32, optional): the number of decimal places to apply to amount (if currency known)
|
||||
- **amount** (u64, optional): the amount in the *currency* adjusted by *minor_unit*, if any
|
||||
- **amount\_msat** (msat, optional): the amount in bitcoin (if specified, and no *currency*)
|
||||
- **send\_invoice** (boolean, optional): present if this is a send_invoice offer (always *true*)
|
||||
- **refund\_for** (hex, optional): the *payment_preimage* of invoice this is a refund for (always 64 characters)
|
||||
- **vendor** (string, optional): the name of the vendor for this offer
|
||||
- **features** (hex, optional): the array of feature bits for this offer
|
||||
- **absolute\_expiry** (u64, optional): UNIX timestamp of when this offer expires
|
||||
- **paths** (array of objects, optional): Paths to the destination:
|
||||
- **offer\_metadata** (hex, optional): any metadata the creater of the offer includes
|
||||
- **offer\_currency** (string, optional): ISO 4217 code of the currency (missing implies Bitcoin) (always 3 characters)
|
||||
- **currency\_minor\_unit** (u32, optional): the number of decimal places to apply to amount (if currency known)
|
||||
- **offer\_amount** (u64, optional): the amount in the `offer_currency` adjusted by `currency_minor_unit`, if any
|
||||
- **offer\_amount\_msat** (msat, optional): the amount in bitcoin (if specified, and no `offer_currency`)
|
||||
- **offer\_issuer** (string, optional): the description of the creator of the offer
|
||||
- **offer\_features** (hex, optional): the feature bits of the offer
|
||||
- **offer\_absolute\_expiry** (u64, optional): UNIX timestamp of when this offer expires
|
||||
- **offer\_quantity\_max** (u64, optional): the maximum quantity (or, if 0, means any quantity)
|
||||
- **offer\_paths** (array of objects, optional): Paths to the destination:
|
||||
- **first\_node\_id** (pubkey): the (presumably well-known) public key of the start of the path
|
||||
- **blinding** (pubkey): blinding factor for this path
|
||||
- **path** (array of objects): an individual path:
|
||||
- **blinded\_node\_id** (pubkey): node_id of the hop
|
||||
- **encrypted\_recipient\_data** (hex): encrypted TLV entry for this hop
|
||||
- **quantity\_max** (u64, optional): the maximum quantity (or, if 0, means any quantity)
|
||||
- **recurrence** (object, optional): how often to this offer should be used:
|
||||
- **offer\_recurrence** (object, optional): how often to this offer should be used:
|
||||
- **time\_unit** (u32): the BOLT12 time unit
|
||||
- **period** (u32): how many *time_unit* per payment period
|
||||
- **time\_unit\_name** (string, optional): the name of *time_unit* (if valid)
|
||||
- **period** (u32): how many `time_unit` per payment period
|
||||
- **time\_unit\_name** (string, optional): the name of `time_unit` (if valid)
|
||||
- **basetime** (u64, optional): period starts at this UNIX timestamp
|
||||
- **start\_any\_period** (u64, optional): you can start at any period (only if **basetime** present)
|
||||
- **start\_any\_period** (u64, optional): you can start at any period (only if `basetime` present)
|
||||
- **limit** (u32, optional): maximum period number for recurrence
|
||||
- **paywindow** (object, optional): when within a period will payment be accepted (default is prior and during the period):
|
||||
- **seconds\_before** (u32): seconds prior to period start
|
||||
- **seconds\_after** (u32): seconds after to period start
|
||||
- **proportional\_amount** (boolean, optional): amount should be scaled if payed after period start (always *true*)
|
||||
- the following warnings are possible:
|
||||
- **warning\_offer\_unknown\_currency**: The currency code is unknown (so no **minor_unit**)
|
||||
- **warning\_unknown\_offer\_currency**: The currency code is unknown (so no `currency_minor_unit`)
|
||||
|
||||
If **type** is "bolt12 offer", and **valid** is *false*:
|
||||
|
||||
- the following warnings are possible:
|
||||
- **warning\_offer\_missing\_description**: No **description**
|
||||
- **warning\_missing\_offer\_node\_id**: `offer_node_id` is not present
|
||||
- **warning\_invalid\_offer\_description**: `offer_description` is not valid UTF8
|
||||
- **warning\_missing\_offer\_description**: `offer_description` is not present
|
||||
- **warning\_invalid\_offer\_currency**: `offer_currency_code` is not valid UTF8
|
||||
- **warning\_invalid\_offer\_issuer**: `offer_issuer` is not valid UTF8
|
||||
|
||||
If **type** is "bolt12 invoice", and **valid** is *true*:
|
||||
If **type** is "bolt12 invoice_request", and **valid** is *true*:
|
||||
|
||||
- **node\_id** (pubkey): public key of the offering node
|
||||
- **signature** (bip340sig): BIP-340 signature of the *node_id* on this invoice
|
||||
- **amount\_msat** (msat): the amount in bitcoin
|
||||
- **description** (string): the description of the purpose of the offer
|
||||
- **created\_at** (u64): the UNIX timestamp of invoice creation
|
||||
- **payment\_hash** (hex): the hash of the *payment_preimage* (always 64 characters)
|
||||
- **relative\_expiry** (u32): the number of seconds after *created_at* when this expires
|
||||
- **offer\_id** (hex, optional): the id of this offer (merkle hash of non-signature fields) (always 64 characters)
|
||||
- **chain** (hex, optional): which blockchain this invoice is for (missing implies bitcoin mainnet only) (always 64 characters)
|
||||
- **send\_invoice** (boolean, optional): present if this offer was a send_invoice offer (always *true*)
|
||||
- **refund\_for** (hex, optional): the *payment_preimage* of invoice this is a refund for (always 64 characters)
|
||||
- **vendor** (string, optional): the name of the vendor for this offer
|
||||
- **features** (hex, optional): the array of feature bits for this offer
|
||||
- **paths** (array of objects, optional): Paths to the destination:
|
||||
- **offer\_description** (string): the description of the purpose of the offer
|
||||
- **offer\_node\_id** (pubkey): public key of the offering node
|
||||
- **invreq\_metadata** (hex): the payer-provided blob to derive invreq_payer_id
|
||||
- **invreq\_payer\_id** (hex): the payer-provided key
|
||||
- **signature** (bip340sig): BIP-340 signature of the `invreq_payer_id` on this invoice_request
|
||||
- **offer\_id** (hex, optional): the id we use to identify this offer (always 64 characters)
|
||||
- **offer\_chains** (array of hexs, optional): which blockchains this offer is for (missing implies bitcoin mainnet only):
|
||||
- the genesis blockhash (always 64 characters)
|
||||
- **offer\_metadata** (hex, optional): any metadata the creator of the offer includes
|
||||
- **offer\_currency** (string, optional): ISO 4217 code of the currency (missing implies Bitcoin) (always 3 characters)
|
||||
- **currency\_minor\_unit** (u32, optional): the number of decimal places to apply to amount (if currency known)
|
||||
- **offer\_amount** (u64, optional): the amount in the `offer_currency` adjusted by `currency_minor_unit`, if any
|
||||
- **offer\_amount\_msat** (msat, optional): the amount in bitcoin (if specified, and no `offer_currency`)
|
||||
- **offer\_issuer** (string, optional): the description of the creator of the offer
|
||||
- **offer\_features** (hex, optional): the feature bits of the offer
|
||||
- **offer\_absolute\_expiry** (u64, optional): UNIX timestamp of when this offer expires
|
||||
- **offer\_quantity\_max** (u64, optional): the maximum quantity (or, if 0, means any quantity)
|
||||
- **offer\_paths** (array of objects, optional): Paths to the destination:
|
||||
- **first\_node\_id** (pubkey): the (presumably well-known) public key of the start of the path
|
||||
- **blinding** (pubkey): blinding factor for this path
|
||||
- **path** (array of objects): an individual path:
|
||||
- **blinded\_node\_id** (pubkey): node_id of the hop
|
||||
- **encrypted\_recipient\_data** (hex): encrypted TLV entry for this hop
|
||||
- **fee\_base\_msat** (msat, optional): base fee for the entire path
|
||||
- **fee\_proportional\_millionths** (u32, optional): proportional fee for the entire path
|
||||
- **cltv\_expiry\_delta** (u32, optional): total CLTV delta across path
|
||||
- **features** (hex, optional): Features allowed/required for this path
|
||||
- **quantity** (u64, optional): the quantity ordered
|
||||
- **recurrence\_counter** (u32, optional): the 0-based counter for a recurring payment
|
||||
- **recurrence\_start** (u32, optional): the optional start period for a recurring payment
|
||||
- **recurrence\_basetime** (u32, optional): the UNIX timestamp of the first recurrence period start
|
||||
- **payer\_key** (pubkey, optional): the transient key which identifies the payer
|
||||
- **invreq\_metadata** (hex, optional): the payer-provided blob to derive payer_key
|
||||
- **fallbacks** (array of objects, optional): onchain addresses:
|
||||
- **offer\_recurrence** (object, optional): how often to this offer should be used:
|
||||
- **time\_unit** (u32): the BOLT12 time unit
|
||||
- **period** (u32): how many `time_unit` per payment period
|
||||
- **time\_unit\_name** (string, optional): the name of `time_unit` (if valid)
|
||||
- **basetime** (u64, optional): period starts at this UNIX timestamp
|
||||
- **start\_any\_period** (u64, optional): you can start at any period (only if `basetime` present)
|
||||
- **limit** (u32, optional): maximum period number for recurrence
|
||||
- **paywindow** (object, optional): when within a period will payment be accepted (default is prior and during the period):
|
||||
- **seconds\_before** (u32): seconds prior to period start
|
||||
- **seconds\_after** (u32): seconds after to period start
|
||||
- **proportional\_amount** (boolean, optional): amount should be scaled if payed after period start (always *true*)
|
||||
- **invreq\_chain** (hex, optional): which blockchain this offer is for (missing implies bitcoin mainnet only) (always 64 characters)
|
||||
- **invreq\_amount\_msat** (msat, optional): the amount the invoice should be for
|
||||
- **invreq\_features** (hex, optional): the feature bits of the invoice_request
|
||||
- **invreq\_quantity** (u64, optional): the number of items to invoice for
|
||||
- **invreq\_payer\_note** (string, optional): a note attached by the payer
|
||||
- **invreq\_recurrence\_counter** (u32, optional): which number request this is for the same invoice
|
||||
- **invreq\_recurrence\_start** (u32, optional): when we're requesting to start an invoice at a non-zero period
|
||||
- the following warnings are possible:
|
||||
- **warning\_unknown\_offer\_currency**: The currency code is unknown (so no `currency_minor_unit`)
|
||||
|
||||
If **type** is "bolt12 invoice_request", and **valid** is *false*:
|
||||
|
||||
- the following warnings are possible:
|
||||
- **warning\_invalid\_offer\_description**: `offer_description` is not valid UTF8
|
||||
- **warning\_missing\_offer\_description**: `offer_description` is not present
|
||||
- **warning\_invalid\_offer\_currency**: `offer_currency_code` is not valid UTF8
|
||||
- **warning\_invalid\_offer\_issuer**: `offer_issuer` is not valid UTF8
|
||||
- **warning\_missing\_invreq\_metadata**: `invreq_metadata` is not present
|
||||
- **warning\_missing\_invreq\_payer\_id**: `invreq_payer_id` is not present
|
||||
- **warning\_invalid\_invreq\_payer\_note**: `invreq_payer_note` is not valid UTF8
|
||||
- **warning\_missing\_invoice\_request\_signature**: `signature` is not present
|
||||
- **warning\_invalid\_invoice\_request\_signature**: Incorrect `signature`
|
||||
|
||||
If **type** is "bolt12 invoice", and **valid** is *true*:
|
||||
|
||||
- **offer\_description** (string): the description of the purpose of the offer
|
||||
- **offer\_node\_id** (pubkey): public key of the offering node
|
||||
- **invreq\_metadata** (hex): the payer-provided blob to derive invreq_payer_id
|
||||
- **invreq\_payer\_id** (hex): the payer-provided key
|
||||
- **invoice\_paths** (array of objects): Paths to pay the destination:
|
||||
- **first\_node\_id** (pubkey): the (presumably well-known) public key of the start of the path
|
||||
- **blinding** (pubkey): blinding factor for this path
|
||||
- **path** (array of objects): an individual path:
|
||||
- **blinded\_node\_id** (pubkey): node_id of the hop
|
||||
- **encrypted\_recipient\_data** (hex): encrypted TLV entry for this hop
|
||||
- **fee\_base\_msat** (msat, optional): basefee for path
|
||||
- **fee\_proportional\_millionths** (u32, optional): proportional fee for path
|
||||
- **cltv\_expiry\_delta** (u32, optional): CLTV delta for path
|
||||
- **features** (hex, optional): features allowed for path
|
||||
- **invoice\_created\_at** (u64): the UNIX timestamp of invoice creation
|
||||
- **invoice\_payment\_hash** (hex): the hash of the *payment_preimage* (always 64 characters)
|
||||
- **invoice\_amount\_msat** (msat): the amount required to fulfill invoice
|
||||
- **signature** (bip340sig): BIP-340 signature of the `offer_node_id` on this invoice
|
||||
- **offer\_id** (hex, optional): the id we use to identify this offer (always 64 characters)
|
||||
- **offer\_chains** (array of hexs, optional): which blockchains this offer is for (missing implies bitcoin mainnet only):
|
||||
- the genesis blockhash (always 64 characters)
|
||||
- **offer\_metadata** (hex, optional): any metadata the creator of the offer includes
|
||||
- **offer\_currency** (string, optional): ISO 4217 code of the currency (missing implies Bitcoin) (always 3 characters)
|
||||
- **currency\_minor\_unit** (u32, optional): the number of decimal places to apply to amount (if currency known)
|
||||
- **offer\_amount** (u64, optional): the amount in the `offer_currency` adjusted by `currency_minor_unit`, if any
|
||||
- **offer\_amount\_msat** (msat, optional): the amount in bitcoin (if specified, and no `offer_currency`)
|
||||
- **offer\_issuer** (string, optional): the description of the creator of the offer
|
||||
- **offer\_features** (hex, optional): the feature bits of the offer
|
||||
- **offer\_absolute\_expiry** (u64, optional): UNIX timestamp of when this offer expires
|
||||
- **offer\_quantity\_max** (u64, optional): the maximum quantity (or, if 0, means any quantity)
|
||||
- **offer\_paths** (array of objects, optional): Paths to the destination:
|
||||
- **first\_node\_id** (pubkey): the (presumably well-known) public key of the start of the path
|
||||
- **blinding** (pubkey): blinding factor for this path
|
||||
- **path** (array of objects): an individual path:
|
||||
- **blinded\_node\_id** (pubkey): node_id of the hop
|
||||
- **encrypted\_recipient\_data** (hex): encrypted TLV entry for this hop
|
||||
- **offer\_recurrence** (object, optional): how often to this offer should be used:
|
||||
- **time\_unit** (u32): the BOLT12 time unit
|
||||
- **period** (u32): how many `time_unit` per payment period
|
||||
- **time\_unit\_name** (string, optional): the name of `time_unit` (if valid)
|
||||
- **basetime** (u64, optional): period starts at this UNIX timestamp
|
||||
- **start\_any\_period** (u64, optional): you can start at any period (only if `basetime` present)
|
||||
- **limit** (u32, optional): maximum period number for recurrence
|
||||
- **paywindow** (object, optional): when within a period will payment be accepted (default is prior and during the period):
|
||||
- **seconds\_before** (u32): seconds prior to period start
|
||||
- **seconds\_after** (u32): seconds after to period start
|
||||
- **proportional\_amount** (boolean, optional): amount should be scaled if payed after period start (always *true*)
|
||||
- **invreq\_chain** (hex, optional): which blockchain this offer is for (missing implies bitcoin mainnet only) (always 64 characters)
|
||||
- **invreq\_amount\_msat** (msat, optional): the amount the invoice should be for
|
||||
- **invreq\_features** (hex, optional): the feature bits of the invoice_request
|
||||
- **invreq\_quantity** (u64, optional): the number of items to invoice for
|
||||
- **invreq\_payer\_note** (string, optional): a note attached by the payer
|
||||
- **invreq\_recurrence\_counter** (u32, optional): which number request this is for the same invoice
|
||||
- **invreq\_recurrence\_start** (u32, optional): when we're requesting to start an invoice at a non-zero period
|
||||
- **invoice\_relative\_expiry** (u32, optional): the number of seconds after *invoice_created_at* when this expires
|
||||
- **invoice\_fallbacks** (array of objects, optional): onchain addresses:
|
||||
- **version** (u8): Segwit address version
|
||||
- **hex** (hex): Raw encoded segwit address
|
||||
- **address** (string, optional): bech32 segwit address
|
||||
- **refund\_signature** (bip340sig, optional): the payer key signature to get a refund
|
||||
- **invoice\_features** (hex, optional): the feature bits of the invoice
|
||||
- **invoice\_node\_id** (pubkey, optional): the id to pay (usually the same as offer_node_id)
|
||||
- **invoice\_recurrence\_basetime** (u64, optional): the UNIX timestamp to base the invoice periods on
|
||||
- the following warnings are possible:
|
||||
- **warning\_unknown\_offer\_currency**: The currency code is unknown (so no `currency_minor_unit`)
|
||||
|
||||
If **type** is "bolt12 invoice", and **valid** is *false*:
|
||||
|
||||
- **fallbacks** (array of objects, optional):
|
||||
- the following warnings are possible:
|
||||
- **warning\_invoice\_fallbacks\_version\_invalid**: **version** is > 16
|
||||
- **warning\_invoice\_fallbacks\_version\_invalid**: `version` is > 16
|
||||
- the following warnings are possible:
|
||||
- **warning\_invoice\_missing\_amount**: **amount_msat* missing
|
||||
- **warning\_invoice\_missing\_description**: No **description**
|
||||
- **warning\_invoice\_missing\_blinded\_payinfo**: Has **paths** without payinfo
|
||||
- **warning\_invoice\_invalid\_blinded\_payinfo**: Does not have exactly one payinfo for each of **paths**
|
||||
- **warning\_invoice\_missing\_recurrence\_basetime**: Has **recurrence_counter** without **recurrence_basetime**
|
||||
- **warning\_invoice\_missing\_created\_at**: Missing **created_at**
|
||||
- **warning\_invoice\_missing\_payment\_hash**: Missing **payment_hash**
|
||||
- **warning\_invoice\_refund\_signature\_missing\_payer\_key**: Missing **payer_key** for refund_signature
|
||||
- **warning\_invoice\_refund\_signature\_invalid**: **refund_signature** incorrect
|
||||
- **warning\_invoice\_refund\_missing\_signature**: No **refund_signature**
|
||||
|
||||
If **type** is "bolt12 invoice_request", and **valid** is *true*:
|
||||
|
||||
- **offer\_id** (hex): the id of the offer this is requesting (merkle hash of non-signature fields) (always 64 characters)
|
||||
- **payer\_key** (pubkey): the transient key which identifies the payer
|
||||
- **chain** (hex, optional): which blockchain this invoice_request is for (missing implies bitcoin mainnet only) (always 64 characters)
|
||||
- **amount\_msat** (msat, optional): the amount in bitcoin
|
||||
- **features** (hex, optional): the array of feature bits for this offer
|
||||
- **quantity** (u64, optional): the quantity ordered
|
||||
- **recurrence\_counter** (u32, optional): the 0-based counter for a recurring payment
|
||||
- **recurrence\_start** (u32, optional): the optional start period for a recurring payment
|
||||
- **invreq\_metadata** (hex, optional): the payer-provided blob to derive payer_key
|
||||
- **recurrence\_signature** (bip340sig, optional): the payer key signature
|
||||
|
||||
If **type** is "bolt12 invoice_request", and **valid** is *false*:
|
||||
|
||||
- the following warnings are possible:
|
||||
- **warning\_invoice\_request\_missing\_offer\_id**: No **offer_id**
|
||||
- **warning\_invoice\_request\_missing\_payer\_key**: No **payer_key**
|
||||
- **warning\_invoice\_request\_missing\_recurrence\_signature**: No **recurrence_signature**
|
||||
- **warning\_invoice\_request\_invalid\_recurrence\_signature**: **recurrence_signature** incorrect
|
||||
- **warning\_invalid\_offer\_description**: `offer_description` is not valid UTF8
|
||||
- **warning\_missing\_offer\_description**: `offer_description` is not present
|
||||
- **warning\_invalid\_offer\_currency**: `offer_currency_code` is not valid UTF8
|
||||
- **warning\_invalid\_offer\_issuer**: `offer_issuer` is not valid UTF8
|
||||
- **warning\_missing\_invreq\_metadata**: `invreq_metadata` is not present
|
||||
- **warning\_invalid\_invreq\_payer\_note**: `invreq_payer_note` is not valid UTF8
|
||||
- **warning\_missing\_invoice\_paths**: `invoice_paths` is not present
|
||||
- **warning\_missing\_invoice\_blindedpay**: `invoice_blindedpay` is not present
|
||||
- **warning\_missing\_invoice\_created\_at**: `invoice_created_at` is not present
|
||||
- **warning\_missing\_invoice\_payment\_hash**: `invoice_payment_hash` is not present
|
||||
- **warning\_missing\_invoice\_amount**: `invoice_amount` is not present
|
||||
- **warning\_missing\_invoice\_recurrence\_basetime**: `invoice_recurrence_basetime` is not present
|
||||
- **warning\_missing\_invoice\_node\_id**: `invoice_node_id` is not present
|
||||
- **warning\_missing\_invoice\_signature**: `signature` is not present
|
||||
- **warning\_invalid\_invoice\_signature**: Incorrect `signature`
|
||||
|
||||
If **type** is "bolt11 invoice", and **valid** is *true*:
|
||||
|
||||
- **currency** (string): the BIP173 name for the currency
|
||||
- **created\_at** (u64): the UNIX-style timestamp of the invoice
|
||||
- **expiry** (u64): the number of seconds this is valid after *timestamp*
|
||||
- **expiry** (u64): the number of seconds this is valid after `created_at`
|
||||
- **payee** (pubkey): the public key of the recipient
|
||||
- **payment\_hash** (hex): the hash of the *payment_preimage* (always 64 characters)
|
||||
- **signature** (signature): signature of the *payee* on this invoice
|
||||
@@ -215,4 +290,4 @@ RESOURCES
|
||||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:3f0c78dd665bff6749352801b0fdd958ee138fda6ede5b3631d9cb136fc45d76)
|
||||
[comment]: # ( SHA256STAMP:e5791741d8b466b2f080dcde3e5a7770ce3a820d0b7e5635e6b6cfd1f104c09d)
|
||||
|
||||
@@ -39,7 +39,7 @@ On success, an object is returned, containing:
|
||||
If **bolt12** is present:
|
||||
|
||||
- **local\_offer\_id** (hex, optional): offer for which this invoice was created
|
||||
- **payer\_note** (string, optional): the optional *payer_note* from invoice_request which created this invoice
|
||||
- **invreq\_payer\_note** (string, optional): the optional *invreq_payer_note* from invoice_request which created this invoice
|
||||
|
||||
If **status** is "paid":
|
||||
|
||||
@@ -81,4 +81,4 @@ RESOURCES
|
||||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:d754daa61ddb65009fced566338af35ffb23069593f4741e6d8f6f138f60bb4f)
|
||||
[comment]: # ( SHA256STAMP:961571f6b2155f0452ac376bdf957474dd20e97e05a89efdf590f6e4da310f4f)
|
||||
|
||||
@@ -32,7 +32,7 @@ On success, an object containing **invoices** is returned. It is an array of ob
|
||||
- **bolt11** (string, optional): the BOLT11 string (always present unless *bolt12* is)
|
||||
- **bolt12** (string, optional): the BOLT12 string (always present unless *bolt11* is)
|
||||
- **local\_offer\_id** (hex, optional): the *id* of our offer which created this invoice (**experimental-offers** only). (always 64 characters)
|
||||
- **payer\_note** (string, optional): the optional *payer_note* from invoice_request which created this invoice (**experimental-offers** only).
|
||||
- **invreq\_payer\_note** (string, optional): the optional *invreq_payer_note* from invoice_request which created this invoice (**experimental-offers** only).
|
||||
|
||||
If **status** is "paid":
|
||||
|
||||
@@ -58,4 +58,4 @@ RESOURCES
|
||||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:58de6b2fa9e3e796689618bf92a78dac66bb6cfe941d099abd73da3e41bfa60e)
|
||||
[comment]: # ( SHA256STAMP:5c64a05bbf7485840010b16005c6f5d57725e4b0bf0a2a2106febe91ff0d4eb8)
|
||||
|
||||
@@ -73,9 +73,9 @@
|
||||
"maxLength": 64,
|
||||
"minLength": 64
|
||||
},
|
||||
"payer_note": {
|
||||
"invreq_payer_note": {
|
||||
"type": "string",
|
||||
"description": "the optional *payer_note* from invoice_request which created this invoice (**experimental-offers** only)."
|
||||
"description": "the optional *invreq_payer_note* from invoice_request which created this invoice (**experimental-offers** only)."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -79,9 +79,9 @@
|
||||
"type": "hex",
|
||||
"description": "offer for which this invoice was created"
|
||||
},
|
||||
"payer_note": {
|
||||
"invreq_payer_note": {
|
||||
"type": "string",
|
||||
"description": "the optional *payer_note* from invoice_request which created this invoice"
|
||||
"description": "the optional *invreq_payer_note* from invoice_request which created this invoice"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -136,7 +136,7 @@
|
||||
"amount_msat": {},
|
||||
"description": {},
|
||||
"payment_hash": {},
|
||||
"payer_note": {},
|
||||
"invreq_payer_note": {},
|
||||
"local_offer_id": {},
|
||||
"pay_index": {
|
||||
"type": "u64",
|
||||
@@ -174,7 +174,7 @@
|
||||
"payment_hash": {},
|
||||
"expires_at": {},
|
||||
"pay_index": {},
|
||||
"payer_note": {},
|
||||
"invreq_payer_note": {},
|
||||
"local_offer_id": {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
"maxLength": 64,
|
||||
"minLength": 64
|
||||
},
|
||||
"payer_note": {
|
||||
"invreq_payer_note": {
|
||||
"type": "string",
|
||||
"description": "the optional *payer_note* from invoice_request which created this invoice (**experimental-offers** only)."
|
||||
"description": "the optional *invreq_payer_note* from invoice_request which created this invoice (**experimental-offers** only)."
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
@@ -101,7 +101,7 @@
|
||||
"bolt11": {},
|
||||
"bolt12": {},
|
||||
"local_offer_id": {},
|
||||
"payer_note": {},
|
||||
"invreq_payer_note": {},
|
||||
"expires_at": {},
|
||||
"pay_index": {
|
||||
"type": "u64",
|
||||
@@ -138,7 +138,7 @@
|
||||
"bolt11": {},
|
||||
"bolt12": {},
|
||||
"local_offer_id": {},
|
||||
"payer_note": {},
|
||||
"invreq_payer_note": {},
|
||||
"expires_at": {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,9 +70,8 @@ static void json_add_invoice_fields(struct json_stream *response,
|
||||
tinv = invoice_decode(tmpctx,
|
||||
inv->invstring, strlen(inv->invstring),
|
||||
NULL, NULL, &fail);
|
||||
/* FIXME-OFFERS: Rename all fields to offer_ as per spec */
|
||||
if (tinv && tinv->invreq_payer_note)
|
||||
json_add_stringn(response, "payer_note",
|
||||
json_add_stringn(response, "invreq_payer_note",
|
||||
tinv->invreq_payer_note,
|
||||
tal_bytelen(tinv->invreq_payer_note));
|
||||
}
|
||||
|
||||
@@ -1136,7 +1136,7 @@ static struct command_result *json_fetchinvoice(struct command *cmd,
|
||||
invreq->invreq_features
|
||||
= plugin_feature_set(cmd->plugin)->bits[BOLT12_OFFER_FEATURE];
|
||||
|
||||
/* invreq->payer_note is not a nul-terminated string! */
|
||||
/* invreq->invreq_payer_note is not a nul-terminated string! */
|
||||
if (payer_note)
|
||||
invreq->invreq_payer_note = tal_dup_arr(invreq, utf8,
|
||||
payer_note,
|
||||
|
||||
567
plugins/offers.c
567
plugins/offers.c
@@ -230,9 +230,10 @@ static struct command_result *param_decodable(struct command *cmd,
|
||||
}
|
||||
|
||||
static void json_add_chains(struct json_stream *js,
|
||||
const char *fieldname,
|
||||
const struct bitcoin_blkid *chains)
|
||||
{
|
||||
json_array_start(js, "chains");
|
||||
json_array_start(js, fieldname);
|
||||
for (size_t i = 0; i < tal_count(chains); i++)
|
||||
json_add_sha256(js, NULL, &chains[i].shad.sha);
|
||||
json_array_end(js);
|
||||
@@ -247,7 +248,8 @@ static void json_add_onionmsg_path(struct json_stream *js,
|
||||
json_add_pubkey(js, "blinded_node_id", &hop->blinded_node_id);
|
||||
json_add_hex_talarr(js, "encrypted_recipient_data", hop->encrypted_recipient_data);
|
||||
if (payinfo) {
|
||||
json_add_u32(js, "fee_base_msat", payinfo->fee_base_msat);
|
||||
json_add_amount_msat_only(js, "fee_base_msat",
|
||||
amount_msat(payinfo->fee_base_msat));
|
||||
json_add_u32(js, "fee_proportional_millionths",
|
||||
payinfo->fee_proportional_millionths);
|
||||
json_add_u32(js, "cltv_expiry_delta",
|
||||
@@ -259,11 +261,12 @@ static void json_add_onionmsg_path(struct json_stream *js,
|
||||
|
||||
/* Returns true if valid */
|
||||
static bool json_add_blinded_paths(struct json_stream *js,
|
||||
const char *fieldname,
|
||||
struct blinded_path **paths,
|
||||
struct blinded_payinfo **blindedpay)
|
||||
{
|
||||
size_t n = 0;
|
||||
json_array_start(js, "paths");
|
||||
json_array_start(js, fieldname);
|
||||
for (size_t i = 0; i < tal_count(paths); i++) {
|
||||
json_object_start(js, NULL);
|
||||
json_add_pubkey(js, "first_node_id", &paths[i]->first_node_id);
|
||||
@@ -286,7 +289,7 @@ static bool json_add_blinded_paths(struct json_stream *js,
|
||||
* `blinded_path`.
|
||||
*/
|
||||
if (blindedpay && n != tal_count(blindedpay)) {
|
||||
json_add_string(js, "warning_invoice_invalid_blinded_payinfo",
|
||||
json_add_string(js, "warning_invalid_invoice_blindedpay",
|
||||
"invoice does not have correct number of blinded_payinfo");
|
||||
return false;
|
||||
}
|
||||
@@ -312,33 +315,57 @@ static const char *recurrence_time_unit_name(u8 time_unit)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void json_add_offer(struct json_stream *js, const struct tlv_offer *offer)
|
||||
static bool json_add_utf8(struct json_stream *js,
|
||||
const char *fieldname,
|
||||
const char *utf8str)
|
||||
{
|
||||
if (utf8_check(utf8str, tal_bytelen(utf8str))) {
|
||||
json_add_stringn(js, fieldname, utf8str, tal_bytelen(utf8str));
|
||||
return true;
|
||||
}
|
||||
json_add_string(js, tal_fmt(tmpctx, "warning_invalid_%s", fieldname),
|
||||
"invalid UTF8");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool json_add_offer_fields(struct json_stream *js,
|
||||
const struct bitcoin_blkid *offer_chains,
|
||||
const u8 *offer_metadata,
|
||||
const char *offer_currency,
|
||||
const u64 *offer_amount,
|
||||
const char *offer_description,
|
||||
const u8 *offer_features,
|
||||
const u64 *offer_absolute_expiry,
|
||||
struct blinded_path **offer_paths,
|
||||
const char *offer_issuer,
|
||||
const u64 *offer_quantity_max,
|
||||
const struct pubkey *offer_node_id,
|
||||
const struct recurrence *offer_recurrence,
|
||||
const struct recurrence_paywindow *offer_recurrence_paywindow,
|
||||
const u32 *offer_recurrence_limit,
|
||||
const struct recurrence_base *offer_recurrence_base)
|
||||
{
|
||||
struct sha256 offer_id;
|
||||
bool valid = true;
|
||||
|
||||
/* FIXME-OFFERS: Rename all fields to offer_ as per spec */
|
||||
offer_offer_id(offer, &offer_id);
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
if (offer->offer_chains)
|
||||
json_add_chains(js, offer->offer_chains);
|
||||
if (offer->offer_currency) {
|
||||
if (offer_chains)
|
||||
json_add_chains(js, "offer_chains", offer_chains);
|
||||
if (offer_metadata)
|
||||
json_add_hex_talarr(js, "offer_metadata", offer_metadata);
|
||||
if (offer_currency) {
|
||||
const struct iso4217_name_and_divisor *iso4217;
|
||||
json_add_stringn(js, "currency",
|
||||
offer->offer_currency,
|
||||
tal_bytelen(offer->offer_currency));
|
||||
if (offer->offer_amount)
|
||||
json_add_u64(js, "amount", *offer->offer_amount);
|
||||
iso4217 = find_iso4217(offer->offer_currency,
|
||||
tal_bytelen(offer->offer_currency));
|
||||
valid &= json_add_utf8(js, "offer_currency", offer_currency);
|
||||
if (offer_amount)
|
||||
json_add_u64(js, "offer_amount", *offer_amount);
|
||||
iso4217 = find_iso4217(offer_currency,
|
||||
tal_bytelen(offer_currency));
|
||||
if (iso4217)
|
||||
json_add_num(js, "minor_unit", iso4217->minor_unit);
|
||||
json_add_num(js, "currency_minor_unit", iso4217->minor_unit);
|
||||
else
|
||||
json_add_string(js, "warning_offer_unknown_currency",
|
||||
json_add_string(js, "warning_unknown_offer_currency",
|
||||
"unknown currency code");
|
||||
} else if (offer->offer_amount)
|
||||
json_add_amount_msat_only(js, "amount_msat",
|
||||
amount_msat(*offer->offer_amount));
|
||||
} else if (offer_amount)
|
||||
json_add_amount_msat_only(js, "offer_amount_msat",
|
||||
amount_msat(*offer_amount));
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* A reader of an offer:
|
||||
@@ -346,71 +373,153 @@ static void json_add_offer(struct json_stream *js, const struct tlv_offer *offer
|
||||
* - if `offer_description` is not set:
|
||||
* - MUST NOT respond to the offer.
|
||||
*/
|
||||
if (offer->offer_description)
|
||||
json_add_stringn(js, "description",
|
||||
offer->offer_description,
|
||||
tal_bytelen(offer->offer_description));
|
||||
if (offer_description)
|
||||
valid &= json_add_utf8(js, "offer_description",
|
||||
offer_description);
|
||||
else {
|
||||
json_add_string(js, "warning_offer_missing_description",
|
||||
json_add_string(js, "warning_missing_offer_description",
|
||||
"offers without a description are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (offer->offer_issuer)
|
||||
json_add_stringn(js, "issuer", offer->offer_issuer,
|
||||
tal_bytelen(offer->offer_issuer));
|
||||
if (offer->offer_features)
|
||||
json_add_hex_talarr(js, "features", offer->offer_features);
|
||||
if (offer->offer_absolute_expiry)
|
||||
json_add_u64(js, "absolute_expiry",
|
||||
*offer->offer_absolute_expiry);
|
||||
if (offer->offer_paths)
|
||||
valid &= json_add_blinded_paths(js, offer->offer_paths, NULL);
|
||||
if (offer_issuer)
|
||||
valid &= json_add_utf8(js, "offer_issuer", offer_issuer);
|
||||
if (offer_features)
|
||||
json_add_hex_talarr(js, "offer_features", offer_features);
|
||||
if (offer_absolute_expiry)
|
||||
json_add_u64(js, "offer_absolute_expiry",
|
||||
*offer_absolute_expiry);
|
||||
if (offer_paths)
|
||||
valid &= json_add_blinded_paths(js, "offer_paths",
|
||||
offer_paths, NULL);
|
||||
|
||||
if (offer->offer_quantity_max)
|
||||
json_add_u64(js, "quantity_max", *offer->offer_quantity_max);
|
||||
if (offer->offer_recurrence) {
|
||||
if (offer_quantity_max)
|
||||
json_add_u64(js, "offer_quantity_max", *offer_quantity_max);
|
||||
|
||||
if (offer_recurrence) {
|
||||
const char *name;
|
||||
json_object_start(js, "recurrence");
|
||||
json_add_num(js, "time_unit", offer->offer_recurrence->time_unit);
|
||||
name = recurrence_time_unit_name(offer->offer_recurrence->time_unit);
|
||||
json_object_start(js, "offer_recurrence");
|
||||
json_add_num(js, "time_unit", offer_recurrence->time_unit);
|
||||
name = recurrence_time_unit_name(offer_recurrence->time_unit);
|
||||
if (name)
|
||||
json_add_string(js, "time_unit_name", name);
|
||||
json_add_num(js, "period", offer->offer_recurrence->period);
|
||||
if (offer->offer_recurrence_base) {
|
||||
json_add_num(js, "period", offer_recurrence->period);
|
||||
if (offer_recurrence_base) {
|
||||
json_add_u64(js, "basetime",
|
||||
offer->offer_recurrence_base->basetime);
|
||||
if (offer->offer_recurrence_base->start_any_period)
|
||||
offer_recurrence_base->basetime);
|
||||
if (offer_recurrence_base->start_any_period)
|
||||
json_add_bool(js, "start_any_period", true);
|
||||
}
|
||||
if (offer->offer_recurrence_limit)
|
||||
json_add_u32(js, "limit", *offer->offer_recurrence_limit);
|
||||
if (offer->offer_recurrence_paywindow) {
|
||||
if (offer_recurrence_limit)
|
||||
json_add_u32(js, "limit", *offer_recurrence_limit);
|
||||
if (offer_recurrence_paywindow) {
|
||||
json_object_start(js, "paywindow");
|
||||
json_add_u32(js, "seconds_before",
|
||||
offer->offer_recurrence_paywindow->seconds_before);
|
||||
offer_recurrence_paywindow->seconds_before);
|
||||
json_add_u32(js, "seconds_after",
|
||||
offer->offer_recurrence_paywindow->seconds_after);
|
||||
if (offer->offer_recurrence_paywindow->proportional_amount)
|
||||
offer_recurrence_paywindow->seconds_after);
|
||||
if (offer_recurrence_paywindow->proportional_amount)
|
||||
json_add_bool(js, "proportional_amount", true);
|
||||
json_object_end(js);
|
||||
}
|
||||
json_object_end(js);
|
||||
}
|
||||
|
||||
/* Required for offers, *not* for others! */
|
||||
if (offer_node_id)
|
||||
json_add_pubkey(js, "offer_node_id", offer_node_id);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
static void json_add_offer(struct json_stream *js, const struct tlv_offer *offer)
|
||||
{
|
||||
struct sha256 offer_id;
|
||||
bool valid = true;
|
||||
|
||||
offer_offer_id(offer, &offer_id);
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
|
||||
valid &= json_add_offer_fields(js,
|
||||
offer->offer_chains,
|
||||
offer->offer_metadata,
|
||||
offer->offer_currency,
|
||||
offer->offer_amount,
|
||||
offer->offer_description,
|
||||
offer->offer_features,
|
||||
offer->offer_absolute_expiry,
|
||||
offer->offer_paths,
|
||||
offer->offer_issuer,
|
||||
offer->offer_quantity_max,
|
||||
offer->offer_node_id,
|
||||
offer->offer_recurrence,
|
||||
offer->offer_recurrence_paywindow,
|
||||
offer->offer_recurrence_limit,
|
||||
offer->offer_recurrence_base);
|
||||
/* BOLT-offers #12:
|
||||
* - if `offer_node_id` is not set:
|
||||
* - MUST NOT respond to the offer.
|
||||
*/
|
||||
/* FIXME-OFFERS: Rename all fields to offer_ as per spec */
|
||||
if (offer->offer_node_id)
|
||||
json_add_pubkey(js, "node_id", offer->offer_node_id);
|
||||
else
|
||||
if (!offer->offer_node_id) {
|
||||
json_add_string(js, "warning_missing_offer_node_id",
|
||||
"offers without a node_id are invalid");
|
||||
valid = false;
|
||||
|
||||
}
|
||||
json_add_bool(js, "valid", valid);
|
||||
}
|
||||
|
||||
static bool json_add_invreq_fields(struct json_stream *js,
|
||||
const u8 *invreq_metadata,
|
||||
const struct bitcoin_blkid *invreq_chain,
|
||||
const u64 *invreq_amount,
|
||||
const u8 *invreq_features,
|
||||
const u64 *invreq_quantity,
|
||||
const struct pubkey *invreq_payer_id,
|
||||
const utf8 *invreq_payer_note,
|
||||
const u32 *invreq_recurrence_counter,
|
||||
const u32 *invreq_recurrence_start)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `invreq_payer_id` or `invreq_metadata` are not present.
|
||||
*/
|
||||
if (invreq_metadata)
|
||||
json_add_hex_talarr(js, "invreq_metadata",
|
||||
invreq_metadata);
|
||||
else {
|
||||
json_add_string(js, "warning_missing_invreq_metadata",
|
||||
"invreq_metadata required");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* This can be missing for an invoice though! */
|
||||
if (invreq_payer_id)
|
||||
json_add_pubkey(js, "invreq_payer_id", invreq_payer_id);
|
||||
|
||||
if (invreq_chain)
|
||||
json_add_sha256(js, "invreq_chain", &invreq_chain->shad.sha);
|
||||
|
||||
if (invreq_amount)
|
||||
json_add_amount_msat_only(js, "invreq_amount_msat",
|
||||
amount_msat(*invreq_amount));
|
||||
if (invreq_features)
|
||||
json_add_hex_talarr(js, "invreq_features", invreq_features);
|
||||
if (invreq_quantity)
|
||||
json_add_u64(js, "invreq_quantity", *invreq_quantity);
|
||||
if (invreq_payer_note)
|
||||
valid &= json_add_utf8(js, "invreq_payer_note", invreq_payer_note);
|
||||
if (invreq_recurrence_counter) {
|
||||
json_add_u32(js, "invreq_recurrence_counter",
|
||||
*invreq_recurrence_counter);
|
||||
if (invreq_recurrence_start)
|
||||
json_add_u32(js, "invreq_recurrence_start",
|
||||
*invreq_recurrence_start);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/* Returns true if valid */
|
||||
static bool json_add_fallback_address(struct json_stream *js,
|
||||
const struct chainparams *chain,
|
||||
@@ -425,7 +534,7 @@ static bool json_add_fallback_address(struct json_stream *js,
|
||||
return true;
|
||||
}
|
||||
json_add_string(js,
|
||||
"warning_invoice_fallbacks_address_invalid",
|
||||
"warning_invalid_invoice_fallbacks_address",
|
||||
"invalid fallback address for this version");
|
||||
return false;
|
||||
}
|
||||
@@ -444,7 +553,7 @@ static bool json_add_fallbacks(struct json_stream *js,
|
||||
else
|
||||
chain = chainparams_for_network("bitcoin");
|
||||
|
||||
json_array_start(js, "fallbacks");
|
||||
json_array_start(js, "invoice_fallbacks");
|
||||
for (size_t i = 0; i < tal_count(fallbacks); i++) {
|
||||
size_t addrlen = tal_bytelen(fallbacks[i]->address);
|
||||
|
||||
@@ -463,12 +572,12 @@ static bool json_add_fallbacks(struct json_stream *js,
|
||||
*/
|
||||
if (fallbacks[i]->version > 16) {
|
||||
json_add_string(js,
|
||||
"warning_invoice_fallbacks_version_invalid",
|
||||
"warning_invalid_invoice_fallbacks_version",
|
||||
"invoice fallback version > 16");
|
||||
valid = false;
|
||||
} else if (addrlen < 2 || addrlen > 40) {
|
||||
json_add_string(js,
|
||||
"warning_invoice_fallbacks_address_invalid",
|
||||
"warning_invalid_invoice_fallbacks_address",
|
||||
"invoice fallback address bad length");
|
||||
valid = false;
|
||||
} else if (chain) {
|
||||
@@ -483,6 +592,82 @@ static bool json_add_fallbacks(struct json_stream *js,
|
||||
return valid;
|
||||
}
|
||||
|
||||
static void json_add_invoice_request(struct json_stream *js,
|
||||
const struct tlv_invoice_request *invreq)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
/* If there's an offer_node_id, then there's an offer. */
|
||||
if (invreq->offer_node_id) {
|
||||
struct sha256 offer_id;
|
||||
|
||||
invreq_offer_id(invreq, &offer_id);
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
}
|
||||
|
||||
valid &= json_add_offer_fields(js,
|
||||
invreq->offer_chains,
|
||||
invreq->offer_metadata,
|
||||
invreq->offer_currency,
|
||||
invreq->offer_amount,
|
||||
invreq->offer_description,
|
||||
invreq->offer_features,
|
||||
invreq->offer_absolute_expiry,
|
||||
invreq->offer_paths,
|
||||
invreq->offer_issuer,
|
||||
invreq->offer_quantity_max,
|
||||
invreq->offer_node_id,
|
||||
invreq->offer_recurrence,
|
||||
invreq->offer_recurrence_paywindow,
|
||||
invreq->offer_recurrence_limit,
|
||||
invreq->offer_recurrence_base);
|
||||
valid &= json_add_invreq_fields(js,
|
||||
invreq->invreq_metadata,
|
||||
invreq->invreq_chain,
|
||||
invreq->invreq_amount,
|
||||
invreq->invreq_features,
|
||||
invreq->invreq_quantity,
|
||||
invreq->invreq_payer_id,
|
||||
invreq->invreq_payer_note,
|
||||
invreq->invreq_recurrence_counter,
|
||||
invreq->invreq_recurrence_start);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `invreq_payer_id` or `invreq_metadata` are not present.
|
||||
*/
|
||||
if (!invreq->invreq_payer_id) {
|
||||
json_add_string(js, "warning_missing_invreq_payer_id",
|
||||
"invreq_payer_id required");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `signature` is not correct as detailed
|
||||
* in [Signature Calculation](#signature-calculation) using the
|
||||
* `invreq_payer_id`.
|
||||
*/
|
||||
if (invreq->signature) {
|
||||
if (invreq->invreq_payer_id
|
||||
&& !bolt12_check_signature(invreq->fields,
|
||||
"invoice_request",
|
||||
"signature",
|
||||
invreq->invreq_payer_id,
|
||||
invreq->signature)) {
|
||||
json_add_string(js, "warning_invalid_invoice_request_signature",
|
||||
"Bad signature");
|
||||
valid = false;
|
||||
} else {
|
||||
json_add_bip340sig(js, "signature", invreq->signature);
|
||||
}
|
||||
} else {
|
||||
json_add_string(js, "warning_missing_invoice_request_signature",
|
||||
"Missing signature");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
json_add_bool(js, "valid", valid);
|
||||
}
|
||||
|
||||
static void json_add_b12_invoice(struct json_stream *js,
|
||||
const struct tlv_invoice *invoice)
|
||||
{
|
||||
@@ -496,66 +681,32 @@ static void json_add_b12_invoice(struct json_stream *js,
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
}
|
||||
|
||||
/* FIXME-OFFERS: Rename all fields to invoice_ as per spec */
|
||||
if (invoice->invreq_chain)
|
||||
json_add_sha256(js, "chain", &invoice->invreq_chain->shad.sha);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST reject the invoice if `invoice_amount` is not present.
|
||||
* - MUST reject the invoice if `invreq_payer_id` is not present.
|
||||
*/
|
||||
if (invoice->invoice_amount)
|
||||
json_add_amount_msat_only(js, "amount_msat",
|
||||
amount_msat(*invoice->invoice_amount));
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_amount",
|
||||
"invoices without an amount are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invreq_payer_id)
|
||||
json_add_pubkey(js, "payer_key", invoice->invreq_payer_id);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_invreq_payer_id",
|
||||
"invoices without an invreq_payer_id are invald");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST reject the invoice if `offer_description` is not present.
|
||||
* - MUST reject the invoice if `invoice_created_at` is not present.
|
||||
* - MUST reject the invoice if `invoice_payment_hash` is not present.
|
||||
*/
|
||||
if (invoice->offer_description)
|
||||
json_add_stringn(js, "description", invoice->offer_description,
|
||||
tal_bytelen(invoice->offer_description));
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_description",
|
||||
"invoices without a description are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invoice_created_at) {
|
||||
json_add_u64(js, "created_at", *invoice->invoice_created_at);
|
||||
} else {
|
||||
json_add_string(js, "warning_invoice_missing_created_at",
|
||||
"invoices without created_at are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invoice_payment_hash)
|
||||
json_add_sha256(js, "payment_hash", invoice->invoice_payment_hash);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_payment_hash",
|
||||
"invoices without a payment_hash are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->offer_issuer)
|
||||
json_add_stringn(js, "issuer", invoice->offer_issuer,
|
||||
tal_bytelen(invoice->offer_issuer));
|
||||
if (invoice->invoice_features)
|
||||
json_add_hex_talarr(js, "features", invoice->invoice_features);
|
||||
valid &= json_add_offer_fields(js,
|
||||
invoice->offer_chains,
|
||||
invoice->offer_metadata,
|
||||
invoice->offer_currency,
|
||||
invoice->offer_amount,
|
||||
invoice->offer_description,
|
||||
invoice->offer_features,
|
||||
invoice->offer_absolute_expiry,
|
||||
invoice->offer_paths,
|
||||
invoice->offer_issuer,
|
||||
invoice->offer_quantity_max,
|
||||
invoice->offer_node_id,
|
||||
invoice->offer_recurrence,
|
||||
invoice->offer_recurrence_paywindow,
|
||||
invoice->offer_recurrence_limit,
|
||||
invoice->offer_recurrence_base);
|
||||
valid &= json_add_invreq_fields(js,
|
||||
invoice->invreq_metadata,
|
||||
invoice->invreq_chain,
|
||||
invoice->invreq_amount,
|
||||
invoice->invreq_features,
|
||||
invoice->invreq_quantity,
|
||||
invoice->invreq_payer_id,
|
||||
invoice->invreq_payer_note,
|
||||
invoice->invreq_recurrence_counter,
|
||||
invoice->invreq_recurrence_start);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST reject the invoice if `invoice_paths` is not present
|
||||
@@ -574,48 +725,27 @@ static void json_add_b12_invoice(struct json_stream *js,
|
||||
* in `blinded_path`.
|
||||
*/
|
||||
if (!invoice->invoice_blindedpay) {
|
||||
json_add_string(js, "warning_invoice_missing_blinded_payinfo",
|
||||
"invoices with blinded_path without blinded_payinfo are invalid");
|
||||
json_add_string(js, "warning_missing_invoice_blindedpay",
|
||||
"invoices with paths without blindedpay are invalid");
|
||||
valid = false;
|
||||
}
|
||||
valid &= json_add_blinded_paths(js, invoice->invoice_paths,
|
||||
valid &= json_add_blinded_paths(js, "invoice_paths",
|
||||
invoice->invoice_paths,
|
||||
invoice->invoice_blindedpay);
|
||||
} else {
|
||||
json_add_string(js, "warning_invoice_missing_blinded_path",
|
||||
"invoices without a payment_hash are invalid");
|
||||
json_add_string(js, "warning_missing_invoice_paths",
|
||||
"invoices without a invoice_paths are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invreq_quantity)
|
||||
json_add_u64(js, "quantity", *invoice->invreq_quantity);
|
||||
if (invoice->invreq_recurrence_counter) {
|
||||
json_add_u32(js, "recurrence_counter",
|
||||
*invoice->invreq_recurrence_counter);
|
||||
if (invoice->invreq_recurrence_start)
|
||||
json_add_u32(js, "recurrence_start",
|
||||
*invoice->invreq_recurrence_start);
|
||||
/* BOLT-offers-recurrence #12:
|
||||
* - if the offer contained `recurrence`:
|
||||
* - MUST reject the invoice if `recurrence_basetime` is not
|
||||
* set.
|
||||
*/
|
||||
if (invoice->invoice_recurrence_basetime)
|
||||
json_add_u64(js, "recurrence_basetime",
|
||||
*invoice->invoice_recurrence_basetime);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_missing_recurrence_basetime",
|
||||
"recurring invoices without a recurrence_basetime are invalid");
|
||||
valid = false;
|
||||
}
|
||||
if (invoice->invoice_created_at) {
|
||||
json_add_u64(js, "invoice_created_at", *invoice->invoice_created_at);
|
||||
} else {
|
||||
json_add_string(js, "warning_missing_invoice_created_at",
|
||||
"invoices without created_at are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invreq_metadata)
|
||||
json_add_hex_talarr(js, "invreq_metadata",
|
||||
invoice->invreq_metadata);
|
||||
if (invoice->invreq_payer_note)
|
||||
json_add_stringn(js, "payer_note", invoice->invreq_payer_note,
|
||||
tal_bytelen(invoice->invreq_payer_note));
|
||||
|
||||
/* BOLT-offers #12:
|
||||
*
|
||||
* - if `invoice_relative_expiry` is present:
|
||||
@@ -626,104 +756,65 @@ static void json_add_b12_invoice(struct json_stream *js,
|
||||
* is greater than `invoice_created_at` plus 7200.
|
||||
*/
|
||||
if (invoice->invoice_relative_expiry)
|
||||
json_add_u32(js, "relative_expiry", *invoice->invoice_relative_expiry);
|
||||
json_add_u32(js, "invoice_relative_expiry", *invoice->invoice_relative_expiry);
|
||||
else
|
||||
json_add_u32(js, "relative_expiry", 7200);
|
||||
json_add_u32(js, "invoice_relative_expiry", BOLT12_DEFAULT_REL_EXPIRY);
|
||||
|
||||
if (invoice->invoice_payment_hash)
|
||||
json_add_sha256(js, "invoice_payment_hash", invoice->invoice_payment_hash);
|
||||
else {
|
||||
json_add_string(js, "warning_missing_invoice_payment_hash",
|
||||
"invoices without a payment_hash are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST reject the invoice if `invoice_amount` is not present.
|
||||
*/
|
||||
if (invoice->invoice_amount)
|
||||
json_add_amount_msat_only(js, "invoice_amount_msat",
|
||||
amount_msat(*invoice->invoice_amount));
|
||||
else {
|
||||
json_add_string(js, "warning_missing_invoice_amount",
|
||||
"invoices without an amount are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invoice->invoice_fallbacks)
|
||||
valid &= json_add_fallbacks(js,
|
||||
invoice->invreq_chain,
|
||||
invoice->invoice_fallbacks);
|
||||
|
||||
/* invoice_decode checked these */
|
||||
json_add_pubkey(js, "node_id", invoice->offer_node_id);
|
||||
json_add_bip340sig(js, "signature", invoice->signature);
|
||||
if (invoice->invoice_features)
|
||||
json_add_hex_talarr(js, "features", invoice->invoice_features);
|
||||
|
||||
json_add_bool(js, "valid", valid);
|
||||
}
|
||||
|
||||
static void json_add_invoice_request(struct json_stream *js,
|
||||
const struct tlv_invoice_request *invreq)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
/* If there's an offer_node_id, then there's an offer. */
|
||||
if (invreq->offer_node_id) {
|
||||
struct sha256 offer_id;
|
||||
|
||||
invreq_offer_id(invreq, &offer_id);
|
||||
json_add_sha256(js, "offer_id", &offer_id);
|
||||
}
|
||||
|
||||
/* FIXME-OFFERS: Rename all fields to invreq_ as per spec */
|
||||
if (invreq->invreq_chain)
|
||||
json_add_sha256(js, "chain", &invreq->invreq_chain->shad.sha);
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `payer_key` is not present.
|
||||
*...
|
||||
* - MUST fail the request if `features` contains unknown even bits.
|
||||
* - MUST fail the request if `offer_id` is not present.
|
||||
*/
|
||||
if (invreq->invreq_amount)
|
||||
json_add_amount_msat_only(js, "amount_msat",
|
||||
amount_msat(*invreq->invreq_amount));
|
||||
if (invreq->invreq_features)
|
||||
json_add_hex_talarr(js, "features", invreq->invreq_features);
|
||||
if (invreq->invreq_quantity)
|
||||
json_add_u64(js, "quantity", *invreq->invreq_quantity);
|
||||
|
||||
if (invreq->invreq_recurrence_counter)
|
||||
json_add_u32(js, "recurrence_counter",
|
||||
*invreq->invreq_recurrence_counter);
|
||||
if (invreq->invreq_recurrence_start)
|
||||
json_add_u32(js, "recurrence_start",
|
||||
*invreq->invreq_recurrence_start);
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `invreq_payer_id` or `invreq_metadata`
|
||||
* are not present.
|
||||
*/
|
||||
if (invreq->invreq_payer_id)
|
||||
json_add_pubkey(js, "payer_key", invreq->invreq_payer_id);
|
||||
if (invoice->invoice_node_id)
|
||||
json_add_pubkey(js, "invoice_node_id", invoice->invoice_node_id);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_request_missing_payer_key",
|
||||
"invoice_request requires payer_key");
|
||||
valid = false;
|
||||
}
|
||||
if (invreq->invreq_metadata)
|
||||
json_add_hex_talarr(js, "invreq_metadata", invreq->invreq_metadata);
|
||||
else {
|
||||
json_add_string(js, "warning_invoice_request_missing_invreq_metadata",
|
||||
"invoice_request requires invreq_metadata");
|
||||
json_add_string(js, "warning_missing_invoice_node_id",
|
||||
"invoices without an invoice_node_id are invalid");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (invreq->invreq_payer_note)
|
||||
json_add_stringn(js, "payer_note", invreq->invreq_payer_note,
|
||||
tal_bytelen(invreq->invreq_payer_note));
|
||||
|
||||
/* BOLT-offers #12:
|
||||
* - MUST fail the request if `signature` is not correct as detailed
|
||||
* in [Signature Calculation](#signature-calculation) using the
|
||||
* `invreq_payer_id`.
|
||||
/* BOLT-offers-recurrence #12:
|
||||
* - if the offer contained `recurrence`:
|
||||
* - MUST reject the invoice if `recurrence_basetime` is not
|
||||
* set.
|
||||
*/
|
||||
if (invreq->signature) {
|
||||
if (invreq->invreq_payer_id
|
||||
&& !bolt12_check_signature(invreq->fields,
|
||||
"invoice_request",
|
||||
"signature",
|
||||
invreq->invreq_payer_id,
|
||||
invreq->signature)) {
|
||||
json_add_string(js, "warning_invoice_request_invalid_signature",
|
||||
"Bad signature");
|
||||
if (invoice->offer_recurrence) {
|
||||
if (invoice->invoice_recurrence_basetime)
|
||||
json_add_u64(js, "invoice_recurrence_basetime",
|
||||
*invoice->invoice_recurrence_basetime);
|
||||
else {
|
||||
json_add_string(js, "warning_missing_invoice_recurrence_basetime",
|
||||
"recurring invoices without a recurrence_basetime are invalid");
|
||||
valid = false;
|
||||
}
|
||||
} else {
|
||||
json_add_string(js, "warning_invoice_request_missing_signature",
|
||||
"Missing signature");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
/* invoice_decode checked this */
|
||||
json_add_bip340sig(js, "signature", invoice->signature);
|
||||
|
||||
json_add_bool(js, "valid", valid);
|
||||
}
|
||||
|
||||
|
||||
@@ -4592,15 +4592,15 @@ def test_fetchinvoice(node_factory, bitcoind):
|
||||
# listinvoices will show these on l3
|
||||
assert [x['local_offer_id'] for x in l3.rpc.listinvoices()['invoices']] == [offer1['offer_id'], offer1['offer_id']]
|
||||
|
||||
assert 'payer_note' not in only_one(l3.rpc.call('listinvoices', {'invstring': inv1['invoice']})['invoices'])
|
||||
assert only_one(l3.rpc.call('listinvoices', {'invstring': inv2['invoice']})['invoices'])['payer_note'] == 'Thanks for the fish!'
|
||||
assert 'invreq_payer_note' not in only_one(l3.rpc.call('listinvoices', {'invstring': inv1['invoice']})['invoices'])
|
||||
assert only_one(l3.rpc.call('listinvoices', {'invstring': inv2['invoice']})['invoices'])['invreq_payer_note'] == 'Thanks for the fish!'
|
||||
|
||||
# BTW, test listinvoices-by-offer_id:
|
||||
assert len(l3.rpc.listinvoices(offer_id=offer1['offer_id'])['invoices']) == 2
|
||||
|
||||
# We can also set the amount explicitly, to tip.
|
||||
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12'], 'amount_msat': 3})
|
||||
assert l1.rpc.call('decode', [inv1['invoice']])['amount_msat'] == 3
|
||||
assert l1.rpc.call('decode', [inv1['invoice']])['invoice_amount_msat'] == 3
|
||||
l1.rpc.pay(inv1['invoice'])
|
||||
|
||||
# More than ~5x expected is rejected as absurd (it's actually a divide test,
|
||||
@@ -5222,4 +5222,4 @@ def test_payerkey(node_factory):
|
||||
|
||||
for n, k in zip(nodes, expected_keys):
|
||||
b12 = n.rpc.createinvoicerequest('lnr1qqgz2d7u2smys9dc5q2447e8thjlgq3qqc3xu3s3rg94nj40zfsy866mhu5vxne6tcej5878k2mneuvgjy8ssqvepgz5zsjrg3z3vggzvkm2khkgvrxj27r96c00pwl4kveecdktm29jdd6w0uwu5jgtv5v9qgqxyfhyvyg6pdvu4tcjvpp7kkal9rp57wj7xv4pl3ajku70rzy3pu')['bolt12']
|
||||
assert n.rpc.decode(b12)['payer_key'] == k
|
||||
assert n.rpc.decode(b12)['invreq_payer_id'] == k
|
||||
|
||||
Reference in New Issue
Block a user