diff --git a/lnbits/extensions/amilk/README.md b/lnbits/extensions/amilk/README.md new file mode 100644 index 00000000..f3c20fb8 --- /dev/null +++ b/lnbits/extensions/amilk/README.md @@ -0,0 +1,11 @@ +
+
+
+curl -H "Content-type: application/json" -X POST https://YOUR-LNBITS/YOUR-EXTENSION/api/v1/EXAMPLE -d '{"amount":"100","memo":"example"}' -H "Grpc-Metadata-macaroon: YOUR_WALLET-ADMIN/INVOICE-KEY"
diff --git a/lnbits/extensions/amilk/__init__.py b/lnbits/extensions/amilk/__init__.py
new file mode 100644
index 00000000..175dcb48
--- /dev/null
+++ b/lnbits/extensions/amilk/__init__.py
@@ -0,0 +1,8 @@
+from flask import Blueprint
+
+
+amilk_ext = Blueprint("amilk", __name__, static_folder="static", template_folder="templates")
+
+
+from .views_api import * # noqa
+from .views import * # noqa
diff --git a/lnbits/extensions/amilk/config.json b/lnbits/extensions/amilk/config.json
new file mode 100644
index 00000000..01959207
--- /dev/null
+++ b/lnbits/extensions/amilk/config.json
@@ -0,0 +1,6 @@
+{
+ "name": "AMilk",
+ "short_description": "Assistant Faucet Milker",
+ "icon": "room_service",
+ "contributors": ["eillarra"]
+}
diff --git a/lnbits/extensions/amilk/crud.py b/lnbits/extensions/amilk/crud.py
new file mode 100644
index 00000000..270e3ae0
--- /dev/null
+++ b/lnbits/extensions/amilk/crud.py
@@ -0,0 +1,44 @@
+from base64 import urlsafe_b64encode
+from uuid import uuid4
+from typing import List, Optional, Union
+
+from lnbits.db import open_ext_db
+
+from .models import AMilk
+
+
+def create_amilk(*, wallet_id: str, url: str, memo: str, amount: int) -> AMilk:
+ with open_ext_db("amilk") as db:
+ amilk_id = urlsafe_b64encode(uuid4().bytes_le).decode('utf-8')
+ db.execute(
+ """
+ INSERT INTO amilks (id, wallet, url, memo, amount)
+ VALUES (?, ?, ?, ?, ?)
+ """,
+ (amilk_id, wallet_id, url, memo, amount),
+ )
+
+ return get_amilk(amilk_id)
+
+
+def get_amilk(amilk_id: str) -> Optional[AMilk]:
+ with open_ext_db("amilk") as db:
+ row = db.fetchone("SELECT * FROM amilks WHERE id = ?", (amilk_id,))
+
+ return AMilk(**row) if row else None
+
+
+def get_amilks(wallet_ids: Union[str, List[str]]) -> List[AMilk]:
+ if isinstance(wallet_ids, str):
+ wallet_ids = [wallet_ids]
+
+ with open_ext_db("amilk") as db:
+ q = ",".join(["?"] * len(wallet_ids))
+ rows = db.fetchall(f"SELECT * FROM amilks WHERE wallet IN ({q})", (*wallet_ids,))
+
+ return [AMilk(**row) for row in rows]
+
+
+def delete_amilk(amilk_id: str) -> None:
+ with open_ext_db("amilk") as db:
+ db.execute("DELETE FROM amilks WHERE id = ?", (amilk_id,))
diff --git a/lnbits/extensions/amilk/models.py b/lnbits/extensions/amilk/models.py
new file mode 100644
index 00000000..acf6033d
--- /dev/null
+++ b/lnbits/extensions/amilk/models.py
@@ -0,0 +1,9 @@
+from typing import NamedTuple
+
+
+class AMilk(NamedTuple):
+ id: str
+ wallet: str
+ lnurl: str
+ atime: str
+ amount: int
diff --git a/lnbits/extensions/amilk/schema.sql b/lnbits/extensions/amilk/schema.sql
new file mode 100644
index 00000000..0b67e48d
--- /dev/null
+++ b/lnbits/extensions/amilk/schema.sql
@@ -0,0 +1,7 @@
+CREATE TABLE IF NOT EXISTS amilks (
+ id TEXT PRIMARY KEY,
+ wallet TEXT NOT NULL,
+ lnurl TEXT NOT NULL,
+ atime TEXT NOT NULL,
+ amount INTEGER NOT NULL
+);
diff --git a/lnbits/extensions/amilk/templates/amilk/_api_docs.html b/lnbits/extensions/amilk/templates/amilk/_api_docs.html
new file mode 100644
index 00000000..bd2c42ae
--- /dev/null
+++ b/lnbits/extensions/amilk/templates/amilk/_api_docs.html
@@ -0,0 +1,16 @@
+
+ Milking faucets with software, known as "assmilking", seems at first to be black-hat, although in fact there might be some unexplored use cases. An LNURL withdraw gives someone the right to pull funds, which can be done over time. An LNURL withdraw could be used outside of just faucets, to provide money streaming and repeat payments.
Paste or scan an LNURL withdraw, enter the amount for the AMilk to pull and the frequency for it to be pulled.
+ Created by, Ben Arc