OpenClaw Skills 闪电网络钱包(LNBits Wallet wtih QR Code)技能使用参考手册

2026-03-06 13:58 更新

概述

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_KEYLNBITS_BASE_URL
  • 触发词:"LNbits 钱包管理"、"闪电钱包余额"、"创建闪电发票"、"支付闪电账单"、"闪电发票二维码"

👤 作者:JamesTsetsekas
🦞 官方地址:https://clawhub.ai/JamesTsetsekas/lnbits-with-qrcode
👉 Skills 下载地址:lnbits-with-qrcode-1.0.2.zip

关键安全协议

为了确保 LNbits 钱包的安全使用,该技能强制遵循以下严格的安全协议:

  1. 绝对不要暴露密钥:不要展示管理密钥、用户 ID 或钱包 ID。
  2. 明确的支付确认:在进行支付前,必须向用户确认 "是 / 否"。
    1. 格式:" 我即将向 **[备注 / 收款方]支付[金额] 聪 **。是否继续?(y/n)"
  3. 先检查余额:在进行支付前,必须先调用balance命令检查余额,避免支付失败。
  4. 必须包含发票和二维码:当生成发票时,必须同时提供可复制的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 "我的钱包"

操作说明

  1. 运行该命令后,CLI 会在终端输出包含adminkeybase_url的 JSON 内容。
  2. 绝对不要暴露密钥:不要在聊天中重复、引用或展示adminkey或任何输出中的密钥,用户会在终端看到命令输出,这是密钥唯一应该出现的地方。
  3. 用简单的语言指导用户,例如:

" 新钱包已创建。上面的命令输出包含你的adminkeybase_url。请从终端复制这些值,并将它们添加到你的配置或.env文件中,分别设置为LNBITS_API_KEYLNBITS_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

强制响应格式:当生成发票时,你的响应必须包含:

  1. 可复制的发票文本:展示完整的payment_request字符串,方便用户复制
  2. 二维码图片:在单独一行输出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
}
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号