@qntx/wallet-engine 0.4.0 → 0.6.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/LICENSE-APACHE +201 -0
- package/LICENSE-MIT +21 -0
- package/README.md +80 -0
- package/dist/contract-D5pguqiZ.mjs +284 -0
- package/dist/contract-D5pguqiZ.mjs.map +1 -0
- package/dist/gateway-contract.d.mts +297 -0
- package/dist/gateway-contract.mjs +1 -0
- package/dist/index.d.mts +758 -167
- package/dist/index.mjs +4427 -1295
- package/dist/index.mjs.map +1 -1
- package/dist/registry-9oeWs_yZ.d.mts +25 -0
- package/package.json +28 -10
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { r as NetworkInfo } from "./registry-9oeWs_yZ.mjs";
|
|
1
2
|
import { StoreApi } from "zustand/vanilla";
|
|
3
|
+
import "@scure/btc-signer";
|
|
2
4
|
import { CooperativeExitResult, LightningInvoice, LightningPayment, SparkClient, SparkExitChain, SparkNetwork, SparkPayment, SparkStore, SparkTransfer } from "@qntx/spark";
|
|
3
|
-
import {
|
|
4
|
-
import { SparkSigner } from "@qntx/wallet/spark";
|
|
5
|
+
import { decodeEvm } from "@qntx/wallet-chains/evm";
|
|
5
6
|
import { BackupHeader, BackupInfo, InitialFactor, UnlockFactor, Wallet, WalletInfo } from "@qntx/wallet";
|
|
6
|
-
import { Event, Filter, NostrSigner } from "@qntx/nostr";
|
|
7
7
|
import { LnurlPayRequest, LnurlWithdrawRequest } from "@qntx/spark/lnurl";
|
|
8
|
+
import { Event, Filter, NostrSigner } from "@qntx/nostr";
|
|
9
|
+
import { NostrKeyRef, WalletSigner } from "@qntx/wallet/nostr";
|
|
10
|
+
import { SparkSigner } from "@qntx/wallet/spark";
|
|
11
|
+
import { PublicClient } from "viem";
|
|
12
|
+
import { chains } from "@qntx/wallet/chains";
|
|
13
|
+
import "@solana/kit";
|
|
8
14
|
import { SparkAccountRef, SparkApproveIntent } from "@qntx/wallet/protocol";
|
|
15
|
+
import "@qntx/wallet-chains";
|
|
16
|
+
import "@scure/btc-signer/psbt.js";
|
|
9
17
|
//#region src/controller.d.ts
|
|
10
18
|
type ControllerOptions<S> = {
|
|
11
19
|
readonly name: string;
|
|
@@ -69,27 +77,166 @@ export declare function createMemoryEngineStore(backing?: {
|
|
|
69
77
|
readonly collections?: Map<string, Map<string, Uint8Array>>;
|
|
70
78
|
}): EngineStore;
|
|
71
79
|
//#endregion
|
|
72
|
-
//#region src/
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
readonly name
|
|
80
|
+
//#region src/addresses/normalize.d.ts
|
|
81
|
+
type AddressFamily = "evm" | "solana" | "bitcoin" | "spark";
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/addresses/record.d.ts
|
|
84
|
+
type AddressBookEntry = {
|
|
85
|
+
readonly id: string;
|
|
86
|
+
readonly name: string;
|
|
87
|
+
readonly family: AddressFamily;
|
|
88
|
+
readonly address: string;
|
|
89
|
+
readonly note?: string;
|
|
90
|
+
readonly createdAt: number;
|
|
79
91
|
readonly updatedAt: number;
|
|
80
92
|
};
|
|
81
|
-
type
|
|
82
|
-
readonly
|
|
83
|
-
readonly
|
|
84
|
-
readonly hidden: boolean;
|
|
85
|
-
readonly boundPubkey?: string;
|
|
93
|
+
type AddressBookTombstone = {
|
|
94
|
+
readonly id: string;
|
|
95
|
+
readonly deleted: true;
|
|
86
96
|
readonly updatedAt: number;
|
|
87
97
|
};
|
|
88
|
-
type
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
98
|
+
type AddressBookRecord = AddressBookEntry | AddressBookTombstone;
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/addresses/controller.d.ts
|
|
101
|
+
type AddressBookState = {
|
|
102
|
+
/** Live entries only; tombstones stay internal. */
|
|
103
|
+
readonly entries: Record<string, AddressBookEntry>;
|
|
104
|
+
};
|
|
105
|
+
type AddressBookOptions = {
|
|
106
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
107
|
+
readonly random: (n: number) => Uint8Array;
|
|
108
|
+
readonly now: () => number;
|
|
109
|
+
readonly logger: EngineLogger;
|
|
110
|
+
};
|
|
111
|
+
export declare class AddressBookController extends Controller<AddressBookState> {
|
|
112
|
+
private readonly options;
|
|
113
|
+
private engineStore;
|
|
114
|
+
/** Every record, tombstones included, by id. */
|
|
115
|
+
private records;
|
|
116
|
+
constructor(options: AddressBookOptions);
|
|
117
|
+
init(): Promise<void>;
|
|
118
|
+
destroy(): Promise<void>;
|
|
119
|
+
lock(): void;
|
|
120
|
+
/** Entries and tombstones, for the metadata document. */
|
|
121
|
+
syncEntries(): ReadonlyArray<AddressBookRecord>;
|
|
122
|
+
/**
|
|
123
|
+
* Merges records from another device (last writer wins, tombstones win over older entries).
|
|
124
|
+
* Returns whether anything local changed and whether the merged set holds something `remote`
|
|
125
|
+
* lacks, i.e. whether the remote copy needs a newer publish.
|
|
126
|
+
*/
|
|
127
|
+
merge(remote: ReadonlyArray<AddressBookRecord>): Promise<{
|
|
128
|
+
readonly changed: boolean;
|
|
129
|
+
readonly localNewer: boolean;
|
|
130
|
+
}>;
|
|
131
|
+
add(params: {
|
|
132
|
+
readonly name: string;
|
|
133
|
+
readonly family: AddressFamily;
|
|
134
|
+
readonly address: string;
|
|
135
|
+
readonly note?: string;
|
|
136
|
+
}): Promise<AddressBookEntry>;
|
|
137
|
+
rename(id: string, name: string): Promise<AddressBookEntry>;
|
|
138
|
+
/** Sets or clears (empty or `undefined`) the note. */
|
|
139
|
+
setNote(id: string, note: string | undefined): Promise<AddressBookEntry>;
|
|
140
|
+
/** Removes the entry, leaving a tombstone so other devices drop it too. */
|
|
141
|
+
remove(id: string): Promise<void>;
|
|
142
|
+
private checkedNote;
|
|
143
|
+
private requireEntry;
|
|
144
|
+
private persist;
|
|
145
|
+
private requireStore;
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region src/addresses/errors.d.ts
|
|
149
|
+
type AddressBookErrorCategory = "invalid-input" | "duplicate" | "not-found" | "locked" | "limit";
|
|
150
|
+
export declare class AddressBookError extends Error {
|
|
151
|
+
readonly category: AddressBookErrorCategory;
|
|
152
|
+
constructor(category: AddressBookErrorCategory, message: string);
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/chains/evm.d.ts
|
|
156
|
+
type EvmFeeTier = "slow" | "normal" | "fast";
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/chains/bitcoin.d.ts
|
|
159
|
+
type Esplora = {
|
|
160
|
+
readonly get: (path: string) => Promise<unknown>;
|
|
161
|
+
readonly post: (path: string, body: string) => Promise<unknown>;
|
|
162
|
+
};
|
|
163
|
+
//#endregion
|
|
164
|
+
//#region src/networks/controller.d.ts
|
|
165
|
+
type SolanaRpc = {
|
|
166
|
+
readonly call: (method: string, params: unknown[]) => Promise<unknown>;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* A host-endpoint-only client for cross-checking pre-signing reads. `not-needed`: the gateway is
|
|
170
|
+
* not this network's first endpoint, so the primary reads already come from the host.
|
|
171
|
+
* `unavailable`: a cross-check is needed but the network has no host endpoint.
|
|
172
|
+
*/
|
|
173
|
+
type Independent<T> = {
|
|
174
|
+
readonly kind: "not-needed";
|
|
175
|
+
} | {
|
|
176
|
+
readonly kind: "unavailable";
|
|
177
|
+
} | {
|
|
178
|
+
readonly kind: "available";
|
|
179
|
+
readonly client: T;
|
|
180
|
+
};
|
|
181
|
+
type NetworkControllerState = {
|
|
182
|
+
readonly customRpc: Record<string, ReadonlyArray<string>>;
|
|
183
|
+
};
|
|
184
|
+
type Options$2 = {
|
|
185
|
+
readonly fetch: typeof globalThis.fetch;
|
|
186
|
+
readonly rpc: Readonly<Record<string, ReadonlyArray<string>>>;
|
|
187
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
188
|
+
readonly logger: EngineLogger;
|
|
189
|
+
readonly gateway?: {
|
|
190
|
+
readonly url: string;
|
|
191
|
+
readonly installId: string;
|
|
192
|
+
} | undefined;
|
|
92
193
|
};
|
|
194
|
+
declare class NetworkController extends Controller<NetworkControllerState> {
|
|
195
|
+
private readonly options;
|
|
196
|
+
private engineStore?;
|
|
197
|
+
private readonly clients;
|
|
198
|
+
private readonly gatewayBase;
|
|
199
|
+
private readonly gatewayOrigin;
|
|
200
|
+
/** Networks the gateway reported at unlock; empty while locked or when the read failed. */
|
|
201
|
+
private gatewayServed;
|
|
202
|
+
constructor(options: Options$2);
|
|
203
|
+
init(): Promise<void>;
|
|
204
|
+
private loadCustomRpc;
|
|
205
|
+
/** Reads the gateway's served networks; any failure leaves the gateway unused until next unlock. */
|
|
206
|
+
private loadGatewayNetworks;
|
|
207
|
+
/** `fetch` that adds the install id to requests bound for the gateway's origin only. */
|
|
208
|
+
private readonly gatewayFetch;
|
|
209
|
+
destroy(): Promise<void>;
|
|
210
|
+
lock(): void;
|
|
211
|
+
/**
|
|
212
|
+
* Ordered endpoints: a network with custom endpoints uses custom → host and never the gateway;
|
|
213
|
+
* otherwise a gateway-served network uses gateway → host; else host only.
|
|
214
|
+
*/
|
|
215
|
+
endpoints(network: string): ReadonlyArray<string>;
|
|
216
|
+
info(network: string): NetworkInfo;
|
|
217
|
+
client(network: string): PublicClient;
|
|
218
|
+
/** True when the gateway heads this network's endpoint list (no custom endpoints, gateway-served). */
|
|
219
|
+
private gatewayFirst;
|
|
220
|
+
private independent;
|
|
221
|
+
/** Host-endpoint EVM client for cross-checking reads; never sends the install id. */
|
|
222
|
+
independentClient(network: string): Independent<PublicClient>;
|
|
223
|
+
independentSolanaRpc(network: string): Independent<SolanaRpc>;
|
|
224
|
+
independentEsplora(network: string): Independent<Esplora>;
|
|
225
|
+
/** Networks with at least one configured endpoint or served by the gateway, by family. */
|
|
226
|
+
enabled(family: "evm" | "solana" | "bitcoin"): ReadonlyArray<string>;
|
|
227
|
+
/** Solana JSON-RPC over the ordered endpoint list — kit's transport is single-endpoint. */
|
|
228
|
+
solanaRpc(network: string): SolanaRpc;
|
|
229
|
+
/** Bounded-concurrency + 429-aware ordered-failover Esplora client. */
|
|
230
|
+
esplora(network: string): Esplora;
|
|
231
|
+
/** Validate a custom endpoint's reported chain id, then persist it first in the list. */
|
|
232
|
+
addRpc(network: string, url: string): Promise<void>;
|
|
233
|
+
}
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/chains/solana.d.ts
|
|
236
|
+
type SolanaFeeTier = "slow" | "normal" | "fast";
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region src/requests/checks.d.ts
|
|
239
|
+
type RequestCheckCode = "decode-partial" | "nonce-mismatch" | "fee-mismatch" | "reads-unverified" | "fee-above-network" | "fee-exceeds-amount";
|
|
93
240
|
//#endregion
|
|
94
241
|
//#region src/spark/notes.d.ts
|
|
95
242
|
/**
|
|
@@ -262,10 +409,467 @@ export declare class SparkController extends Controller<SparkControllerState> {
|
|
|
262
409
|
}): Promise<CooperativeExitResult>;
|
|
263
410
|
}
|
|
264
411
|
//#endregion
|
|
412
|
+
//#region src/payments/action.d.ts
|
|
413
|
+
/**
|
|
414
|
+
* What the host shows for a Spark, Lightning or exit request; `family` tells it apart from a chain
|
|
415
|
+
* intent.
|
|
416
|
+
*/
|
|
417
|
+
type SparkDisplay = {
|
|
418
|
+
readonly family: "spark";
|
|
419
|
+
readonly network: SparkNetwork;
|
|
420
|
+
readonly kind: "transfer" | "lightning" | "exit";
|
|
421
|
+
readonly amountSats: number;
|
|
422
|
+
readonly maxFeeSats?: number;
|
|
423
|
+
/** Spark address, Lightning payee public key (hex) or bitcoin address. */
|
|
424
|
+
readonly receiver: string;
|
|
425
|
+
/** Invoice description or the LNURL metadata text. */
|
|
426
|
+
readonly description?: string;
|
|
427
|
+
};
|
|
428
|
+
type SparkResult = {
|
|
429
|
+
readonly kind: "spark";
|
|
430
|
+
readonly transfer: SparkTransfer;
|
|
431
|
+
} | {
|
|
432
|
+
readonly kind: "lightning";
|
|
433
|
+
readonly payment: LightningPayment;
|
|
434
|
+
} | {
|
|
435
|
+
readonly kind: "withdraw";
|
|
436
|
+
readonly exit: CooperativeExitResult;
|
|
437
|
+
};
|
|
438
|
+
/**
|
|
439
|
+
* A validated, fixed Spark payment: everything that does not need the user's verification has
|
|
440
|
+
* happened (including any LNURL invoice fetch), so approval only re-checks expiry and executes.
|
|
441
|
+
*/
|
|
442
|
+
type PreparedSparkAction = {
|
|
443
|
+
readonly display: SparkDisplay;
|
|
444
|
+
readonly checks: ReadonlyArray<RequestCheckCode>;
|
|
445
|
+
/** Why the action can no longer be paid at `now` (an expiring invoice), if so. */
|
|
446
|
+
readonly staleReason: (now: number) => string | undefined;
|
|
447
|
+
/** Runs the controller's approve-first payment call. */
|
|
448
|
+
readonly execute: (spark: SparkController, verify: UnlockFactor) => Promise<SparkResult>;
|
|
449
|
+
};
|
|
450
|
+
//#endregion
|
|
451
|
+
//#region src/payments/parse.d.ts
|
|
452
|
+
type PaymentOption = {
|
|
453
|
+
readonly kind: "spark";
|
|
454
|
+
readonly address: string;
|
|
455
|
+
} | {
|
|
456
|
+
readonly kind: "spark-invoice";
|
|
457
|
+
readonly invoice: string;
|
|
458
|
+
readonly amountSats?: number;
|
|
459
|
+
readonly memo?: string;
|
|
460
|
+
readonly expiresAt?: number;
|
|
461
|
+
} | {
|
|
462
|
+
readonly kind: "lightning";
|
|
463
|
+
readonly invoice: string;
|
|
464
|
+
readonly amountSats?: number;
|
|
465
|
+
readonly paymentHash: string;
|
|
466
|
+
readonly description?: string;
|
|
467
|
+
readonly expiresAt: number;
|
|
468
|
+
} | {
|
|
469
|
+
readonly kind: "lnurl-pay";
|
|
470
|
+
readonly request: LnurlPayRequest;
|
|
471
|
+
readonly address?: string;
|
|
472
|
+
} | {
|
|
473
|
+
readonly kind: "lnurl-withdraw";
|
|
474
|
+
readonly request: LnurlWithdrawRequest;
|
|
475
|
+
} | {
|
|
476
|
+
readonly kind: "bitcoin";
|
|
477
|
+
readonly address: string;
|
|
478
|
+
};
|
|
479
|
+
type PaymentRequest = {
|
|
480
|
+
readonly options: ReadonlyArray<PaymentOption>;
|
|
481
|
+
readonly amountSats?: number;
|
|
482
|
+
readonly label?: string;
|
|
483
|
+
readonly message?: string;
|
|
484
|
+
};
|
|
485
|
+
type PaymentParse = {
|
|
486
|
+
readonly kind: "request";
|
|
487
|
+
readonly request: PaymentRequest;
|
|
488
|
+
} | {
|
|
489
|
+
readonly kind: "lnurl";
|
|
490
|
+
readonly url: string;
|
|
491
|
+
readonly address?: string;
|
|
492
|
+
} | {
|
|
493
|
+
readonly kind: "unsupported";
|
|
494
|
+
readonly format: "bolt12" | "silent-payment" | "lnurl-auth" | "spark-token-invoice" | "nostr-wallet-connect";
|
|
495
|
+
} | {
|
|
496
|
+
readonly kind: "invalid";
|
|
497
|
+
readonly reason: "network" | "expired" | "amount-mismatch" | "malformed";
|
|
498
|
+
} | {
|
|
499
|
+
readonly kind: "unrecognized";
|
|
500
|
+
};
|
|
501
|
+
type ParseOptions = {
|
|
502
|
+
readonly network: SparkNetwork;
|
|
503
|
+
readonly now: number;
|
|
504
|
+
};
|
|
505
|
+
/** `input` → PaymentParse. Never throws: every failure is a structured result. */
|
|
506
|
+
export declare function parsePayment(input: string, options: ParseOptions): PaymentParse;
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/payments/pay.d.ts
|
|
509
|
+
type PayParams = {
|
|
510
|
+
readonly account: SparkAccountRef;
|
|
511
|
+
readonly option: PaymentOption;
|
|
512
|
+
/** Caller-supplied amount — required by open invoices, the `spark` option, and LNURL flows. */
|
|
513
|
+
readonly amountSats?: number;
|
|
514
|
+
readonly comment?: string;
|
|
515
|
+
readonly maxFeeSats?: number;
|
|
516
|
+
readonly speed?: "FAST" | "MEDIUM" | "SLOW";
|
|
517
|
+
};
|
|
518
|
+
type WithdrawLnurlParams = {
|
|
519
|
+
readonly account: SparkAccountRef;
|
|
520
|
+
readonly option: Extract<PaymentOption, {
|
|
521
|
+
kind: "lnurl-withdraw";
|
|
522
|
+
}>;
|
|
523
|
+
readonly amountSats: number;
|
|
524
|
+
};
|
|
525
|
+
//#endregion
|
|
526
|
+
//#region src/payments/zap.d.ts
|
|
527
|
+
/** A profile zap names the recipient pubkey; an event zap carries the event it zaps. */
|
|
528
|
+
type ZapRecipient = {
|
|
529
|
+
readonly pubkey: string;
|
|
530
|
+
readonly lightning: string;
|
|
531
|
+
} | {
|
|
532
|
+
readonly event: Event;
|
|
533
|
+
readonly lightning: string;
|
|
534
|
+
};
|
|
535
|
+
type PrepareZapParams = {
|
|
536
|
+
/** Any `NostrSigner` — wallet key, external key, NIP-07/46 — signs the 9734. */
|
|
537
|
+
readonly signer: NostrSigner;
|
|
538
|
+
readonly recipient: ZapRecipient;
|
|
539
|
+
readonly amountSats: number;
|
|
540
|
+
readonly comment?: string | undefined;
|
|
541
|
+
readonly relays: ReadonlyArray<string>;
|
|
542
|
+
readonly network: SparkNetwork;
|
|
543
|
+
};
|
|
544
|
+
type PrepareZapContext = {
|
|
545
|
+
readonly fetch: typeof globalThis.fetch;
|
|
546
|
+
readonly now: () => number;
|
|
547
|
+
};
|
|
548
|
+
/** Everything a payer needs: the signed 9734, the invoice, and the note fields. */
|
|
549
|
+
type PreparedZap = {
|
|
550
|
+
readonly zapRequest: Event;
|
|
551
|
+
readonly invoice: string;
|
|
552
|
+
/** Hex payment hash decoded from the invoice. */
|
|
553
|
+
readonly paymentHash: string;
|
|
554
|
+
/** Millisecond expiry decoded from the invoice. */
|
|
555
|
+
readonly expiresAt: number;
|
|
556
|
+
readonly amountSats: number;
|
|
557
|
+
/** The LNURL service's 9735 signing pubkey. */
|
|
558
|
+
readonly receiptPubkey: string;
|
|
559
|
+
readonly recipientPubkey: string;
|
|
560
|
+
readonly eventId?: string;
|
|
561
|
+
readonly comment?: string;
|
|
562
|
+
/** The lud16 or LNURL as given. */
|
|
563
|
+
readonly lightning: string;
|
|
564
|
+
};
|
|
565
|
+
/** Everything up to payment: resolve LNURL, sign the 9734, request the invoice. */
|
|
566
|
+
export declare function prepareZap(params: PrepareZapParams, context: PrepareZapContext): Promise<PreparedZap>;
|
|
567
|
+
//#endregion
|
|
568
|
+
//#region src/transactions/route.d.ts
|
|
569
|
+
type SignParams = Parameters<ReturnType<typeof chains>["sign"]>[0];
|
|
570
|
+
type AccountRef = SignParams["request"]["account"];
|
|
571
|
+
type DisplayIntent = ReturnType<typeof decodeEvm>;
|
|
572
|
+
type TxState = "draft" | "signed" | "submitted" | "pending" | "confirmed" | "failed" | "rejected" | "dropped" | "replaced";
|
|
573
|
+
type TrackedTransaction = {
|
|
574
|
+
readonly id: string;
|
|
575
|
+
readonly family: "evm" | "solana" | "bitcoin";
|
|
576
|
+
readonly network: string;
|
|
577
|
+
readonly account: string;
|
|
578
|
+
readonly hash: string | undefined;
|
|
579
|
+
readonly state: TxState;
|
|
580
|
+
readonly intent: DisplayIntent | undefined;
|
|
581
|
+
readonly nonce: number;
|
|
582
|
+
/** Solana only — the blockhash expiry that turns an unconfirmed tx `dropped`. */
|
|
583
|
+
readonly lastValidBlockHeight?: number;
|
|
584
|
+
/** EVM replacement — the earlier transaction this one bumps or cancels. */
|
|
585
|
+
readonly replaces?: string;
|
|
586
|
+
/** CPFP — the unconfirmed parent this child pushes. */
|
|
587
|
+
readonly parentId?: string;
|
|
588
|
+
/** Bitcoin build record persisted at send for RBF/CPFP rebuilds. */
|
|
589
|
+
readonly btc?: {
|
|
590
|
+
readonly inputs: ReadonlyArray<{
|
|
591
|
+
readonly txid: string;
|
|
592
|
+
readonly vout: number;
|
|
593
|
+
readonly value: number;
|
|
594
|
+
readonly address: string;
|
|
595
|
+
}>;
|
|
596
|
+
readonly outputs: ReadonlyArray<{
|
|
597
|
+
readonly address: string;
|
|
598
|
+
readonly value: number;
|
|
599
|
+
readonly own: boolean;
|
|
600
|
+
}>;
|
|
601
|
+
readonly vsize: number;
|
|
602
|
+
readonly fee: number;
|
|
603
|
+
readonly feeRate: number;
|
|
604
|
+
};
|
|
605
|
+
readonly submittedAt: number;
|
|
606
|
+
readonly error: string | undefined;
|
|
607
|
+
};
|
|
608
|
+
type SendParams = {
|
|
609
|
+
readonly account: AccountRef;
|
|
610
|
+
readonly network: string;
|
|
611
|
+
readonly to: string;
|
|
612
|
+
readonly amount: bigint;
|
|
613
|
+
/** ERC-20 contract — when set, `to`/`amount` are the transfer recipient/units and value is 0. */
|
|
614
|
+
readonly token?: string;
|
|
615
|
+
readonly fee: EvmFeeTier | SolanaFeeTier;
|
|
616
|
+
/** SPL mint decimals — required when `token` is a Solana mint. */
|
|
617
|
+
readonly decimals?: number;
|
|
618
|
+
readonly verify: SignParams["verify"];
|
|
619
|
+
};
|
|
620
|
+
type PrepareParams = Omit<SendParams, "verify">;
|
|
621
|
+
type ChainRequestMethod = "send" | "speed-up" | "cancel" | "cpfp";
|
|
622
|
+
/** What a request asks for; replacements and CPFP name the original transaction. */
|
|
623
|
+
type ChainRequestInput = ({
|
|
624
|
+
readonly method: "send";
|
|
625
|
+
} & PrepareParams) | {
|
|
626
|
+
readonly method: "speed-up" | "cancel";
|
|
627
|
+
readonly txId: string;
|
|
628
|
+
} | {
|
|
629
|
+
readonly method: "cpfp";
|
|
630
|
+
readonly txId: string;
|
|
631
|
+
readonly feeRate: number;
|
|
632
|
+
};
|
|
633
|
+
/**
|
|
634
|
+
* A fully built, estimated and cross-checked send that has not been signed. The unsigned content
|
|
635
|
+
* lives in the closures and cannot change after `prepare` returns.
|
|
636
|
+
*/
|
|
637
|
+
type PreparedRequest = {
|
|
638
|
+
/** Id of the tracked transaction `submit` creates. */
|
|
639
|
+
readonly txId: string;
|
|
640
|
+
readonly account: AccountRef;
|
|
641
|
+
readonly network: string;
|
|
642
|
+
/** The transaction being replaced or accelerated; absent for a plain send. */
|
|
643
|
+
readonly target?: string;
|
|
644
|
+
readonly intent: DisplayIntent;
|
|
645
|
+
readonly checks: ReadonlyArray<RequestCheckCode>;
|
|
646
|
+
/** Why the build can no longer be signed (nonce taken, blockhash expired), if so. */
|
|
647
|
+
readonly staleReason: () => string | undefined | Promise<string | undefined>;
|
|
648
|
+
/** Signs, finalizes, broadcasts and hands the transaction to tracking. */
|
|
649
|
+
readonly submit: (verify: SendParams["verify"]) => Promise<TrackedTransaction>;
|
|
650
|
+
/** Frees what `prepare` reserved; safe to call more than once. */
|
|
651
|
+
readonly release: () => void;
|
|
652
|
+
};
|
|
653
|
+
type Options$1 = {
|
|
654
|
+
readonly wallet: Wallet;
|
|
655
|
+
readonly networks: NetworkController;
|
|
656
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
657
|
+
readonly random: (n: number) => Uint8Array;
|
|
658
|
+
readonly setTimer: (ms: number, fn: () => unknown) => () => void;
|
|
659
|
+
readonly now: () => number;
|
|
660
|
+
readonly logger: EngineLogger;
|
|
661
|
+
readonly pollMs?: number;
|
|
662
|
+
/** Test seam — defaults to the wallet's real chains proxy. */
|
|
663
|
+
readonly chains?: ReturnType<typeof chains>;
|
|
664
|
+
};
|
|
665
|
+
//#endregion
|
|
666
|
+
//#region src/transactions/controller.d.ts
|
|
667
|
+
type TransactionControllerState = {
|
|
668
|
+
readonly txs: Record<string, TrackedTransaction>;
|
|
669
|
+
};
|
|
670
|
+
declare class TransactionController extends Controller<TransactionControllerState> {
|
|
671
|
+
private readonly options;
|
|
672
|
+
private engineStore?;
|
|
673
|
+
private readonly timers;
|
|
674
|
+
private evmRoute;
|
|
675
|
+
private bitcoinRoute;
|
|
676
|
+
private locked;
|
|
677
|
+
constructor(options: Options$1);
|
|
678
|
+
init(): Promise<void>;
|
|
679
|
+
destroy(): Promise<void>;
|
|
680
|
+
lock(): void;
|
|
681
|
+
private persist;
|
|
682
|
+
private transition;
|
|
683
|
+
private routeCtx;
|
|
684
|
+
/**
|
|
685
|
+
* Internal entry for the request pipeline: builds, estimates and cross-checks a send without
|
|
686
|
+
* signing it. Bitcoin outputs it selects stay locked under `requestId` until the returned
|
|
687
|
+
* `release` runs or the broadcast moves them to the transaction.
|
|
688
|
+
*/
|
|
689
|
+
prepareSend(params: PrepareParams, requestId: string): Promise<PreparedRequest>;
|
|
690
|
+
/**
|
|
691
|
+
* Internal entry for replacements and CPFP: builds, cross-checks and reserves what the
|
|
692
|
+
* replacement needs without signing it. The original must be `submitted` or `pending`.
|
|
693
|
+
*/
|
|
694
|
+
prepareReplacement(input: Exclude<ChainRequestInput, {
|
|
695
|
+
method: "send";
|
|
696
|
+
}>, requestId: string): Promise<PreparedRequest>;
|
|
697
|
+
private track;
|
|
698
|
+
}
|
|
699
|
+
//#endregion
|
|
700
|
+
//#region src/requests/risk.d.ts
|
|
701
|
+
/**
|
|
702
|
+
* Recipient risk, pure: a recipient the wallet has never paid or saved is a `warning`; one that
|
|
703
|
+
* looks like a known address (same first and last four characters, different address) is a `danger`
|
|
704
|
+
* — the shape of an address-poisoning lookalike. Both can apply to one recipient.
|
|
705
|
+
*/
|
|
706
|
+
type RiskFinding = {
|
|
707
|
+
readonly code: "first-recipient" | "address-poisoning";
|
|
708
|
+
readonly level: "warning" | "danger";
|
|
709
|
+
};
|
|
710
|
+
//#endregion
|
|
711
|
+
//#region src/requests/sign-log.d.ts
|
|
712
|
+
type SignLogOutcome = "submitted" | "rejected" | "failed" | "expired" | "invalidated";
|
|
713
|
+
type SignLogEntry = {
|
|
714
|
+
readonly id: string;
|
|
715
|
+
readonly at: number;
|
|
716
|
+
readonly origin: {
|
|
717
|
+
readonly kind: "internal";
|
|
718
|
+
};
|
|
719
|
+
readonly method: RequestMethod;
|
|
720
|
+
readonly account: AccountRef | SparkAccountRef;
|
|
721
|
+
readonly network: string;
|
|
722
|
+
readonly summary: string;
|
|
723
|
+
readonly verification: "verified" | "unverifiable";
|
|
724
|
+
readonly checks: ReadonlyArray<RequestCheckCode>;
|
|
725
|
+
readonly risk: ReadonlyArray<RiskFinding>;
|
|
726
|
+
readonly outcome: SignLogOutcome;
|
|
727
|
+
readonly error?: string;
|
|
728
|
+
};
|
|
729
|
+
//#endregion
|
|
730
|
+
//#region src/requests/controller.d.ts
|
|
731
|
+
/** A Spark, Lightning (including LNURL-pay and lightning addresses) or cooperative-exit payment. */
|
|
732
|
+
type PayInput = {
|
|
733
|
+
readonly method: "pay";
|
|
734
|
+
} & PayParams;
|
|
735
|
+
/** A prepared zap; its invoice was fetched by `engine.zaps.prepare` and is paid as-is. */
|
|
736
|
+
type ZapInput = {
|
|
737
|
+
readonly method: "zap";
|
|
738
|
+
readonly account: SparkAccountRef;
|
|
739
|
+
readonly zap: PreparedZap;
|
|
740
|
+
readonly maxFeeSats: number;
|
|
741
|
+
};
|
|
742
|
+
type RequestMethod = ChainRequestMethod | "pay" | "zap";
|
|
743
|
+
type RequestInput = ChainRequestInput | PayInput | ZapInput;
|
|
744
|
+
type RequestStage = "awaiting-approval" | "signing" | "submitted" | "rejected" | "failed" | "expired" | "invalidated";
|
|
745
|
+
type PendingRequest = {
|
|
746
|
+
readonly id: string;
|
|
747
|
+
readonly origin: {
|
|
748
|
+
readonly kind: "internal";
|
|
749
|
+
};
|
|
750
|
+
readonly method: RequestMethod;
|
|
751
|
+
readonly account: AccountRef | SparkAccountRef;
|
|
752
|
+
readonly network: string;
|
|
753
|
+
readonly stage: RequestStage;
|
|
754
|
+
/** Decoded locally from the exact content that will be signed; `family` tells the shapes apart. */
|
|
755
|
+
readonly display: DisplayIntent | SparkDisplay;
|
|
756
|
+
/** `unverifiable` as soon as any check is recorded; the host must ask for explicit confirmation. */
|
|
757
|
+
readonly verification: "verified" | "unverifiable";
|
|
758
|
+
readonly checks: ReadonlyArray<RequestCheckCode>;
|
|
759
|
+
/**
|
|
760
|
+
* Recipient risk; independent of `verification`. A `danger` needs the user's explicit
|
|
761
|
+
* acknowledgement.
|
|
762
|
+
*/
|
|
763
|
+
readonly risk: ReadonlyArray<RiskFinding>;
|
|
764
|
+
readonly createdAt: number;
|
|
765
|
+
readonly expiresAt: number;
|
|
766
|
+
/** The transaction being replaced or accelerated; absent for a plain send. */
|
|
767
|
+
readonly target?: string;
|
|
768
|
+
/** The tracked transaction once submitted. */
|
|
769
|
+
readonly txId?: string;
|
|
770
|
+
readonly error?: string;
|
|
771
|
+
};
|
|
772
|
+
type RequestControllerState = {
|
|
773
|
+
readonly requests: Record<string, PendingRequest>;
|
|
774
|
+
};
|
|
775
|
+
type RequestControllerOptions = {
|
|
776
|
+
readonly transactions: TransactionController;
|
|
777
|
+
/** The full controller: its payment methods are reachable only through this pipeline. */
|
|
778
|
+
readonly spark: SparkController;
|
|
779
|
+
readonly addressBook: AddressBookController;
|
|
780
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
781
|
+
readonly fetch: typeof globalThis.fetch;
|
|
782
|
+
readonly random: (n: number) => Uint8Array;
|
|
783
|
+
readonly now: () => number;
|
|
784
|
+
readonly setTimer: (ms: number, fn: () => unknown) => () => void;
|
|
785
|
+
readonly logger: EngineLogger;
|
|
786
|
+
};
|
|
787
|
+
/** Requests expire this long after creation. */
|
|
788
|
+
export declare const REQUEST_TTL_MS: number;
|
|
789
|
+
export declare class RequestController extends Controller<RequestControllerState> {
|
|
790
|
+
private readonly options;
|
|
791
|
+
private readonly entries;
|
|
792
|
+
private readonly log;
|
|
793
|
+
/** Original transaction id → the unfinished request replacing or accelerating it. */
|
|
794
|
+
private readonly targets;
|
|
795
|
+
private locked;
|
|
796
|
+
/** Bumped on every unlock and lock so work that outlives a session never touches the next one. */
|
|
797
|
+
private session;
|
|
798
|
+
constructor(options: RequestControllerOptions);
|
|
799
|
+
init(): Promise<void>;
|
|
800
|
+
destroy(): Promise<void>;
|
|
801
|
+
/** Locking is not consent: every unfinished request becomes `invalidated` and frees its resources. */
|
|
802
|
+
lock(): void;
|
|
803
|
+
/** The signature record, newest first. */
|
|
804
|
+
signLog(): Promise<ReadonlyArray<SignLogEntry>>;
|
|
805
|
+
clearSignLog(): Promise<void>;
|
|
806
|
+
prepare(input: RequestInput): Promise<PendingRequest>;
|
|
807
|
+
private build;
|
|
808
|
+
/**
|
|
809
|
+
* Signs and submits a request. Anything but a live, unexpired `send` request with this id throws
|
|
810
|
+
* before any signing; a stale build (nonce taken, blockhash expired) fails without signing.
|
|
811
|
+
*/
|
|
812
|
+
approve(id: string, method: ChainRequestMethod, verify: SendParams["verify"]): Promise<TrackedTransaction>;
|
|
813
|
+
approve(id: string, method: "pay" | "zap", verify: SendParams["verify"]): Promise<SparkResult>;
|
|
814
|
+
/**
|
|
815
|
+
* A cancelled or refused verification is `rejected`; anything after it is `failed`. Chain
|
|
816
|
+
* requests record which step failed on the tracked transaction; for Spark, the approval round is
|
|
817
|
+
* the only source of `WalletError`.
|
|
818
|
+
*/
|
|
819
|
+
private failureStage;
|
|
820
|
+
reject(id: string): void;
|
|
821
|
+
private requireRequest;
|
|
822
|
+
private put;
|
|
823
|
+
private unclaim;
|
|
824
|
+
/** Ends a request in a terminal stage and frees what it reserved. */
|
|
825
|
+
private finish;
|
|
826
|
+
/** Appends the final stage to the signature record; a failed write is a warning, not an error. */
|
|
827
|
+
private record;
|
|
828
|
+
private appendLog;
|
|
829
|
+
/**
|
|
830
|
+
* Addresses the wallet already knows for a family: contacts, plus recipients of tracked chain
|
|
831
|
+
* sends (Spark payments are not tracked).
|
|
832
|
+
*/
|
|
833
|
+
private knownAddresses;
|
|
834
|
+
private chainRisk;
|
|
835
|
+
/** Only a Spark transfer has a recipient to check; Lightning and exits are not assessed. */
|
|
836
|
+
private sparkRisk;
|
|
837
|
+
}
|
|
838
|
+
//#endregion
|
|
839
|
+
//#region src/meta/doc.d.ts
|
|
840
|
+
/**
|
|
841
|
+
* Wallet metadata document — the plaintext exchanged over kind-30078 events between this wallet's
|
|
842
|
+
* own devices. One document per wallet; entry-level last-writer-wins on `updatedAt`.
|
|
843
|
+
*/
|
|
844
|
+
type MetaDocWallet = {
|
|
845
|
+
readonly name?: string;
|
|
846
|
+
readonly updatedAt: number;
|
|
847
|
+
};
|
|
848
|
+
type MetaDocGroup = {
|
|
849
|
+
readonly index: number;
|
|
850
|
+
readonly name?: string;
|
|
851
|
+
readonly hidden: boolean;
|
|
852
|
+
readonly boundPubkey?: string;
|
|
853
|
+
readonly updatedAt: number;
|
|
854
|
+
};
|
|
855
|
+
/** The per-wallet part of the document: this wallet's name and account groups. */
|
|
856
|
+
type MetaDocTree = {
|
|
857
|
+
readonly wallet: MetaDocWallet;
|
|
858
|
+
readonly groups: ReadonlyArray<MetaDocGroup>;
|
|
859
|
+
};
|
|
860
|
+
/** Every wallet's document also carries the whole address book, which is shared across wallets. */
|
|
861
|
+
type MetaDoc = MetaDocTree & {
|
|
862
|
+
readonly v: 2;
|
|
863
|
+
readonly contacts: ReadonlyArray<AddressBookRecord>;
|
|
864
|
+
};
|
|
865
|
+
//#endregion
|
|
265
866
|
//#region src/accounts/controller.d.ts
|
|
266
867
|
type AccountGroup = {
|
|
267
868
|
readonly walletId: string;
|
|
268
869
|
readonly index: number;
|
|
870
|
+
/** `discoverGroups` result — family key → used; a family error lives under `errors`. */
|
|
871
|
+
readonly used?: Readonly<Record<string, boolean>>;
|
|
872
|
+
readonly errors?: Readonly<Record<string, string>>;
|
|
269
873
|
readonly name?: string;
|
|
270
874
|
readonly hidden: boolean;
|
|
271
875
|
/** A social identity (64 lowercase hex) bound to this group; one identity binds one group. */
|
|
@@ -287,21 +891,41 @@ type AccountTreeState = {
|
|
|
287
891
|
} | null;
|
|
288
892
|
readonly totals: Readonly<Record<string, number>>;
|
|
289
893
|
};
|
|
894
|
+
type DiscoveryNetworks = {
|
|
895
|
+
readonly client: (network: string) => {
|
|
896
|
+
readonly getTransactionCount: (p: {
|
|
897
|
+
readonly address: `0x${string}`;
|
|
898
|
+
readonly blockTag: "latest";
|
|
899
|
+
}) => Promise<number>;
|
|
900
|
+
readonly getBalance: (p: {
|
|
901
|
+
readonly address: `0x${string}`;
|
|
902
|
+
}) => Promise<bigint>;
|
|
903
|
+
};
|
|
904
|
+
readonly solanaRpc: (network: string) => {
|
|
905
|
+
readonly call: (method: string, params: unknown[]) => Promise<unknown>;
|
|
906
|
+
};
|
|
907
|
+
readonly esplora: (network: string) => Esplora;
|
|
908
|
+
readonly enabled: (family: "evm" | "solana" | "bitcoin") => ReadonlyArray<string>;
|
|
909
|
+
};
|
|
290
910
|
type AccountTreeControllerOptions = {
|
|
291
911
|
readonly wallet: Wallet;
|
|
292
912
|
readonly spark: SparkController;
|
|
293
913
|
readonly sparkNetwork: SparkNetwork;
|
|
914
|
+
readonly networks?: DiscoveryNetworks;
|
|
915
|
+
readonly chains?: {
|
|
916
|
+
readonly account: (params: {
|
|
917
|
+
readonly walletId: string;
|
|
918
|
+
readonly groupIndex: number;
|
|
919
|
+
readonly template: string;
|
|
920
|
+
readonly network: string;
|
|
921
|
+
}) => Promise<{
|
|
922
|
+
readonly address?: string;
|
|
923
|
+
readonly xpub?: string;
|
|
924
|
+
}>;
|
|
925
|
+
};
|
|
294
926
|
readonly logger: EngineLogger;
|
|
295
927
|
readonly now: () => number;
|
|
296
928
|
};
|
|
297
|
-
/**
|
|
298
|
-
* Declarative account tree: wallets come from the Wallet snapshot (reconciled on unlock and on
|
|
299
|
-
* every snapshot change while unlocked), groups/names/hidden/selected/totals persist to the engine
|
|
300
|
-
* store under `accounts/tree`. The controller drives `spark.setAccounts` with the selected group
|
|
301
|
-
* only — an unselected group needs no live client (incoming transfers are claimed whenever it is
|
|
302
|
-
* selected again). The active account's `balanceSats` feeds `totals`, debounced 1 s before
|
|
303
|
-
* persist.
|
|
304
|
-
*/
|
|
305
929
|
export declare class AccountTreeController extends Controller<AccountTreeState> {
|
|
306
930
|
private readonly options;
|
|
307
931
|
private col;
|
|
@@ -338,19 +962,25 @@ export declare class AccountTreeController extends Controller<AccountTreeState>
|
|
|
338
962
|
groupIndex: number;
|
|
339
963
|
} | undefined;
|
|
340
964
|
/** The wallet's metadata document — every group, hidden included. */
|
|
341
|
-
exportMeta(walletId: string):
|
|
965
|
+
exportMeta(walletId: string): MetaDocTree;
|
|
342
966
|
/**
|
|
343
967
|
* Entry-level last-writer-wins merge: a newer remote `updatedAt` replaces the local entry, a tie
|
|
344
968
|
* keeps local; remote-only groups are added. `selected`/hidden rules are re-validated — if the
|
|
345
969
|
* merge hides the selected group it is re-selected, and a merge may never leave every group
|
|
346
970
|
* hidden (the selected one stays visible and is re-stamped so the fix propagates).
|
|
347
971
|
*/
|
|
348
|
-
mergeMeta(walletId: string, doc:
|
|
972
|
+
mergeMeta(walletId: string, doc: MetaDocTree): {
|
|
349
973
|
changed: boolean;
|
|
350
974
|
localNewer: boolean;
|
|
351
975
|
};
|
|
352
976
|
/** Sequential inspect from 0 upward; index 0 always included; stop after 2 consecutive unused. */
|
|
353
977
|
discoverSpark(walletId: string): Promise<number[]>;
|
|
978
|
+
/**
|
|
979
|
+
* Per-group chain-family discovery — same stop rule as `discoverSpark`: group 0 always, stop
|
|
980
|
+
* after two consecutive fully-unused groups. A family error is reported on the group and does NOT
|
|
981
|
+
* count as unused (the group stays in `found` — it can't be proven empty).
|
|
982
|
+
*/
|
|
983
|
+
discoverGroups(walletId: string): Promise<number[]>;
|
|
354
984
|
/** Refresh `totals` for every other visible group; per-group failures are logged and skipped. */
|
|
355
985
|
refreshTotals(): Promise<void>;
|
|
356
986
|
private onSparkState;
|
|
@@ -370,6 +1000,62 @@ export declare class AccountTreeController extends Controller<AccountTreeState>
|
|
|
370
1000
|
private flushTotals;
|
|
371
1001
|
}
|
|
372
1002
|
//#endregion
|
|
1003
|
+
//#region src/assets/controller.d.ts
|
|
1004
|
+
type TokenBalance = {
|
|
1005
|
+
readonly address: string;
|
|
1006
|
+
readonly symbol: string;
|
|
1007
|
+
readonly decimals: number;
|
|
1008
|
+
readonly balance: string;
|
|
1009
|
+
/** False for user-added tokens until they appear in the built-in table. */
|
|
1010
|
+
readonly verified: boolean;
|
|
1011
|
+
};
|
|
1012
|
+
type AccountBalances = {
|
|
1013
|
+
readonly native: string;
|
|
1014
|
+
readonly tokens: ReadonlyArray<TokenBalance>;
|
|
1015
|
+
/** Bitcoin only — confirmed + own unconfirmed change; frozen 546/330-sat UTXOs shown apart. */
|
|
1016
|
+
readonly unconfirmed?: string;
|
|
1017
|
+
readonly frozen?: string;
|
|
1018
|
+
};
|
|
1019
|
+
type AssetsControllerState = {
|
|
1020
|
+
readonly balances: Record<string, AccountBalances>;
|
|
1021
|
+
};
|
|
1022
|
+
type Options = {
|
|
1023
|
+
readonly networks: NetworkController;
|
|
1024
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
1025
|
+
readonly setTimer: (ms: number, fn: () => unknown) => () => void;
|
|
1026
|
+
readonly logger: EngineLogger;
|
|
1027
|
+
};
|
|
1028
|
+
declare class AssetsController extends Controller<AssetsControllerState> {
|
|
1029
|
+
private readonly options;
|
|
1030
|
+
private engineStore;
|
|
1031
|
+
private readonly bitcoinUtxos;
|
|
1032
|
+
private visible;
|
|
1033
|
+
private cancelPoll;
|
|
1034
|
+
private readonly customTokens;
|
|
1035
|
+
constructor(options: Options);
|
|
1036
|
+
init(): Promise<void>;
|
|
1037
|
+
lock(): void;
|
|
1038
|
+
destroy(): Promise<void>;
|
|
1039
|
+
setVisible(visible: boolean): void;
|
|
1040
|
+
private armPoll;
|
|
1041
|
+
private refreshAll;
|
|
1042
|
+
refresh(address: string, network: string): Promise<void>;
|
|
1043
|
+
/** SOL via getBalance; SPL via getTokenAccountsByOwner (jsonParsed) for known mints. */
|
|
1044
|
+
private refreshSolana;
|
|
1045
|
+
private readTokens;
|
|
1046
|
+
private balanceOfBatch;
|
|
1047
|
+
private balanceOf;
|
|
1048
|
+
private callString;
|
|
1049
|
+
private callNumber;
|
|
1050
|
+
/** Reads symbol/decimals on-chain, marks unverified, persists; throws when the calls fail. */
|
|
1051
|
+
addToken(network: string, address: string): Promise<void>;
|
|
1052
|
+
private persistToken;
|
|
1053
|
+
private rpc;
|
|
1054
|
+
private rpcHex;
|
|
1055
|
+
/** BTC balance = confirmed spendable + own unconfirmed change; frozen 546/330 shown separately. */
|
|
1056
|
+
refreshBitcoin(xpub: string, network: string): Promise<void>;
|
|
1057
|
+
}
|
|
1058
|
+
//#endregion
|
|
373
1059
|
//#region src/backup/errors.d.ts
|
|
374
1060
|
/** BackupController error categories — never carry file contents, digests or secrets. */
|
|
375
1061
|
type BackupErrorCategory = "cloud" | "conflict" | "unavailable";
|
|
@@ -493,9 +1179,21 @@ type MetaSyncWalletStatus = {
|
|
|
493
1179
|
type MetaSyncState = {
|
|
494
1180
|
readonly wallets: Readonly<Record<string, MetaSyncWalletStatus>>;
|
|
495
1181
|
};
|
|
1182
|
+
/** What the sync needs from the address book: its records, a merge, and a change subscription. */
|
|
1183
|
+
type AddressBookSync = {
|
|
1184
|
+
readonly syncEntries: () => ReadonlyArray<AddressBookRecord>;
|
|
1185
|
+
readonly merge: (remote: ReadonlyArray<AddressBookRecord>) => Promise<{
|
|
1186
|
+
readonly changed: boolean;
|
|
1187
|
+
readonly localNewer: boolean;
|
|
1188
|
+
}>;
|
|
1189
|
+
readonly store: {
|
|
1190
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
1191
|
+
};
|
|
1192
|
+
};
|
|
496
1193
|
type MetaSyncControllerOptions = {
|
|
497
1194
|
readonly wallet: Wallet;
|
|
498
1195
|
readonly accounts: AccountTreeController;
|
|
1196
|
+
readonly addressBook: AddressBookSync;
|
|
499
1197
|
/** `nostr(wallet)` — the signer is requested per wallet for its group-0 derived key. */
|
|
500
1198
|
readonly nostr: {
|
|
501
1199
|
readonly signer: (ref: NostrKeyRef) => WalletSigner;
|
|
@@ -519,6 +1217,7 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
|
|
|
519
1217
|
private readonly timers;
|
|
520
1218
|
private readonly inflight;
|
|
521
1219
|
private accountsUnsubscribe;
|
|
1220
|
+
private addressBookUnsubscribe;
|
|
522
1221
|
constructor(options: MetaSyncControllerOptions);
|
|
523
1222
|
/** Unlocked: pull every wallet whose group-0 identity exists, then watch the tree. */
|
|
524
1223
|
init(): Promise<void>;
|
|
@@ -534,6 +1233,8 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
|
|
|
534
1233
|
private signerFor;
|
|
535
1234
|
private setStatus;
|
|
536
1235
|
private pullOne;
|
|
1236
|
+
/** The wallet's tree plus the shared address book — every wallet's document carries both. */
|
|
1237
|
+
private exportDoc;
|
|
537
1238
|
private filterFor;
|
|
538
1239
|
private acceptableEvent;
|
|
539
1240
|
/** Snapshot the wallet's exported doc — the debounce publishes only on a real change. */
|
|
@@ -542,140 +1243,6 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
|
|
|
542
1243
|
private publishNow;
|
|
543
1244
|
}
|
|
544
1245
|
//#endregion
|
|
545
|
-
//#region src/payments/parse.d.ts
|
|
546
|
-
type PaymentOption = {
|
|
547
|
-
readonly kind: "spark";
|
|
548
|
-
readonly address: string;
|
|
549
|
-
} | {
|
|
550
|
-
readonly kind: "spark-invoice";
|
|
551
|
-
readonly invoice: string;
|
|
552
|
-
readonly amountSats?: number;
|
|
553
|
-
readonly memo?: string;
|
|
554
|
-
readonly expiresAt?: number;
|
|
555
|
-
} | {
|
|
556
|
-
readonly kind: "lightning";
|
|
557
|
-
readonly invoice: string;
|
|
558
|
-
readonly amountSats?: number;
|
|
559
|
-
readonly paymentHash: string;
|
|
560
|
-
readonly description?: string;
|
|
561
|
-
readonly expiresAt: number;
|
|
562
|
-
} | {
|
|
563
|
-
readonly kind: "lnurl-pay";
|
|
564
|
-
readonly request: LnurlPayRequest;
|
|
565
|
-
readonly address?: string;
|
|
566
|
-
} | {
|
|
567
|
-
readonly kind: "lnurl-withdraw";
|
|
568
|
-
readonly request: LnurlWithdrawRequest;
|
|
569
|
-
} | {
|
|
570
|
-
readonly kind: "bitcoin";
|
|
571
|
-
readonly address: string;
|
|
572
|
-
};
|
|
573
|
-
type PaymentRequest = {
|
|
574
|
-
readonly options: ReadonlyArray<PaymentOption>;
|
|
575
|
-
readonly amountSats?: number;
|
|
576
|
-
readonly label?: string;
|
|
577
|
-
readonly message?: string;
|
|
578
|
-
};
|
|
579
|
-
type PaymentParse = {
|
|
580
|
-
readonly kind: "request";
|
|
581
|
-
readonly request: PaymentRequest;
|
|
582
|
-
} | {
|
|
583
|
-
readonly kind: "lnurl";
|
|
584
|
-
readonly url: string;
|
|
585
|
-
readonly address?: string;
|
|
586
|
-
} | {
|
|
587
|
-
readonly kind: "unsupported";
|
|
588
|
-
readonly format: "bolt12" | "silent-payment" | "lnurl-auth" | "spark-token-invoice" | "nostr-wallet-connect";
|
|
589
|
-
} | {
|
|
590
|
-
readonly kind: "invalid";
|
|
591
|
-
readonly reason: "network" | "expired" | "amount-mismatch" | "malformed";
|
|
592
|
-
} | {
|
|
593
|
-
readonly kind: "unrecognized";
|
|
594
|
-
};
|
|
595
|
-
type ParseOptions = {
|
|
596
|
-
readonly network: SparkNetwork;
|
|
597
|
-
readonly now: number;
|
|
598
|
-
};
|
|
599
|
-
/** `input` → PaymentParse. Never throws: every failure is a structured result. */
|
|
600
|
-
export declare function parsePayment(input: string, options: ParseOptions): PaymentParse;
|
|
601
|
-
//#endregion
|
|
602
|
-
//#region src/payments/pay.d.ts
|
|
603
|
-
type PayParams = {
|
|
604
|
-
readonly account: SparkAccountRef;
|
|
605
|
-
readonly option: PaymentOption;
|
|
606
|
-
/** Caller-supplied amount — required by open invoices, the `spark` option, and LNURL flows. */
|
|
607
|
-
readonly amountSats?: number;
|
|
608
|
-
readonly comment?: string;
|
|
609
|
-
readonly maxFeeSats?: number;
|
|
610
|
-
readonly speed?: "FAST" | "MEDIUM" | "SLOW";
|
|
611
|
-
readonly verify: UnlockFactor;
|
|
612
|
-
};
|
|
613
|
-
type PayResult = {
|
|
614
|
-
readonly kind: "spark";
|
|
615
|
-
readonly transfer: SparkTransfer;
|
|
616
|
-
} | {
|
|
617
|
-
readonly kind: "lightning";
|
|
618
|
-
readonly payment: LightningPayment;
|
|
619
|
-
} | {
|
|
620
|
-
readonly kind: "withdraw";
|
|
621
|
-
readonly exit: CooperativeExitResult;
|
|
622
|
-
} | {
|
|
623
|
-
readonly kind: "lnurl-withdraw";
|
|
624
|
-
readonly invoice: LightningInvoice;
|
|
625
|
-
};
|
|
626
|
-
//#endregion
|
|
627
|
-
//#region src/payments/zap.d.ts
|
|
628
|
-
/** A profile zap names the recipient pubkey; an event zap carries the event it zaps. */
|
|
629
|
-
type ZapRecipient = {
|
|
630
|
-
readonly pubkey: string;
|
|
631
|
-
readonly lightning: string;
|
|
632
|
-
} | {
|
|
633
|
-
readonly event: Event;
|
|
634
|
-
readonly lightning: string;
|
|
635
|
-
};
|
|
636
|
-
type PrepareZapParams = {
|
|
637
|
-
/** Any `NostrSigner` — wallet key, external key, NIP-07/46 — signs the 9734. */
|
|
638
|
-
readonly signer: NostrSigner;
|
|
639
|
-
readonly recipient: ZapRecipient;
|
|
640
|
-
readonly amountSats: number;
|
|
641
|
-
readonly comment?: string | undefined;
|
|
642
|
-
readonly relays: ReadonlyArray<string>;
|
|
643
|
-
readonly network: SparkNetwork;
|
|
644
|
-
};
|
|
645
|
-
type PrepareZapContext = {
|
|
646
|
-
readonly fetch: typeof globalThis.fetch;
|
|
647
|
-
readonly now: () => number;
|
|
648
|
-
};
|
|
649
|
-
/** Everything a payer needs: the signed 9734, the invoice, and the note fields. */
|
|
650
|
-
type PreparedZap = {
|
|
651
|
-
readonly zapRequest: Event;
|
|
652
|
-
readonly invoice: string;
|
|
653
|
-
/** Hex payment hash decoded from the invoice. */
|
|
654
|
-
readonly paymentHash: string;
|
|
655
|
-
/** Millisecond expiry decoded from the invoice. */
|
|
656
|
-
readonly expiresAt: number;
|
|
657
|
-
readonly amountSats: number;
|
|
658
|
-
/** The LNURL service's 9735 signing pubkey. */
|
|
659
|
-
readonly receiptPubkey: string;
|
|
660
|
-
readonly recipientPubkey: string;
|
|
661
|
-
readonly eventId?: string;
|
|
662
|
-
readonly comment?: string;
|
|
663
|
-
/** The lud16 or LNURL as given. */
|
|
664
|
-
readonly lightning: string;
|
|
665
|
-
};
|
|
666
|
-
type PayZapOptions = {
|
|
667
|
-
readonly maxFeeSats: number;
|
|
668
|
-
readonly verify: UnlockFactor;
|
|
669
|
-
readonly now: () => number;
|
|
670
|
-
};
|
|
671
|
-
/** Everything up to payment: resolve LNURL, sign the 9734, request the invoice. */
|
|
672
|
-
export declare function prepareZap(params: PrepareZapParams, context: PrepareZapContext): Promise<PreparedZap>;
|
|
673
|
-
/**
|
|
674
|
-
* Pays a prepared zap through the controller's approve-first path. A nearly-expired invoice is
|
|
675
|
-
* rejected before approval — the user may have sat on the confirm screen since `prepareZap`.
|
|
676
|
-
*/
|
|
677
|
-
export declare function payZap(spark: SparkController, account: SparkAccountRef, prepared: PreparedZap, options: PayZapOptions): Promise<LightningPayment>;
|
|
678
|
-
//#endregion
|
|
679
1246
|
//#region src/engine.d.ts
|
|
680
1247
|
type EngineOptions = {
|
|
681
1248
|
readonly wallet: Wallet;
|
|
@@ -688,24 +1255,48 @@ type EngineOptions = {
|
|
|
688
1255
|
readonly openStore: () => Promise<EngineStore>;
|
|
689
1256
|
/** Cloud file transport for the backup controller; absent → `unavailable`. */
|
|
690
1257
|
readonly cloud?: CloudStore;
|
|
1258
|
+
/**
|
|
1259
|
+
* Host endpoints per network (CAIP-2), ordered by preference, for all three chain families: EVM
|
|
1260
|
+
* and Solana JSON-RPC URLs, and for Bitcoin the Esplora base URL.
|
|
1261
|
+
*/
|
|
1262
|
+
readonly rpc?: Readonly<Record<string, ReadonlyArray<string>>>;
|
|
1263
|
+
/**
|
|
1264
|
+
* The wallet gateway: tried first for the networks it serves (read at each unlock) unless a
|
|
1265
|
+
* network has custom endpoints. The install id is sent only to the gateway's origin.
|
|
1266
|
+
*/
|
|
1267
|
+
readonly gateway?: {
|
|
1268
|
+
readonly url: string;
|
|
1269
|
+
readonly installId: string;
|
|
1270
|
+
};
|
|
1271
|
+
/** Injected timer for transaction polling; defaults to setTimeout. */
|
|
1272
|
+
readonly setTimer?: (ms: number, fn: () => void) => () => void;
|
|
691
1273
|
/** Kind-30078 wallet-metadata sync; absent → every wallet reports `unavailable`. */
|
|
692
1274
|
readonly metaSync?: MetaSyncConfig;
|
|
693
1275
|
/** Test seam — defaults to the wallet's real spark proxy. */
|
|
694
1276
|
readonly sparkApis?: SparkControllerOptions["spark"];
|
|
695
1277
|
};
|
|
696
1278
|
type WalletEngine = {
|
|
697
|
-
readonly
|
|
1279
|
+
readonly networks: NetworkController;
|
|
1280
|
+
readonly assets: AssetsController;
|
|
1281
|
+
readonly transactions: TransactionController;
|
|
1282
|
+
readonly requests: RequestController;
|
|
1283
|
+
readonly addressBook: AddressBookController;
|
|
1284
|
+
/** Read and receive surface; every payment goes through `requests`. */
|
|
1285
|
+
readonly spark: Omit<SparkController, "send" | "payInvoice" | "paySparkInvoice" | "withdraw">;
|
|
698
1286
|
readonly accounts: AccountTreeController;
|
|
699
1287
|
readonly metaSync: MetaSyncController;
|
|
700
1288
|
readonly backup: BackupController;
|
|
701
1289
|
readonly zaps: {
|
|
702
1290
|
readonly prepare: (params: PrepareZapParams) => Promise<PreparedZap>;
|
|
703
|
-
readonly pay: (account: SparkAccountRef, prepared: PreparedZap, options: Omit<PayZapOptions, "now">) => Promise<LightningPayment>;
|
|
704
1291
|
};
|
|
705
1292
|
readonly payments: {
|
|
706
1293
|
readonly parse: (input: string, network: SparkNetwork) => PaymentParse;
|
|
707
1294
|
readonly resolve: (input: string, network: SparkNetwork) => Promise<PaymentParse>;
|
|
708
|
-
|
|
1295
|
+
/** Receives funds from an LNURL-withdraw service; needs no verification factor. */
|
|
1296
|
+
readonly withdrawLnurl: (params: WithdrawLnurlParams) => Promise<{
|
|
1297
|
+
readonly kind: "lnurl-withdraw";
|
|
1298
|
+
readonly invoice: LightningInvoice;
|
|
1299
|
+
}>;
|
|
709
1300
|
};
|
|
710
1301
|
readonly unsubscribe: () => void;
|
|
711
1302
|
};
|
|
@@ -754,5 +1345,5 @@ export declare function resolvePayment(input: string, options: ResolveOptions):
|
|
|
754
1345
|
export declare function encodeExitChain(chain: SparkExitChain): Uint8Array;
|
|
755
1346
|
export declare function decodeExitChain(bytes: Uint8Array): SparkExitChain;
|
|
756
1347
|
//#endregion
|
|
757
|
-
export type { AccountGroup, AccountTreeState, BackupControllerState, BackupErrorCategory, CloudStore, ControllerOptions, EngineCollection, EngineErrorCode, EngineLogger, EngineOptions, EngineStore, EventBus, MetaDoc, MetaDocGroup, MetaDocWallet, MetaSyncConfig, MetaSyncRelayPort, MetaSyncState, MetaSyncWalletStatus,
|
|
1348
|
+
export type { AccountGroup, AccountTreeState, AddressBookEntry, AddressBookErrorCategory, AddressBookState, AddressFamily, BackupControllerState, BackupErrorCategory, CloudStore, ControllerOptions, EngineCollection, EngineErrorCode, EngineLogger, EngineOptions, EngineStore, EventBus, MetaDoc, MetaDocGroup, MetaDocTree, MetaDocWallet, MetaSyncConfig, MetaSyncRelayPort, MetaSyncState, MetaSyncWalletStatus, PayInput, PayParams, PaymentNote, PaymentOption, PaymentParse, PaymentRequest, PendingRequest, PrepareZapContext, PrepareZapParams, PreparedSparkAction, PreparedZap, RequestCheckCode, RequestControllerState, RequestInput, RequestMethod, RequestStage, RiskFinding, SignLogEntry, SignLogOutcome, SparkAccountState, SparkActivity, SparkClientFactory, SparkControllerOptions, SparkControllerState, SparkDisplay, SparkErrorCategory, SparkResult, WalletEngine, WithdrawLnurlParams, ZapRecipient };
|
|
758
1349
|
//# sourceMappingURL=index.d.mts.map
|