feat: add hub-managed Wallet Connections scaffolding
This commit is contained in:
committed by
GitHub
parent
5860f40e82
commit
9673f6733a
@@ -0,0 +1,128 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
from . import server
|
||||
|
||||
|
||||
def _print(data) -> None:
|
||||
print(json.dumps(data, indent=2, sort_keys=True))
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(prog="nwc-wallet")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
create = sub.add_parser("create")
|
||||
create.add_argument("name")
|
||||
create.add_argument("alias")
|
||||
preset_group = create.add_mutually_exclusive_group()
|
||||
preset_group.add_argument("--receive-only", action="store_true")
|
||||
preset_group.add_argument("--limit-sats", type=int)
|
||||
|
||||
sub.add_parser("list")
|
||||
|
||||
drain = sub.add_parser("drain")
|
||||
drain.add_argument("wallet")
|
||||
|
||||
delete = sub.add_parser("delete")
|
||||
delete.add_argument("wallet")
|
||||
|
||||
addr = sub.add_parser("address")
|
||||
addr_sub = addr.add_subparsers(dest="address_cmd", required=True)
|
||||
addr_show = addr_sub.add_parser("show")
|
||||
addr_show.add_argument("alias")
|
||||
|
||||
sub.add_parser("health")
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
state = server._nwc_load_state()
|
||||
domain = server._nwc_domain()
|
||||
|
||||
if args.cmd == "list":
|
||||
_print({"wallets": [server._nwc_wallet_meta(w, domain) for w in state.get("wallets", [])]})
|
||||
return 0
|
||||
|
||||
if args.cmd == "health":
|
||||
_print({"ok": True, "domain": domain, "wallet_count": len(state.get("wallets", []))})
|
||||
return 0
|
||||
|
||||
if args.cmd == "address" and args.address_cmd == "show":
|
||||
test = server._nwc_test_address(args.alias.strip().lower())
|
||||
_print(test)
|
||||
return 0 if test.get("ok") else 1
|
||||
|
||||
wallet = server._nwc_find_wallet(state, getattr(args, "wallet", ""))
|
||||
if args.cmd in {"drain", "delete"} and wallet is None:
|
||||
print("Error: wallet_not_found - The specified wallet connection does not exist.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.cmd == "drain":
|
||||
if int(wallet.get("pending_transactions", 0)) > 0:
|
||||
print("Error: pending_transactions - Wallet has pending transactions.", file=sys.stderr)
|
||||
return 1
|
||||
drained = int(wallet.get("balance_sats", 0))
|
||||
wallet["balance_sats"] = 0
|
||||
server._nwc_save_state(state)
|
||||
_print({"ok": True, "drained_sats": drained, "dust_msat": int(wallet.get("dust_msat", 0))})
|
||||
return 0
|
||||
|
||||
if args.cmd == "delete":
|
||||
if int(wallet.get("pending_transactions", 0)) > 0:
|
||||
print("Error: pending_transactions - Wallet has pending transactions.", file=sys.stderr)
|
||||
return 1
|
||||
if int(wallet.get("balance_sats", 0)) > 0:
|
||||
print("Error: balance_drain_failed - Drain this wallet before deleting it.", file=sys.stderr)
|
||||
return 1
|
||||
wallet_id = wallet.get("id")
|
||||
state["wallets"] = [w for w in state.get("wallets", []) if w.get("id") != wallet_id]
|
||||
server._nwc_save_state(state)
|
||||
_print({"ok": True})
|
||||
return 0
|
||||
|
||||
if args.cmd == "create":
|
||||
alias = args.alias.strip().lower()
|
||||
if not server._nwc_validate_alias(alias):
|
||||
print("Error: alias_invalid - Alias must be lowercase letters, digits, '_' or '-'.", file=sys.stderr)
|
||||
return 1
|
||||
if any(w.get("alias") == alias for w in state.get("wallets", [])):
|
||||
print("Error: alias_exists - This alias already exists.", file=sys.stderr)
|
||||
return 1
|
||||
if any(w.get("name", "").lower() == args.name.strip().lower() for w in state.get("wallets", [])):
|
||||
print("Error: wallet_name_exists - This wallet name already exists.", file=sys.stderr)
|
||||
return 1
|
||||
access_preset = "send_receive_limited" if args.limit_sats is not None else "receive_only"
|
||||
wallet = {
|
||||
"id": server.secrets.token_hex(8),
|
||||
"pubkey": server.secrets.token_hex(16),
|
||||
"name": args.name.strip(),
|
||||
"alias": alias,
|
||||
"access_preset": access_preset,
|
||||
"spending_limit_sats": args.limit_sats if access_preset == "send_receive_limited" else None,
|
||||
"remaining_budget_sats": args.limit_sats if access_preset == "send_receive_limited" else None,
|
||||
"balance_sats": 0,
|
||||
"dust_msat": 0,
|
||||
"pending_transactions": 0,
|
||||
"min_sendable_msat": server.NWC_MIN_SENDABLE_MSAT,
|
||||
"max_sendable_msat": server.NWC_MAX_SENDABLE_MSAT,
|
||||
"created_at": int(server.time.time()),
|
||||
}
|
||||
state.setdefault("wallets", []).append(wallet)
|
||||
server._nwc_save_state(state)
|
||||
_print(
|
||||
{
|
||||
"wallet": server._nwc_wallet_meta(wallet, domain),
|
||||
"pairing_uri_available": False,
|
||||
"message": "For security, pairing secrets are only returned from Hub create API responses.",
|
||||
"verification": server._nwc_test_address(alias),
|
||||
}
|
||||
)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user