mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-21 11:04:19 +01:00
request fee from mint
This commit is contained in:
@@ -153,10 +153,14 @@ class CheckRequest(BaseModel):
|
||||
proofs: List[Proof]
|
||||
|
||||
|
||||
class CheckInternalRequest(BaseModel):
|
||||
class CheckFeesRequest(BaseModel):
|
||||
pr: str
|
||||
|
||||
|
||||
class CheckFeesResponse(BaseModel):
|
||||
fee: Union[int, None]
|
||||
|
||||
|
||||
class MeltRequest(BaseModel):
|
||||
proofs: List[Proof]
|
||||
amount: int = None # deprecated
|
||||
|
||||
@@ -28,8 +28,10 @@ def async_unwrap(to_await):
|
||||
return async_response[0]
|
||||
|
||||
|
||||
def fee_reserve(amount_msat: int) -> int:
|
||||
def fee_reserve(amount_msat: int, internal=False) -> int:
|
||||
"""Function for calculating the Lightning fee reserve"""
|
||||
if internal:
|
||||
return 0
|
||||
return max(
|
||||
int(LIGHTNING_RESERVE_FEE_MIN), int(amount_msat * LIGHTNING_FEE_PERCENT / 100.0)
|
||||
)
|
||||
|
||||
@@ -116,6 +116,8 @@ class LNbitsWallet(Wallet):
|
||||
)
|
||||
except:
|
||||
return PaymentStatus(None)
|
||||
if r.json().get("detail"):
|
||||
return PaymentStatus(None)
|
||||
return PaymentStatus(r.json()["paid"])
|
||||
|
||||
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
|
||||
|
||||
@@ -197,13 +197,13 @@ class Ledger:
|
||||
await update_lightning_invoice(payment_hash, issued=True, db=self.db)
|
||||
return status.paid
|
||||
|
||||
async def _pay_lightning_invoice(self, invoice: str, amount: int):
|
||||
async def _pay_lightning_invoice(self, invoice: str, fees_msat: int):
|
||||
"""Returns an invoice from the Lightning backend."""
|
||||
error, _ = await WALLET.status()
|
||||
if error:
|
||||
raise Exception(f"Lightning wallet not responding: {error}")
|
||||
ok, checking_id, fee_msat, preimage, error_message = await WALLET.pay_invoice(
|
||||
invoice, fee_limit_msat=fee_reserve(amount * 1000)
|
||||
invoice, fee_limit_msat=fees_msat
|
||||
)
|
||||
return ok, preimage
|
||||
|
||||
@@ -258,16 +258,15 @@ class Ledger:
|
||||
if not all([self._verify_proof(p) for p in proofs]):
|
||||
raise Exception("could not verify proofs.")
|
||||
|
||||
total = sum([p["amount"] for p in proofs])
|
||||
total_provided = sum([p["amount"] for p in proofs])
|
||||
invoice_obj = bolt11.decode(invoice)
|
||||
amount = math.ceil(invoice_obj.amount_msat / 1000)
|
||||
|
||||
# check that lightning fees are included
|
||||
assert total + fee_reserve(amount * 1000) >= amount, Exception(
|
||||
fees_msat = await self.check_fees(invoice)
|
||||
assert total_provided >= amount + fees_msat / 1000, Exception(
|
||||
"provided proofs not enough for Lightning payment."
|
||||
)
|
||||
|
||||
status, preimage = await self._pay_lightning_invoice(invoice, amount)
|
||||
status, preimage = await self._pay_lightning_invoice(invoice, fees_msat)
|
||||
if status == True:
|
||||
await self._invalidate_proofs(proofs)
|
||||
return status, preimage
|
||||
@@ -276,6 +275,17 @@ class Ledger:
|
||||
"""Checks if all provided proofs are valid and still spendable (i.e. have not been spent)."""
|
||||
return {i: self._check_spendable(p) for i, p in enumerate(proofs)}
|
||||
|
||||
async def check_fees(self, pr: str):
|
||||
"""Returns the fees (in msat) required to pay this pr."""
|
||||
decoded_invoice = bolt11.decode(pr)
|
||||
amount = math.ceil(decoded_invoice.amount_msat / 1000)
|
||||
# hack: check if it's internal, if it exists, it will return paid = False,
|
||||
# if id does not exist (not internal), it returns paid = None
|
||||
paid = await WALLET.get_invoice_status(decoded_invoice.payment_hash)
|
||||
internal = paid.paid == False
|
||||
fees_msat = fee_reserve(amount * 1000, internal)
|
||||
return fees_msat
|
||||
|
||||
async def split(
|
||||
self, proofs: List[Proof], amount: int, outputs: List[BlindedMessage]
|
||||
):
|
||||
|
||||
@@ -5,7 +5,9 @@ from secp256k1 import PublicKey
|
||||
|
||||
from cashu.core.base import (
|
||||
CashuError,
|
||||
CheckFeesResponse,
|
||||
CheckRequest,
|
||||
CheckFeesRequest,
|
||||
GetMeltResponse,
|
||||
GetMintResponse,
|
||||
MeltRequest,
|
||||
@@ -72,6 +74,12 @@ async def check_spendable(payload: CheckRequest):
|
||||
return await ledger.check_spendable(payload.proofs)
|
||||
|
||||
|
||||
@router.post("/checkfees")
|
||||
async def check_fees(payload: CheckFeesRequest):
|
||||
fees_msat = await ledger.check_fees(payload.pr)
|
||||
return CheckFeesResponse(fee=fees_msat / 1000)
|
||||
|
||||
|
||||
@router.post("/split")
|
||||
async def split(payload: SplitRequest):
|
||||
"""
|
||||
|
||||
@@ -17,7 +17,7 @@ from loguru import logger
|
||||
|
||||
import cashu.core.bolt11 as bolt11
|
||||
from cashu.core.base import Proof
|
||||
from cashu.core.bolt11 import Invoice
|
||||
from cashu.core.bolt11 import Invoice, decode
|
||||
from cashu.core.helpers import fee_reserve
|
||||
from cashu.core.migrations import migrate_databases
|
||||
from cashu.core.settings import CASHU_DIR, DEBUG, ENV_FILE, LIGHTNING, MINT_URL, VERSION
|
||||
@@ -125,11 +125,13 @@ async def pay(ctx, invoice: str):
|
||||
wallet.load_mint()
|
||||
wallet.status()
|
||||
decoded_invoice: Invoice = bolt11.decode(invoice)
|
||||
# check if it's an internal payment
|
||||
fees = (await wallet.check_fees(invoice))["fee"]
|
||||
amount = math.ceil(
|
||||
(decoded_invoice.amount_msat + fee_reserve(decoded_invoice.amount_msat)) / 1000
|
||||
(decoded_invoice.amount_msat + fees * 1000) / 1000
|
||||
) # 1% fee for Lightning
|
||||
print(
|
||||
f"Paying Lightning invoice of {decoded_invoice.amount_msat // 1000} sat ({amount} sat incl. fees)"
|
||||
f"Paying Lightning invoice of {decoded_invoice.amount_msat//1000} sat ({amount} sat incl. fees)"
|
||||
)
|
||||
assert amount > 0, "amount is not positive"
|
||||
if wallet.available_balance < amount:
|
||||
|
||||
@@ -11,7 +11,7 @@ import cashu.core.b_dhke as b_dhke
|
||||
from cashu.core.base import (
|
||||
BlindedMessage,
|
||||
BlindedSignature,
|
||||
CheckInternalRequest,
|
||||
CheckFeesRequest,
|
||||
CheckRequest,
|
||||
MeltRequest,
|
||||
MintRequest,
|
||||
@@ -211,14 +211,13 @@ class LedgerAPI:
|
||||
|
||||
return return_dict
|
||||
|
||||
async def check_internal(self, payment_request: str):
|
||||
async def check_fees(self, payment_request: str):
|
||||
"""Checks whether the Lightning payment is internal."""
|
||||
payload = CheckInternalRequest(pr=payment_request)
|
||||
payload = CheckFeesRequest(pr=payment_request)
|
||||
return_dict = requests.post(
|
||||
self.url + "/checkinternal",
|
||||
self.url + "/checkfees",
|
||||
json=payload.dict(),
|
||||
).json()
|
||||
|
||||
return return_dict
|
||||
|
||||
async def pay_lightning(self, proofs: List[Proof], invoice: str):
|
||||
|
||||
Reference in New Issue
Block a user