add MVP for lnbits skill
This commit is contained in:
parent
735aea9efa
commit
33aef395e9
64
skills/lnbits/SKILL.md
Normal file
64
skills/lnbits/SKILL.md
Normal file
@ -0,0 +1,64 @@
|
||||
---
|
||||
name: lnbits
|
||||
description: Manage LNbits Lightning Wallet (Balance, Pay, Invoice)
|
||||
homepage: https://lnbits.com
|
||||
metadata: {"clawdbot":{"emoji":"⚡","requires":{"bins":["python3"],"env":["LNBITS_API_KEY", "LNBITS_BASE_URL"]},"primaryEnv":"LNBITS_API_KEY"}}
|
||||
---
|
||||
|
||||
# LNbits Wallet Manager
|
||||
|
||||
Enable the assistant to safely and effectively manage an LNbits Lightning Network wallet.
|
||||
|
||||
## 🛑 CRITICAL SECURITY PROTOCOLS 🛑
|
||||
|
||||
1. **NEVER Expose Secrets**: Do NOT display Admin Keys, User IDs, or Wallet IDs.
|
||||
2. **Explicit Confirmation**: You MUST ask for "Yes/No" confirmation before paying.
|
||||
* *Format*: "I am about to send **[Amount] sats** to **[Memo/Dest]**. Proceed? (y/n)"
|
||||
3. **Check Balance First**: Always call `balance` before `pay` to prevent errors.
|
||||
|
||||
## Usage
|
||||
|
||||
### 0. Setup / Create Wallet
|
||||
If the user does not have an LNbits wallet, you can create one for them on the demo server.
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/lnbits_cli.py create --name "My Wallet"
|
||||
```
|
||||
|
||||
**Action**:
|
||||
1. Run the command.
|
||||
2. Capture the `adminkey` (Admin Key) and `base_url` (defaults to https://demo.lnbits.com).
|
||||
3. **IMPORTANT**: Instruct the user to save these credentials securely:
|
||||
> "I've created a new wallet! Please add these to your Moltbot configuration or `.env` file:
|
||||
> `export LNBITS_BASE_URL=https://demo.lnbits.com`
|
||||
> `export LNBITS_API_KEY=<adminkey>`"
|
||||
|
||||
### 1. Check Balance
|
||||
Get the current wallet balance in Satoshis.
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/lnbits_cli.py balance
|
||||
```
|
||||
|
||||
### 2. Create Invoice (Receive)
|
||||
Generate a Bolt11 invoice to receive funds.
|
||||
* **amount**: Amount in Satoshis (Integer).
|
||||
* **memo**: Optional description.
|
||||
|
||||
```bash
|
||||
python3 {baseDir}/scripts/lnbits_cli.py invoice --amount 1000 --memo "Pizza"
|
||||
```
|
||||
|
||||
### 3. Pay Invoice (Send)
|
||||
**⚠️ REQUIRES CONFIRMATION**: Decode first, verify balance, ask user, then execute.
|
||||
|
||||
```bash
|
||||
# Step 1: Decode to verify amount/memo
|
||||
python3 {baseDir}/scripts/lnbits_cli.py decode <bolt11_string>
|
||||
|
||||
# Step 2: Pay (Only after user CONFIRMS)
|
||||
python3 {baseDir}/scripts/lnbits_cli.py pay <bolt11_string>
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
If the CLI returns a JSON error (e.g., `{"error": "Insufficient funds"}`), summarize it clearly for the user. Do not show raw stack traces.
|
||||
128
skills/lnbits/scripts/lnbits_cli.py
Executable file
128
skills/lnbits/scripts/lnbits_cli.py
Executable file
@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
# Configuration
|
||||
BASE_URL = os.getenv("LNBITS_BASE_URL", "https://legend.lnbits.com").rstrip("/")
|
||||
API_KEY = os.getenv("LNBITS_API_KEY")
|
||||
|
||||
# --- Helpers ---
|
||||
|
||||
def error(msg, code=1):
|
||||
print(json.dumps({"error": msg}))
|
||||
sys.exit(code)
|
||||
|
||||
def request(method, endpoint, data=None):
|
||||
if not API_KEY:
|
||||
error("LNBITS_API_KEY environment variable is not set.")
|
||||
|
||||
url = f"{BASE_URL}/api/v1{endpoint}"
|
||||
headers = {
|
||||
"X-Api-Key": API_KEY,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
body = json.dumps(data).encode("utf-8") if data else None
|
||||
|
||||
req = urllib.request.Request(url, method=method, headers=headers, data=body)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=20) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
except urllib.error.HTTPError as e:
|
||||
error_body = e.read().decode("utf-8", errors="replace")
|
||||
error(f"API Error ({e.code}): {error_body}")
|
||||
except Exception as e:
|
||||
error(f"Network Error: {str(e)}")
|
||||
|
||||
# --- Core Logic ---
|
||||
|
||||
def get_balance():
|
||||
data = request("GET", "/wallet")
|
||||
return {
|
||||
"name": data.get("name"),
|
||||
"balance_msat": data.get("balance"),
|
||||
"balance_sats": int(data.get("balance", 0) / 1000)
|
||||
}
|
||||
|
||||
def create_invoice(amount, memo):
|
||||
return request("POST", "/payments", {
|
||||
"out": False, "amount": amount, "memo": memo, "unit": "sat"
|
||||
})
|
||||
|
||||
def pay_invoice(bolt11):
|
||||
return request("POST", "/payments", {"out": True, "bolt11": bolt11})
|
||||
|
||||
def decode_invoice(bolt11):
|
||||
return request("POST", "/payments/decode", {"data": bolt11})
|
||||
|
||||
def create_wallet(name):
|
||||
url = f"{BASE_URL}/api/v1/account"
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
method="POST",
|
||||
headers={"Content-Type": "application/json"},
|
||||
data=json.dumps({"name": name}).encode("utf-8")
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=20) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
# --- CLI Handlers ---
|
||||
|
||||
def cmd_balance(args):
|
||||
print(json.dumps(get_balance(), indent=2))
|
||||
|
||||
def cmd_create(args):
|
||||
print(json.dumps(create_wallet(args.name), indent=2))
|
||||
|
||||
def cmd_invoice(args):
|
||||
print(json.dumps(create_invoice(args.amount, args.memo), indent=2))
|
||||
|
||||
def cmd_pay(args):
|
||||
print(json.dumps(pay_invoice(args.bolt11), indent=2))
|
||||
|
||||
def cmd_decode(args):
|
||||
print(json.dumps(decode_invoice(args.bolt11), indent=2))
|
||||
|
||||
# --- Main ---
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="LNbits CLI Bridge for Clawdbot")
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
# Balance
|
||||
p_balance = subparsers.add_parser("balance", help="Get wallet balance")
|
||||
p_balance.set_defaults(func=cmd_balance)
|
||||
|
||||
# Create Wallet (Account)
|
||||
p_create = subparsers.add_parser("create", help="Create a new LNbits wallet")
|
||||
p_create.add_argument("--name", type=str, default="Moltbot Wallet", help="Name of the new wallet")
|
||||
p_create.set_defaults(func=cmd_create)
|
||||
|
||||
# Invoice
|
||||
p_invoice = subparsers.add_parser("invoice", help="Create a lightning invoice")
|
||||
p_invoice.add_argument("--amount", type=int, required=True, help="Amount in satoshis")
|
||||
p_invoice.add_argument("--memo", type=str, default="", help="Optional memo")
|
||||
p_invoice.set_defaults(func=cmd_invoice)
|
||||
|
||||
# Pay
|
||||
p_pay = subparsers.add_parser("pay", help="Pay a lightning invoice")
|
||||
p_pay.add_argument("bolt11", type=str, help="The Bolt11 invoice string")
|
||||
p_pay.set_defaults(func=cmd_pay)
|
||||
|
||||
# Decode
|
||||
p_decode = subparsers.add_parser("decode", help="Decode a lightning invoice")
|
||||
p_decode.add_argument("bolt11", type=str, help="The Bolt11 invoice string")
|
||||
p_decode.set_defaults(func=cmd_decode)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
args.func(args)
|
||||
except Exception as e:
|
||||
error(str(e))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user