request fee from mint

This commit is contained in:
callebtc
2022-10-05 22:26:57 +02:00
parent 16eb3cf6c5
commit 2d48c3116c
7 changed files with 44 additions and 17 deletions

View File

@@ -153,10 +153,14 @@ class CheckRequest(BaseModel):
proofs: List[Proof] proofs: List[Proof]
class CheckInternalRequest(BaseModel): class CheckFeesRequest(BaseModel):
pr: str pr: str
class CheckFeesResponse(BaseModel):
fee: Union[int, None]
class MeltRequest(BaseModel): class MeltRequest(BaseModel):
proofs: List[Proof] proofs: List[Proof]
amount: int = None # deprecated amount: int = None # deprecated

View File

@@ -28,8 +28,10 @@ def async_unwrap(to_await):
return async_response[0] 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""" """Function for calculating the Lightning fee reserve"""
if internal:
return 0
return max( return max(
int(LIGHTNING_RESERVE_FEE_MIN), int(amount_msat * LIGHTNING_FEE_PERCENT / 100.0) int(LIGHTNING_RESERVE_FEE_MIN), int(amount_msat * LIGHTNING_FEE_PERCENT / 100.0)
) )

View File

@@ -116,6 +116,8 @@ class LNbitsWallet(Wallet):
) )
except: except:
return PaymentStatus(None) return PaymentStatus(None)
if r.json().get("detail"):
return PaymentStatus(None)
return PaymentStatus(r.json()["paid"]) return PaymentStatus(r.json()["paid"])
async def get_payment_status(self, checking_id: str) -> PaymentStatus: async def get_payment_status(self, checking_id: str) -> PaymentStatus:

View File

@@ -197,13 +197,13 @@ class Ledger:
await update_lightning_invoice(payment_hash, issued=True, db=self.db) await update_lightning_invoice(payment_hash, issued=True, db=self.db)
return status.paid 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.""" """Returns an invoice from the Lightning backend."""
error, _ = await WALLET.status() error, _ = await WALLET.status()
if error: if error:
raise Exception(f"Lightning wallet not responding: {error}") raise Exception(f"Lightning wallet not responding: {error}")
ok, checking_id, fee_msat, preimage, error_message = await WALLET.pay_invoice( 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 return ok, preimage
@@ -258,16 +258,15 @@ class Ledger:
if not all([self._verify_proof(p) for p in proofs]): if not all([self._verify_proof(p) for p in proofs]):
raise Exception("could not verify 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) invoice_obj = bolt11.decode(invoice)
amount = math.ceil(invoice_obj.amount_msat / 1000) amount = math.ceil(invoice_obj.amount_msat / 1000)
fees_msat = await self.check_fees(invoice)
# check that lightning fees are included assert total_provided >= amount + fees_msat / 1000, Exception(
assert total + fee_reserve(amount * 1000) >= amount, Exception(
"provided proofs not enough for Lightning payment." "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: if status == True:
await self._invalidate_proofs(proofs) await self._invalidate_proofs(proofs)
return status, preimage 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).""" """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)} 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( async def split(
self, proofs: List[Proof], amount: int, outputs: List[BlindedMessage] self, proofs: List[Proof], amount: int, outputs: List[BlindedMessage]
): ):

View File

@@ -5,7 +5,9 @@ from secp256k1 import PublicKey
from cashu.core.base import ( from cashu.core.base import (
CashuError, CashuError,
CheckFeesResponse,
CheckRequest, CheckRequest,
CheckFeesRequest,
GetMeltResponse, GetMeltResponse,
GetMintResponse, GetMintResponse,
MeltRequest, MeltRequest,
@@ -72,6 +74,12 @@ async def check_spendable(payload: CheckRequest):
return await ledger.check_spendable(payload.proofs) 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") @router.post("/split")
async def split(payload: SplitRequest): async def split(payload: SplitRequest):
""" """

View File

@@ -17,7 +17,7 @@ from loguru import logger
import cashu.core.bolt11 as bolt11 import cashu.core.bolt11 as bolt11
from cashu.core.base import Proof 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.helpers import fee_reserve
from cashu.core.migrations import migrate_databases from cashu.core.migrations import migrate_databases
from cashu.core.settings import CASHU_DIR, DEBUG, ENV_FILE, LIGHTNING, MINT_URL, VERSION from cashu.core.settings import CASHU_DIR, DEBUG, ENV_FILE, LIGHTNING, MINT_URL, VERSION
@@ -125,8 +125,10 @@ async def pay(ctx, invoice: str):
wallet.load_mint() wallet.load_mint()
wallet.status() wallet.status()
decoded_invoice: Invoice = bolt11.decode(invoice) decoded_invoice: Invoice = bolt11.decode(invoice)
# check if it's an internal payment
fees = (await wallet.check_fees(invoice))["fee"]
amount = math.ceil( 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 ) # 1% fee for Lightning
print( 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)"

View File

@@ -11,7 +11,7 @@ import cashu.core.b_dhke as b_dhke
from cashu.core.base import ( from cashu.core.base import (
BlindedMessage, BlindedMessage,
BlindedSignature, BlindedSignature,
CheckInternalRequest, CheckFeesRequest,
CheckRequest, CheckRequest,
MeltRequest, MeltRequest,
MintRequest, MintRequest,
@@ -211,14 +211,13 @@ class LedgerAPI:
return return_dict 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.""" """Checks whether the Lightning payment is internal."""
payload = CheckInternalRequest(pr=payment_request) payload = CheckFeesRequest(pr=payment_request)
return_dict = requests.post( return_dict = requests.post(
self.url + "/checkinternal", self.url + "/checkfees",
json=payload.dict(), json=payload.dict(),
).json() ).json()
return return_dict return return_dict
async def pay_lightning(self, proofs: List[Proof], invoice: str): async def pay_lightning(self, proofs: List[Proof], invoice: str):