mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-22 03:24:18 +01:00
[FIX] NUT-15 mpp amount in millisats (#703)
* fix lndrest * fix clnrest * fix clnrest and lndrest * lnd grpc fix * wallet * convert amount to millisats in CLI pay invoice * fix tests * format * fix kw arg in regtest test * fix payment quote validation check * clean comment * avoid overwriting variable * deprecated response with amount --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
This commit is contained in:
@@ -332,12 +332,8 @@ class CLNRestWallet(LightningBackend):
|
|||||||
invoice_obj = decode(melt_quote.request)
|
invoice_obj = decode(melt_quote.request)
|
||||||
assert invoice_obj.amount_msat, "invoice has no amount."
|
assert invoice_obj.amount_msat, "invoice has no amount."
|
||||||
assert invoice_obj.amount_msat > 0, "invoice has 0 amount."
|
assert invoice_obj.amount_msat > 0, "invoice has 0 amount."
|
||||||
amount_msat = invoice_obj.amount_msat
|
amount_msat = melt_quote.mpp_amount if melt_quote.is_mpp else (
|
||||||
if melt_quote.is_mpp:
|
invoice_obj.amount_msat
|
||||||
amount_msat = (
|
|
||||||
Amount(Unit[melt_quote.unit], melt_quote.mpp_amount)
|
|
||||||
.to(Unit.msat)
|
|
||||||
.amount
|
|
||||||
)
|
)
|
||||||
fees_msat = fee_reserve(amount_msat)
|
fees_msat = fee_reserve(amount_msat)
|
||||||
fees = Amount(unit=Unit.msat, amount=fees_msat)
|
fees = Amount(unit=Unit.msat, amount=fees_msat)
|
||||||
|
|||||||
@@ -371,8 +371,8 @@ class LndRPCWallet(LightningBackend):
|
|||||||
self, melt_quote: PostMeltQuoteRequest
|
self, melt_quote: PostMeltQuoteRequest
|
||||||
) -> PaymentQuoteResponse:
|
) -> PaymentQuoteResponse:
|
||||||
# get amount from melt_quote or from bolt11
|
# get amount from melt_quote or from bolt11
|
||||||
amount = (
|
amount_msat = (
|
||||||
Amount(Unit[melt_quote.unit], melt_quote.mpp_amount)
|
melt_quote.mpp_amount
|
||||||
if melt_quote.is_mpp
|
if melt_quote.is_mpp
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
@@ -380,9 +380,7 @@ class LndRPCWallet(LightningBackend):
|
|||||||
invoice_obj = bolt11.decode(melt_quote.request)
|
invoice_obj = bolt11.decode(melt_quote.request)
|
||||||
assert invoice_obj.amount_msat, "invoice has no amount."
|
assert invoice_obj.amount_msat, "invoice has no amount."
|
||||||
|
|
||||||
if amount:
|
if amount_msat is None:
|
||||||
amount_msat = amount.to(Unit.msat).amount
|
|
||||||
else:
|
|
||||||
amount_msat = int(invoice_obj.amount_msat)
|
amount_msat = int(invoice_obj.amount_msat)
|
||||||
|
|
||||||
fees_msat = fee_reserve(amount_msat)
|
fees_msat = fee_reserve(amount_msat)
|
||||||
|
|||||||
@@ -394,19 +394,12 @@ class LndRestWallet(LightningBackend):
|
|||||||
async def get_payment_quote(
|
async def get_payment_quote(
|
||||||
self, melt_quote: PostMeltQuoteRequest
|
self, melt_quote: PostMeltQuoteRequest
|
||||||
) -> PaymentQuoteResponse:
|
) -> PaymentQuoteResponse:
|
||||||
# get amount from melt_quote or from bolt11
|
amount_msat = melt_quote.mpp_amount if melt_quote.is_mpp else None
|
||||||
amount = (
|
|
||||||
Amount(Unit[melt_quote.unit], melt_quote.mpp_amount)
|
|
||||||
if melt_quote.is_mpp
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
invoice_obj = decode(melt_quote.request)
|
invoice_obj = decode(melt_quote.request)
|
||||||
assert invoice_obj.amount_msat, "invoice has no amount."
|
assert invoice_obj.amount_msat, "invoice has no amount."
|
||||||
|
|
||||||
if amount:
|
if amount_msat is None:
|
||||||
amount_msat = amount.to(Unit.msat).amount
|
|
||||||
else:
|
|
||||||
amount_msat = int(invoice_obj.amount_msat)
|
amount_msat = int(invoice_obj.amount_msat)
|
||||||
|
|
||||||
fees_msat = fee_reserve(amount_msat)
|
fees_msat = fee_reserve(amount_msat)
|
||||||
|
|||||||
@@ -666,7 +666,7 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
|||||||
if not payment_quote.checking_id:
|
if not payment_quote.checking_id:
|
||||||
raise Exception("quote has no checking id")
|
raise Exception("quote has no checking id")
|
||||||
# verify that payment quote amount is as expected
|
# verify that payment quote amount is as expected
|
||||||
if melt_quote.is_mpp and melt_quote.mpp_amount != payment_quote.amount.amount:
|
if melt_quote.is_mpp and melt_quote.mpp_amount != payment_quote.amount.to(Unit.msat).amount:
|
||||||
raise TransactionError("quote amount not as requested")
|
raise TransactionError("quote amount not as requested")
|
||||||
# make sure the backend returned the amount with a correct unit
|
# make sure the backend returned the amount with a correct unit
|
||||||
if not payment_quote.amount.unit == unit:
|
if not payment_quote.amount.unit == unit:
|
||||||
|
|||||||
@@ -263,7 +263,10 @@ async def pay(
|
|||||||
await wallet.load_mint()
|
await wallet.load_mint()
|
||||||
await print_balance(ctx)
|
await print_balance(ctx)
|
||||||
payment_hash = bolt11.decode(invoice).payment_hash
|
payment_hash = bolt11.decode(invoice).payment_hash
|
||||||
quote = await wallet.melt_quote(invoice, amount)
|
if amount:
|
||||||
|
# we assume `amount` to be in sats
|
||||||
|
amount_mpp_msat = amount * 1000
|
||||||
|
quote = await wallet.melt_quote(invoice, amount_mpp_msat)
|
||||||
logger.debug(f"Quote: {quote}")
|
logger.debug(f"Quote: {quote}")
|
||||||
total_amount = quote.amount + quote.fee_reserve
|
total_amount = quote.amount + quote.fee_reserve
|
||||||
# estimate ecash fee for the coinselected proofs
|
# estimate ecash fee for the coinselected proofs
|
||||||
|
|||||||
@@ -434,16 +434,17 @@ class LedgerAPI(LedgerAPIDeprecated, SupportsAuth):
|
|||||||
@async_set_httpx_client
|
@async_set_httpx_client
|
||||||
@async_ensure_mint_loaded
|
@async_ensure_mint_loaded
|
||||||
async def melt_quote(
|
async def melt_quote(
|
||||||
self, payment_request: str, unit: Unit, amount: Optional[int] = None
|
self, payment_request: str, unit: Unit, amount_msat: Optional[int] = None
|
||||||
) -> PostMeltQuoteResponse:
|
) -> PostMeltQuoteResponse:
|
||||||
"""Checks whether the Lightning payment is internal."""
|
"""Checks whether the Lightning payment is internal."""
|
||||||
invoice_obj = bolt11.decode(payment_request)
|
invoice_obj = bolt11.decode(payment_request)
|
||||||
assert invoice_obj.amount_msat, "invoice must have amount"
|
assert invoice_obj.amount_msat, "invoice must have amount"
|
||||||
|
|
||||||
# add mpp amount for partial melts
|
# add mpp amount for partial melts
|
||||||
melt_options = None
|
melt_options = None
|
||||||
if amount:
|
if amount_msat:
|
||||||
melt_options = PostMeltRequestOptions(
|
melt_options = PostMeltRequestOptions(
|
||||||
mpp=PostMeltRequestOptionMpp(amount=amount)
|
mpp=PostMeltRequestOptionMpp(amount=amount_msat)
|
||||||
)
|
)
|
||||||
|
|
||||||
payload = PostMeltQuoteRequest(
|
payload = PostMeltQuoteRequest(
|
||||||
@@ -462,9 +463,12 @@ class LedgerAPI(LedgerAPIDeprecated, SupportsAuth):
|
|||||||
payment_request
|
payment_request
|
||||||
)
|
)
|
||||||
quote_id = f"deprecated_{uuid.uuid4()}"
|
quote_id = f"deprecated_{uuid.uuid4()}"
|
||||||
|
amount_sat = (
|
||||||
|
amount_msat // 1000 if amount_msat else invoice_obj.amount_msat // 1000
|
||||||
|
)
|
||||||
return PostMeltQuoteResponse(
|
return PostMeltQuoteResponse(
|
||||||
quote=quote_id,
|
quote=quote_id,
|
||||||
amount=amount or invoice_obj.amount_msat // 1000,
|
amount=amount_sat,
|
||||||
fee_reserve=ret.fee or 0,
|
fee_reserve=ret.fee or 0,
|
||||||
paid=False,
|
paid=False,
|
||||||
state=MeltQuoteState.unpaid.value,
|
state=MeltQuoteState.unpaid.value,
|
||||||
|
|||||||
@@ -701,14 +701,14 @@ class Wallet(
|
|||||||
return keep_proofs, send_proofs
|
return keep_proofs, send_proofs
|
||||||
|
|
||||||
async def melt_quote(
|
async def melt_quote(
|
||||||
self, invoice: str, amount: Optional[int] = None
|
self, invoice: str, amount_msat: Optional[int] = None
|
||||||
) -> PostMeltQuoteResponse:
|
) -> PostMeltQuoteResponse:
|
||||||
"""
|
"""
|
||||||
Fetches a melt quote from the mint and either uses the amount in the invoice or the amount provided.
|
Fetches a melt quote from the mint and either uses the amount in the invoice or the amount provided.
|
||||||
"""
|
"""
|
||||||
if amount and not self.mint_info.supports_mpp("bolt11", self.unit):
|
if amount_msat and not self.mint_info.supports_mpp("bolt11", self.unit):
|
||||||
raise Exception("Mint does not support MPP, cannot specify amount.")
|
raise Exception("Mint does not support MPP, cannot specify amount.")
|
||||||
melt_quote_resp = await super().melt_quote(invoice, self.unit, amount)
|
melt_quote_resp = await super().melt_quote(invoice, self.unit, amount_msat)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Mint wants {self.unit.str(melt_quote_resp.fee_reserve)} as fee reserve."
|
f"Mint wants {self.unit.str(melt_quote_resp.fee_reserve)} as fee reserve."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ async def test_regtest_pay_mpp(wallet: Wallet, ledger: Ledger):
|
|||||||
|
|
||||||
async def _mint_pay_mpp(invoice: str, amount: int, proofs: List[Proof]):
|
async def _mint_pay_mpp(invoice: str, amount: int, proofs: List[Proof]):
|
||||||
# wallet pays 32 sat of the invoice
|
# wallet pays 32 sat of the invoice
|
||||||
quote = await wallet.melt_quote(invoice, amount=amount)
|
quote = await wallet.melt_quote(invoice, amount_msat=amount*1000)
|
||||||
assert quote.amount == amount
|
assert quote.amount == amount
|
||||||
await wallet.melt(
|
await wallet.melt(
|
||||||
proofs,
|
proofs,
|
||||||
@@ -118,7 +118,7 @@ async def test_regtest_pay_mpp_incomplete_payment(wallet: Wallet, ledger: Ledger
|
|||||||
async def pay_mpp(amount: int, proofs: List[Proof], delay: float = 0.0):
|
async def pay_mpp(amount: int, proofs: List[Proof], delay: float = 0.0):
|
||||||
await asyncio.sleep(delay)
|
await asyncio.sleep(delay)
|
||||||
# wallet pays 32 sat of the invoice
|
# wallet pays 32 sat of the invoice
|
||||||
quote = await wallet.melt_quote(invoice_payment_request, amount=amount)
|
quote = await wallet.melt_quote(invoice_payment_request, amount_msat=amount*1000)
|
||||||
assert quote.amount == amount
|
assert quote.amount == amount
|
||||||
await wallet.melt(
|
await wallet.melt(
|
||||||
proofs,
|
proofs,
|
||||||
@@ -154,5 +154,5 @@ async def test_regtest_internal_mpp_melt_quotes(wallet: Wallet, ledger: Ledger):
|
|||||||
|
|
||||||
# try and create a multi-part melt quote
|
# try and create a multi-part melt quote
|
||||||
await assert_err(
|
await assert_err(
|
||||||
wallet.melt_quote(mint_quote.request, 100), "internal mpp not allowed"
|
wallet.melt_quote(mint_quote.request, 100*1000), "internal mpp not allowed"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user