mirror of
https://github.com/daywalker90/cln-nip47.git
synced 2026-08-13 12:33:43 +02:00
fix paying of amount-less invoices with a request amount
This commit is contained in:
parent
ffd9bd21e9
commit
ae4e00967d
2 changed files with 58 additions and 35 deletions
|
|
@ -63,16 +63,42 @@ async fn pay_invoice(
|
|||
|
||||
let id = get_payment_id(¶ms, &decoded_invoice)?;
|
||||
|
||||
let invoice_amt_msat = get_invoice_amount_msat(&decoded_invoice, &id)?;
|
||||
let invoice_amt_msat = get_invoice_amount_msat(&decoded_invoice);
|
||||
|
||||
let nwc_store =
|
||||
load_nwc_and_check_budget(&mut rpc, label, ¶ms, invoice_amt_msat, &id).await?;
|
||||
|
||||
let amt_msat = match (params.amount, invoice_amt_msat) {
|
||||
(None, None) => {
|
||||
return Err((
|
||||
nip47::NIP47Error {
|
||||
code: nip47::ErrorCode::Internal,
|
||||
message: "No amount found in request or invoice".to_owned(),
|
||||
},
|
||||
Some(id.clone()),
|
||||
));
|
||||
}
|
||||
(None, Some(b)) => b,
|
||||
(Some(a), None) => a,
|
||||
(Some(a), Some(b)) => {
|
||||
if a != b {
|
||||
return Err((
|
||||
nip47::NIP47Error {
|
||||
code: nip47::ErrorCode::Internal,
|
||||
message: "request amount does not match invoice amount".to_owned(),
|
||||
},
|
||||
Some(id.clone()),
|
||||
));
|
||||
}
|
||||
a
|
||||
}
|
||||
};
|
||||
|
||||
// Reserve the invoice amount plus the worst case fee so that no
|
||||
// combination of concurrent payments can exceed the budget and so that
|
||||
// balance queries during the payment reflect the reserved amount.
|
||||
if get_budget_msat(&nwc_store).unwrap_or(u64::MAX)
|
||||
< invoice_amt_msat.saturating_add(payment_fee_reserve_msat(invoice_amt_msat))
|
||||
< amt_msat.saturating_add(payment_fee_reserve_msat(amt_msat))
|
||||
{
|
||||
return Err((
|
||||
nip47::NIP47Error {
|
||||
|
|
@ -83,7 +109,7 @@ async fn pay_invoice(
|
|||
));
|
||||
}
|
||||
|
||||
let reservation = reserve_budget(&mut rpc, label, &nwc_store, invoice_amt_msat)
|
||||
let reservation = reserve_budget(&mut rpc, label, &nwc_store, amt_msat)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
(
|
||||
|
|
@ -215,30 +241,15 @@ fn get_payment_id(
|
|||
Ok(id)
|
||||
}
|
||||
|
||||
fn get_invoice_amount_msat(
|
||||
decoded_invoice: &DecodeResponse,
|
||||
id: &str,
|
||||
) -> Result<u64, (nip47::NIP47Error, Option<String>)> {
|
||||
decoded_invoice
|
||||
.amount_msat
|
||||
.as_ref()
|
||||
.ok_or_else(|| {
|
||||
(
|
||||
nip47::NIP47Error {
|
||||
code: nip47::ErrorCode::Internal,
|
||||
message: "Missing amount_msat in decoded invoice".to_owned(),
|
||||
},
|
||||
Some(id.to_owned()),
|
||||
)
|
||||
})
|
||||
.map(Amount::msat)
|
||||
fn get_invoice_amount_msat(decoded_invoice: &DecodeResponse) -> Option<u64> {
|
||||
decoded_invoice.amount_msat.as_ref().map(Amount::msat)
|
||||
}
|
||||
|
||||
async fn load_nwc_and_check_budget(
|
||||
rpc: &mut ClnRpc,
|
||||
label: &str,
|
||||
params: &nip47::PayInvoiceRequest,
|
||||
invoice_amt_msat: u64,
|
||||
invoice_amt_msat: Option<u64>,
|
||||
id: &str,
|
||||
) -> Result<NwcStore, (nip47::NIP47Error, Option<String>)> {
|
||||
let nwc_store = load_nwc_store(rpc, label).await.map_err(|e| {
|
||||
|
|
@ -251,12 +262,8 @@ async fn load_nwc_and_check_budget(
|
|||
)
|
||||
})?;
|
||||
|
||||
budget_amount_check(
|
||||
params.amount,
|
||||
Some(invoice_amt_msat),
|
||||
get_budget_msat(&nwc_store),
|
||||
)
|
||||
.map_err(|e| {
|
||||
budget_amount_check(params.amount, invoice_amt_msat, get_budget_msat(&nwc_store)).map_err(
|
||||
|e| {
|
||||
(
|
||||
nip47::NIP47Error {
|
||||
code: nip47::ErrorCode::QuotaExceeded,
|
||||
|
|
@ -264,7 +271,8 @@ async fn load_nwc_and_check_budget(
|
|||
},
|
||||
Some(id.to_owned()),
|
||||
)
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(nwc_store)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -984,6 +984,21 @@ async def test_pay_invoice(nostr_relay, node_factory, get_plugin): # noqa: F811
|
|||
PayInvoiceRequest(id=None, amount=None, invoice=invoice["bolt11"])
|
||||
)
|
||||
|
||||
invoice = l2.rpc.call(
|
||||
"invoice",
|
||||
{
|
||||
"label": generate_random_label(),
|
||||
"description": "test1",
|
||||
"amount_msat": "any",
|
||||
},
|
||||
)
|
||||
result = await nwc.pay_invoice(
|
||||
PayInvoiceRequest(id=None, amount=2, invoice=invoice["bolt11"])
|
||||
)
|
||||
pay = l1.rpc.call("listpays", {"payment_hash": invoice["payment_hash"]})["pays"][0]
|
||||
assert result.preimage == pay["preimage"]
|
||||
assert pay["amount_msat"] == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_persistency(nostr_relay, node_factory, get_plugin): # noqa: F811
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue