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 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 =
|
let nwc_store =
|
||||||
load_nwc_and_check_budget(&mut rpc, label, ¶ms, invoice_amt_msat, &id).await?;
|
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
|
// Reserve the invoice amount plus the worst case fee so that no
|
||||||
// combination of concurrent payments can exceed the budget and so that
|
// combination of concurrent payments can exceed the budget and so that
|
||||||
// balance queries during the payment reflect the reserved amount.
|
// balance queries during the payment reflect the reserved amount.
|
||||||
if get_budget_msat(&nwc_store).unwrap_or(u64::MAX)
|
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((
|
return Err((
|
||||||
nip47::NIP47Error {
|
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
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
(
|
(
|
||||||
|
|
@ -215,30 +241,15 @@ fn get_payment_id(
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_invoice_amount_msat(
|
fn get_invoice_amount_msat(decoded_invoice: &DecodeResponse) -> Option<u64> {
|
||||||
decoded_invoice: &DecodeResponse,
|
decoded_invoice.amount_msat.as_ref().map(Amount::msat)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_nwc_and_check_budget(
|
async fn load_nwc_and_check_budget(
|
||||||
rpc: &mut ClnRpc,
|
rpc: &mut ClnRpc,
|
||||||
label: &str,
|
label: &str,
|
||||||
params: &nip47::PayInvoiceRequest,
|
params: &nip47::PayInvoiceRequest,
|
||||||
invoice_amt_msat: u64,
|
invoice_amt_msat: Option<u64>,
|
||||||
id: &str,
|
id: &str,
|
||||||
) -> Result<NwcStore, (nip47::NIP47Error, Option<String>)> {
|
) -> Result<NwcStore, (nip47::NIP47Error, Option<String>)> {
|
||||||
let nwc_store = load_nwc_store(rpc, label).await.map_err(|e| {
|
let nwc_store = load_nwc_store(rpc, label).await.map_err(|e| {
|
||||||
|
|
@ -251,20 +262,17 @@ async fn load_nwc_and_check_budget(
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
budget_amount_check(
|
budget_amount_check(params.amount, invoice_amt_msat, get_budget_msat(&nwc_store)).map_err(
|
||||||
params.amount,
|
|e| {
|
||||||
Some(invoice_amt_msat),
|
(
|
||||||
get_budget_msat(&nwc_store),
|
nip47::NIP47Error {
|
||||||
)
|
code: nip47::ErrorCode::QuotaExceeded,
|
||||||
.map_err(|e| {
|
message: e.to_string(),
|
||||||
(
|
},
|
||||||
nip47::NIP47Error {
|
Some(id.to_owned()),
|
||||||
code: nip47::ErrorCode::QuotaExceeded,
|
)
|
||||||
message: e.to_string(),
|
},
|
||||||
},
|
)?;
|
||||||
Some(id.to_owned()),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(nwc_store)
|
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"])
|
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
|
@pytest.mark.asyncio
|
||||||
async def test_persistency(nostr_relay, node_factory, get_plugin): # noqa: F811
|
async def test_persistency(nostr_relay, node_factory, get_plugin): # noqa: F811
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue