From 3fd66f38dad185c9b895beab66118cc7e2b1a2f4 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Sat, 27 Nov 2021 12:42:19 +0100 Subject: [PATCH 1/6] rename endpoint to avoid collision --- lnbits/extensions/usermanager/views_api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/usermanager/views_api.py b/lnbits/extensions/usermanager/views_api.py index 26b9874b1..1439b6820 100644 --- a/lnbits/extensions/usermanager/views_api.py +++ b/lnbits/extensions/usermanager/views_api.py @@ -23,7 +23,7 @@ from .crud import ( ) from .models import CreateUserData, CreateUserWallet -### Users +# Users @usermanager_ext.get("/api/v1/users", status_code=HTTPStatus.OK) @@ -72,7 +72,7 @@ async def api_usermanager_users_delete( raise HTTPException(status_code=HTTPStatus.NO_CONTENT) -###Activate Extension +# Activate Extension @usermanager_ext.post("/api/v1/extensions") @@ -88,7 +88,7 @@ async def api_usermanager_activate_extension( return {"extension": "updated"} -###Wallets +# Wallets @usermanager_ext.post("/api/v1/wallets") @@ -107,7 +107,7 @@ async def api_usermanager_wallets(wallet: WalletTypeInfo = Depends(get_key_type) return [wallet.dict() for wallet in await get_usermanager_wallets(admin_id)] -@usermanager_ext.get("/api/v1/wallets/{wallet_id}") +@usermanager_ext.get("/api/v1/transactions/{wallet_id}") async def api_usermanager_wallet_transactions( wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) ): From 2612e6064718dcab9049cf274ef9243dec7193e7 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Sat, 27 Nov 2021 12:43:14 +0100 Subject: [PATCH 2/6] annotation for optional attributes --- lnbits/extensions/usermanager/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/usermanager/models.py b/lnbits/extensions/usermanager/models.py index e65bdb52c..67facec68 100644 --- a/lnbits/extensions/usermanager/models.py +++ b/lnbits/extensions/usermanager/models.py @@ -2,6 +2,7 @@ from sqlite3 import Row from fastapi.param_functions import Query from pydantic import BaseModel +from typing import Optional class CreateUserData(BaseModel): @@ -22,8 +23,8 @@ class Users(BaseModel): id: str name: str admin: str - email: str - password: str + email: Optional[str] = None + password: Optional[str] = None class Wallets(BaseModel): From 9b58bfe06a940aee9b101182aa5fb39d21474b06 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Sat, 27 Nov 2021 12:54:01 +0100 Subject: [PATCH 3/6] remove trio_typing --- mypy.ini | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index b991c7cc2..000000000 --- a/mypy.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mypy] -plugins = trio_typing.plugin From ad3942f844fc0657964598b5c12d2c50ad0a40be Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Sat, 27 Nov 2021 13:01:12 +0100 Subject: [PATCH 4/6] remove type comment --- lnbits/jinja2_templating.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/jinja2_templating.py b/lnbits/jinja2_templating.py index f74f05c05..5abcd0bff 100644 --- a/lnbits/jinja2_templating.py +++ b/lnbits/jinja2_templating.py @@ -23,7 +23,7 @@ class Jinja2Templates(templating.Jinja2Templates): def get_environment(self, loader: "jinja2.BaseLoader") -> "jinja2.Environment": @jinja2.contextfunction def url_for(context: dict, name: str, **path_params: typing.Any) -> str: - request: Request = context["request"] # type: starlette.requests.Request + request: Request = context["request"] return request.app.url_path_for(name, **path_params) def url_params_update(init: QueryParams, **new: typing.Any) -> QueryParams: From b178d9a38d27730a294130c9b271e36d0faa573e Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Sat, 27 Nov 2021 13:11:29 +0100 Subject: [PATCH 5/6] readd mypy.ini --- mypy.ini | 1 + 1 file changed, 1 insertion(+) create mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 000000000..f8b1844b6 --- /dev/null +++ b/mypy.ini @@ -0,0 +1 @@ +[mypy] From 12c2a04b2ac9567662132bd05cd1833b649dfb5b Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Mon, 29 Nov 2021 18:10:11 +0100 Subject: [PATCH 6/6] LNDRest fee limit --- lnbits/core/services.py | 5 ++++- lnbits/core/views/api.py | 17 +++++++++++------ lnbits/wallets/lndrest.py | 21 ++++++++++++++++++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/lnbits/core/services.py b/lnbits/core/services.py index 57722dfd5..3ce1248b8 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -170,6 +170,8 @@ async def pay_invoice( ) await delete_payment(temp_id, conn=conn) else: + async with db.connect() as conn: + await delete_payment(temp_id, conn=conn) raise PaymentFailure( payment.error_message or "Payment failed, but backend didn't give us an error message." @@ -314,7 +316,8 @@ async def check_invoice_status( if not payment.pending: return status if payment.is_out and status.failed: - print(f" - deleting outgoing failed payment {payment.checking_id}: {status}") + print( + f" - deleting outgoing failed payment {payment.checking_id}: {status}") await payment.delete() elif not status.pending: print( diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index b0ea56098..c919821ff 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -72,7 +72,7 @@ async def api_update_wallet( @core_app.get("/api/v1/payments") async def api_payments(wallet: WalletTypeInfo = Depends(get_key_type)): await get_payments(wallet_id=wallet.wallet.id, pending=True, complete=True) - pendingPayments = await get_payments(wallet_id=wallet.wallet.id, pending=True) + pendingPayments = await get_payments(wallet_id=wallet.wallet.id, pending=True, exclude_uncheckable=True) for payment in pendingPayments: await check_invoice_status( wallet_id=payment.wallet_id, payment_hash=payment.payment_hash @@ -193,7 +193,8 @@ async def api_payments_create( invoiceData: CreateInvoiceData = Body(...), ): if wallet.wallet_type < 0 or wallet.wallet_type > 2: - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Key is invalid") + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, detail="Key is invalid") if invoiceData.out is True and wallet.wallet_type == 0: if not invoiceData.bolt11: @@ -204,7 +205,8 @@ async def api_payments_create( return await api_payments_pay_invoice( invoiceData.bolt11, wallet.wallet ) # admin key - return await api_payments_create_invoice(invoiceData, wallet.wallet) # invoice key + # invoice key + return await api_payments_create_invoice(invoiceData, wallet.wallet) class CreateLNURLData(BaseModel): @@ -372,14 +374,16 @@ async def api_lnurlscan(code: str): params.update(callback=url) # with k1 already in it lnurlauth_key = g().wallet.lnurlauth_key(domain) - params.update(pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex()) + params.update( + pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex()) else: async with httpx.AsyncClient() as client: r = await client.get(url, timeout=5) if r.is_error: raise HTTPException( status_code=HTTPStatus.SERVICE_UNAVAILABLE, - detail={"domain": domain, "message": "failed to get parameters"}, + detail={"domain": domain, + "message": "failed to get parameters"}, ) try: @@ -409,7 +413,8 @@ async def api_lnurlscan(code: str): if tag == "withdrawRequest": params.update(kind="withdraw") - params.update(fixed=data["minWithdrawable"] == data["maxWithdrawable"]) + params.update(fixed=data["minWithdrawable"] + == data["maxWithdrawable"]) # callback with k1 already in it parsed_callback: ParseResult = urlparse(data["callback"]) diff --git a/lnbits/wallets/lndrest.py b/lnbits/wallets/lndrest.py index f0824dacc..e3addfd68 100644 --- a/lnbits/wallets/lndrest.py +++ b/lnbits/wallets/lndrest.py @@ -5,6 +5,8 @@ import base64 from os import getenv from typing import Optional, Dict, AsyncGenerator +from lnbits import bolt11 as lnbits_bolt11 + from .base import ( StatusResponse, InvoiceResponse, @@ -21,7 +23,8 @@ class LndRestWallet(Wallet): endpoint = getenv("LND_REST_ENDPOINT") endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint endpoint = ( - "https://" + endpoint if not endpoint.startswith("http") else endpoint + "https://" + + endpoint if not endpoint.startswith("http") else endpoint ) self.endpoint = endpoint @@ -89,10 +92,21 @@ class LndRestWallet(Wallet): async def pay_invoice(self, bolt11: str) -> PaymentResponse: async with httpx.AsyncClient(verify=self.cert) as client: + # set the fee limit for the payment + invoice = lnbits_bolt11.decode(bolt11) + lnrpcFeeLimit = dict() + if invoice.amount_msat > 1000_000: + lnrpcFeeLimit["percent"] = "1" # in percent + else: + lnrpcFeeLimit["fixed"] = "10" # in sat + r = await client.post( url=f"{self.endpoint}/v1/channels/transactions", headers=self.auth, - json={"payment_request": bolt11}, + json={ + "payment_request": bolt11, + "fee_limit": lnrpcFeeLimit, + }, timeout=180, ) @@ -168,7 +182,8 @@ class LndRestWallet(Wallet): except: continue - payment_hash = base64.b64decode(inv["r_hash"]).hex() + payment_hash = base64.b64decode( + inv["r_hash"]).hex() yield payment_hash except (OSError, httpx.ConnectError, httpx.ReadError): pass