run402 4.76.2 → 4.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/gitvault-surface.json +1 -1
- package/lib/allowance.mjs +6 -2
- package/lib/command-manifest.mjs +1 -0
- package/lib/image.mjs +5 -2
- package/lib/init.mjs +46 -12
- package/lib/lightning-wallet.mjs +115 -0
- package/lib/wallets.mjs +52 -3
- package/package.json +1 -1
- package/sdk/dist/credentials.d.ts +11 -1
- package/sdk/dist/credentials.d.ts.map +1 -1
- package/sdk/dist/index.d.ts +5 -0
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +5 -0
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/namespaces/agent.d.ts +34 -0
- package/sdk/dist/namespaces/agent.d.ts.map +1 -0
- package/sdk/dist/namespaces/agent.js +66 -0
- package/sdk/dist/namespaces/agent.js.map +1 -0
- package/sdk/dist/namespaces/agent.types.d.ts +37 -0
- package/sdk/dist/namespaces/agent.types.d.ts.map +1 -0
- package/sdk/dist/namespaces/agent.types.js +3 -0
- package/sdk/dist/namespaces/agent.types.js.map +1 -0
- package/sdk/dist/namespaces/ai.d.ts +6 -0
- package/sdk/dist/namespaces/ai.d.ts.map +1 -1
- package/sdk/dist/namespaces/ai.js +1 -1
- package/sdk/dist/namespaces/ai.js.map +1 -1
- package/sdk/dist/namespaces/allowance.d.ts +12 -0
- package/sdk/dist/namespaces/allowance.d.ts.map +1 -1
- package/sdk/dist/namespaces/allowance.js +14 -0
- package/sdk/dist/namespaces/allowance.js.map +1 -1
- package/sdk/dist/node/_paid-stack.d.ts +20 -0
- package/sdk/dist/node/_paid-stack.d.ts.map +1 -1
- package/sdk/dist/node/_paid-stack.js +8 -0
- package/sdk/dist/node/_paid-stack.js.map +1 -1
- package/sdk/dist/node/index.d.ts +4 -0
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +3 -0
- package/sdk/dist/node/index.js.map +1 -1
- package/sdk/dist/node/lightning-paid-fetch.d.ts +46 -0
- package/sdk/dist/node/lightning-paid-fetch.d.ts.map +1 -0
- package/sdk/dist/node/lightning-paid-fetch.js +149 -0
- package/sdk/dist/node/lightning-paid-fetch.js.map +1 -0
- package/sdk/dist/node/nwc.d.ts +68 -0
- package/sdk/dist/node/nwc.d.ts.map +1 -0
- package/sdk/dist/node/nwc.js +375 -0
- package/sdk/dist/node/nwc.js.map +1 -0
- package/sdk/dist/node/paid-fetch.d.ts +3 -1
- package/sdk/dist/node/paid-fetch.d.ts.map +1 -1
- package/sdk/dist/node/paid-fetch.js +21 -3
- package/sdk/dist/node/paid-fetch.js.map +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Lightning rail's buyer: a `fetch` that selects Run402's MPP Lightning
|
|
3
|
+
* safety profile on every request, pays the one fixed BOLT11 challenge a 402
|
|
4
|
+
* carries from the agent's own wallet (the budgeted sub-wallet on Run402's
|
|
5
|
+
* Hub, over NWC), presents the preimage as the credential on a byte-identical
|
|
6
|
+
* retry, and falls back to the x402 buyer when the seller offers no Lightning
|
|
7
|
+
* challenge (the rail is unavailable, or the surface is not charged over it).
|
|
8
|
+
*
|
|
9
|
+
* The all-in debit cap (invoice plus routing fee, in msat and USD) is checked
|
|
10
|
+
* against the wallet's remaining budget before paying. The pairing secret,
|
|
11
|
+
* the preimage, and the invoice never reach a log or an error.
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
import { loadLightningStack } from "./_paid-stack.js";
|
|
15
|
+
import { NwcError, NwcWallet } from "./nwc.js";
|
|
16
|
+
export const RUN402_MPP_LIGHTNING_PROFILE = "run402-mpp-lightning-charge-draft00-safety-v1";
|
|
17
|
+
const ACCEPT_PAYMENT = `lightning/charge;profile=${RUN402_MPP_LIGHTNING_PROFILE}, tempo/charge;q=0.5`;
|
|
18
|
+
/** Routing-fee headroom on top of the invoice, in sats (internal Hub payments cost 0). */
|
|
19
|
+
const FEE_HEADROOM_SATS = 10;
|
|
20
|
+
/** A single Run402 charge above this is refused before paying (the spec's conservative USD ceiling in sats). */
|
|
21
|
+
export const LIGHTNING_MAX_DEBIT_SATS = 250_000;
|
|
22
|
+
export class LightningPaymentError extends Error {
|
|
23
|
+
code;
|
|
24
|
+
details;
|
|
25
|
+
constructor(code, message, details = {}) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.code = code;
|
|
28
|
+
this.details = details;
|
|
29
|
+
this.name = "LightningPaymentError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** The `WWW-Authenticate: Payment …` challenge for lightning/charge, or null. */
|
|
33
|
+
export function readLightningChallenge(response, stack) {
|
|
34
|
+
if (response.status !== 402)
|
|
35
|
+
return null;
|
|
36
|
+
const header = response.headers.get("www-authenticate");
|
|
37
|
+
if (!header || !/^payment\s/i.test(header))
|
|
38
|
+
return null;
|
|
39
|
+
let challenge;
|
|
40
|
+
try {
|
|
41
|
+
challenge = stack.Challenge.deserialize(header);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (challenge.method !== "lightning" || challenge.intent !== "charge")
|
|
47
|
+
return null;
|
|
48
|
+
const request = (challenge.request ?? {});
|
|
49
|
+
const details = (request.methodDetails ?? {});
|
|
50
|
+
const invoice = typeof details.invoice === "string" ? details.invoice : "";
|
|
51
|
+
const paymentHash = typeof details.paymentHash === "string" ? details.paymentHash.toLowerCase() : "";
|
|
52
|
+
const amountSats = Number(request.amount);
|
|
53
|
+
if (!invoice || !/^[0-9a-f]{64}$/.test(paymentHash) || !Number.isFinite(amountSats) || amountSats <= 0)
|
|
54
|
+
return null;
|
|
55
|
+
return { header, invoice, paymentHash, amountSats, expires: typeof challenge.expires === "string" ? challenge.expires : null };
|
|
56
|
+
}
|
|
57
|
+
function withLightningHeaders(init, idempotencyKey) {
|
|
58
|
+
const headers = new Headers(init?.headers ?? {});
|
|
59
|
+
headers.set("run402-payment-profile", RUN402_MPP_LIGHTNING_PROFILE);
|
|
60
|
+
headers.set("accept-payment", ACCEPT_PAYMENT);
|
|
61
|
+
if (!headers.has("idempotency-key"))
|
|
62
|
+
headers.set("idempotency-key", idempotencyKey);
|
|
63
|
+
return { ...init, headers };
|
|
64
|
+
}
|
|
65
|
+
function sha256Hex(hex) {
|
|
66
|
+
return createHash("sha256").update(Buffer.from(hex, "hex")).digest("hex");
|
|
67
|
+
}
|
|
68
|
+
function defaultIdempotencyKey(input, init) {
|
|
69
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
70
|
+
const method = (init?.method ?? (typeof input === "object" && "method" in input ? input.method : "GET")).toUpperCase();
|
|
71
|
+
const body = typeof init?.body === "string" ? init.body : init?.body instanceof Uint8Array ? Buffer.from(init.body).toString("utf8") : "";
|
|
72
|
+
const digest = createHash("sha256").update(`${method}\n${url}\n${body}`).digest("hex");
|
|
73
|
+
return `lnc_${digest.slice(0, 32)}`;
|
|
74
|
+
}
|
|
75
|
+
export function createLightningFetch(options) {
|
|
76
|
+
const baseFetch = options.baseFetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
77
|
+
const wallet = options.wallet ?? new NwcWallet(options.pairingUri);
|
|
78
|
+
const loadStack = options.stack ?? loadLightningStack;
|
|
79
|
+
let fallbackFetch;
|
|
80
|
+
const fallback = async () => {
|
|
81
|
+
if (fallbackFetch === undefined)
|
|
82
|
+
fallbackFetch = await options.fallback();
|
|
83
|
+
return fallbackFetch;
|
|
84
|
+
};
|
|
85
|
+
return async (input, init) => {
|
|
86
|
+
// Deterministic over the request bytes: a retry of the identical call
|
|
87
|
+
// (after a crash, a timeout, or a gateway hiccup between payment and
|
|
88
|
+
// fulfilment) lands on the same payment intent and is fulfilled without
|
|
89
|
+
// a second payment. A deliberate second identical purchase passes its
|
|
90
|
+
// own Idempotency-Key.
|
|
91
|
+
const idempotencyKey = defaultIdempotencyKey(input, init);
|
|
92
|
+
const firstInit = withLightningHeaders(init, idempotencyKey);
|
|
93
|
+
const first = await baseFetch(input, firstInit);
|
|
94
|
+
if (first.status !== 402)
|
|
95
|
+
return first;
|
|
96
|
+
const stack = await loadStack();
|
|
97
|
+
const challenge = readLightningChallenge(first, stack);
|
|
98
|
+
if (!challenge) {
|
|
99
|
+
// No Lightning offer: the seller wants x402 (or the rail is paused).
|
|
100
|
+
const x402 = await fallback();
|
|
101
|
+
if (!x402)
|
|
102
|
+
return first;
|
|
103
|
+
await first.body?.cancel().catch(() => undefined);
|
|
104
|
+
return x402(input, init);
|
|
105
|
+
}
|
|
106
|
+
await first.body?.cancel().catch(() => undefined);
|
|
107
|
+
const allIn = challenge.amountSats + FEE_HEADROOM_SATS;
|
|
108
|
+
if (allIn > LIGHTNING_MAX_DEBIT_SATS) {
|
|
109
|
+
throw new LightningPaymentError("LIGHTNING_DEBIT_ABOVE_CAP", `A Lightning charge of ${challenge.amountSats} sats exceeds the ${LIGHTNING_MAX_DEBIT_SATS}-sat ceiling.`, { amount_sats: challenge.amountSats, cap_sats: LIGHTNING_MAX_DEBIT_SATS, next_action: "pay over x402 (run402 init --switch-rail)" });
|
|
110
|
+
}
|
|
111
|
+
const budget = await wallet.getBudgetSats().catch(() => null);
|
|
112
|
+
if (budget && budget.totalSats !== null && budget.totalSats - budget.usedSats < allIn) {
|
|
113
|
+
throw new LightningPaymentError("LIGHTNING_BUDGET_EXHAUSTED", `The Lightning wallet's remaining budget (${budget.totalSats - budget.usedSats} sats) cannot cover ${allIn} sats.`, { remaining_sats: budget.totalSats - budget.usedSats, required_sats: allIn, next_action: "pay over x402 (run402 init --switch-rail), or ask the platform for a new wallet" });
|
|
114
|
+
}
|
|
115
|
+
let preimage;
|
|
116
|
+
try {
|
|
117
|
+
preimage = (await wallet.payInvoice(challenge.invoice)).preimage;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
// Unknown outcome: resolve by hash before ever paying again.
|
|
121
|
+
if (error instanceof NwcError && (error.code === "TIMEOUT" || error.code === "RELAY_CLOSED" || error.code === "RELAY_UNREACHABLE")) {
|
|
122
|
+
const looked = await wallet.lookupInvoice(challenge.paymentHash).catch(() => null);
|
|
123
|
+
if (looked?.preimage)
|
|
124
|
+
preimage = looked.preimage;
|
|
125
|
+
else
|
|
126
|
+
throw new LightningPaymentError("LIGHTNING_PAYMENT_OUTCOME_UNKNOWN", "The Lightning payment's outcome is unknown; the same request may be retried with the same Idempotency-Key once the wallet is reachable.", { payment_hash: challenge.paymentHash, idempotency_key: idempotencyKey });
|
|
127
|
+
}
|
|
128
|
+
else if (error instanceof NwcError) {
|
|
129
|
+
throw new LightningPaymentError(`LIGHTNING_${error.code}`, `The Lightning wallet refused the payment (${error.code}).`, { payment_hash: challenge.paymentHash, next_action: "pay over x402 (run402 init --switch-rail)" });
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (sha256Hex(preimage) !== challenge.paymentHash) {
|
|
136
|
+
throw new LightningPaymentError("LIGHTNING_PREIMAGE_MISMATCH", "The wallet returned a preimage that does not hash to the challenge's payment hash.", { payment_hash: challenge.paymentHash });
|
|
137
|
+
}
|
|
138
|
+
options.onPaid?.(challenge.paymentHash);
|
|
139
|
+
const credential = stack.Credential.serialize(stack.Credential.from({
|
|
140
|
+
challenge: stack.Challenge.deserialize(challenge.header),
|
|
141
|
+
payload: { preimage },
|
|
142
|
+
}));
|
|
143
|
+
const retryHeaders = new Headers(firstInit.headers);
|
|
144
|
+
retryHeaders.set("authorization", credential);
|
|
145
|
+
// Byte-identical retry: same body, same Idempotency-Key, plus the credential.
|
|
146
|
+
return baseFetch(input, { ...firstInit, headers: retryHeaders });
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=lightning-paid-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lightning-paid-fetch.js","sourceRoot":"","sources":["../../src/node/lightning-paid-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export declare const NWC_REQUEST_KIND = 23194;
|
|
2
|
+
export declare const NWC_RESPONSE_KIND = 23195;
|
|
3
|
+
export interface NwcConnection {
|
|
4
|
+
walletPubkey: string;
|
|
5
|
+
relayUrl: string;
|
|
6
|
+
secretHex: string;
|
|
7
|
+
clientPubkey: string;
|
|
8
|
+
}
|
|
9
|
+
/** Nostr wire time: unix seconds (the protocol's own field name). */
|
|
10
|
+
export type UnixSeconds = number;
|
|
11
|
+
export interface NwcNostrEvent {
|
|
12
|
+
id: string;
|
|
13
|
+
pubkey: string;
|
|
14
|
+
created_at: UnixSeconds;
|
|
15
|
+
kind: number;
|
|
16
|
+
tags: string[][];
|
|
17
|
+
content: string;
|
|
18
|
+
sig: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class NwcError extends Error {
|
|
21
|
+
readonly code: string;
|
|
22
|
+
constructor(code: string, message: string);
|
|
23
|
+
}
|
|
24
|
+
export declare function parseNwcUri(uri: string): NwcConnection;
|
|
25
|
+
export declare function nip44ConversationKey(secretHex: string, peerPubkeyHex: string): Uint8Array;
|
|
26
|
+
export declare function nip44Encrypt(conversation: Uint8Array, plaintext: string, nonce?: Uint8Array): string;
|
|
27
|
+
export declare function nip44Decrypt(conversation: Uint8Array, payload: string): string;
|
|
28
|
+
export declare function signNwcEvent(secretHex: string, kind: number, tags: string[][], content: string): NwcNostrEvent;
|
|
29
|
+
/** Closes every standing relay connection (process exit, tests). */
|
|
30
|
+
export declare function closeNwcConnections(): void;
|
|
31
|
+
export type NwcTransport = (connection: NwcConnection, request: NwcNostrEvent, timeoutMs: number) => Promise<NwcNostrEvent>;
|
|
32
|
+
/**
|
|
33
|
+
* One NIP-47 call. Throws `NwcError` with the wallet's error code
|
|
34
|
+
* (`INSUFFICIENT_BALANCE`, `QUOTA_EXCEEDED`, `NOT_FOUND`, `UNAUTHORIZED`, …)
|
|
35
|
+
* or a transport code (`TIMEOUT`, `RELAY_UNREACHABLE`, `RELAY_REJECTED`, `RELAY_CLOSED`, `BAD_RESPONSE`).
|
|
36
|
+
*/
|
|
37
|
+
export declare function nwcRequest<T = Record<string, unknown>>(connection: NwcConnection, method: string, params: Record<string, unknown>, options?: {
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
transport?: NwcTransport;
|
|
40
|
+
}): Promise<T>;
|
|
41
|
+
/** The agent-side wallet verbs the Lightning rail needs. Amounts are in sats. */
|
|
42
|
+
export declare class NwcWallet {
|
|
43
|
+
private readonly options;
|
|
44
|
+
private readonly connection;
|
|
45
|
+
constructor(pairingUri: string, options?: {
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
transport?: NwcTransport;
|
|
48
|
+
});
|
|
49
|
+
private call;
|
|
50
|
+
getBalanceSats(): Promise<number>;
|
|
51
|
+
/** Remaining budget in sats, or null when the wallet has no budget. */
|
|
52
|
+
getBudgetSats(): Promise<{
|
|
53
|
+
usedSats: number;
|
|
54
|
+
totalSats: number | null;
|
|
55
|
+
renewsAtSeconds: UnixSeconds | null;
|
|
56
|
+
} | null>;
|
|
57
|
+
/** Pays a BOLT11 invoice; returns the preimage (hex) the wallet reports. */
|
|
58
|
+
payInvoice(bolt11: string): Promise<{
|
|
59
|
+
preimage: string;
|
|
60
|
+
feesPaidMsat: number | null;
|
|
61
|
+
}>;
|
|
62
|
+
/** Looks an invoice up by payment hash; a settled outgoing payment carries its preimage. */
|
|
63
|
+
lookupInvoice(paymentHash: string): Promise<{
|
|
64
|
+
state: string | null;
|
|
65
|
+
preimage: string | null;
|
|
66
|
+
} | null>;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=nwc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nwc.d.ts","sourceRoot":"","sources":["../../src/node/nwc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal NIP-47 (Nostr Wallet Connect) client for the agent's Lightning
|
|
3
|
+
* wallet: the budgeted sub-wallet Run402 minted on its Hub (`run402 init
|
|
4
|
+
* lightning`). One standing relay WebSocket per pairing, NIP-44 v2 only,
|
|
5
|
+
* requests matched to replies by event id. The pairing URI carries the
|
|
6
|
+
* client's secret key: this module never logs or returns it.
|
|
7
|
+
*
|
|
8
|
+
* Node ≥ 22 (global `WebSocket`).
|
|
9
|
+
*/
|
|
10
|
+
import { createCipheriv, createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
11
|
+
import { schnorr, secp256k1 } from "@noble/curves/secp256k1.js";
|
|
12
|
+
import { expand, extract } from "@noble/hashes/hkdf.js";
|
|
13
|
+
import { hmac } from "@noble/hashes/hmac.js";
|
|
14
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
15
|
+
export const NWC_REQUEST_KIND = 23194;
|
|
16
|
+
export const NWC_RESPONSE_KIND = 23195;
|
|
17
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
18
|
+
const RELAY_HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
19
|
+
// Short: a one-shot CLI process must not linger on an open relay socket after its
|
|
20
|
+
// last request; reconnecting costs one handshake and long-lived callers keep
|
|
21
|
+
// the socket warm by talking.
|
|
22
|
+
const RELAY_IDLE_CLOSE_MS = 1_500;
|
|
23
|
+
export class NwcError extends Error {
|
|
24
|
+
code;
|
|
25
|
+
constructor(code, message) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.code = code;
|
|
28
|
+
this.name = "NwcError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function parseNwcUri(uri) {
|
|
32
|
+
let url;
|
|
33
|
+
try {
|
|
34
|
+
url = new URL(uri.replace(/^nostr\+walletconnect:\/\//i, "nostr+walletconnect://"));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw new NwcError("BAD_URI", "pairing URI is not a URL");
|
|
38
|
+
}
|
|
39
|
+
if (!/^nostr\+walletconnect:$/i.test(url.protocol))
|
|
40
|
+
throw new NwcError("BAD_URI", "pairing URI must use nostr+walletconnect://");
|
|
41
|
+
const walletPubkey = (url.host || url.pathname.replace(/^\/+/, "")).toLowerCase();
|
|
42
|
+
const relayUrl = url.searchParams.get("relay") ?? "";
|
|
43
|
+
const secretHex = (url.searchParams.get("secret") ?? "").toLowerCase();
|
|
44
|
+
if (!/^[0-9a-f]{64}$/.test(walletPubkey))
|
|
45
|
+
throw new NwcError("BAD_URI", "pairing URI lacks the wallet pubkey");
|
|
46
|
+
if (!/^wss?:\/\//.test(relayUrl))
|
|
47
|
+
throw new NwcError("BAD_URI", "pairing URI lacks a relay");
|
|
48
|
+
if (!/^[0-9a-f]{64}$/.test(secretHex))
|
|
49
|
+
throw new NwcError("BAD_URI", "pairing URI lacks the connection secret");
|
|
50
|
+
const clientPubkey = Buffer.from(schnorr.getPublicKey(Buffer.from(secretHex, "hex"))).toString("hex");
|
|
51
|
+
return { walletPubkey, relayUrl, secretHex, clientPubkey };
|
|
52
|
+
}
|
|
53
|
+
// --- NIP-44 v2 ------------------------------------------------------------
|
|
54
|
+
function calcPaddedLen(unpaddedLen) {
|
|
55
|
+
if (unpaddedLen <= 32)
|
|
56
|
+
return 32;
|
|
57
|
+
const nextPower = 1 << (Math.floor(Math.log2(unpaddedLen - 1)) + 1);
|
|
58
|
+
const chunk = nextPower <= 256 ? 32 : nextPower / 8;
|
|
59
|
+
return chunk * (Math.floor((unpaddedLen - 1) / chunk) + 1);
|
|
60
|
+
}
|
|
61
|
+
export function nip44ConversationKey(secretHex, peerPubkeyHex) {
|
|
62
|
+
const shared = secp256k1.getSharedSecret(Buffer.from(secretHex, "hex"), Buffer.from("02" + peerPubkeyHex, "hex"), true);
|
|
63
|
+
return extract(sha256, shared.subarray(1, 33), new TextEncoder().encode("nip44-v2"));
|
|
64
|
+
}
|
|
65
|
+
function messageKeys(conversation, nonce) {
|
|
66
|
+
const keys = expand(sha256, conversation, nonce, 76);
|
|
67
|
+
return { chacha: keys.subarray(0, 32), chachaNonce: keys.subarray(32, 44), hmacKey: keys.subarray(44, 76) };
|
|
68
|
+
}
|
|
69
|
+
function chacha20(key, nonce12, data) {
|
|
70
|
+
const cipher = createCipheriv("chacha20", Buffer.from(key), Buffer.concat([Buffer.alloc(4), Buffer.from(nonce12)]));
|
|
71
|
+
return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);
|
|
72
|
+
}
|
|
73
|
+
export function nip44Encrypt(conversation, plaintext, nonce = randomBytes(32)) {
|
|
74
|
+
const bytes = new TextEncoder().encode(plaintext);
|
|
75
|
+
if (bytes.length < 1 || bytes.length > 65_535)
|
|
76
|
+
throw new NwcError("BAD_PAYLOAD", "plaintext length out of range");
|
|
77
|
+
const padded = new Uint8Array(2 + calcPaddedLen(bytes.length));
|
|
78
|
+
padded[0] = bytes.length >> 8;
|
|
79
|
+
padded[1] = bytes.length & 0xff;
|
|
80
|
+
padded.set(bytes, 2);
|
|
81
|
+
const keys = messageKeys(conversation, nonce);
|
|
82
|
+
const ciphertext = chacha20(keys.chacha, keys.chachaNonce, padded);
|
|
83
|
+
const mac = hmac(sha256, keys.hmacKey, Buffer.concat([Buffer.from(nonce), Buffer.from(ciphertext)]));
|
|
84
|
+
return Buffer.concat([Buffer.from([2]), Buffer.from(nonce), Buffer.from(ciphertext), Buffer.from(mac)]).toString("base64");
|
|
85
|
+
}
|
|
86
|
+
export function nip44Decrypt(conversation, payload) {
|
|
87
|
+
if (payload.startsWith("#"))
|
|
88
|
+
throw new NwcError("UNSUPPORTED_ENCRYPTION", "unknown NIP-44 version");
|
|
89
|
+
const data = Buffer.from(payload, "base64");
|
|
90
|
+
if (data.length < 99 || data[0] !== 2)
|
|
91
|
+
throw new NwcError("BAD_PAYLOAD", "NIP-44 payload is malformed");
|
|
92
|
+
const nonce = data.subarray(1, 33);
|
|
93
|
+
const ciphertext = data.subarray(33, data.length - 32);
|
|
94
|
+
const mac = data.subarray(data.length - 32);
|
|
95
|
+
const keys = messageKeys(conversation, nonce);
|
|
96
|
+
const expected = Buffer.from(hmac(sha256, keys.hmacKey, Buffer.concat([nonce, ciphertext])));
|
|
97
|
+
if (!timingSafeEqual(expected, mac))
|
|
98
|
+
throw new NwcError("BAD_PAYLOAD", "NIP-44 MAC mismatch");
|
|
99
|
+
const padded = chacha20(keys.chacha, keys.chachaNonce, ciphertext);
|
|
100
|
+
const length = (padded[0] << 8) | padded[1];
|
|
101
|
+
return new TextDecoder().decode(padded.subarray(2, 2 + length));
|
|
102
|
+
}
|
|
103
|
+
export function signNwcEvent(secretHex, kind, tags, content) {
|
|
104
|
+
const pubkey = Buffer.from(schnorr.getPublicKey(Buffer.from(secretHex, "hex"))).toString("hex");
|
|
105
|
+
const created_at = Math.floor(Date.now() / 1000);
|
|
106
|
+
const id = createHash("sha256").update(JSON.stringify([0, pubkey, created_at, kind, tags, content])).digest("hex");
|
|
107
|
+
const sig = Buffer.from(schnorr.sign(Buffer.from(id, "hex"), Buffer.from(secretHex, "hex"))).toString("hex");
|
|
108
|
+
return { id, pubkey, created_at, kind, tags, content, sig };
|
|
109
|
+
}
|
|
110
|
+
function verifyEvent(event) {
|
|
111
|
+
try {
|
|
112
|
+
const id = createHash("sha256").update(JSON.stringify([0, event.pubkey, event.created_at, event.kind, event.tags, event.content])).digest("hex");
|
|
113
|
+
if (id !== event.id)
|
|
114
|
+
return false;
|
|
115
|
+
return schnorr.verify(Buffer.from(event.sig, "hex"), Buffer.from(id, "hex"), Buffer.from(event.pubkey, "hex"));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
class Relay {
|
|
122
|
+
url;
|
|
123
|
+
clientPubkey;
|
|
124
|
+
socket = null;
|
|
125
|
+
opening = null;
|
|
126
|
+
pending = new Map();
|
|
127
|
+
idle = null;
|
|
128
|
+
subId = randomBytes(8).toString("hex");
|
|
129
|
+
constructor(url, clientPubkey) {
|
|
130
|
+
this.url = url;
|
|
131
|
+
this.clientPubkey = clientPubkey;
|
|
132
|
+
}
|
|
133
|
+
async send(request, timeoutMs) {
|
|
134
|
+
const socket = await this.connected(timeoutMs);
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
const timer = setTimeout(() => {
|
|
137
|
+
this.pending.delete(request.id);
|
|
138
|
+
this.armIdle();
|
|
139
|
+
reject(new NwcError("TIMEOUT", "no wallet response within the timeout"));
|
|
140
|
+
}, timeoutMs);
|
|
141
|
+
this.pending.set(request.id, { resolve, reject, timer });
|
|
142
|
+
if (this.idle) {
|
|
143
|
+
clearTimeout(this.idle);
|
|
144
|
+
this.idle = null;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
socket.send(JSON.stringify(["EVENT", request]));
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
this.settle(request.id, new NwcError("RELAY_CLOSED", error instanceof Error ? error.message : "send failed"));
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
close() {
|
|
155
|
+
if (this.idle) {
|
|
156
|
+
clearTimeout(this.idle);
|
|
157
|
+
this.idle = null;
|
|
158
|
+
}
|
|
159
|
+
const socket = this.socket;
|
|
160
|
+
this.socket = null;
|
|
161
|
+
this.opening = null;
|
|
162
|
+
if (socket) {
|
|
163
|
+
try {
|
|
164
|
+
socket.close();
|
|
165
|
+
}
|
|
166
|
+
catch { /* closed */ }
|
|
167
|
+
}
|
|
168
|
+
for (const id of [...this.pending.keys()])
|
|
169
|
+
this.settle(id, new NwcError("RELAY_CLOSED", "relay connection closed"));
|
|
170
|
+
}
|
|
171
|
+
armIdle() {
|
|
172
|
+
if (this.idle)
|
|
173
|
+
clearTimeout(this.idle);
|
|
174
|
+
this.idle = setTimeout(() => this.close(), RELAY_IDLE_CLOSE_MS);
|
|
175
|
+
this.idle.unref?.();
|
|
176
|
+
}
|
|
177
|
+
settle(id, error, event) {
|
|
178
|
+
const entry = this.pending.get(id);
|
|
179
|
+
if (!entry)
|
|
180
|
+
return;
|
|
181
|
+
this.pending.delete(id);
|
|
182
|
+
clearTimeout(entry.timer);
|
|
183
|
+
if (error)
|
|
184
|
+
entry.reject(error);
|
|
185
|
+
else
|
|
186
|
+
entry.resolve(event);
|
|
187
|
+
if (this.pending.size === 0)
|
|
188
|
+
this.armIdle();
|
|
189
|
+
}
|
|
190
|
+
connected(timeoutMs) {
|
|
191
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN)
|
|
192
|
+
return Promise.resolve(this.socket);
|
|
193
|
+
if (this.opening)
|
|
194
|
+
return this.opening;
|
|
195
|
+
this.opening = new Promise((resolve, reject) => {
|
|
196
|
+
let socket;
|
|
197
|
+
try {
|
|
198
|
+
socket = new WebSocket(this.url);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
this.opening = null;
|
|
202
|
+
reject(new NwcError("RELAY_UNREACHABLE", error instanceof Error ? error.message : "cannot open relay"));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
let opened = false;
|
|
206
|
+
const handshake = setTimeout(() => {
|
|
207
|
+
if (!opened) {
|
|
208
|
+
this.opening = null;
|
|
209
|
+
try {
|
|
210
|
+
socket.close();
|
|
211
|
+
}
|
|
212
|
+
catch { /* */ }
|
|
213
|
+
reject(new NwcError("RELAY_UNREACHABLE", "relay handshake timed out"));
|
|
214
|
+
}
|
|
215
|
+
}, Math.min(timeoutMs, RELAY_HANDSHAKE_TIMEOUT_MS));
|
|
216
|
+
socket.addEventListener("open", () => {
|
|
217
|
+
opened = true;
|
|
218
|
+
clearTimeout(handshake);
|
|
219
|
+
this.socket = socket;
|
|
220
|
+
this.opening = null;
|
|
221
|
+
socket.send(JSON.stringify(["REQ", this.subId, { kinds: [NWC_RESPONSE_KIND], "#p": [this.clientPubkey], since: Math.floor(Date.now() / 1000) - 60 }]));
|
|
222
|
+
resolve(socket);
|
|
223
|
+
});
|
|
224
|
+
socket.addEventListener("message", (message) => this.onMessage(String(message.data)));
|
|
225
|
+
socket.addEventListener("error", () => {
|
|
226
|
+
if (!opened) {
|
|
227
|
+
clearTimeout(handshake);
|
|
228
|
+
this.opening = null;
|
|
229
|
+
reject(new NwcError("RELAY_UNREACHABLE", "relay connection failed"));
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
socket.addEventListener("close", () => {
|
|
233
|
+
if (this.socket === socket)
|
|
234
|
+
this.socket = null;
|
|
235
|
+
if (!opened) {
|
|
236
|
+
clearTimeout(handshake);
|
|
237
|
+
this.opening = null;
|
|
238
|
+
reject(new NwcError("RELAY_UNREACHABLE", "relay closed during handshake"));
|
|
239
|
+
}
|
|
240
|
+
for (const id of [...this.pending.keys()])
|
|
241
|
+
this.settle(id, new NwcError("RELAY_CLOSED", "relay closed the connection"));
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
return this.opening;
|
|
245
|
+
}
|
|
246
|
+
onMessage(raw) {
|
|
247
|
+
let message;
|
|
248
|
+
try {
|
|
249
|
+
message = JSON.parse(raw);
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (!Array.isArray(message))
|
|
255
|
+
return;
|
|
256
|
+
if (message[0] === "EVENT" && message[1] === this.subId && message[2] && typeof message[2] === "object") {
|
|
257
|
+
const event = message[2];
|
|
258
|
+
if (event.kind !== NWC_RESPONSE_KIND || !Array.isArray(event.tags))
|
|
259
|
+
return;
|
|
260
|
+
const ref = event.tags.find((tag) => tag[0] === "e" && typeof tag[1] === "string");
|
|
261
|
+
if (ref?.[1])
|
|
262
|
+
this.settle(ref[1], null, event);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (message[0] === "OK" && typeof message[1] === "string" && message[2] === false) {
|
|
266
|
+
this.settle(message[1], new NwcError("RELAY_REJECTED", typeof message[3] === "string" ? message[3] : "relay rejected the request"));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const relays = new Map();
|
|
271
|
+
function relayFor(connection) {
|
|
272
|
+
const key = `${connection.relayUrl}|${connection.clientPubkey}`;
|
|
273
|
+
let relay = relays.get(key);
|
|
274
|
+
if (!relay) {
|
|
275
|
+
relay = new Relay(connection.relayUrl, connection.clientPubkey);
|
|
276
|
+
relays.set(key, relay);
|
|
277
|
+
}
|
|
278
|
+
return relay;
|
|
279
|
+
}
|
|
280
|
+
/** Closes every standing relay connection (process exit, tests). */
|
|
281
|
+
export function closeNwcConnections() {
|
|
282
|
+
for (const relay of relays.values())
|
|
283
|
+
relay.close();
|
|
284
|
+
relays.clear();
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* One NIP-47 call. Throws `NwcError` with the wallet's error code
|
|
288
|
+
* (`INSUFFICIENT_BALANCE`, `QUOTA_EXCEEDED`, `NOT_FOUND`, `UNAUTHORIZED`, …)
|
|
289
|
+
* or a transport code (`TIMEOUT`, `RELAY_UNREACHABLE`, `RELAY_REJECTED`, `RELAY_CLOSED`, `BAD_RESPONSE`).
|
|
290
|
+
*/
|
|
291
|
+
export async function nwcRequest(connection, method, params, options = {}) {
|
|
292
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
293
|
+
const transport = options.transport ?? ((c, request, t) => relayFor(c).send(request, t));
|
|
294
|
+
const key = nip44ConversationKey(connection.secretHex, connection.walletPubkey);
|
|
295
|
+
const content = nip44Encrypt(key, JSON.stringify({ method, params }));
|
|
296
|
+
const request = signNwcEvent(connection.secretHex, NWC_REQUEST_KIND, [["p", connection.walletPubkey], ["encryption", "nip44_v2"]], content);
|
|
297
|
+
const response = await transport(connection, request, timeoutMs);
|
|
298
|
+
if (response.pubkey !== connection.walletPubkey || !verifyEvent(response)) {
|
|
299
|
+
throw new NwcError("BAD_RESPONSE", "response is not signed by the wallet service");
|
|
300
|
+
}
|
|
301
|
+
let body;
|
|
302
|
+
try {
|
|
303
|
+
body = JSON.parse(nip44Decrypt(key, response.content));
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
throw error instanceof NwcError ? error : new NwcError("BAD_RESPONSE", "response payload is not JSON");
|
|
307
|
+
}
|
|
308
|
+
if (body.error && typeof body.error === "object") {
|
|
309
|
+
throw new NwcError(typeof body.error.code === "string" ? body.error.code : "OTHER", typeof body.error.message === "string" ? body.error.message : "wallet error");
|
|
310
|
+
}
|
|
311
|
+
if (body.result_type !== undefined && body.result_type !== method)
|
|
312
|
+
throw new NwcError("BAD_RESPONSE", `unexpected result_type ${String(body.result_type)}`);
|
|
313
|
+
if (body.result === undefined || body.result === null)
|
|
314
|
+
throw new NwcError("BAD_RESPONSE", "response carries no result");
|
|
315
|
+
return body.result;
|
|
316
|
+
}
|
|
317
|
+
/** The agent-side wallet verbs the Lightning rail needs. Amounts are in sats. */
|
|
318
|
+
export class NwcWallet {
|
|
319
|
+
options;
|
|
320
|
+
connection;
|
|
321
|
+
constructor(pairingUri, options = {}) {
|
|
322
|
+
this.options = options;
|
|
323
|
+
this.connection = parseNwcUri(pairingUri);
|
|
324
|
+
}
|
|
325
|
+
call(method, params) {
|
|
326
|
+
return nwcRequest(this.connection, method, params, this.options);
|
|
327
|
+
}
|
|
328
|
+
async getBalanceSats() {
|
|
329
|
+
const result = await this.call("get_balance", {});
|
|
330
|
+
return Math.floor(Number(result.balance ?? 0) / 1_000);
|
|
331
|
+
}
|
|
332
|
+
/** Remaining budget in sats, or null when the wallet has no budget. */
|
|
333
|
+
async getBudgetSats() {
|
|
334
|
+
let result;
|
|
335
|
+
try {
|
|
336
|
+
result = await this.call("get_budget", {});
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
if (error instanceof NwcError && (error.code === "NOT_IMPLEMENTED" || error.code === "RESTRICTED"))
|
|
340
|
+
return null;
|
|
341
|
+
throw error;
|
|
342
|
+
}
|
|
343
|
+
const total = result["total_budget"];
|
|
344
|
+
if (total === undefined || total === null)
|
|
345
|
+
return null;
|
|
346
|
+
const renews = result["renews_at"];
|
|
347
|
+
return {
|
|
348
|
+
usedSats: Math.floor(Number(result["used_budget"] ?? 0) / 1_000),
|
|
349
|
+
totalSats: Math.floor(Number(total) / 1_000),
|
|
350
|
+
renewsAtSeconds: typeof renews === "number" ? renews : null,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
/** Pays a BOLT11 invoice; returns the preimage (hex) the wallet reports. */
|
|
354
|
+
async payInvoice(bolt11) {
|
|
355
|
+
const result = await this.call("pay_invoice", { invoice: bolt11 });
|
|
356
|
+
const preimage = typeof result.preimage === "string" ? result.preimage.toLowerCase() : "";
|
|
357
|
+
if (!/^[0-9a-f]{64}$/.test(preimage))
|
|
358
|
+
throw new NwcError("BAD_RESPONSE", "pay_invoice returned no preimage");
|
|
359
|
+
return { preimage, feesPaidMsat: typeof result.fees_paid === "number" ? result.fees_paid : null };
|
|
360
|
+
}
|
|
361
|
+
/** Looks an invoice up by payment hash; a settled outgoing payment carries its preimage. */
|
|
362
|
+
async lookupInvoice(paymentHash) {
|
|
363
|
+
try {
|
|
364
|
+
const result = await this.call("lookup_invoice", { payment_hash: paymentHash });
|
|
365
|
+
const preimage = typeof result.preimage === "string" && /^[0-9a-f]{64}$/i.test(result.preimage) ? result.preimage.toLowerCase() : null;
|
|
366
|
+
return { state: typeof result.state === "string" ? result.state.toLowerCase() : null, preimage };
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
if (error instanceof NwcError && error.code === "NOT_FOUND")
|
|
370
|
+
return null;
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=nwc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nwc.js","sourceRoot":"","sources":["../../src/node/nwc.ts"],"names":[],"mappings":"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"}
|