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]
|
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
|
||||||
|
|||||||
@@ -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)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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]
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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)"
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user