diff --git a/lnbits/extensions/lnurlp/crud.py b/lnbits/extensions/lnurlp/crud.py index 4215faf66..2eda3322c 100644 --- a/lnbits/extensions/lnurlp/crud.py +++ b/lnbits/extensions/lnurlp/crud.py @@ -9,6 +9,12 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: returning = "" if db.type == SQLITE else "RETURNING ID" method = db.execute if db.type == SQLITE else db.fetchone + # database only allows int4 entries for min and max. For fiat currencies, + # we multiply by data.fiat_base_multiplier (usually 100) to save the value in cents. + if data.currency and data.fiat_base_multiplier: + data.min *= data.fiat_base_multiplier + data.max *= data.fiat_base_multiplier + result = await (method)( f""" INSERT INTO lnurlp.pay_links ( @@ -22,9 +28,10 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: success_text, success_url, comment_chars, - currency + currency, + fiat_base_multiplier ) - VALUES (?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?, ?) {returning} """, ( @@ -37,6 +44,7 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: data.success_url, data.comment_chars, data.currency, + data.fiat_base_multiplier, ), ) if db.type == SQLITE: diff --git a/lnbits/extensions/lnurlp/lnurl.py b/lnbits/extensions/lnurlp/lnurl.py index 173b4823a..9052b99b5 100644 --- a/lnbits/extensions/lnurlp/lnurl.py +++ b/lnbits/extensions/lnurlp/lnurl.py @@ -29,11 +29,15 @@ async def api_lnurl_response(request: Request, link_id): status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." ) - rate = await get_fiat_rate_satoshis(link.currency) if link.currency else 1 + rate = ( + await get_fiat_rate_satoshis(link.currency) / link.fiat_base_multiplier + if link.currency + else 1 + ) resp = LnurlPayResponse( callback=request.url_for("lnurlp.api_lnurl_callback", link_id=link.id), - min_sendable=math.ceil(link.min * rate) * 1000, + min_sendable=round(link.min * rate) * 1000, max_sendable=round(link.max * rate) * 1000, metadata=link.lnurlpay_metadata, ) diff --git a/lnbits/extensions/lnurlp/migrations.py b/lnbits/extensions/lnurlp/migrations.py index 428bde2c8..81dd62f83 100644 --- a/lnbits/extensions/lnurlp/migrations.py +++ b/lnbits/extensions/lnurlp/migrations.py @@ -50,3 +50,13 @@ async def m003_min_max_comment_fiat(db): await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN max INTEGER;") await db.execute("UPDATE lnurlp.pay_links SET max = min;") await db.execute("DROP TABLE lnurlp.invoices") + + +async def m004_fiat_base_multiplier(db): + """ + Store the multiplier for fiat prices. We store the price in cents and + remember to multiply by 100 when we use it to convert to Dollars. + """ + await db.execute( + "ALTER TABLE lnurlp.pay_links ADD COLUMN fiat_base_multiplier INTEGER DEFAULT 1;" + ) diff --git a/lnbits/extensions/lnurlp/models.py b/lnbits/extensions/lnurlp/models.py index 6fc9cc1a0..bd121cc84 100644 --- a/lnbits/extensions/lnurlp/models.py +++ b/lnbits/extensions/lnurlp/models.py @@ -11,20 +11,21 @@ from pydantic import BaseModel class CreatePayLinkData(BaseModel): description: str - min: int = Query(0.01, ge=0.01) - max: int = Query(0.01, ge=0.01) + min: float = Query(1, ge=0.01) + max: float = Query(1, ge=0.01) currency: str = Query(None) comment_chars: int = Query(0, ge=0, lt=800) webhook_url: str = Query(None) success_text: str = Query(None) success_url: str = Query(None) + fiat_base_multiplier: int = Query(100, ge=1) class PayLink(BaseModel): id: int wallet: str description: str - min: int + min: float served_meta: int served_pr: int webhook_url: Optional[str] @@ -32,11 +33,15 @@ class PayLink(BaseModel): success_url: Optional[str] currency: Optional[str] comment_chars: int - max: int + max: float + fiat_base_multiplier: int @classmethod def from_row(cls, row: Row) -> "PayLink": data = dict(row) + if data["currency"] and data["fiat_base_multiplier"]: + data["min"] /= data["fiat_base_multiplier"] + data["max"] /= data["fiat_base_multiplier"] return cls(**data) def lnurl(self, req: Request) -> str: diff --git a/lnbits/extensions/lnurlp/views_api.py b/lnbits/extensions/lnurlp/views_api.py index ff6e96e21..52d729a98 100644 --- a/lnbits/extensions/lnurlp/views_api.py +++ b/lnbits/extensions/lnurlp/views_api.py @@ -76,10 +76,6 @@ async def api_link_create_or_update( link_id=None, wallet: WalletTypeInfo = Depends(get_key_type), ): - if data.min < 1: - raise HTTPException( - detail="Min must be more than 1.", status_code=HTTPStatus.BAD_REQUEST - ) if data.min > data.max: raise HTTPException( @@ -87,7 +83,7 @@ async def api_link_create_or_update( ) if data.currency == None and ( - round(data.min) != data.min or round(data.max) != data.max + round(data.min) != data.min or round(data.max) != data.max or data.min < 1 ): raise HTTPException( detail="Must use full satoshis.", status_code=HTTPStatus.BAD_REQUEST