feat: pay_invoice
This commit is contained in:
@@ -26,6 +26,8 @@ from .models import (
|
|||||||
LogRequest,
|
LogRequest,
|
||||||
LogResponse,
|
LogResponse,
|
||||||
NowResponse,
|
NowResponse,
|
||||||
|
PayInvoiceRequest,
|
||||||
|
PayInvoiceResponse,
|
||||||
RandomIdRequest,
|
RandomIdRequest,
|
||||||
RandomIdResponse,
|
RandomIdResponse,
|
||||||
StorageDeleteRequest,
|
StorageDeleteRequest,
|
||||||
@@ -37,6 +39,8 @@ from .models import (
|
|||||||
StorageSetRequest,
|
StorageSetRequest,
|
||||||
StorageSetResponse,
|
StorageSetResponse,
|
||||||
UserWalletSummary,
|
UserWalletSummary,
|
||||||
|
WalletBalanceRequest,
|
||||||
|
WalletBalanceResponse,
|
||||||
)
|
)
|
||||||
from .storage import (
|
from .storage import (
|
||||||
storage_delete_row,
|
storage_delete_row,
|
||||||
@@ -410,6 +414,92 @@ class ExtensionAPI:
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@extension_api_method(
|
||||||
|
method_id="wallet.balance",
|
||||||
|
namespace="wallet",
|
||||||
|
name="Read wallet balance",
|
||||||
|
host_name="wallet_balance",
|
||||||
|
sdk_name="balance",
|
||||||
|
description="Read the balance of a wallet available to the user.",
|
||||||
|
required_permission="wallet.balance.read",
|
||||||
|
)
|
||||||
|
async def wallet_balance(
|
||||||
|
self, request: WalletBalanceRequest
|
||||||
|
) -> WalletBalanceResponse:
|
||||||
|
from lnbits.core.crud.wallets import get_wallet
|
||||||
|
|
||||||
|
if not self.user_id:
|
||||||
|
raise PermissionError(
|
||||||
|
"Reading a wallet balance requires an authenticated user context."
|
||||||
|
)
|
||||||
|
|
||||||
|
wallet = await get_wallet(request.wallet_id)
|
||||||
|
if wallet is None or wallet.user != self.user_id:
|
||||||
|
raise PermissionError("Reading this wallet balance is not allowed.")
|
||||||
|
|
||||||
|
withdrawable_msat = max(wallet.withdrawable_balance, 0)
|
||||||
|
fee_reserve_msat = max(wallet.balance_msat - withdrawable_msat, 0)
|
||||||
|
return WalletBalanceResponse(
|
||||||
|
wallet_id=wallet.id,
|
||||||
|
name=wallet.name,
|
||||||
|
currency=wallet.currency,
|
||||||
|
balance_msat=wallet.balance_msat,
|
||||||
|
balance_sat=wallet.balance,
|
||||||
|
withdrawable_msat=withdrawable_msat,
|
||||||
|
withdrawable_sat=withdrawable_msat // 1000,
|
||||||
|
fee_reserve_msat=fee_reserve_msat,
|
||||||
|
fee_reserve_sat=fee_reserve_msat // 1000,
|
||||||
|
can_send_payments=wallet.can_send_payments,
|
||||||
|
)
|
||||||
|
|
||||||
|
@extension_api_method(
|
||||||
|
method_id="wallet.pay_invoice",
|
||||||
|
namespace="wallet",
|
||||||
|
name="Pay invoice",
|
||||||
|
host_name="pay_invoice",
|
||||||
|
sdk_name="payInvoice",
|
||||||
|
description="Pay a Lightning invoice from a wallet available to the user.",
|
||||||
|
required_permission="wallet.pay_invoice",
|
||||||
|
)
|
||||||
|
async def wallet_pay_invoice(
|
||||||
|
self, request: PayInvoiceRequest
|
||||||
|
) -> PayInvoiceResponse:
|
||||||
|
from lnbits.core.crud.wallets import get_wallet
|
||||||
|
from lnbits.core.services.payments import pay_invoice
|
||||||
|
from lnbits.exceptions import PaymentError
|
||||||
|
|
||||||
|
if not self.user_id:
|
||||||
|
raise PermissionError(
|
||||||
|
"Paying an invoice requires an authenticated user context."
|
||||||
|
)
|
||||||
|
|
||||||
|
wallet = await get_wallet(request.wallet_id)
|
||||||
|
if wallet is None or wallet.user != self.user_id:
|
||||||
|
raise PermissionError("Paying invoices from this wallet is not allowed.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
payment = await pay_invoice(
|
||||||
|
wallet_id=request.wallet_id,
|
||||||
|
payment_request=request.payment_request,
|
||||||
|
max_sat=request.max_sat,
|
||||||
|
extra={"tag": self.extension_id, **request.extra},
|
||||||
|
description=request.description,
|
||||||
|
tag=self.extension_id,
|
||||||
|
)
|
||||||
|
except (PaymentError, ValueError) as exc:
|
||||||
|
return PayInvoiceResponse(ok=False, error=str(exc))
|
||||||
|
|
||||||
|
return PayInvoiceResponse(
|
||||||
|
ok=True,
|
||||||
|
checking_id=payment.checking_id,
|
||||||
|
payment_hash=payment.payment_hash,
|
||||||
|
status=payment.status,
|
||||||
|
amount_msat=abs(payment.amount),
|
||||||
|
fee_msat=abs(payment.fee),
|
||||||
|
pending=payment.pending,
|
||||||
|
success=payment.success,
|
||||||
|
)
|
||||||
|
|
||||||
@extension_api_method(
|
@extension_api_method(
|
||||||
method_id="http.request",
|
method_id="http.request",
|
||||||
namespace="http",
|
namespace="http",
|
||||||
|
|||||||
@@ -117,6 +117,43 @@ class ListUserWalletsResponse(BaseModel):
|
|||||||
wallets: list[UserWalletSummary] = Field(default_factory=list)
|
wallets: list[UserWalletSummary] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
class WalletBalanceRequest(BaseModel):
|
||||||
|
wallet_id: str = Field(..., min_length=1, max_length=128)
|
||||||
|
|
||||||
|
|
||||||
|
class WalletBalanceResponse(BaseModel):
|
||||||
|
wallet_id: str
|
||||||
|
name: str
|
||||||
|
currency: str | None = None
|
||||||
|
balance_msat: int
|
||||||
|
balance_sat: int
|
||||||
|
withdrawable_msat: int
|
||||||
|
withdrawable_sat: int
|
||||||
|
fee_reserve_msat: int
|
||||||
|
fee_reserve_sat: int
|
||||||
|
can_send_payments: bool
|
||||||
|
|
||||||
|
|
||||||
|
class PayInvoiceRequest(BaseModel):
|
||||||
|
wallet_id: str = Field(..., min_length=1, max_length=128)
|
||||||
|
payment_request: str = Field(..., min_length=1, max_length=8192)
|
||||||
|
max_sat: int | None = Field(None, gt=0)
|
||||||
|
description: str = Field("", max_length=512)
|
||||||
|
extra: dict[str, str] = Field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
class PayInvoiceResponse(BaseModel):
|
||||||
|
ok: bool = True
|
||||||
|
error: str | None = None
|
||||||
|
checking_id: str | None = None
|
||||||
|
payment_hash: str | None = None
|
||||||
|
status: str | None = None
|
||||||
|
amount_msat: int = 0
|
||||||
|
fee_msat: int = 0
|
||||||
|
pending: bool = False
|
||||||
|
success: bool = False
|
||||||
|
|
||||||
|
|
||||||
class HttpRequest(BaseModel):
|
class HttpRequest(BaseModel):
|
||||||
method: Literal["DELETE", "GET", "HEAD", "PATCH", "POST", "PUT"] = "GET"
|
method: Literal["DELETE", "GET", "HEAD", "PATCH", "POST", "PUT"] = "GET"
|
||||||
url: str = Field(..., min_length=1, max_length=2048)
|
url: str = Field(..., min_length=1, max_length=2048)
|
||||||
|
|||||||
@@ -542,7 +542,13 @@ window.localisation.en = {
|
|||||||
'Create Lightning invoices from public pages',
|
'Create Lightning invoices from public pages',
|
||||||
extension_permission_wallet_create_invoice_public_desc:
|
extension_permission_wallet_create_invoice_public_desc:
|
||||||
'Create incoming Lightning invoices from public pages.',
|
'Create incoming Lightning invoices from public pages.',
|
||||||
|
extension_permission_wallet_balance_read: 'View wallet balances',
|
||||||
|
extension_permission_wallet_balance_read_desc:
|
||||||
|
'Read balances of wallets available to your account.',
|
||||||
extension_permission_wallet_list: 'List wallets',
|
extension_permission_wallet_list: 'List wallets',
|
||||||
|
extension_permission_wallet_pay_invoice: 'Pay invoices',
|
||||||
|
extension_permission_wallet_pay_invoice_desc:
|
||||||
|
'Send Lightning payments from wallets available to your account.',
|
||||||
create_extension: 'Create Extension',
|
create_extension: 'Create Extension',
|
||||||
release_details_error: 'Cannot get the release details.',
|
release_details_error: 'Cannot get the release details.',
|
||||||
pay_from_wallet: 'Pay from Wallet',
|
pay_from_wallet: 'Pay from Wallet',
|
||||||
|
|||||||
Reference in New Issue
Block a user