OpenClaw Skills 闪电网络钱包(LNBits Wallet wtih QR Code)技能使用参考手册
概述
lnbits-with-qrcode 是用于管理 LNbits 闪电钱包的 OpenClaw 技能,支持余额查询、创建发票、支付发票、生成二维码等功能,帮助用户安全地管理 LNbits 钱包,适合需要处理闪电网络支付的用户,用户可以通过简单的命令行操作完成钱包的各项管理操作,同时该技能会强制遵循严格的安全协议,保障用户的钱包安全。
该技能可以帮助用户在 OpenClaw 中直接管理 LNbits 钱包,适合需要处理闪电网络支付的场景,比如接收小额支付、支付闪电网络账单等,能够让用户安全、高效地处理闪电网络相关的金融操作。
技能信息
- 名称:lnbits-with-qrcode
- 描述:管理 LNbits 闪电钱包,支持余额查询、支付、创建发票,并为发票生成二维码。
- 版本:1.0.2
- 作者:JamesTsetsekas
- 主页:
https://lnbits.com - 依赖:
- 需要 Python3 环境
- 需要安装 qrcode [pil] 库(
pip install qrcode[pil]) - 需要设置环境变量
LNBITS_API_KEY和LNBITS_BASE_URL
- 触发词:"LNbits 钱包管理"、"闪电钱包余额"、"创建闪电发票"、"支付闪电账单"、"闪电发票二维码"
👤 作者:JamesTsetsekas
🦞 官方地址:https://clawhub.ai/JamesTsetsekas/lnbits-with-qrcode
👉 Skills 下载地址:lnbits-with-qrcode-1.0.2.zip
关键安全协议
为了确保 LNbits 钱包的安全使用,该技能强制遵循以下严格的安全协议:
- 绝对不要暴露密钥:不要展示管理密钥、用户 ID 或钱包 ID。
- 明确的支付确认:在进行支付前,必须向用户确认 "是 / 否"。
- 格式:" 我即将向 **[备注 / 收款方]支付[金额] 聪 **。是否继续?(y/n)"
- 先检查余额:在进行支付前,必须先调用
balance命令检查余额,避免支付失败。 - 必须包含发票和二维码:当生成发票时,必须同时提供可复制的
payment_request文本,并且在单独一行输出MEDIA:加上二维码文件路径。
安装方法
1. 安装 ClawHub CLI
npm i -g clawhub
2. 安装该技能
clawhub install lnbits-with-qrcode
3. 安装依赖
该技能需要qrcode[pil]Python 库,使用以下命令安装:
pip install qrcode[pil]
配置设置
该技能使用环境变量来存储 LNbits 的 API 凭证,建议将这些变量添加到你的 OpenClaw 配置或代理的.env文件中:
LNBITS_BASE_URL:你的 LNbits 实例的基础 URL(例如:https://legend.lnbits.com或你自托管的 LNbits 地址)LNBITS_API_KEY:你的 LNbits 钱包的管理密钥
示例.env配置:
export LNBITS_BASE_URL=https://legend.lnbits.com
export LNBITS_API_KEY=你的管理密钥
使用方法
0. 创建钱包
如果你还没有 LNbits 钱包,可以使用以下命令在演示服务器上创建一个新钱包:
python3 {baseDir}/scripts/lnbits_cli.py create --name "我的钱包"
操作说明:
- 运行该命令后,CLI 会在终端输出包含
adminkey和base_url的 JSON 内容。 - 绝对不要暴露密钥:不要在聊天中重复、引用或展示
adminkey或任何输出中的密钥,用户会在终端看到命令输出,这是密钥唯一应该出现的地方。 - 用简单的语言指导用户,例如:
" 新钱包已创建。上面的命令输出包含你的adminkey和base_url。请从终端复制这些值,并将它们添加到你的配置或
.env文件中,分别设置为LNBITS_API_KEY和LNBITS_BASE_URL。不要在这里或任何聊天中粘贴 adminkey。"
1. 检查余额
查询当前钱包的余额(单位:聪):
python3 {baseDir}/scripts/lnbits_cli.py balance
2. 创建发票(收款)
生成 Bolt11 发票来接收资金,默认会自动生成二维码。
- amount:金额(单位:聪,整数)
- memo:可选的描述信息
- --no-qr:跳过二维码生成(如果不需要)
## 生成带二维码的发票(默认)
python3 {baseDir}/scripts/lnbits_cli.py invoice --amount 1000 --memo "披萨费用"
## 生成不带二维码的发票
python3 {baseDir}/scripts/lnbits_cli.py invoice --amount 1000 --memo "披萨费用" --no-qr
强制响应格式:当生成发票时,你的响应必须包含:
- 可复制的发票文本:展示完整的
payment_request字符串,方便用户复制 - 二维码图片:在单独一行输出
MEDIA:加上二维码文件路径
示例格式:
这是你的100聪发票:
lnbc1u1p5abc123...
MEDIA:./clawd/.lnbits_qr/invoice_xxx.png
2b. 为已有发票生成二维码
将任意 Bolt11 字符串转换为二维码图片文件:
python3 {baseDir}/scripts/lnbits_cli.py qr <bolt11字符串>
返回结果示例:{"qr_file": "./.lnbits_qr/invoice_xxx.png", "bolt11": "..."}
3. 支付发票(付款)
需要确认:先解码发票,验证金额和备注,然后向用户确认,最后执行支付。
## 步骤1:解码发票以验证金额和备注
python3 {baseDir}/scripts/lnbits_cli.py decode <bolt11字符串>
## 步骤2:支付(仅在用户确认后执行)
python3 {baseDir}/scripts/lnbits_cli.py pay <bolt11字符串>
错误处理
如果 CLI 返回 JSON 格式的错误(例如:{"error": "Insufficient funds"}),会为用户清晰地总结错误信息,不会展示原始的堆栈跟踪信息。
工具代码说明
lnbits_cli.py(LNbits 钱包管理脚本)
#!/usr/bin/env python3
import argparse
import base64
import io
import json
import os
import sys
import time
import urllib.request
import urllib.error
try:
import qrcode
HAS_QRCODE = True
except ImportError:
HAS_QRCODE = False
## 配置
## 从环境变量获取LNbits基础URL,默认值为https://legend.lnbits.com
BASE_URL = os.getenv("LNBITS_BASE_URL", "https://legend.lnbits.com").rstrip("/")
## 从环境变量获取LNbits API密钥
API_KEY = os.getenv("LNBITS_API_KEY")
## 保存二维码的目录,相对于当前工作目录,这样路径可以用./表示
QR_DIR = os.path.join(os.getcwd(), ".lnbits_qr")
## 二维码文件的最大保存时间(5分钟)
QR_MAX_AGE_SECONDS = 300
## --- 辅助函数 ---
def error(msg, code=1):
"""输出JSON格式的错误信息并退出程序"""
print(json.dumps({"error": msg}))
sys.exit(code)
def cleanup_old_qr_files():
"""删除超过QR_MAX_AGE_SECONDS时间的二维码文件"""
if not os.path.exists(QR_DIR):
return
now = time.time()
for filename in os.listdir(QR_DIR):
if not filename.endswith(".png"):
continue
filepath = os.path.join(QR_DIR, filename)
try:
if now - os.path.getmtime(filepath) > QR_MAX_AGE_SECONDS:
os.remove(filepath)
except OSError:
pass
def get_qr_path():
"""获取新二维码文件的唯一路径,返回(绝对路径, 媒体路径)
媒体路径是相对于网关的主目录的./相对路径,因为OpenClaw的MEDIA:解析器只接受./相对路径
"""
os.makedirs(QR_DIR, exist_ok=True)
cleanup_old_qr_files()
# 使用时间戳作为文件名,确保唯一性
filename = f"invoice_{int(time.time() * 1000)}.png"
abs_path = os.path.join(QR_DIR, filename)
media_path = "./" + os.path.relpath(abs_path, os.path.expanduser("~"))
return abs_path, media_path
def generate_qr(data, output_path=None):
"""生成二维码。如果提供了output_path,保存到文件并返回路径;否则返回base64编码的字符串"""
if not HAS_QRCODE:
return None
# 创建QRCode对象,设置版本、纠错级别、盒子大小和边框
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_M,
box_size=10,
border=4,
)
# BOLT11字符串应该大写以生成正确的二维码
qr.add_data(data.upper())
qr.make(fit=True)
# 创建二维码图片
img = qr.make_image(fill_color="black", back_color="white")
if output_path:
# 保存图片到指定路径
img.save(output_path, format="PNG")
return output_path
else:
# 将图片保存到内存并返回base64编码
buffer = io.BytesIO()
img.save(buffer, format="PNG")
buffer.seek(0)
return base64.b64encode(buffer.read()).decode("utf-8")
def request(method, endpoint, data=None):
"""向LNbits API发送请求"""
if not API_KEY:
error("未设置LNBITS_API_KEY环境变量。")
# 构建完整的API URL
url = f"{BASE_URL}/api/v1{endpoint}"
headers = {
"X-Api-Key": API_KEY,
"Content-Type": "application/json",
"User-Agent": "LNbits-CLI/1.0"
}
# 处理请求数据
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:
# 处理HTTP错误
error_body = e.read().decode("utf-8", errors="replace")
error(f"API错误 ({e.code}): {error_body}")
except Exception as e:
# 处理其他网络错误
error(f"网络错误: {str(e)}")
## --- 核心逻辑 ---
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, include_qr=True):
"""创建收款发票"""
result = request("POST", "/payments", {
"out": False, "amount": amount, "memo": memo, "unit": "sat"
})
# 如果需要生成二维码
if include_qr and result.get("payment_request"):
abs_path, rel_path = get_qr_path()
qr_result = generate_qr(result["payment_request"], abs_path)
if qr_result:
result["qr_file"] = rel_path
# 同时生成base64编码的二维码,用于直接嵌入
with open(abs_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")
result["qr_base64"] = f"image/png;base64,{b64}"
else:
result["qr_error"] = "未安装qrcode库(请运行pip install qrcode[pil])"
return result
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", "User-Agent": "LNbits-CLI/1.0"},
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命令处理 ---
def cmd_balance(args):
"""处理balance命令"""
print(json.dumps(get_balance(), indent=2))
def cmd_create(args):
"""处理create命令"""
print(json.dumps(create_wallet(args.name), indent=2))
def cmd_invoice(args):
"""处理invoice命令"""
print(json.dumps(create_invoice(args.amount, args.memo, not args.no_qr), indent=2))
def cmd_pay(args):
"""处理pay命令"""
print(json.dumps(pay_invoice(args.bolt11), indent=2))
def cmd_decode(args):
"""处理decode命令"""
print(json.dumps(decode_invoice(args.bolt11), indent=2))
def cmd_qr(args):
"""处理qr命令,为BOLT11发票生成二维码"""
if args.output:
abs_path = args.output
rel_path = args.output
else:
abs_path, rel_path = get_qr_path()
qr_result = generate_qr(args.bolt11, abs_path)
if qr_result:
result = {"qr_file": rel_path, "bolt11": args.bolt11}
with open(abs_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")
result["qr_base64"] = f"image/png;base64,{b64}"
print(json.dumps(result, indent=2))
else:
error("未安装qrcode库(请运行pip install qrcode[pil])")
## --- 主函数 ---
def main():
"""解析命令行参数并执行相应命令"""
parser = argparse.ArgumentParser(description="LNbits CLI Bridge for Clawdbot")
subparsers = parser.add_subparsers(dest="command", required=True)
# 余额查询命令
p_balance = subparsers.add_parser("balance", help="获取钱包余额")
p_balance.set_defaults(func=cmd_balance)
# 创建钱包命令
p_create = subparsers.add_parser("create", help="创建新的LNbits钱包")
p_create.add_argument("--name", type=str, default="Moltbot Wallet", help="新钱包的名称")
p_create.set_defaults(func=cmd_create)
# 创建发票命令
p_invoice = subparsers.add_parser("invoice", help="创建闪电发票")
p_invoice.add_argument("--amount", type=int, required=True, help="金额(单位:聪)")
p_invoice.add_argument("--memo", type=str, default="", help="可选备注")
p_invoice.add_argument("--no-qr", action="store_true", dest="no_qr", help="跳过二维码生成")
p_invoice.set_defaults(func=cmd_invoice)
# 支付发票命令
p_pay = subparsers.add_parser("pay", help="支付闪电发票")
p_pay.add_argument("bolt11", type=str, help="Bolt11发票字符串")
p_pay.set_defaults(func=cmd_pay)
# 解码发票命令
p_decode = subparsers.add_parser("decode", help="解码闪电发票")
p_decode.add_argument("bolt11", type=str, help="Bolt11发票字符串")
p_decode.set_defaults(func=cmd_decode)
# 生成二维码命令
p_qr = subparsers.add_parser("qr", help="为BOLT11发票生成二维码")
p_qr.add_argument("bolt11", type=str, help="Bolt11发票字符串")
p_qr.add_argument("-o", "--output", type=str, help="输出PNG文件路径(默认:自动生成临时文件)")
p_qr.set_defaults(func=cmd_qr)
args = parser.parse_args()
try:
args.func(args)
except Exception as e:
error(str(e))
if __name__ == "__main__":
main()
元数据信息
该技能的元数据信息如下:
{
"ownerId": "kn72w6ykh3h1j23s9eagy1cpdd80ppvx",
"slug": "lnbits-with-qrcode",
"version": "1.0.2",
"publishedAt": 1770509935863
}
免费 AI IDE


更多建议: