From 43a974af838944ae2e77b576ac6b848dfabdd5fa Mon Sep 17 00:00:00 2001 From: Uthpala Heenatigala Date: Tue, 29 Nov 2022 23:18:24 +0100 Subject: [PATCH 01/49] initializing the deezy extension --- lnbits/extensions/deezy/README.md | 11 ++++ lnbits/extensions/deezy/__init__.py | 16 +++++ lnbits/extensions/deezy/config.json | 6 ++ lnbits/extensions/deezy/migrations.py | 10 ++++ lnbits/extensions/deezy/models.py | 5 ++ .../deezy/templates/example/index.html | 59 +++++++++++++++++++ lnbits/extensions/deezy/views.py | 21 +++++++ lnbits/extensions/deezy/views_api.py | 35 +++++++++++ 8 files changed, 163 insertions(+) create mode 100644 lnbits/extensions/deezy/README.md create mode 100644 lnbits/extensions/deezy/__init__.py create mode 100644 lnbits/extensions/deezy/config.json create mode 100644 lnbits/extensions/deezy/migrations.py create mode 100644 lnbits/extensions/deezy/models.py create mode 100644 lnbits/extensions/deezy/templates/example/index.html create mode 100644 lnbits/extensions/deezy/views.py create mode 100644 lnbits/extensions/deezy/views_api.py diff --git a/lnbits/extensions/deezy/README.md b/lnbits/extensions/deezy/README.md new file mode 100644 index 000000000..277294592 --- /dev/null +++ b/lnbits/extensions/deezy/README.md @@ -0,0 +1,11 @@ +

Example Extension

+

*tagline*

+This is an example extension to help you organise and build you own. + +Try to include an image + + + +

If your extension has API endpoints, include useful ones here

+ +curl -H "Content-type: application/json" -X POST https://YOUR-LNBITS/YOUR-EXTENSION/api/v1/EXAMPLE -d '{"amount":"100","memo":"example"}' -H "X-Api-Key: YOUR_WALLET-ADMIN/INVOICE-KEY" diff --git a/lnbits/extensions/deezy/__init__.py b/lnbits/extensions/deezy/__init__.py new file mode 100644 index 000000000..663920cd7 --- /dev/null +++ b/lnbits/extensions/deezy/__init__.py @@ -0,0 +1,16 @@ +from fastapi import APIRouter + +from lnbits.db import Database +from lnbits.helpers import template_renderer + +db = Database("ext_deezy") + +deezy_ext: APIRouter = APIRouter(prefix="/deezy", tags=["deezy"]) + + +def deezy_renderer(): + return template_renderer(["lnbits/extensions/deezy/templates"]) + + +from .views import * # noqa +from .views_api import * # noqa diff --git a/lnbits/extensions/deezy/config.json b/lnbits/extensions/deezy/config.json new file mode 100644 index 000000000..200d1220f --- /dev/null +++ b/lnbits/extensions/deezy/config.json @@ -0,0 +1,6 @@ +{ + "name": "Deezy", + "short_description": "Join us, make an extension", + "icon": "info", + "contributors": ["Uthpala"] +} diff --git a/lnbits/extensions/deezy/migrations.py b/lnbits/extensions/deezy/migrations.py new file mode 100644 index 000000000..99d7c362d --- /dev/null +++ b/lnbits/extensions/deezy/migrations.py @@ -0,0 +1,10 @@ +# async def m001_initial(db): +# await db.execute( +# f""" +# CREATE TABLE example.example ( +# id TEXT PRIMARY KEY, +# wallet TEXT NOT NULL, +# time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} +# ); +# """ +# ) diff --git a/lnbits/extensions/deezy/models.py b/lnbits/extensions/deezy/models.py new file mode 100644 index 000000000..bfeb7517f --- /dev/null +++ b/lnbits/extensions/deezy/models.py @@ -0,0 +1,5 @@ +# from pydantic import BaseModel + +# class Example(BaseModel): +# id: str +# wallet: str diff --git a/lnbits/extensions/deezy/templates/example/index.html b/lnbits/extensions/deezy/templates/example/index.html new file mode 100644 index 000000000..d732ef376 --- /dev/null +++ b/lnbits/extensions/deezy/templates/example/index.html @@ -0,0 +1,59 @@ +{% extends "base.html" %} {% from "macros.jinja" import window_vars with context +%} {% block page %} + + +
+ Frameworks used by {{SITE_TITLE}} +
+ + + {% raw %} + + + {{ tool.name }} + {{ tool.language }} + + {% endraw %} + + + +

+ A magical "g" is always available, with info about the user, wallets and + extensions: +

+ {% raw %}{{ g }}{% endraw %} +
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }} + +{% endblock %} diff --git a/lnbits/extensions/deezy/views.py b/lnbits/extensions/deezy/views.py new file mode 100644 index 000000000..b8efeae8f --- /dev/null +++ b/lnbits/extensions/deezy/views.py @@ -0,0 +1,21 @@ +from fastapi import FastAPI, Request +from fastapi.params import Depends +from fastapi.templating import Jinja2Templates +from starlette.responses import HTMLResponse + +from lnbits.core.models import User +from lnbits.decorators import check_user_exists + +from . import deezy_ext, deezy_renderer + +templates = Jinja2Templates(directory="templates") + + +@deezy_ext.get("/", response_class=HTMLResponse) +async def index( + request: Request, + user: User = Depends(check_user_exists), # type: ignore +): + return deezy_renderer().TemplateResponse( + "example/index.html", {"request": request, "user": user.dict()} + ) diff --git a/lnbits/extensions/deezy/views_api.py b/lnbits/extensions/deezy/views_api.py new file mode 100644 index 000000000..e8d270a9b --- /dev/null +++ b/lnbits/extensions/deezy/views_api.py @@ -0,0 +1,35 @@ +# views_api.py is for you API endpoints that could be hit by another service + +# add your dependencies here + +# import httpx +# (use httpx just like requests, except instead of response.ok there's only the +# response.is_error that is its inverse) + +from . import deezy_ext + +# add your endpoints here + + +@deezy_ext.get("/api/v1/tools") +async def api_example(): + """Try to add descriptions for others.""" + tools = [ + { + "name": "fastAPI", + "url": "https://fastapi.tiangolo.com/", + "language": "Python", + }, + { + "name": "Vue.js", + "url": "https://vuejs.org/", + "language": "JavaScript", + }, + { + "name": "Quasar Framework", + "url": "https://quasar.dev/", + "language": "JavaScript", + }, + ] + + return tools From 4645b8338b1719abde50fdf6f6f8ff15b971343d Mon Sep 17 00:00:00 2001 From: Uthpala Heenatigala Date: Sun, 4 Dec 2022 23:29:57 +0100 Subject: [PATCH 02/49] added the reverse swap as well --- lnbits/extensions/deezy/config.json | 2 +- .../deezy/templates/deezy/index.html | 255 ++++++++++++++++++ .../deezy/templates/example/index.html | 59 ---- lnbits/extensions/deezy/views.py | 2 +- 4 files changed, 257 insertions(+), 61 deletions(-) create mode 100644 lnbits/extensions/deezy/templates/deezy/index.html delete mode 100644 lnbits/extensions/deezy/templates/example/index.html diff --git a/lnbits/extensions/deezy/config.json b/lnbits/extensions/deezy/config.json index 200d1220f..27c4df2d0 100644 --- a/lnbits/extensions/deezy/config.json +++ b/lnbits/extensions/deezy/config.json @@ -1,6 +1,6 @@ { "name": "Deezy", "short_description": "Join us, make an extension", - "icon": "info", + "icon": "swap_horiz", "contributors": ["Uthpala"] } diff --git a/lnbits/extensions/deezy/templates/deezy/index.html b/lnbits/extensions/deezy/templates/deezy/index.html new file mode 100644 index 000000000..007144f0e --- /dev/null +++ b/lnbits/extensions/deezy/templates/deezy/index.html @@ -0,0 +1,255 @@ +{% extends "base.html" %} {% from "macros.jinja" import window_vars with context +%} {% block page %} + + +
+ Deezy +
+ + + + + + Send onchain funds offchain (BTC -> LN) + + + + + Send offchain funds to onchain address (LN -> BTC) + + + + +
+
Lightning Btc -> Btc
+ + + + + + Cancel + + + + +
+
Pay invoice to complete swap
+ + + +
+
+ + + + + + + +
+
+
+
+
Btc -> Lightning Btc
+ + + + + + Cancel + + + + +
+
Response - Important
+ + + +
+
+ {% raw %} + + Address - {{ swapBtcToLn.response.address }} + + + Commitment - {{ swapBtcToLn.response.commitment }} + + + Secret Access Key - {{ swapBtcToLn.response.secret_access_key }} + + + Signature - {{ swapBtcToLn.response.signature }} + + + Webhook Url - {{ swapBtcToLn.response.webhook_url }} + + {% endraw %} +
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }} + +{% endblock %} diff --git a/lnbits/extensions/deezy/templates/example/index.html b/lnbits/extensions/deezy/templates/example/index.html deleted file mode 100644 index d732ef376..000000000 --- a/lnbits/extensions/deezy/templates/example/index.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} - - -
- Frameworks used by {{SITE_TITLE}} -
- - - {% raw %} - - - {{ tool.name }} - {{ tool.language }} - - {% endraw %} - - - -

- A magical "g" is always available, with info about the user, wallets and - extensions: -

- {% raw %}{{ g }}{% endraw %} -
-
-{% endblock %} {% block scripts %} {{ window_vars(user) }} - -{% endblock %} diff --git a/lnbits/extensions/deezy/views.py b/lnbits/extensions/deezy/views.py index b8efeae8f..131c03b2a 100644 --- a/lnbits/extensions/deezy/views.py +++ b/lnbits/extensions/deezy/views.py @@ -17,5 +17,5 @@ async def index( user: User = Depends(check_user_exists), # type: ignore ): return deezy_renderer().TemplateResponse( - "example/index.html", {"request": request, "user": user.dict()} + "deezy/index.html", {"request": request, "user": user.dict()} ) From 6ec5b9abf6771071daab96f446619f74c3f3a650 Mon Sep 17 00:00:00 2001 From: Uthpala Heenatigala Date: Mon, 5 Dec 2022 21:07:38 +0100 Subject: [PATCH 03/49] convert string to ints --- lnbits/extensions/deezy/templates/deezy/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/deezy/templates/deezy/index.html b/lnbits/extensions/deezy/templates/deezy/index.html index 007144f0e..0d68f0a97 100644 --- a/lnbits/extensions/deezy/templates/deezy/index.html +++ b/lnbits/extensions/deezy/templates/deezy/index.html @@ -53,7 +53,7 @@ filled dense emit-value - v-model.trim="swapLnToBtc.data.onChainFees" + v-model.trim="swapLnToBtc.data.on_chain_sats_per_vbyte" label="On chain fees" min="1" type="number" @@ -204,9 +204,9 @@ sendLnToBtc() { var self = this axios.post('https://api-testnet.deezy.io/v1/swap', { - amount_sats: self.swapLnToBtc.data.amount, + amount_sats: parseInt(self.swapLnToBtc.data.amount), on_chain_address: self.swapLnToBtc.data.on_chain_address, - on_chain_sats_per_vbyte: self.swapLnToBtc.data.on_chain_sats_per_vbyte + on_chain_sats_per_vbyte: parseInt(self.swapLnToBtc.data.on_chain_sats_per_vbyte) }) .then(function (response) { self.swapLnToBtc = { From 209750386edcafec949a60fe0ce2881c67da8ff4 Mon Sep 17 00:00:00 2001 From: Uthpala Heenatigala Date: Mon, 5 Dec 2022 21:12:17 +0100 Subject: [PATCH 04/49] forgot to update this one --- lnbits/extensions/deezy/templates/deezy/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/deezy/templates/deezy/index.html b/lnbits/extensions/deezy/templates/deezy/index.html index 0d68f0a97..95bdc14b0 100644 --- a/lnbits/extensions/deezy/templates/deezy/index.html +++ b/lnbits/extensions/deezy/templates/deezy/index.html @@ -45,7 +45,7 @@ filled dense emit-value - v-model.trim="swapLnToBtc.data.refund_address" + v-model.trim="swapLnToBtc.data.on_chain_address" type="string" label="Onchain address to receive funds" > From 1b2e8d218d00babcd2058f8724d84dc4ecbab921 Mon Sep 17 00:00:00 2001 From: Uthpala Heenatigala Date: Tue, 6 Dec 2022 22:39:45 +0100 Subject: [PATCH 05/49] add api docs and update according to requirements --- .../deezy/templates/deezy/_api_docs.html | 221 ++++++++++++ .../deezy/templates/deezy/index.html | 332 +++++++++--------- 2 files changed, 384 insertions(+), 169 deletions(-) create mode 100644 lnbits/extensions/deezy/templates/deezy/_api_docs.html diff --git a/lnbits/extensions/deezy/templates/deezy/_api_docs.html b/lnbits/extensions/deezy/templates/deezy/_api_docs.html new file mode 100644 index 000000000..88e64e1fd --- /dev/null +++ b/lnbits/extensions/deezy/templates/deezy/_api_docs.html @@ -0,0 +1,221 @@ + + + + +
+ Deezy.io: Do onchain to offchain and vice-versa swaps +
+

+ Link : + + https://deezy.io/ + +

+

+ API DOCS +

+

+ Created by, + Uthpala +

+
+
+
+ + + + + +
+ Get the current info about the swap service for converting LN btc to on-chain BTC. +
+ + GET (mainnet) + https://api.deezy.io/v1/swap/info + +
+ + GET (testnet) + https://api-testnet.deezy.io/v1/swap/info + +
Response
+
+            {
+              "liquidity_fee_ppm": 2000,
+              "on_chain_bytes_estimate": 300,
+              "max_swap_amount_sats": 100000000,
+              "min_swap_amount_sats": 100000,
+              "available": true
+            }
+          
+
+
+
+ + + +
+ Initiate a new swap to send lightning btc in exchange for on-chain btc +
+ + POST (mainnet) + https://api.deezy.io/v1/swap + +
+ + POST (testnet) + https://api-testnet.deezy.io/v1/swap + +
Payload
+
+            {
+              "amount_sats": 500000,
+              "on_chain_address": "tb1qrcdhlm0m...",
+              "on_chain_sats_per_vbyte": 2
+            }
+          
+
Response
+
+            {
+              "bolt11_invoice": "lntb603u1p3vmxj7p...",
+              "fee_sats": 600
+            }
+          
+
+
+
+ + + +
+ Lookup the on-chain transaction information for an existing swap +
+ + GET (mainnet) + https://api.deezy.io/v1/swap/lookup + +
+ + GET (testnet) + https://api-testnet.deezy.io/v1/swap/lookup + +
Query Parameter
+
+            "bolt11_invoice": "lntb603u1p3vmxj7pp54...",
+          
+
Response
+
+            {
+              "on_chain_txid": "string",
+              "tx_hex": "string"
+            }
+          
+
+
+
+
+ + + + +
+ Generate an on-chain deposit address for your lnurl or lightning address. +
+ + POST (mainnet) + https://api.deezy.io/v1/source + +
+ + POST (testnet) + https://api-testnet.deezy.io/v1/source + +
Payload
+
+            {
+              "lnurl_or_lnaddress": "LNURL1DP68GURN8GHJ...",
+              "secret_access_key": "b3c6056d2845867fa7..",
+              "webhook_url": "https://your.website.com/dee.."
+            }
+          
+
Response
+
+            {
+              "address": "bc1qkceyc5...",
+              "secret_access_key": "b3c6056d28458...",
+              "commitment": "for any satoshis sent to bc1..",
+              "signature": "d69j6aj1ssz5egmsr..",
+              "webhook_url": "https://your.website.com/deez.."
+            }
+          
+
+
+
+ + + +
+ Lookup (BTC to LN) swaps +
+ + GET (mainnet) + https://api.deezy.io/v1/source/lookup + +
+ + GET (testnet) + https://api-testnet.deezy.io/v1/source/lookup + +
Response
+
+            {
+              "swaps": [
+                {
+                  "lnurl_or_lnaddress": "string",
+                  "deposit_address": "string",
+                  "utxo_key": "string",
+                  "deposit_amount_sats": 0,
+                  "target_payout_amount_sats": 0,
+                  "paid_amount_sats": 0,
+                  "deezy_fee_sats": 0,
+                  "status": "string"
+                }
+              ],
+              "total_sent_sats": 0,
+              "total_received_sats": 0,
+              "total_pending_payout_sats": 0,
+              "total_deezy_fees_sats": 0
+            }
+          
+
+
+
+
+
diff --git a/lnbits/extensions/deezy/templates/deezy/index.html b/lnbits/extensions/deezy/templates/deezy/index.html index 95bdc14b0..233fce34d 100644 --- a/lnbits/extensions/deezy/templates/deezy/index.html +++ b/lnbits/extensions/deezy/templates/deezy/index.html @@ -1,176 +1,172 @@ {% extends "base.html" %} {% from "macros.jinja" import window_vars with context %} {% block page %} - - -
- Deezy -
- +
+
- - - Send onchain funds offchain (BTC -> LN) - - - - - Send offchain funds to onchain address (LN -> BTC) - - +
+ Deezy +
+ + + + + + Send onchain funds offchain (BTC -> LN) + + + + + Send offchain funds to onchain address (LN -> BTC) + + + + +
+
LIGHTNING BTC -> BTC
+ + + + + + Cancel + + + + +
+
Pay invoice to complete swap
+ + + +
+
+ + + + + + + +
+
+
+
+
BTC -> LIGHTNING BTC
+ + + + Cancel + + + + +
+
Response - Important
+ + + +
+
+ {% raw %} + + Address - {{ swapBtcToLn.response.address }} + + + Commitment - {{ swapBtcToLn.response.commitment }} + + + Secret Access Key - {{ swapBtcToLn.response.secret_access_key }} + + + Signature - {{ swapBtcToLn.response.signature }} + + {% endraw %} +
+
+
+
+
+
+ + +
{{SITE_TITLE}} Boltz extension
+
+ + + {% include "deezy/_api_docs.html" %}
-
-
Lightning Btc -> Btc
- - - - - - Cancel - - - - -
-
Pay invoice to complete swap
- - - -
-
- - - - - - - -
-
-
-
-
Btc -> Lightning Btc
- - - - - - Cancel - - - - -
-
Response - Important
- - - -
-
- {% raw %} - - Address - {{ swapBtcToLn.response.address }} - - - Commitment - {{ swapBtcToLn.response.commitment }} - - - Secret Access Key - {{ swapBtcToLn.response.secret_access_key }} - - - Signature - {{ swapBtcToLn.response.signature }} - - - Webhook Url - {{ swapBtcToLn.response.webhook_url }} - - {% endraw %} -
-
-
- +
+
{% endblock %} {% block scripts %} {{ window_vars(user) }} From d338e3889a74602854057a4084060aa78c39cee9 Mon Sep 17 00:00:00 2001 From: Uthpala Heenatigala Date: Thu, 8 Dec 2022 16:42:33 +0100 Subject: [PATCH 12/49] Add on chain fee suggestions --- .../deezy/templates/deezy/index.html | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/deezy/templates/deezy/index.html b/lnbits/extensions/deezy/templates/deezy/index.html index 537ed8872..60b31a093 100644 --- a/lnbits/extensions/deezy/templates/deezy/index.html +++ b/lnbits/extensions/deezy/templates/deezy/index.html @@ -12,7 +12,7 @@ label="SWAP (LIGHTNING -> BTC)" unelevated color="primary" - @click="swapLnToBtc.show = true; swapBtcToLn.show = false" + @click="showLnToBtcForm" > Send lightning btc and receive on-chain btc @@ -60,7 +60,9 @@ label="On chain fee rate (sats/vbyte)" min="1" type="number" - > + :hint="swapLnToBtc.suggested_fees && `Economy Fee - ${swapLnToBtc.suggested_fees?.economyFee} | Half an hour fee - ${swapLnToBtc.suggested_fees?.halfHourFee} | Fastest fee - ${swapLnToBtc.suggested_fees?.fastestFee}`" + > + { + console.log(result.data) + this.swapLnToBtc.suggested_fees = result.data + }) + }, checkIfInvoiceIsPaid() { if (this.swapLnToBtc.response && !this.swapLnToBtc.invoicePaid) { var self = this From c2423605ccff3604640d765e5304ea424c280782 Mon Sep 17 00:00:00 2001 From: Danny Diekroeger Date: Sat, 10 Dec 2022 11:00:36 -0800 Subject: [PATCH 13/49] add migrations --- lnbits/extensions/deezy/migrations.py | 39 ++++++++++++++++++++------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/lnbits/extensions/deezy/migrations.py b/lnbits/extensions/deezy/migrations.py index 99d7c362d..86edcf099 100644 --- a/lnbits/extensions/deezy/migrations.py +++ b/lnbits/extensions/deezy/migrations.py @@ -1,10 +1,29 @@ -# async def m001_initial(db): -# await db.execute( -# f""" -# CREATE TABLE example.example ( -# id TEXT PRIMARY KEY, -# wallet TEXT NOT NULL, -# time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} -# ); -# """ -# ) +async def m001_initial(db): + await db.execute( + f""" + CREATE TABLE deezy.ln_to_btc_swap ( + id TEXT PRIMARY KEY, + amount_sats {db.big_int} NOT NULL, + on_chain_address TEXT NOT NULL, + on_chain_sats_per_vbyte INT NOT NULL, + bolt11_invoice TEXT NOT NULL, + fee_sats {db.big_int} NOT NULL, + txid TEXT NULL, + tx_hex TEXT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + ); + """ + ) + await db.execute( + f""" + CREATE TABLE deezy.btc_to_ln_swap ( + id TEXT PRIMARY KEY, + ln_address TEXT NOT NULL, + on_chain_address TEXT NOT NULL, + secret_access_key TEXT NOT NULL, + commitment TEXT NOT NULL, + signature TEXT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + ); + """ + ) From 663cee8fbe1b5836d9421c854d7f075b9c081fa5 Mon Sep 17 00:00:00 2001 From: Uthpala Heenatigala Date: Sun, 11 Dec 2022 17:42:47 +0100 Subject: [PATCH 14/49] fix ui bug --- lnbits/extensions/deezy/templates/deezy/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/deezy/templates/deezy/index.html b/lnbits/extensions/deezy/templates/deezy/index.html index 60b31a093..98067fd7e 100644 --- a/lnbits/extensions/deezy/templates/deezy/index.html +++ b/lnbits/extensions/deezy/templates/deezy/index.html @@ -223,12 +223,12 @@ showLnToBtcForm() { this.getSuggestedOnChainFees() this.swapLnToBtc.show = true + this.swapBtcToLn.show = false }, getSuggestedOnChainFees() { axios .get('https://mempool.space/api/v1/fees/recommended') .then(result => { - console.log(result.data) this.swapLnToBtc.suggested_fees = result.data }) }, From cd05eba183bc7b8bfdbd1c98d52bd07fae90a256 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 5 Jan 2023 00:52:08 +0000 Subject: [PATCH 15/49] Added tile and tweaked description for size limitation --- lnbits/extensions/deezy/__init__.py | 9 +++++++++ lnbits/extensions/deezy/config.json | 4 ++-- lnbits/extensions/deezy/static/deezy.png | Bin 0 -> 5196 bytes 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 lnbits/extensions/deezy/static/deezy.png diff --git a/lnbits/extensions/deezy/__init__.py b/lnbits/extensions/deezy/__init__.py index 120124e75..97f6d9ef5 100644 --- a/lnbits/extensions/deezy/__init__.py +++ b/lnbits/extensions/deezy/__init__.py @@ -1,4 +1,5 @@ from fastapi import APIRouter +from starlette.staticfiles import StaticFiles from lnbits.db import Database from lnbits.helpers import template_renderer @@ -7,6 +8,14 @@ db = Database("ext_deezy") deezy_ext: APIRouter = APIRouter(prefix="/deezy", tags=["deezy"]) +deezy_static_files = [ + { + "path": "/deezy/static", + "app": StaticFiles(directory="lnbits/extensions/deezy/static"), + "name": "deezy_static", + } +] + def deezy_renderer(): return template_renderer(["lnbits/extensions/deezy/templates"]) diff --git a/lnbits/extensions/deezy/config.json b/lnbits/extensions/deezy/config.json index e3c1a3d71..4f945a791 100644 --- a/lnbits/extensions/deezy/config.json +++ b/lnbits/extensions/deezy/config.json @@ -1,6 +1,6 @@ { "name": "Deezy", - "short_description": "Swap lightning to on-chain, or receive on-chain to lightning addresses.", - "icon": "swap_horiz", + "short_description": "LN to onchain, onchain to LN swaps", + "tile": "/deezy/static/deezy.png", "contributors": ["Uthpala"] } diff --git a/lnbits/extensions/deezy/static/deezy.png b/lnbits/extensions/deezy/static/deezy.png new file mode 100644 index 0000000000000000000000000000000000000000..cb526705c4f83e165699236de8bdf4d69b61e1b7 GIT binary patch literal 5196 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 At^fc4 literal 0 HcmV?d00001 From 2b46fa6c5642d5293dd1901c2c66fd6a12499db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 5 Jan 2023 09:28:38 +0100 Subject: [PATCH 16/49] fix livestream mypy issues --- lnbits/extensions/livestream/lnurl.py | 29 +++++++++++++---------- lnbits/extensions/livestream/models.py | 16 ++++++------- lnbits/extensions/livestream/tasks.py | 3 +++ lnbits/extensions/livestream/views.py | 24 +++++++++++-------- lnbits/extensions/livestream/views_api.py | 15 ++++++------ pyproject.toml | 1 - 6 files changed, 50 insertions(+), 38 deletions(-) diff --git a/lnbits/extensions/livestream/lnurl.py b/lnbits/extensions/livestream/lnurl.py index 89e431e5c..f50912b3a 100644 --- a/lnbits/extensions/livestream/lnurl.py +++ b/lnbits/extensions/livestream/lnurl.py @@ -1,12 +1,9 @@ -import hashlib import math from http import HTTPStatus -from os import name -from fastapi.exceptions import HTTPException -from fastapi.params import Query +from fastapi import HTTPException, Query, Request from lnurl import LnurlErrorResponse, LnurlPayActionResponse, LnurlPayResponse -from starlette.requests import Request # type: ignore +from lnurl.models import ClearnetUrl, LightningInvoice, MilliSatoshi from lnbits.core.services import create_invoice @@ -29,9 +26,12 @@ async def lnurl_livestream(ls_id, request: Request): ) resp = LnurlPayResponse( - callback=request.url_for("livestream.lnurl_callback", track_id=track.id), - min_sendable=track.min_sendable, - max_sendable=track.max_sendable, + callback=ClearnetUrl( + request.url_for("livestream.lnurl_callback", track_id=track.id), + scheme="https", + ), + minSendable=MilliSatoshi(track.min_sendable), + maxSendable=MilliSatoshi(track.max_sendable), metadata=await track.lnurlpay_metadata(), ) @@ -48,9 +48,12 @@ async def lnurl_track(track_id, request: Request): raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Track not found.") resp = LnurlPayResponse( - callback=request.url_for("livestream.lnurl_callback", track_id=track.id), - min_sendable=track.min_sendable, - max_sendable=track.max_sendable, + callback=ClearnetUrl( + request.url_for("livestream.lnurl_callback", track_id=track.id), + scheme="https", + ), + minSendable=MilliSatoshi(track.min_sendable), + maxSendable=MilliSatoshi(track.max_sendable), metadata=await track.lnurlpay_metadata(), ) @@ -85,6 +88,7 @@ async def lnurl_callback( ).dict() ls = await get_livestream_by_track(track_id) + assert ls payment_hash, payment_request = await create_invoice( wallet_id=ls.wallet, @@ -94,13 +98,14 @@ async def lnurl_callback( extra={"tag": "livestream", "track": track.id, "comment": comment}, ) + assert track.price_msat if amount_received < track.price_msat: success_action = None else: success_action = track.success_action(payment_hash, request=request) resp = LnurlPayActionResponse( - pr=payment_request, success_action=success_action, routes=[] + pr=LightningInvoice(payment_request), successAction=success_action, routes=[] ) return resp.dict() diff --git a/lnbits/extensions/livestream/models.py b/lnbits/extensions/livestream/models.py index 0034f4a79..5d617da99 100644 --- a/lnbits/extensions/livestream/models.py +++ b/lnbits/extensions/livestream/models.py @@ -1,13 +1,12 @@ import json from typing import Optional -from fastapi import Query +from fastapi import Query, Request from lnurl import Lnurl -from lnurl import encode as lnurl_encode # type: ignore -from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore -from lnurl.types import LnurlPayMetadata # type: ignore +from lnurl import encode as lnurl_encode +from lnurl.models import ClearnetUrl, Max144Str, UrlAction +from lnurl.types import LnurlPayMetadata from pydantic import BaseModel -from starlette.requests import Request class CreateTrack(BaseModel): @@ -32,7 +31,7 @@ class Livestream(BaseModel): class Track(BaseModel): id: int download_url: Optional[str] - price_msat: Optional[int] + price_msat: int = 0 name: str producer: int @@ -71,7 +70,7 @@ class Track(BaseModel): def success_action( self, payment_hash: str, request: Request - ) -> Optional[LnurlPaySuccessAction]: + ) -> Optional[UrlAction]: if not self.download_url: return None @@ -79,7 +78,8 @@ class Track(BaseModel): url_with_query = f"{url}?p={payment_hash}" return UrlAction( - url=url_with_query, description=f"Download the track {self.name}!" + url=ClearnetUrl(url_with_query, scheme="https"), + description=Max144Str(f"Download the track {self.name}!"), ) diff --git a/lnbits/extensions/livestream/tasks.py b/lnbits/extensions/livestream/tasks.py index d081332f5..4e9787692 100644 --- a/lnbits/extensions/livestream/tasks.py +++ b/lnbits/extensions/livestream/tasks.py @@ -22,6 +22,9 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: + if not payment.extra: + return + if payment.extra.get("tag") != "livestream": # not a livestream invoice return diff --git a/lnbits/extensions/livestream/views.py b/lnbits/extensions/livestream/views.py index 97f803a31..ca12f16bd 100644 --- a/lnbits/extensions/livestream/views.py +++ b/lnbits/extensions/livestream/views.py @@ -1,20 +1,16 @@ from http import HTTPStatus -from fastapi.param_functions import Depends -from fastapi.params import Query -from starlette.exceptions import HTTPException -from starlette.requests import Request +from fastapi import Depends, HTTPException, Query, Request +from starlette.datastructures import URL from starlette.responses import HTMLResponse, RedirectResponse from lnbits.core.crud import get_wallet_payment -from lnbits.core.models import Payment, User +from lnbits.core.models import User from lnbits.decorators import check_user_exists from . import livestream_ext, livestream_renderer from .crud import get_livestream_by_track, get_track -# from mmap import MAP_DENYWRITE - @livestream_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): @@ -28,12 +24,18 @@ async def track_redirect_download(track_id, p: str = Query(...)): payment_hash = p track = await get_track(track_id) ls = await get_livestream_by_track(track_id) - payment: Payment = await get_wallet_payment(ls.wallet, payment_hash) + assert ls + payment = await get_wallet_payment(ls.wallet, payment_hash) if not payment: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, - detail=f"Couldn't find the payment {payment_hash} or track {track.id}.", + detail=f"Couldn't find the payment {payment_hash}.", + ) + if not track: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail=f"Couldn't find the track {track_id}.", ) if payment.pending: @@ -41,4 +43,6 @@ async def track_redirect_download(track_id, p: str = Query(...)): status_code=HTTPStatus.PAYMENT_REQUIRED, detail=f"Payment {payment_hash} wasn't received yet. Please try again in a minute.", ) - return RedirectResponse(url=track.download_url) + + assert track.download_url + return RedirectResponse(url=URL(track.download_url)) diff --git a/lnbits/extensions/livestream/views_api.py b/lnbits/extensions/livestream/views_api.py index 0c169a71f..63a017428 100644 --- a/lnbits/extensions/livestream/views_api.py +++ b/lnbits/extensions/livestream/views_api.py @@ -1,9 +1,7 @@ from http import HTTPStatus -from fastapi.param_functions import Depends +from fastapi import Depends, HTTPException, Request from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl -from starlette.exceptions import HTTPException -from starlette.requests import Request # type: ignore from lnbits.decorators import WalletTypeInfo, get_key_type from lnbits.extensions.livestream.models import CreateTrack @@ -27,6 +25,7 @@ async def api_livestream_from_wallet( req: Request, g: WalletTypeInfo = Depends(get_key_type) ): ls = await get_or_create_livestream_by_wallet(g.wallet.id) + assert ls tracks = await get_tracks(ls.id) producers = await get_producers(ls.id) @@ -55,17 +54,17 @@ async def api_update_track(track_id, g: WalletTypeInfo = Depends(get_key_type)): id = int(track_id) except ValueError: id = 0 - if id <= 0: - id = None ls = await get_or_create_livestream_by_wallet(g.wallet.id) - await update_current_track(ls.id, id) + assert ls + await update_current_track(ls.id, None if id <= 0 else id) return "", HTTPStatus.NO_CONTENT @livestream_ext.put("/api/v1/livestream/fee/{fee_pct}") async def api_update_fee(fee_pct, g: WalletTypeInfo = Depends(get_key_type)): ls = await get_or_create_livestream_by_wallet(g.wallet.id) + assert ls await update_livestream_fee(ls.id, int(fee_pct)) return "", HTTPStatus.NO_CONTENT @@ -76,9 +75,10 @@ async def api_add_track( data: CreateTrack, id=None, g: WalletTypeInfo = Depends(get_key_type) ): ls = await get_or_create_livestream_by_wallet(g.wallet.id) + assert ls if data.producer_id: - p_id = data.producer_id + p_id = int(data.producer_id) elif data.producer_name: p_id = await add_producer(ls.id, data.producer_name) else: @@ -96,5 +96,6 @@ async def api_add_track( @livestream_ext.delete("/api/v1/livestream/tracks/{track_id}") async def api_delete_track(track_id, g: WalletTypeInfo = Depends(get_key_type)): ls = await get_or_create_livestream_by_wallet(g.wallet.id) + assert ls await delete_track_from_livestream(ls.id, track_id) return "", HTTPStatus.NO_CONTENT diff --git a/pyproject.toml b/pyproject.toml index e2116ed08..d251c91e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,7 +92,6 @@ exclude = """(?x)( ^lnbits/extensions/bleskomat. | ^lnbits/extensions/boltz. | ^lnbits/extensions/boltcards. - | ^lnbits/extensions/livestream. | ^lnbits/extensions/lnaddress. | ^lnbits/extensions/lnurldevice. | ^lnbits/extensions/satspay. From 93d6d1279e8092f4b9c769a736ce4dede402f3c5 Mon Sep 17 00:00:00 2001 From: Uthpala Heenatigala Date: Thu, 5 Jan 2023 11:46:01 +0100 Subject: [PATCH 17/49] adding deezy token --- lnbits/extensions/deezy/__init__.py | 1 + lnbits/extensions/deezy/crud.py | 38 +++++ lnbits/extensions/deezy/migrations.py | 8 + lnbits/extensions/deezy/models.py | 9 +- .../deezy/templates/deezy/index.html | 151 +++++++++++++++++- lnbits/extensions/deezy/views_api.py | 31 ++++ 6 files changed, 233 insertions(+), 5 deletions(-) create mode 100644 lnbits/extensions/deezy/crud.py create mode 100644 lnbits/extensions/deezy/views_api.py diff --git a/lnbits/extensions/deezy/__init__.py b/lnbits/extensions/deezy/__init__.py index 97f6d9ef5..05d1c9a70 100644 --- a/lnbits/extensions/deezy/__init__.py +++ b/lnbits/extensions/deezy/__init__.py @@ -22,3 +22,4 @@ def deezy_renderer(): from .views import * # noqa +from .views_api import * # noqa diff --git a/lnbits/extensions/deezy/crud.py b/lnbits/extensions/deezy/crud.py new file mode 100644 index 000000000..69630610d --- /dev/null +++ b/lnbits/extensions/deezy/crud.py @@ -0,0 +1,38 @@ +from http import HTTPStatus +from typing import List + +from . import db +from .models import ( + Token, +) + +""" +Get Deezy Token +""" + + +async def get_token() -> Token: + + row = await db.fetchone( + f"SELECT * FROM deezy.token ORDER BY created_at DESC", + ) + + return Token(**row) if row else None + + +async def save_token( + data: Token, +) -> Token: + + await db.execute( + """ + INSERT INTO deezy.token ( + deezy_token + ) + VALUES (?) + """, + ( + data.deezy_token, + ), + ) + return data diff --git a/lnbits/extensions/deezy/migrations.py b/lnbits/extensions/deezy/migrations.py index 86edcf099..67455d6b5 100644 --- a/lnbits/extensions/deezy/migrations.py +++ b/lnbits/extensions/deezy/migrations.py @@ -27,3 +27,11 @@ async def m001_initial(db): ); """ ) + await db.execute( + f""" + CREATE TABLE deezy.token ( + deezy_token TEXT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + ); + """ + ) diff --git a/lnbits/extensions/deezy/models.py b/lnbits/extensions/deezy/models.py index bfeb7517f..751191f0b 100644 --- a/lnbits/extensions/deezy/models.py +++ b/lnbits/extensions/deezy/models.py @@ -1,5 +1,6 @@ -# from pydantic import BaseModel +from pydantic.main import BaseModel +from sqlalchemy.engine import base # type: ignore -# class Example(BaseModel): -# id: str -# wallet: str + +class Token(BaseModel): + deezy_token: str diff --git a/lnbits/extensions/deezy/templates/deezy/index.html b/lnbits/extensions/deezy/templates/deezy/index.html index 98067fd7e..5c2f9ae42 100644 --- a/lnbits/extensions/deezy/templates/deezy/index.html +++ b/lnbits/extensions/deezy/templates/deezy/index.html @@ -5,6 +5,30 @@
Deezy
+

Due to regulatory reasons you need to get a access token from deezy. Contact - support@deezy.io or @dannydeezy on telegram

+
+
+ Deezy token + Add or Update token +
+

+
+ + + + @@ -189,6 +213,14 @@ +
+ +
{% endblock %} {% block scripts %} {{ window_vars(user) }} -{% endblock %} +{% endblock %} \ No newline at end of file From a5cdd69dbe990be5df2041e6e19a48b4173429f0 Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 6 Jan 2023 17:46:41 +0000 Subject: [PATCH 23/49] Moved sub-menu for mobile --- .../example/templates/example/index.html | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lnbits/extensions/example/templates/example/index.html b/lnbits/extensions/example/templates/example/index.html index 64a4d3dde..47319ac6e 100644 --- a/lnbits/extensions/example/templates/example/index.html +++ b/lnbits/extensions/example/templates/example/index.html @@ -79,9 +79,9 @@
Frameworks
- -