@qntx/wallet-engine 0.5.2 → 0.7.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/README.md +21 -0
- package/dist/contract-CEsgLme3.mjs +277 -0
- package/dist/contract-CEsgLme3.mjs.map +1 -0
- package/dist/gateway-contract.d.mts +285 -0
- package/dist/gateway-contract.mjs +1 -0
- package/dist/idb.d.mts +0 -4
- package/dist/idb.mjs +3 -6
- package/dist/idb.mjs.map +1 -1
- package/dist/index.d.mts +976 -499
- package/dist/index.mjs +2971 -965
- package/dist/index.mjs.map +1 -1
- package/dist/registry-LcFSPrE1.d.mts +23 -0
- package/package.json +14 -8
package/dist/index.d.mts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
+
import { r as NetworkInfo } from "./registry-LcFSPrE1.mjs";
|
|
1
2
|
import { StoreApi } from "zustand/vanilla";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { SparkSigner } from "@qntx/wallet/spark";
|
|
5
|
-
import { PublicClient } from "viem";
|
|
6
|
-
import { chains } from "@qntx/wallet/chains";
|
|
3
|
+
import { SignRequest } from "@qntx/wallet-chains";
|
|
4
|
+
import { BackupHeader, BackupInfo, InitialFactor, UnlockFactor, Wallet, WalletInfo } from "@qntx/wallet";
|
|
7
5
|
import "@scure/btc-signer";
|
|
6
|
+
import { CooperativeExitResult, LightningInvoice, LightningPayment, SparkClient, SparkExitChain, SparkNetwork, SparkPayment, SparkStore, SparkTransfer } from "@qntx/spark";
|
|
8
7
|
import { decodeEvm } from "@qntx/wallet-chains/evm";
|
|
9
|
-
import { BackupHeader, BackupInfo, InitialFactor, UnlockFactor, Wallet, WalletInfo } from "@qntx/wallet";
|
|
10
|
-
import { Event, Filter, NostrSigner } from "@qntx/nostr";
|
|
11
8
|
import { LnurlPayRequest, LnurlWithdrawRequest } from "@qntx/spark/lnurl";
|
|
9
|
+
import { Event, Filter, NostrSigner } from "@qntx/nostr";
|
|
10
|
+
import { chains } from "@qntx/wallet/chains";
|
|
11
|
+
import { WalletSyncSigner } from "@qntx/wallet/nostr";
|
|
12
|
+
import { SparkSigner } from "@qntx/wallet/spark";
|
|
13
|
+
import { PublicClient } from "viem";
|
|
12
14
|
import "@solana/kit";
|
|
13
|
-
import { SparkAccountRef, SparkApproveIntent } from "@qntx/wallet/protocol";
|
|
14
15
|
import "@scure/btc-signer/psbt.js";
|
|
15
|
-
import "@qntx/wallet
|
|
16
|
-
//#region src/controller.d.ts
|
|
16
|
+
import { SparkAccountRef, SparkApproveIntent } from "@qntx/wallet/protocol";
|
|
17
17
|
type ControllerOptions<S> = {
|
|
18
18
|
readonly name: string;
|
|
19
19
|
readonly defaultState: () => S;
|
|
@@ -32,8 +32,6 @@ export declare abstract class Controller<S extends Record<string, unknown>> {
|
|
|
32
32
|
abstract init(): Promise<void>;
|
|
33
33
|
abstract destroy(): Promise<void>;
|
|
34
34
|
}
|
|
35
|
-
//#endregion
|
|
36
|
-
//#region src/events.d.ts
|
|
37
35
|
/** Log port: listener failures are reported here and never reach the emitter or peers. */
|
|
38
36
|
type EngineLogger = {
|
|
39
37
|
readonly warn: (message: string, error?: unknown) => void;
|
|
@@ -44,16 +42,12 @@ type EventBus<E> = {
|
|
|
44
42
|
on: <K extends keyof E>(type: K, listener: (payload: E[K]) => void) => () => void;
|
|
45
43
|
};
|
|
46
44
|
export declare function createEventBus<E>(logger: EngineLogger): EventBus<E>;
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/errors.d.ts
|
|
49
45
|
type EngineErrorCode = "closed" | "integrity" | "invalid-input";
|
|
50
46
|
/** Typed engine errors: store codes are `closed` and `integrity` (decrypt or bind failure). */
|
|
51
47
|
export declare class EngineStoreError extends Error {
|
|
52
48
|
readonly code: EngineErrorCode;
|
|
53
49
|
constructor(code: EngineErrorCode, message: string);
|
|
54
50
|
}
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region src/store/port.d.ts
|
|
57
51
|
/**
|
|
58
52
|
* Engine storage port: named collections of byte values. `collection` is synchronous and cheap —
|
|
59
53
|
* the same collection object backs every call, so guards (closed) live on the store.
|
|
@@ -69,42 +63,247 @@ type EngineStore = {
|
|
|
69
63
|
readonly collection: (name: string) => EngineCollection;
|
|
70
64
|
readonly close: () => Promise<void>;
|
|
71
65
|
};
|
|
72
|
-
//#endregion
|
|
73
|
-
//#region src/store/memory.d.ts
|
|
74
66
|
/** In-memory EngineStore: the Node/test implementation — same contract, no durability. */
|
|
75
67
|
export declare function createMemoryEngineStore(backing?: {
|
|
76
68
|
readonly collections?: Map<string, Map<string, Uint8Array>>;
|
|
77
69
|
}): EngineStore;
|
|
78
|
-
|
|
79
|
-
|
|
70
|
+
type ConnectionOrigin = {
|
|
71
|
+
readonly kind: "browser";
|
|
72
|
+
readonly origin: string;
|
|
73
|
+
};
|
|
74
|
+
type ConnectionScope = {
|
|
75
|
+
/** CAIP-10 */
|
|
76
|
+
readonly accounts: ReadonlyArray<string>;
|
|
77
|
+
readonly methods: ReadonlyArray<string>;
|
|
78
|
+
readonly notifications: ReadonlyArray<string>;
|
|
79
|
+
};
|
|
80
|
+
type ConnectionSession = {
|
|
81
|
+
readonly id: string;
|
|
82
|
+
readonly origin: ConnectionOrigin;
|
|
83
|
+
/** Keyed by CAIP-2. */
|
|
84
|
+
readonly scopes: Readonly<Record<string, ConnectionScope>>;
|
|
85
|
+
/** The session's current EVM network; only dApp sessions have one. */
|
|
86
|
+
readonly currentNetwork: string;
|
|
87
|
+
readonly createdAt: number;
|
|
88
|
+
readonly lastUsedAt: number;
|
|
89
|
+
};
|
|
90
|
+
/** `connect` asks for accounts; `network` asks to add a network the session does not cover. */
|
|
91
|
+
type PendingConnection = {
|
|
92
|
+
readonly id: string;
|
|
93
|
+
readonly origin: ConnectionOrigin;
|
|
94
|
+
readonly kind: "connect" | "network";
|
|
95
|
+
readonly network?: string;
|
|
96
|
+
readonly createdAt: number;
|
|
97
|
+
};
|
|
98
|
+
type AccountGroup$1 = {
|
|
99
|
+
readonly walletId: string;
|
|
100
|
+
readonly groupIndex: number;
|
|
101
|
+
};
|
|
102
|
+
type ConnectionState = {
|
|
103
|
+
readonly sessions: Readonly<Record<string, ConnectionSession>>;
|
|
104
|
+
readonly pending: Readonly<Record<string, PendingConnection>>;
|
|
105
|
+
};
|
|
106
|
+
type ConnectionControllerOptions = {
|
|
107
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
108
|
+
readonly random: (n: number) => Uint8Array;
|
|
109
|
+
readonly now: () => number;
|
|
110
|
+
readonly logger: EngineLogger;
|
|
111
|
+
/** Development builds also accept `http://localhost`. */
|
|
112
|
+
readonly allowLocalhost: boolean;
|
|
113
|
+
/** The group the app currently shows; sessions are bound to it. */
|
|
114
|
+
readonly selectedGroup: () => AccountGroup$1 | undefined;
|
|
115
|
+
/** The group's EVM address on `network`. */
|
|
116
|
+
readonly evmAddress: (group: AccountGroup$1, network: string) => Promise<string>;
|
|
117
|
+
readonly enabledNetworks: () => ReadonlyArray<string>;
|
|
118
|
+
/** Voids a page's unfinished requests (revoked, or its network changed). */
|
|
119
|
+
readonly invalidate: (origin: string) => void;
|
|
120
|
+
};
|
|
121
|
+
export declare class ConnectionController extends Controller<ConnectionState> {
|
|
122
|
+
private readonly options;
|
|
123
|
+
private engineStore;
|
|
124
|
+
private readonly waiters;
|
|
125
|
+
private group;
|
|
126
|
+
constructor(options: ConnectionControllerOptions);
|
|
127
|
+
init(): Promise<void>;
|
|
128
|
+
destroy(): Promise<void>;
|
|
129
|
+
/** Locking is not consent: every pending connection is rejected. */
|
|
130
|
+
lock(): void;
|
|
131
|
+
/** Throws `4100` unless `origin` is `https://host[:port]` (or localhost in development). */
|
|
132
|
+
checkOrigin(origin: string): ConnectionOrigin;
|
|
133
|
+
session(origin: string): ConnectionSession | undefined;
|
|
134
|
+
pending(): ReadonlyArray<PendingConnection>;
|
|
135
|
+
/** The group sessions are bound to: the host's last `setActiveGroup`, else the app's selection. */
|
|
136
|
+
activeGroup(): AccountGroup$1 | undefined;
|
|
137
|
+
/** Whether `network` is an EVM network the wallet has enabled. */
|
|
138
|
+
isEnabled(network: string): boolean;
|
|
139
|
+
/** The origin's authorized addresses on its current network; empty when not connected. */
|
|
140
|
+
accounts(origin: string): ReadonlyArray<string>;
|
|
141
|
+
/** Throws `4100` unless the origin's session covers `method` on `network`. */
|
|
142
|
+
authorize(origin: string, network: string, method: string): ConnectionSession;
|
|
143
|
+
/** Resolves with the session once the host approves; rejects with `4001` when it refuses. */
|
|
144
|
+
request(origin: string, kind: PendingConnection["kind"], network?: string): Promise<ConnectionSession>;
|
|
145
|
+
/**
|
|
146
|
+
* The host's approval, by id: the accounts granted (EVM addresses of the active group) and the
|
|
147
|
+
* network.
|
|
148
|
+
*/
|
|
149
|
+
approveConnection(id: string, grant: {
|
|
150
|
+
readonly accounts: ReadonlyArray<string>;
|
|
151
|
+
readonly network: string;
|
|
152
|
+
}): Promise<ConnectionSession>;
|
|
153
|
+
rejectConnection(id: string): void;
|
|
154
|
+
/** Ends the origin's session; its pending connection and unfinished requests are void. */
|
|
155
|
+
revoke(origin: string): Promise<void>;
|
|
156
|
+
/** Switches within the session's scope; the origin's unfinished requests are void. */
|
|
157
|
+
setCurrentNetwork(origin: string, network: string): Promise<void>;
|
|
158
|
+
touch(origin: string): Promise<void>;
|
|
159
|
+
/**
|
|
160
|
+
* The host switched account group: every session's accounts become the new group's addresses. A
|
|
161
|
+
* session that cannot get one (no address derivable) is left with an empty list and has to be
|
|
162
|
+
* authorized again.
|
|
163
|
+
*/
|
|
164
|
+
setActiveGroup(walletId: string, groupIndex: number): Promise<void>;
|
|
165
|
+
private dropPending;
|
|
166
|
+
private persist;
|
|
167
|
+
private requireStore;
|
|
168
|
+
}
|
|
80
169
|
type Esplora = {
|
|
81
170
|
readonly get: (path: string) => Promise<unknown>;
|
|
82
171
|
readonly post: (path: string, body: string) => Promise<unknown>;
|
|
83
172
|
};
|
|
84
|
-
|
|
85
|
-
|
|
173
|
+
type SolanaRpc = {
|
|
174
|
+
readonly call: (method: string, params: unknown[]) => Promise<unknown>;
|
|
175
|
+
};
|
|
86
176
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
177
|
+
* A host-endpoint-only client for cross-checking pre-signing reads. `not-needed`: the gateway is
|
|
178
|
+
* not this network's first endpoint, so the primary reads already come from the host.
|
|
179
|
+
* `unavailable`: a cross-check is needed but the network has no host endpoint.
|
|
89
180
|
*/
|
|
90
|
-
type
|
|
91
|
-
readonly
|
|
181
|
+
type Independent<T> = {
|
|
182
|
+
readonly kind: "not-needed";
|
|
183
|
+
} | {
|
|
184
|
+
readonly kind: "unavailable";
|
|
185
|
+
} | {
|
|
186
|
+
readonly kind: "available";
|
|
187
|
+
readonly client: T;
|
|
188
|
+
};
|
|
189
|
+
type NetworkControllerState = {
|
|
190
|
+
readonly customRpc: Record<string, ReadonlyArray<string>>;
|
|
191
|
+
};
|
|
192
|
+
type Options$2 = {
|
|
193
|
+
readonly fetch: typeof globalThis.fetch;
|
|
194
|
+
readonly rpc: Readonly<Record<string, ReadonlyArray<string>>>;
|
|
195
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
196
|
+
readonly logger: EngineLogger;
|
|
197
|
+
readonly gateway?: {
|
|
198
|
+
readonly url: string;
|
|
199
|
+
readonly installId: string;
|
|
200
|
+
} | undefined;
|
|
201
|
+
};
|
|
202
|
+
declare class NetworkController extends Controller<NetworkControllerState> {
|
|
203
|
+
private readonly options;
|
|
204
|
+
private engineStore?;
|
|
205
|
+
private readonly clients;
|
|
206
|
+
private readonly gatewayBase;
|
|
207
|
+
private readonly gatewayOrigin;
|
|
208
|
+
/** Networks the gateway reported at unlock; empty while locked or when the read failed. */
|
|
209
|
+
private gatewayServed;
|
|
210
|
+
constructor(options: Options$2);
|
|
211
|
+
init(): Promise<void>;
|
|
212
|
+
private loadCustomRpc;
|
|
213
|
+
/** Reads the gateway's served networks; any failure leaves the gateway unused until next unlock. */
|
|
214
|
+
private loadGatewayNetworks;
|
|
215
|
+
/** `fetch` that adds the install id to requests bound for the gateway's origin only. */
|
|
216
|
+
private readonly gatewayFetch;
|
|
217
|
+
destroy(): Promise<void>;
|
|
218
|
+
lock(): void;
|
|
219
|
+
/**
|
|
220
|
+
* Ordered endpoints: a network with custom endpoints uses custom → host and never the gateway;
|
|
221
|
+
* otherwise a gateway-served network uses gateway → host; else host only.
|
|
222
|
+
*/
|
|
223
|
+
endpoints(network: string): ReadonlyArray<string>;
|
|
224
|
+
info(network: string): NetworkInfo;
|
|
225
|
+
client(network: string): PublicClient;
|
|
226
|
+
/** True when the gateway heads this network's endpoint list (no custom endpoints, gateway-served). */
|
|
227
|
+
private gatewayFirst;
|
|
228
|
+
private independent;
|
|
229
|
+
/** Host-endpoint EVM client for cross-checking reads; never sends the install id. */
|
|
230
|
+
independentClient(network: string): Independent<PublicClient>;
|
|
231
|
+
independentSolanaRpc(network: string): Independent<SolanaRpc>;
|
|
232
|
+
independentEsplora(network: string): Independent<Esplora>;
|
|
233
|
+
/** Networks with at least one configured endpoint or served by the gateway, by family. */
|
|
234
|
+
enabled(family: "evm" | "solana" | "bitcoin"): ReadonlyArray<string>;
|
|
235
|
+
/** Solana JSON-RPC over the ordered endpoint list — kit's transport is single-endpoint. */
|
|
236
|
+
solanaRpc(network: string): SolanaRpc;
|
|
237
|
+
/** Bounded-concurrency + 429-aware ordered-failover Esplora client. */
|
|
238
|
+
esplora(network: string): Esplora;
|
|
239
|
+
/** Validate a custom endpoint's reported chain id, then persist it first in the list. */
|
|
240
|
+
addRpc(network: string, url: string): Promise<void>;
|
|
241
|
+
}
|
|
242
|
+
type AddressFamily = "evm" | "solana" | "bitcoin" | "spark";
|
|
243
|
+
type AddressBookEntry = {
|
|
244
|
+
readonly id: string;
|
|
245
|
+
readonly name: string;
|
|
246
|
+
readonly family: AddressFamily;
|
|
247
|
+
readonly address: string;
|
|
248
|
+
readonly note?: string;
|
|
249
|
+
readonly createdAt: number;
|
|
92
250
|
readonly updatedAt: number;
|
|
93
251
|
};
|
|
94
|
-
type
|
|
95
|
-
readonly
|
|
96
|
-
readonly
|
|
97
|
-
readonly hidden: boolean;
|
|
98
|
-
readonly boundPubkey?: string;
|
|
252
|
+
type AddressBookTombstone = {
|
|
253
|
+
readonly id: string;
|
|
254
|
+
readonly deleted: true;
|
|
99
255
|
readonly updatedAt: number;
|
|
100
256
|
};
|
|
101
|
-
type
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
readonly
|
|
257
|
+
type AddressBookRecord = AddressBookEntry | AddressBookTombstone;
|
|
258
|
+
type AddressBookState = {
|
|
259
|
+
/** Live entries only; tombstones stay internal. */
|
|
260
|
+
readonly entries: Record<string, AddressBookEntry>;
|
|
261
|
+
};
|
|
262
|
+
type AddressBookOptions = {
|
|
263
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
264
|
+
readonly random: (n: number) => Uint8Array;
|
|
265
|
+
readonly now: () => number;
|
|
266
|
+
readonly logger: EngineLogger;
|
|
105
267
|
};
|
|
106
|
-
|
|
107
|
-
|
|
268
|
+
export declare class AddressBookController extends Controller<AddressBookState> {
|
|
269
|
+
private readonly options;
|
|
270
|
+
private engineStore;
|
|
271
|
+
/** Every record, tombstones included, by id. */
|
|
272
|
+
private records;
|
|
273
|
+
constructor(options: AddressBookOptions);
|
|
274
|
+
init(): Promise<void>;
|
|
275
|
+
destroy(): Promise<void>;
|
|
276
|
+
lock(): void;
|
|
277
|
+
/** Entries and tombstones, for the metadata document. */
|
|
278
|
+
syncEntries(): ReadonlyArray<AddressBookRecord>;
|
|
279
|
+
/**
|
|
280
|
+
* Merges records from another device (last writer wins, tombstones win over older entries).
|
|
281
|
+
* Returns whether anything local changed and whether the merged set holds something `remote`
|
|
282
|
+
* lacks, i.e. whether the remote copy needs a newer publish.
|
|
283
|
+
*/
|
|
284
|
+
merge(remote: ReadonlyArray<AddressBookRecord>): Promise<{
|
|
285
|
+
readonly changed: boolean;
|
|
286
|
+
readonly localNewer: boolean;
|
|
287
|
+
}>;
|
|
288
|
+
add(params: {
|
|
289
|
+
readonly name: string;
|
|
290
|
+
readonly family: AddressFamily;
|
|
291
|
+
readonly address: string;
|
|
292
|
+
readonly note?: string;
|
|
293
|
+
}): Promise<AddressBookEntry>;
|
|
294
|
+
rename(id: string, name: string): Promise<AddressBookEntry>;
|
|
295
|
+
/** Sets or clears (empty or `undefined`) the note. */
|
|
296
|
+
setNote(id: string, note: string | undefined): Promise<AddressBookEntry>;
|
|
297
|
+
/** Removes the entry, leaving a tombstone so other devices drop it too. */
|
|
298
|
+
remove(id: string): Promise<void>;
|
|
299
|
+
private checkedNote;
|
|
300
|
+
private requireEntry;
|
|
301
|
+
private persist;
|
|
302
|
+
private requireStore;
|
|
303
|
+
}
|
|
304
|
+
type EvmFeeTier = "slow" | "normal" | "fast";
|
|
305
|
+
type SolanaFeeTier = "slow" | "normal" | "fast";
|
|
306
|
+
type RequestCheckCode = "decode-partial" | "nonce-mismatch" | "fee-mismatch" | "reads-unverified" | "fee-above-network" | "fee-exceeds-amount";
|
|
108
307
|
/**
|
|
109
308
|
* Local, engine-side metadata pinned to a history entry by transfer id. Written after the payment
|
|
110
309
|
* it annotates has already succeeded — a missing or malformed note must never affect the payment
|
|
@@ -124,15 +323,11 @@ type PaymentNote = {
|
|
|
124
323
|
type SparkActivity = SparkPayment & {
|
|
125
324
|
readonly note?: PaymentNote;
|
|
126
325
|
};
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/spark/store.d.ts
|
|
129
326
|
/**
|
|
130
327
|
* SparkStore over one EngineCollection: chains keyed by leafId, plus an index record listing them
|
|
131
328
|
* (`exitChains` is a full listing — the port has no secondary index).
|
|
132
329
|
*/
|
|
133
330
|
export declare function sparkStore(col: EngineCollection): SparkStore;
|
|
134
|
-
//#endregion
|
|
135
|
-
//#region src/spark/controller.d.ts
|
|
136
331
|
type SparkAccountState = {
|
|
137
332
|
readonly status: "locked" | "connecting" | "ready" | "error";
|
|
138
333
|
readonly balanceSats?: number;
|
|
@@ -260,6 +455,10 @@ export declare class SparkController extends Controller<SparkControllerState> {
|
|
|
260
455
|
amountSats: number;
|
|
261
456
|
memo?: string;
|
|
262
457
|
}): Promise<LightningInvoice>;
|
|
458
|
+
/** A fresh single-use L1 deposit address (with the SO's proof of possession). */
|
|
459
|
+
newDepositAddress(ref: SparkAccountRef): Promise<string>;
|
|
460
|
+
/** Claims a confirmed L1 deposit paying one of the account's unused deposit addresses. */
|
|
461
|
+
claimDeposit(ref: SparkAccountRef, transaction: Uint8Array): Promise<void>;
|
|
263
462
|
receiveAddress(ref: SparkAccountRef): Promise<string | undefined>;
|
|
264
463
|
/**
|
|
265
464
|
* Cooperative exit to an L1 address. The client exits `amountSats` of leaves and the payout is
|
|
@@ -274,198 +473,707 @@ export declare class SparkController extends Controller<SparkControllerState> {
|
|
|
274
473
|
verify: UnlockFactor;
|
|
275
474
|
}): Promise<CooperativeExitResult>;
|
|
276
475
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
readonly
|
|
284
|
-
readonly
|
|
285
|
-
readonly
|
|
286
|
-
readonly
|
|
287
|
-
/**
|
|
288
|
-
readonly
|
|
289
|
-
/**
|
|
290
|
-
readonly
|
|
291
|
-
};
|
|
292
|
-
type AccountTreeState = {
|
|
293
|
-
readonly status: "locked" | "ready";
|
|
294
|
-
readonly wallets: ReadonlyArray<{
|
|
295
|
-
readonly walletId: string;
|
|
296
|
-
readonly name?: string;
|
|
297
|
-
readonly updatedAt: number;
|
|
298
|
-
}>;
|
|
299
|
-
readonly groups: Readonly<Record<string, ReadonlyArray<AccountGroup>>>;
|
|
300
|
-
readonly selected: {
|
|
301
|
-
readonly walletId: string;
|
|
302
|
-
readonly groupIndex: number;
|
|
303
|
-
} | null;
|
|
304
|
-
readonly totals: Readonly<Record<string, number>>;
|
|
305
|
-
};
|
|
306
|
-
type DiscoveryNetworks = {
|
|
307
|
-
readonly client: (network: string) => {
|
|
308
|
-
readonly getTransactionCount: (p: {
|
|
309
|
-
readonly address: `0x${string}`;
|
|
310
|
-
readonly blockTag: "latest";
|
|
311
|
-
}) => Promise<number>;
|
|
312
|
-
readonly getBalance: (p: {
|
|
313
|
-
readonly address: `0x${string}`;
|
|
314
|
-
}) => Promise<bigint>;
|
|
315
|
-
};
|
|
316
|
-
readonly solanaRpc: (network: string) => {
|
|
317
|
-
readonly call: (method: string, params: unknown[]) => Promise<unknown>;
|
|
318
|
-
};
|
|
319
|
-
readonly esplora: (network: string) => Esplora;
|
|
320
|
-
readonly enabled: (family: "evm" | "solana" | "bitcoin") => ReadonlyArray<string>;
|
|
476
|
+
/**
|
|
477
|
+
* What the host shows for a Spark, Lightning or exit request; `family` tells it apart from a chain
|
|
478
|
+
* intent.
|
|
479
|
+
*/
|
|
480
|
+
type SparkDisplay = {
|
|
481
|
+
readonly family: "spark";
|
|
482
|
+
readonly network: SparkNetwork;
|
|
483
|
+
readonly kind: "transfer" | "lightning" | "exit";
|
|
484
|
+
readonly amountSats: number;
|
|
485
|
+
readonly maxFeeSats?: number;
|
|
486
|
+
/** Spark address, Lightning payee public key (hex) or bitcoin address. */
|
|
487
|
+
readonly receiver: string;
|
|
488
|
+
/** Invoice description or the LNURL metadata text. */
|
|
489
|
+
readonly description?: string;
|
|
321
490
|
};
|
|
322
|
-
type
|
|
323
|
-
readonly
|
|
324
|
-
readonly
|
|
325
|
-
|
|
326
|
-
readonly
|
|
327
|
-
readonly
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
readonly template: string;
|
|
332
|
-
readonly network: string;
|
|
333
|
-
}) => Promise<{
|
|
334
|
-
readonly address?: string;
|
|
335
|
-
readonly xpub?: string;
|
|
336
|
-
}>;
|
|
337
|
-
};
|
|
338
|
-
readonly logger: EngineLogger;
|
|
339
|
-
readonly now: () => number;
|
|
491
|
+
type SparkResult = {
|
|
492
|
+
readonly kind: "spark";
|
|
493
|
+
readonly transfer: SparkTransfer;
|
|
494
|
+
} | {
|
|
495
|
+
readonly kind: "lightning";
|
|
496
|
+
readonly payment: LightningPayment;
|
|
497
|
+
} | {
|
|
498
|
+
readonly kind: "withdraw";
|
|
499
|
+
readonly exit: CooperativeExitResult;
|
|
340
500
|
};
|
|
341
|
-
export declare class AccountTreeController extends Controller<AccountTreeState> {
|
|
342
|
-
private readonly options;
|
|
343
|
-
private col;
|
|
344
|
-
private sparkUnsubscribe;
|
|
345
|
-
private totalsTimer;
|
|
346
|
-
private persistChain;
|
|
347
|
-
constructor(options: AccountTreeControllerOptions);
|
|
348
|
-
setStore(store: EngineStore | undefined): void;
|
|
349
|
-
/** Load persisted state, reconcile with the snapshot, start driving Spark. */
|
|
350
|
-
init(): Promise<void>;
|
|
351
|
-
destroy(): Promise<void>;
|
|
352
|
-
/** Locked: stop every Spark client, flush pending persists, then drop to the empty state. */
|
|
353
|
-
lock(): Promise<void>;
|
|
354
|
-
/** Reconcile groups/names/selected with `wallet.getSnapshot().wallets`; persists on change. */
|
|
355
|
-
reconcile(): void;
|
|
356
|
-
addGroup(walletId: string): number;
|
|
357
|
-
addGroups(walletId: string, indices: ReadonlyArray<number>): void;
|
|
358
|
-
renameWallet(walletId: string, name: string): void;
|
|
359
|
-
renameGroup(walletId: string, index: number, name: string): void;
|
|
360
|
-
setHidden(walletId: string, index: number, hidden: boolean): void;
|
|
361
|
-
select(walletId: string, index: number): void;
|
|
362
|
-
/**
|
|
363
|
-
* Binds a social identity to one group. The identity is unique across the whole tree — every
|
|
364
|
-
* group in every wallet carrying it loses the binding (each entry re-stamped).
|
|
365
|
-
*/
|
|
366
|
-
bind(walletId: string, index: number, pubkey: string): void;
|
|
367
|
-
unbind(walletId: string, index: number): void;
|
|
368
|
-
/**
|
|
369
|
-
* Which group currently holds a pubkey — merges can leave the same identity on groups in two
|
|
370
|
-
* wallets; the newest `updatedAt` wins, ties resolve by snapshot wallet order then lower index.
|
|
371
|
-
*/
|
|
372
|
-
bindingOf(pubkey: string): {
|
|
373
|
-
walletId: string;
|
|
374
|
-
groupIndex: number;
|
|
375
|
-
} | undefined;
|
|
376
|
-
/** The wallet's metadata document — every group, hidden included. */
|
|
377
|
-
exportMeta(walletId: string): MetaDoc;
|
|
378
|
-
/**
|
|
379
|
-
* Entry-level last-writer-wins merge: a newer remote `updatedAt` replaces the local entry, a tie
|
|
380
|
-
* keeps local; remote-only groups are added. `selected`/hidden rules are re-validated — if the
|
|
381
|
-
* merge hides the selected group it is re-selected, and a merge may never leave every group
|
|
382
|
-
* hidden (the selected one stays visible and is re-stamped so the fix propagates).
|
|
383
|
-
*/
|
|
384
|
-
mergeMeta(walletId: string, doc: MetaDoc): {
|
|
385
|
-
changed: boolean;
|
|
386
|
-
localNewer: boolean;
|
|
387
|
-
};
|
|
388
|
-
/** Sequential inspect from 0 upward; index 0 always included; stop after 2 consecutive unused. */
|
|
389
|
-
discoverSpark(walletId: string): Promise<number[]>;
|
|
390
|
-
/**
|
|
391
|
-
* Per-group chain-family discovery — same stop rule as `discoverSpark`: group 0 always, stop
|
|
392
|
-
* after two consecutive fully-unused groups. A family error is reported on the group and does NOT
|
|
393
|
-
* count as unused (the group stays in `found` — it can't be proven empty).
|
|
394
|
-
*/
|
|
395
|
-
discoverGroups(walletId: string): Promise<number[]>;
|
|
396
|
-
/** Refresh `totals` for every other visible group; per-group failures are logged and skipped. */
|
|
397
|
-
refreshTotals(): Promise<void>;
|
|
398
|
-
private onSparkState;
|
|
399
|
-
private setTotal;
|
|
400
|
-
private driveSpark;
|
|
401
|
-
private visibleGroups;
|
|
402
|
-
private validSelection;
|
|
403
|
-
private selectFallback;
|
|
404
|
-
private mutateGroups;
|
|
405
|
-
private mustWallet;
|
|
406
|
-
private mustGroup;
|
|
407
|
-
private checkedName;
|
|
408
|
-
private load;
|
|
409
|
-
/** Queues a store write behind the previous one — the last queued write always lands last. */
|
|
410
|
-
private persist;
|
|
411
|
-
private scheduleTotalsPersist;
|
|
412
|
-
private flushTotals;
|
|
413
|
-
}
|
|
414
|
-
//#endregion
|
|
415
|
-
//#region src/networks/registry.d.ts
|
|
416
501
|
/**
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
* Signing-time chainId always comes from this table, never from an RPC endpoint.
|
|
502
|
+
* A validated, fixed Spark payment: everything that does not need the user's verification has
|
|
503
|
+
* happened (including any LNURL invoice fetch), so approval only re-checks expiry and executes.
|
|
420
504
|
*/
|
|
421
|
-
type
|
|
422
|
-
readonly
|
|
423
|
-
readonly
|
|
424
|
-
|
|
425
|
-
readonly
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
readonly family: "evm" | "solana" | "bitcoin";
|
|
429
|
-
readonly genesisHash?: string;
|
|
430
|
-
readonly decimals: number;
|
|
431
|
-
readonly testnet: boolean;
|
|
505
|
+
type PreparedSparkAction = {
|
|
506
|
+
readonly display: SparkDisplay;
|
|
507
|
+
readonly checks: ReadonlyArray<RequestCheckCode>;
|
|
508
|
+
/** Why the action can no longer be paid at `now` (an expiring invoice), if so. */
|
|
509
|
+
readonly staleReason: (now: number) => string | undefined;
|
|
510
|
+
/** Runs the controller's approve-first payment call. */
|
|
511
|
+
readonly execute: (spark: SparkController, verify: UnlockFactor) => Promise<SparkResult>;
|
|
432
512
|
};
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
513
|
+
type PaymentOption = {
|
|
514
|
+
readonly kind: "spark";
|
|
515
|
+
readonly address: string;
|
|
516
|
+
} | {
|
|
517
|
+
readonly kind: "spark-invoice";
|
|
518
|
+
readonly invoice: string;
|
|
519
|
+
readonly amountSats?: number;
|
|
520
|
+
readonly memo?: string;
|
|
521
|
+
readonly expiresAt?: number;
|
|
522
|
+
} | {
|
|
523
|
+
readonly kind: "lightning";
|
|
524
|
+
readonly invoice: string;
|
|
525
|
+
readonly amountSats?: number;
|
|
526
|
+
readonly paymentHash: string;
|
|
527
|
+
readonly description?: string;
|
|
528
|
+
readonly expiresAt: number;
|
|
529
|
+
} | {
|
|
530
|
+
readonly kind: "lnurl-pay";
|
|
531
|
+
readonly request: LnurlPayRequest;
|
|
532
|
+
readonly address?: string;
|
|
533
|
+
} | {
|
|
534
|
+
readonly kind: "lnurl-withdraw";
|
|
535
|
+
readonly request: LnurlWithdrawRequest;
|
|
536
|
+
} | {
|
|
537
|
+
readonly kind: "bitcoin";
|
|
538
|
+
readonly address: string;
|
|
437
539
|
};
|
|
438
|
-
type
|
|
439
|
-
readonly
|
|
540
|
+
type PaymentRequest = {
|
|
541
|
+
readonly options: ReadonlyArray<PaymentOption>;
|
|
542
|
+
readonly amountSats?: number;
|
|
543
|
+
readonly label?: string;
|
|
544
|
+
readonly message?: string;
|
|
440
545
|
};
|
|
441
|
-
type
|
|
546
|
+
type PaymentParse = {
|
|
547
|
+
readonly kind: "request";
|
|
548
|
+
readonly request: PaymentRequest;
|
|
549
|
+
} | {
|
|
550
|
+
readonly kind: "lnurl";
|
|
551
|
+
readonly url: string;
|
|
552
|
+
readonly address?: string;
|
|
553
|
+
} | {
|
|
554
|
+
readonly kind: "unsupported";
|
|
555
|
+
readonly format: "bolt12" | "silent-payment" | "lnurl-auth" | "spark-token-invoice" | "nostr-wallet-connect";
|
|
556
|
+
} | {
|
|
557
|
+
readonly kind: "invalid";
|
|
558
|
+
readonly reason: "network" | "expired" | "amount-mismatch" | "malformed";
|
|
559
|
+
} | {
|
|
560
|
+
readonly kind: "unrecognized";
|
|
561
|
+
};
|
|
562
|
+
type ParseOptions = {
|
|
563
|
+
readonly network: SparkNetwork;
|
|
564
|
+
readonly now: number;
|
|
565
|
+
};
|
|
566
|
+
/** `input` → PaymentParse. Never throws: every failure is a structured result. */
|
|
567
|
+
export declare function parsePayment(input: string, options: ParseOptions): PaymentParse;
|
|
568
|
+
type PayParams = {
|
|
569
|
+
readonly account: SparkAccountRef;
|
|
570
|
+
readonly option: PaymentOption;
|
|
571
|
+
/** Caller-supplied amount — required by open invoices, the `spark` option, and LNURL flows. */
|
|
572
|
+
readonly amountSats?: number;
|
|
573
|
+
readonly comment?: string;
|
|
574
|
+
readonly maxFeeSats?: number;
|
|
575
|
+
readonly speed?: "FAST" | "MEDIUM" | "SLOW";
|
|
576
|
+
};
|
|
577
|
+
type WithdrawLnurlParams = {
|
|
578
|
+
readonly account: SparkAccountRef;
|
|
579
|
+
readonly option: Extract<PaymentOption, {
|
|
580
|
+
kind: "lnurl-withdraw";
|
|
581
|
+
}>;
|
|
582
|
+
readonly amountSats: number;
|
|
583
|
+
};
|
|
584
|
+
/** A profile zap names the recipient pubkey; an event zap carries the event it zaps. */
|
|
585
|
+
type ZapRecipient = {
|
|
586
|
+
readonly pubkey: string;
|
|
587
|
+
readonly lightning: string;
|
|
588
|
+
} | {
|
|
589
|
+
readonly event: Event;
|
|
590
|
+
readonly lightning: string;
|
|
591
|
+
};
|
|
592
|
+
type PrepareZapParams = {
|
|
593
|
+
/** Any `NostrSigner` — wallet key, external key, NIP-07/46 — signs the 9734. */
|
|
594
|
+
readonly signer: NostrSigner;
|
|
595
|
+
readonly recipient: ZapRecipient;
|
|
596
|
+
readonly amountSats: number;
|
|
597
|
+
readonly comment?: string | undefined;
|
|
598
|
+
readonly relays: ReadonlyArray<string>;
|
|
599
|
+
readonly network: SparkNetwork;
|
|
600
|
+
};
|
|
601
|
+
type PrepareZapContext = {
|
|
442
602
|
readonly fetch: typeof globalThis.fetch;
|
|
443
|
-
readonly
|
|
603
|
+
readonly now: () => number;
|
|
604
|
+
};
|
|
605
|
+
/** Everything a payer needs: the signed 9734, the invoice, and the note fields. */
|
|
606
|
+
type PreparedZap = {
|
|
607
|
+
readonly zapRequest: Event;
|
|
608
|
+
readonly invoice: string;
|
|
609
|
+
/** Hex payment hash decoded from the invoice. */
|
|
610
|
+
readonly paymentHash: string;
|
|
611
|
+
/** Millisecond expiry decoded from the invoice. */
|
|
612
|
+
readonly expiresAt: number;
|
|
613
|
+
readonly amountSats: number;
|
|
614
|
+
/** The LNURL service's 9735 signing pubkey. */
|
|
615
|
+
readonly receiptPubkey: string;
|
|
616
|
+
readonly recipientPubkey: string;
|
|
617
|
+
readonly eventId?: string;
|
|
618
|
+
readonly comment?: string;
|
|
619
|
+
/** The lud16 or LNURL as given. */
|
|
620
|
+
readonly lightning: string;
|
|
621
|
+
};
|
|
622
|
+
/** Everything up to payment: resolve LNURL, sign the 9734, request the invoice. */
|
|
623
|
+
export declare function prepareZap(params: PrepareZapParams, context: PrepareZapContext): Promise<PreparedZap>;
|
|
624
|
+
type ChainApis = ReturnType<typeof chains>;
|
|
625
|
+
type SignParams = Parameters<ChainApis["sign"]>[0];
|
|
626
|
+
type AccountRef = SignParams["request"]["account"];
|
|
627
|
+
type DisplayIntent = ReturnType<typeof decodeEvm>;
|
|
628
|
+
type TxState = "draft" | "signed" | "submitted" | "pending" | "confirmed" | "failed" | "rejected" | "dropped" | "replaced";
|
|
629
|
+
/** A bitcoin transaction that funds the wallet's own Spark account; it is claimed once confirmed. */
|
|
630
|
+
type SparkDepositTag = {
|
|
631
|
+
readonly walletId: string;
|
|
632
|
+
readonly groupIndex: number;
|
|
633
|
+
readonly network: SparkNetwork;
|
|
634
|
+
readonly claimed?: boolean;
|
|
635
|
+
};
|
|
636
|
+
type TrackedTransaction = {
|
|
637
|
+
readonly id: string;
|
|
638
|
+
readonly family: "evm" | "solana" | "bitcoin";
|
|
639
|
+
readonly network: string;
|
|
640
|
+
readonly account: string;
|
|
641
|
+
readonly hash: string | undefined;
|
|
642
|
+
readonly state: TxState;
|
|
643
|
+
readonly intent: DisplayIntent | undefined;
|
|
644
|
+
readonly nonce: number;
|
|
645
|
+
/** Solana only — the blockhash expiry that turns an unconfirmed tx `dropped`. */
|
|
646
|
+
readonly lastValidBlockHeight?: number;
|
|
647
|
+
/** EVM replacement — the earlier transaction this one bumps or cancels. */
|
|
648
|
+
readonly replaces?: string;
|
|
649
|
+
/** CPFP — the unconfirmed parent this child pushes. */
|
|
650
|
+
readonly parentId?: string;
|
|
651
|
+
/** Set on a Spark deposit; `claimed` flips once the deposit is credited on Spark. */
|
|
652
|
+
readonly sparkDeposit?: SparkDepositTag;
|
|
653
|
+
/** Bitcoin build record persisted at send for RBF/CPFP rebuilds. */
|
|
654
|
+
readonly btc?: {
|
|
655
|
+
readonly inputs: ReadonlyArray<{
|
|
656
|
+
readonly txid: string;
|
|
657
|
+
readonly vout: number;
|
|
658
|
+
readonly value: number;
|
|
659
|
+
readonly address: string;
|
|
660
|
+
}>;
|
|
661
|
+
readonly outputs: ReadonlyArray<{
|
|
662
|
+
readonly address: string;
|
|
663
|
+
readonly value: number;
|
|
664
|
+
readonly own: boolean;
|
|
665
|
+
}>;
|
|
666
|
+
readonly vsize: number;
|
|
667
|
+
readonly fee: number;
|
|
668
|
+
readonly feeRate: number;
|
|
669
|
+
};
|
|
670
|
+
readonly submittedAt: number;
|
|
671
|
+
readonly error: string | undefined;
|
|
672
|
+
};
|
|
673
|
+
type SendParams = {
|
|
674
|
+
readonly account: AccountRef;
|
|
675
|
+
readonly network: string;
|
|
676
|
+
readonly to: string;
|
|
677
|
+
readonly amount: bigint;
|
|
678
|
+
/** ERC-20 contract — when set, `to`/`amount` are the transfer recipient/units and value is 0. */
|
|
679
|
+
readonly token?: string;
|
|
680
|
+
readonly fee: EvmFeeTier | SolanaFeeTier;
|
|
681
|
+
/** SPL mint decimals — required when `token` is a Solana mint. */
|
|
682
|
+
readonly decimals?: number;
|
|
683
|
+
readonly verify: SignParams["verify"];
|
|
684
|
+
};
|
|
685
|
+
type PrepareParams = Omit<SendParams, "verify">;
|
|
686
|
+
type ChainRequestMethod = "send" | "speed-up" | "cancel" | "cpfp";
|
|
687
|
+
/** What a request asks for; replacements and CPFP name the original transaction. */
|
|
688
|
+
type ChainRequestInput = ({
|
|
689
|
+
readonly method: "send";
|
|
690
|
+
} & PrepareParams) | {
|
|
691
|
+
readonly method: "speed-up" | "cancel";
|
|
692
|
+
readonly txId: string;
|
|
693
|
+
} | {
|
|
694
|
+
readonly method: "cpfp";
|
|
695
|
+
readonly txId: string;
|
|
696
|
+
readonly feeRate: number;
|
|
697
|
+
};
|
|
698
|
+
/**
|
|
699
|
+
* A fully built, estimated and cross-checked send that has not been signed. The unsigned content
|
|
700
|
+
* lives in the closures and cannot change after `prepare` returns.
|
|
701
|
+
*/
|
|
702
|
+
type PreparedRequest = {
|
|
703
|
+
/** Id of the tracked transaction `submit` creates. */
|
|
704
|
+
readonly txId: string;
|
|
705
|
+
readonly account: AccountRef;
|
|
706
|
+
readonly network: string;
|
|
707
|
+
/** The transaction being replaced or accelerated; absent for a plain send. */
|
|
708
|
+
readonly target?: string;
|
|
709
|
+
readonly intent: DisplayIntent;
|
|
710
|
+
readonly checks: ReadonlyArray<RequestCheckCode>;
|
|
711
|
+
/** Why the build can no longer be signed (nonce taken, blockhash expired), if so. */
|
|
712
|
+
readonly staleReason: () => string | undefined | Promise<string | undefined>;
|
|
713
|
+
/** Signs, finalizes, broadcasts and hands the transaction to tracking. */
|
|
714
|
+
readonly submit: (verify: SendParams["verify"]) => Promise<TrackedTransaction>;
|
|
715
|
+
/** Frees what `prepare` reserved; safe to call more than once. */
|
|
716
|
+
readonly release: () => void;
|
|
717
|
+
};
|
|
718
|
+
type SignatureResult = {
|
|
719
|
+
readonly kind: "evm.personal-message" | "evm.typed-data";
|
|
720
|
+
readonly signature: Uint8Array;
|
|
721
|
+
};
|
|
722
|
+
/** A prepared message signature: nothing is broadcast or tracked, `submit` returns the signature. */
|
|
723
|
+
type PreparedMessage = Omit<PreparedRequest, "submit" | "txId"> & {
|
|
724
|
+
readonly submit: (verify: SendParams["verify"]) => Promise<SignatureResult>;
|
|
725
|
+
};
|
|
726
|
+
type Options$1 = {
|
|
727
|
+
readonly wallet: Wallet;
|
|
728
|
+
readonly networks: NetworkController;
|
|
444
729
|
readonly openStore: () => Promise<EngineStore>;
|
|
730
|
+
readonly random: (n: number) => Uint8Array;
|
|
731
|
+
readonly setTimer: (ms: number, fn: () => unknown) => () => void;
|
|
732
|
+
readonly now: () => number;
|
|
445
733
|
readonly logger: EngineLogger;
|
|
734
|
+
readonly pollMs?: number;
|
|
735
|
+
/** Test seam — defaults to the wallet's real chains proxy. */
|
|
736
|
+
readonly chains?: ReturnType<typeof chains>;
|
|
446
737
|
};
|
|
447
|
-
|
|
738
|
+
type TransactionControllerState = {
|
|
739
|
+
readonly txs: Record<string, TrackedTransaction>;
|
|
740
|
+
};
|
|
741
|
+
declare class TransactionController extends Controller<TransactionControllerState> {
|
|
448
742
|
private readonly options;
|
|
449
743
|
private engineStore?;
|
|
450
|
-
private readonly
|
|
451
|
-
|
|
744
|
+
private readonly timers;
|
|
745
|
+
private evmRoute;
|
|
746
|
+
private bitcoinRoute;
|
|
747
|
+
private locked;
|
|
748
|
+
constructor(options: Options$1);
|
|
452
749
|
init(): Promise<void>;
|
|
453
750
|
destroy(): Promise<void>;
|
|
454
751
|
lock(): void;
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
752
|
+
private persist;
|
|
753
|
+
private transition;
|
|
754
|
+
private routeCtx;
|
|
755
|
+
/**
|
|
756
|
+
* Internal entry for the request pipeline: builds, estimates and cross-checks a send without
|
|
757
|
+
* signing it. Bitcoin outputs it selects stay locked under `requestId` until the returned
|
|
758
|
+
* `release` runs or the broadcast moves them to the transaction.
|
|
759
|
+
*/
|
|
760
|
+
prepareSend(params: PrepareParams, requestId: string, sparkDeposit?: SparkDepositTag): Promise<PreparedRequest>;
|
|
761
|
+
/** The group's next unused `btc.bip84` receive address on a bitcoin `network`. */
|
|
762
|
+
nextReceiveAddress(walletId: string, groupIndex: number, network: string): Promise<string>;
|
|
763
|
+
/** Records that a Spark deposit was credited; persisted with the transaction. */
|
|
764
|
+
markDepositClaimed(id: string): Promise<void>;
|
|
765
|
+
/**
|
|
766
|
+
* Internal entry for a dApp's EVM signature request: the request is normalized first, a
|
|
767
|
+
* transaction is rebuilt with fresh nonce and fees (the dApp's own are discarded), and a message
|
|
768
|
+
* is decoded and signed as is.
|
|
769
|
+
*/
|
|
770
|
+
prepareDapp(account: AccountRef, request: SignRequest): Promise<PreparedRequest | PreparedMessage>;
|
|
771
|
+
/**
|
|
772
|
+
* Internal entry for replacements and CPFP: builds, cross-checks and reserves what the
|
|
773
|
+
* replacement needs without signing it. The original must be `submitted` or `pending`.
|
|
774
|
+
*/
|
|
775
|
+
prepareReplacement(input: Exclude<ChainRequestInput, {
|
|
776
|
+
method: "send";
|
|
777
|
+
}>, requestId: string): Promise<PreparedRequest>;
|
|
778
|
+
private track;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Recipient risk, pure: a recipient the wallet has never paid or saved is a `warning`; one that
|
|
782
|
+
* looks like a known address (same first and last four characters, different address) is a `danger`
|
|
783
|
+
* — the shape of an address-poisoning lookalike. Both can apply to one recipient.
|
|
784
|
+
*/
|
|
785
|
+
type RiskFinding = {
|
|
786
|
+
readonly code: "first-recipient" | "address-poisoning";
|
|
787
|
+
readonly level: "warning" | "danger";
|
|
788
|
+
};
|
|
789
|
+
/** A web page; `origin` is `scheme://host[:port]`, computed by the host from the top-level URL. */
|
|
790
|
+
type BrowserOrigin = {
|
|
791
|
+
readonly kind: "browser";
|
|
792
|
+
readonly origin: string;
|
|
793
|
+
};
|
|
794
|
+
type RequestOrigin = {
|
|
795
|
+
readonly kind: "internal";
|
|
796
|
+
} | BrowserOrigin;
|
|
797
|
+
type RequestMethod = ChainRequestMethod | "pay" | "zap" | "evm-sign" | "spark-deposit" | "spark-exit";
|
|
798
|
+
type SignLogOutcome = "submitted" | "rejected" | "failed" | "expired" | "invalidated";
|
|
799
|
+
type SignLogEntry = {
|
|
800
|
+
readonly id: string;
|
|
801
|
+
readonly at: number;
|
|
802
|
+
readonly origin: RequestOrigin;
|
|
803
|
+
readonly method: RequestMethod;
|
|
804
|
+
readonly account: AccountRef | SparkAccountRef;
|
|
805
|
+
readonly network: string;
|
|
806
|
+
readonly summary: string;
|
|
807
|
+
readonly verification: "verified" | "unverifiable";
|
|
808
|
+
readonly checks: ReadonlyArray<RequestCheckCode>;
|
|
809
|
+
readonly risk: ReadonlyArray<RiskFinding>;
|
|
810
|
+
readonly outcome: SignLogOutcome;
|
|
811
|
+
readonly error?: string;
|
|
812
|
+
};
|
|
813
|
+
/** A Spark, Lightning (including LNURL-pay and lightning addresses) or cooperative-exit payment. */
|
|
814
|
+
type PayInput = {
|
|
815
|
+
readonly method: "pay";
|
|
816
|
+
} & PayParams;
|
|
817
|
+
/** A prepared zap; its invoice was fetched by `engine.zaps.prepare` and is paid as-is. */
|
|
818
|
+
type ZapInput = {
|
|
819
|
+
readonly method: "zap";
|
|
820
|
+
readonly account: SparkAccountRef;
|
|
821
|
+
readonly zap: PreparedZap;
|
|
822
|
+
readonly maxFeeSats: number;
|
|
823
|
+
};
|
|
824
|
+
/**
|
|
825
|
+
* A dApp's EVM request: a transaction (rebuilt here with fresh nonce and fees), a personal message
|
|
826
|
+
* or EIP-712 typed data.
|
|
827
|
+
*/
|
|
828
|
+
type EvmSignInput = {
|
|
829
|
+
readonly method: "evm-sign";
|
|
830
|
+
readonly origin: BrowserOrigin;
|
|
831
|
+
readonly account: AccountRef;
|
|
832
|
+
readonly network: string;
|
|
833
|
+
readonly request: SignRequest;
|
|
834
|
+
};
|
|
835
|
+
/**
|
|
836
|
+
* Funds the wallet's own Spark account from a bitcoin account of the same wallet; the transaction
|
|
837
|
+
* is an ordinary bitcoin send to a fresh Spark deposit address and is claimed once confirmed.
|
|
838
|
+
*/
|
|
839
|
+
type SparkDepositInput = {
|
|
840
|
+
readonly method: "spark-deposit";
|
|
841
|
+
readonly account: SparkAccountRef;
|
|
842
|
+
readonly from: AccountRef;
|
|
843
|
+
readonly amountSats: number;
|
|
844
|
+
readonly fee: PrepareParams["fee"];
|
|
845
|
+
};
|
|
846
|
+
/** A cooperative exit to the group's own next unused `btc.bip84` receive address. */
|
|
847
|
+
type SparkExitInput = {
|
|
848
|
+
readonly method: "spark-exit";
|
|
849
|
+
readonly account: SparkAccountRef;
|
|
850
|
+
readonly amountSats: number;
|
|
851
|
+
readonly maxFeeSats: number;
|
|
852
|
+
readonly speed?: "FAST" | "MEDIUM" | "SLOW";
|
|
853
|
+
};
|
|
854
|
+
type RequestInput = ChainRequestInput | PayInput | ZapInput | EvmSignInput | SparkDepositInput | SparkExitInput;
|
|
855
|
+
type RequestStage = "awaiting-approval" | "signing" | "submitted" | "rejected" | "failed" | "expired" | "invalidated";
|
|
856
|
+
type PendingRequest = {
|
|
857
|
+
readonly id: string;
|
|
858
|
+
readonly origin: RequestOrigin;
|
|
859
|
+
readonly method: RequestMethod;
|
|
860
|
+
readonly account: AccountRef | SparkAccountRef;
|
|
861
|
+
readonly network: string;
|
|
862
|
+
readonly stage: RequestStage;
|
|
863
|
+
/** Decoded locally from the exact content that will be signed; `family` tells the shapes apart. */
|
|
864
|
+
readonly display: DisplayIntent | SparkDisplay;
|
|
865
|
+
/** `unverifiable` as soon as any check is recorded; the host must ask for explicit confirmation. */
|
|
866
|
+
readonly verification: "verified" | "unverifiable";
|
|
867
|
+
readonly checks: ReadonlyArray<RequestCheckCode>;
|
|
868
|
+
/**
|
|
869
|
+
* Recipient risk; independent of `verification`. A `danger` needs the user's explicit
|
|
870
|
+
* acknowledgement.
|
|
871
|
+
*/
|
|
872
|
+
readonly risk: ReadonlyArray<RiskFinding>;
|
|
873
|
+
readonly createdAt: number;
|
|
874
|
+
readonly expiresAt: number;
|
|
875
|
+
/** The transaction being replaced or accelerated; absent for a plain send. */
|
|
876
|
+
readonly target?: string;
|
|
877
|
+
/** The tracked transaction once submitted. */
|
|
878
|
+
readonly txId?: string;
|
|
879
|
+
readonly error?: string;
|
|
880
|
+
};
|
|
881
|
+
type RequestControllerState = {
|
|
882
|
+
readonly requests: Record<string, PendingRequest>;
|
|
883
|
+
};
|
|
884
|
+
type RequestControllerOptions = {
|
|
885
|
+
readonly transactions: TransactionController;
|
|
886
|
+
/** The full controller: its payment methods are reachable only through this pipeline. */
|
|
887
|
+
readonly spark: SparkController;
|
|
888
|
+
readonly addressBook: AddressBookController;
|
|
889
|
+
readonly openStore: () => Promise<EngineStore>;
|
|
890
|
+
readonly fetch: typeof globalThis.fetch;
|
|
891
|
+
readonly random: (n: number) => Uint8Array;
|
|
892
|
+
readonly now: () => number;
|
|
893
|
+
readonly setTimer: (ms: number, fn: () => unknown) => () => void;
|
|
894
|
+
readonly logger: EngineLogger;
|
|
895
|
+
};
|
|
896
|
+
/** Requests expire this long after creation. */
|
|
897
|
+
export declare const REQUEST_TTL_MS: number;
|
|
898
|
+
export declare class RequestController extends Controller<RequestControllerState> {
|
|
899
|
+
private readonly options;
|
|
900
|
+
private readonly entries;
|
|
901
|
+
private readonly log;
|
|
902
|
+
private readonly settlers;
|
|
903
|
+
/** Original transaction id → the unfinished request replacing or accelerating it. */
|
|
904
|
+
private readonly targets;
|
|
905
|
+
private locked;
|
|
906
|
+
/** Bumped on every unlock and lock so work that outlives a session never touches the next one. */
|
|
907
|
+
private session;
|
|
908
|
+
constructor(options: RequestControllerOptions);
|
|
909
|
+
init(): Promise<void>;
|
|
910
|
+
destroy(): Promise<void>;
|
|
911
|
+
/** Locking is not consent: every unfinished request becomes `invalidated` and frees its resources. */
|
|
912
|
+
lock(): void;
|
|
913
|
+
/** A page navigated away, was revoked or changed network: its unfinished requests are void. */
|
|
914
|
+
invalidateOrigin(origin: string): void;
|
|
915
|
+
/** The signature record, newest first. */
|
|
916
|
+
signLog(): Promise<ReadonlyArray<SignLogEntry>>;
|
|
917
|
+
clearSignLog(): Promise<void>;
|
|
918
|
+
prepare(input: RequestInput): Promise<PendingRequest>;
|
|
919
|
+
/**
|
|
920
|
+
* Resolves with what `approve` returned, or rejects with `RequestEndedError` when the request
|
|
921
|
+
* ends any other way — how a dApp's pending call learns the outcome.
|
|
922
|
+
*/
|
|
923
|
+
outcome(id: string): Promise<TrackedTransaction | SparkResult | SignatureResult>;
|
|
924
|
+
private openSettler;
|
|
925
|
+
private settle;
|
|
926
|
+
/** The bitcoin network `account`'s Spark network settles on; any other pairing is refused. */
|
|
927
|
+
private l1Network;
|
|
928
|
+
private sparkBuilt;
|
|
929
|
+
private build;
|
|
930
|
+
/**
|
|
931
|
+
* Signs and submits a request. Anything but a live, unexpired `send` request with this id throws
|
|
932
|
+
* before any signing; a stale build (nonce taken, blockhash expired) fails without signing.
|
|
933
|
+
*/
|
|
934
|
+
approve(id: string, method: ChainRequestMethod | "spark-deposit", verify: SendParams["verify"]): Promise<TrackedTransaction>;
|
|
935
|
+
approve(id: string, method: "pay" | "zap" | "spark-exit", verify: SendParams["verify"]): Promise<SparkResult>;
|
|
936
|
+
approve(id: string, method: "evm-sign", verify: SendParams["verify"]): Promise<TrackedTransaction | SignatureResult>;
|
|
937
|
+
/**
|
|
938
|
+
* A cancelled or refused verification is `rejected`; anything after it is `failed`. Chain
|
|
939
|
+
* requests record which step failed on the tracked transaction; for Spark, the approval round is
|
|
940
|
+
* the only source of `WalletError`.
|
|
941
|
+
*/
|
|
942
|
+
private failureStage;
|
|
943
|
+
reject(id: string): void;
|
|
944
|
+
private requireRequest;
|
|
945
|
+
private put;
|
|
946
|
+
private unclaim;
|
|
947
|
+
/** Ends a request in a terminal stage and frees what it reserved. */
|
|
948
|
+
private finish;
|
|
949
|
+
/** Appends the final stage to the signature record; a failed write is a warning, not an error. */
|
|
950
|
+
private record;
|
|
951
|
+
private appendLog;
|
|
952
|
+
/**
|
|
953
|
+
* Addresses the wallet already knows for a family: contacts, plus recipients of tracked chain
|
|
954
|
+
* sends (Spark payments are not tracked).
|
|
955
|
+
*/
|
|
956
|
+
private knownAddresses;
|
|
957
|
+
private chainRisk;
|
|
958
|
+
/** Only a Spark transfer has a recipient to check; Lightning and exits are not assessed. */
|
|
959
|
+
private sparkRisk;
|
|
960
|
+
}
|
|
961
|
+
type Eip1193Request = {
|
|
962
|
+
readonly method: string;
|
|
963
|
+
readonly params?: unknown;
|
|
964
|
+
};
|
|
965
|
+
type Eip1193Event = {
|
|
966
|
+
readonly name: "connect";
|
|
967
|
+
readonly origin: string;
|
|
968
|
+
readonly chainId: string;
|
|
969
|
+
} | {
|
|
970
|
+
readonly name: "accountsChanged";
|
|
971
|
+
readonly origin: string;
|
|
972
|
+
readonly accounts: ReadonlyArray<string>;
|
|
973
|
+
} | {
|
|
974
|
+
readonly name: "chainChanged";
|
|
975
|
+
readonly origin: string;
|
|
976
|
+
readonly chainId: string;
|
|
977
|
+
} | {
|
|
978
|
+
readonly name: "disconnect";
|
|
979
|
+
readonly origin: string;
|
|
980
|
+
};
|
|
981
|
+
type Eip1193HandlerOptions = {
|
|
982
|
+
readonly connections: ConnectionController;
|
|
983
|
+
readonly requests: RequestController;
|
|
984
|
+
readonly networks: NetworkController;
|
|
985
|
+
/** The network an unconnected page sees. */
|
|
986
|
+
readonly defaultNetwork: () => string;
|
|
987
|
+
};
|
|
988
|
+
export declare class Eip1193Handler {
|
|
989
|
+
private readonly options;
|
|
990
|
+
private readonly listeners;
|
|
991
|
+
private unsubscribe;
|
|
992
|
+
constructor(options: Eip1193HandlerOptions);
|
|
993
|
+
/** Events for the host to forward to pages; derived from changes to the sessions. */
|
|
994
|
+
subscribe(listener: (event: Eip1193Event) => void): () => void;
|
|
995
|
+
handle(origin: string, request: Eip1193Request): Promise<unknown>;
|
|
996
|
+
private requestAccounts;
|
|
997
|
+
private permissions;
|
|
998
|
+
private switchChain;
|
|
999
|
+
private authorizedAccount;
|
|
1000
|
+
private personalSign;
|
|
1001
|
+
private typedData;
|
|
1002
|
+
private sendTransaction;
|
|
1003
|
+
private signingSession;
|
|
1004
|
+
private sign;
|
|
1005
|
+
private read;
|
|
1006
|
+
}
|
|
1007
|
+
/** EIP-1193 / EIP-1474 / EIP-3326 error: `code` is what the page's promise rejects with. */
|
|
1008
|
+
export declare class ProviderError extends Error {
|
|
1009
|
+
readonly code: number;
|
|
1010
|
+
constructor(code: number, message: string);
|
|
1011
|
+
}
|
|
1012
|
+
type AddressBookErrorCategory = "invalid-input" | "duplicate" | "not-found" | "locked" | "limit";
|
|
1013
|
+
export declare class AddressBookError extends Error {
|
|
1014
|
+
readonly category: AddressBookErrorCategory;
|
|
1015
|
+
constructor(category: AddressBookErrorCategory, message: string);
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Wallet metadata document — the plaintext exchanged over kind-30078 events between this wallet's
|
|
1019
|
+
* own devices. One document per wallet; entry-level last-writer-wins on `updatedAt`.
|
|
1020
|
+
*/
|
|
1021
|
+
type MetaDocWallet = {
|
|
1022
|
+
readonly name?: string;
|
|
1023
|
+
readonly updatedAt: number;
|
|
1024
|
+
};
|
|
1025
|
+
type MetaDocGroup = {
|
|
1026
|
+
readonly index: number;
|
|
1027
|
+
readonly name?: string;
|
|
1028
|
+
readonly hidden: boolean;
|
|
1029
|
+
readonly boundPubkey?: string;
|
|
1030
|
+
readonly updatedAt: number;
|
|
1031
|
+
};
|
|
1032
|
+
/** The per-wallet part of the document: this wallet's name and account groups. */
|
|
1033
|
+
type MetaDocTree = {
|
|
1034
|
+
readonly wallet: MetaDocWallet;
|
|
1035
|
+
readonly groups: ReadonlyArray<MetaDocGroup>;
|
|
1036
|
+
};
|
|
1037
|
+
/** Every wallet's document also carries the whole address book, which is shared across wallets. */
|
|
1038
|
+
type MetaDoc = MetaDocTree & {
|
|
1039
|
+
readonly v: 2;
|
|
1040
|
+
readonly contacts: ReadonlyArray<AddressBookRecord>;
|
|
1041
|
+
};
|
|
1042
|
+
type AccountGroup = {
|
|
1043
|
+
readonly walletId: string;
|
|
1044
|
+
readonly index: number;
|
|
1045
|
+
/** `discoverGroups` result — family key → used; a family error lives under `errors`. */
|
|
1046
|
+
readonly used?: Readonly<Record<string, boolean>>;
|
|
1047
|
+
readonly errors?: Readonly<Record<string, string>>;
|
|
1048
|
+
readonly name?: string;
|
|
1049
|
+
readonly hidden: boolean;
|
|
1050
|
+
/** A social identity (64 lowercase hex) bound to this group; one identity binds one group. */
|
|
1051
|
+
readonly boundPubkey?: string;
|
|
1052
|
+
/** Last local modification time (ms); reconcile-created entries start at 0. */
|
|
1053
|
+
readonly updatedAt: number;
|
|
1054
|
+
};
|
|
1055
|
+
type AccountTreeState = {
|
|
1056
|
+
readonly status: "locked" | "ready";
|
|
1057
|
+
readonly wallets: ReadonlyArray<{
|
|
1058
|
+
readonly walletId: string;
|
|
1059
|
+
readonly name?: string;
|
|
1060
|
+
readonly updatedAt: number;
|
|
1061
|
+
}>;
|
|
1062
|
+
readonly groups: Readonly<Record<string, ReadonlyArray<AccountGroup>>>;
|
|
1063
|
+
readonly selected: {
|
|
1064
|
+
readonly walletId: string;
|
|
1065
|
+
readonly groupIndex: number;
|
|
1066
|
+
} | null;
|
|
1067
|
+
readonly totals: Readonly<Record<string, number>>;
|
|
1068
|
+
};
|
|
1069
|
+
type DiscoveryNetworks = {
|
|
1070
|
+
readonly client: (network: string) => {
|
|
1071
|
+
readonly getTransactionCount: (p: {
|
|
1072
|
+
readonly address: `0x${string}`;
|
|
1073
|
+
readonly blockTag: "latest";
|
|
1074
|
+
}) => Promise<number>;
|
|
1075
|
+
readonly getBalance: (p: {
|
|
1076
|
+
readonly address: `0x${string}`;
|
|
1077
|
+
}) => Promise<bigint>;
|
|
1078
|
+
};
|
|
1079
|
+
readonly solanaRpc: (network: string) => {
|
|
1080
|
+
readonly call: (method: string, params: unknown[]) => Promise<unknown>;
|
|
1081
|
+
};
|
|
1082
|
+
readonly esplora: (network: string) => Esplora;
|
|
1083
|
+
readonly enabled: (family: "evm" | "solana" | "bitcoin") => ReadonlyArray<string>;
|
|
1084
|
+
};
|
|
1085
|
+
type AccountTreeControllerOptions = {
|
|
1086
|
+
readonly wallet: Wallet;
|
|
1087
|
+
readonly spark: SparkController;
|
|
1088
|
+
readonly sparkNetwork: SparkNetwork;
|
|
1089
|
+
readonly networks?: DiscoveryNetworks;
|
|
1090
|
+
readonly chains?: {
|
|
1091
|
+
readonly account: (params: {
|
|
1092
|
+
readonly walletId: string;
|
|
1093
|
+
readonly groupIndex: number;
|
|
1094
|
+
readonly template: string;
|
|
1095
|
+
readonly network: string;
|
|
1096
|
+
}) => Promise<{
|
|
1097
|
+
readonly address?: string;
|
|
1098
|
+
readonly xpub?: string;
|
|
1099
|
+
}>;
|
|
1100
|
+
};
|
|
1101
|
+
readonly logger: EngineLogger;
|
|
1102
|
+
readonly now: () => number;
|
|
1103
|
+
};
|
|
1104
|
+
export declare class AccountTreeController extends Controller<AccountTreeState> {
|
|
1105
|
+
private readonly options;
|
|
1106
|
+
private col;
|
|
1107
|
+
private sparkUnsubscribe;
|
|
1108
|
+
private totalsTimer;
|
|
1109
|
+
private persistChain;
|
|
1110
|
+
constructor(options: AccountTreeControllerOptions);
|
|
1111
|
+
setStore(store: EngineStore | undefined): void;
|
|
1112
|
+
/** Load persisted state, reconcile with the snapshot, start driving Spark. */
|
|
1113
|
+
init(): Promise<void>;
|
|
1114
|
+
destroy(): Promise<void>;
|
|
1115
|
+
/** Locked: stop every Spark client, flush pending persists, then drop to the empty state. */
|
|
1116
|
+
lock(): Promise<void>;
|
|
1117
|
+
/** Reconcile groups/names/selected with `wallet.getSnapshot().wallets`; persists on change. */
|
|
1118
|
+
reconcile(): void;
|
|
1119
|
+
addGroup(walletId: string): number;
|
|
1120
|
+
addGroups(walletId: string, indices: ReadonlyArray<number>): void;
|
|
1121
|
+
renameWallet(walletId: string, name: string): void;
|
|
1122
|
+
renameGroup(walletId: string, index: number, name: string): void;
|
|
1123
|
+
setHidden(walletId: string, index: number, hidden: boolean): void;
|
|
1124
|
+
select(walletId: string, index: number): void;
|
|
1125
|
+
/**
|
|
1126
|
+
* Binds a social identity to one group. The identity is unique across the whole tree — every
|
|
1127
|
+
* group in every wallet carrying it loses the binding (each entry re-stamped).
|
|
1128
|
+
*/
|
|
1129
|
+
bind(walletId: string, index: number, pubkey: string): void;
|
|
1130
|
+
unbind(walletId: string, index: number): void;
|
|
1131
|
+
/**
|
|
1132
|
+
* Which group currently holds a pubkey — merges can leave the same identity on groups in two
|
|
1133
|
+
* wallets; the newest `updatedAt` wins, ties resolve by snapshot wallet order then lower index.
|
|
1134
|
+
*/
|
|
1135
|
+
bindingOf(pubkey: string): {
|
|
1136
|
+
walletId: string;
|
|
1137
|
+
groupIndex: number;
|
|
1138
|
+
} | undefined;
|
|
1139
|
+
/** The wallet's metadata document — every group, hidden included. */
|
|
1140
|
+
exportMeta(walletId: string): MetaDocTree;
|
|
1141
|
+
/**
|
|
1142
|
+
* Entry-level last-writer-wins merge: a newer remote `updatedAt` replaces the local entry, a tie
|
|
1143
|
+
* keeps local; remote-only groups are added. `selected`/hidden rules are re-validated — if the
|
|
1144
|
+
* merge hides the selected group it is re-selected, and a merge may never leave every group
|
|
1145
|
+
* hidden (the selected one stays visible and is re-stamped so the fix propagates).
|
|
1146
|
+
*/
|
|
1147
|
+
mergeMeta(walletId: string, doc: MetaDocTree): {
|
|
1148
|
+
changed: boolean;
|
|
1149
|
+
localNewer: boolean;
|
|
1150
|
+
};
|
|
1151
|
+
/** Sequential inspect from 0 upward; index 0 always included; stop after 2 consecutive unused. */
|
|
1152
|
+
discoverSpark(walletId: string): Promise<number[]>;
|
|
1153
|
+
/**
|
|
1154
|
+
* Per-group chain-family discovery — same stop rule as `discoverSpark`: group 0 always, stop
|
|
1155
|
+
* after two consecutive fully-unused groups. A family error is reported on the group and does NOT
|
|
1156
|
+
* count as unused (the group stays in `found` — it can't be proven empty).
|
|
1157
|
+
*/
|
|
1158
|
+
discoverGroups(walletId: string): Promise<number[]>;
|
|
1159
|
+
/** Refresh `totals` for every other visible group; per-group failures are logged and skipped. */
|
|
1160
|
+
refreshTotals(): Promise<void>;
|
|
1161
|
+
private onSparkState;
|
|
1162
|
+
private setTotal;
|
|
1163
|
+
private driveSpark;
|
|
1164
|
+
private visibleGroups;
|
|
1165
|
+
private validSelection;
|
|
1166
|
+
private selectFallback;
|
|
1167
|
+
private mutateGroups;
|
|
1168
|
+
private mustWallet;
|
|
1169
|
+
private mustGroup;
|
|
1170
|
+
private checkedName;
|
|
1171
|
+
private load;
|
|
1172
|
+
/** Queues a store write behind the previous one — the last queued write always lands last. */
|
|
1173
|
+
private persist;
|
|
1174
|
+
private scheduleTotalsPersist;
|
|
1175
|
+
private flushTotals;
|
|
466
1176
|
}
|
|
467
|
-
//#endregion
|
|
468
|
-
//#region src/assets/controller.d.ts
|
|
469
1177
|
type TokenBalance = {
|
|
470
1178
|
readonly address: string;
|
|
471
1179
|
readonly symbol: string;
|
|
@@ -484,7 +1192,7 @@ type AccountBalances = {
|
|
|
484
1192
|
type AssetsControllerState = {
|
|
485
1193
|
readonly balances: Record<string, AccountBalances>;
|
|
486
1194
|
};
|
|
487
|
-
type Options
|
|
1195
|
+
type Options = {
|
|
488
1196
|
readonly networks: NetworkController;
|
|
489
1197
|
readonly openStore: () => Promise<EngineStore>;
|
|
490
1198
|
readonly setTimer: (ms: number, fn: () => unknown) => () => void;
|
|
@@ -497,7 +1205,7 @@ declare class AssetsController extends Controller<AssetsControllerState> {
|
|
|
497
1205
|
private visible;
|
|
498
1206
|
private cancelPoll;
|
|
499
1207
|
private readonly customTokens;
|
|
500
|
-
constructor(options: Options
|
|
1208
|
+
constructor(options: Options);
|
|
501
1209
|
init(): Promise<void>;
|
|
502
1210
|
lock(): void;
|
|
503
1211
|
destroy(): Promise<void>;
|
|
@@ -510,26 +1218,19 @@ declare class AssetsController extends Controller<AssetsControllerState> {
|
|
|
510
1218
|
private readTokens;
|
|
511
1219
|
private balanceOfBatch;
|
|
512
1220
|
private balanceOf;
|
|
513
|
-
private
|
|
514
|
-
private callNumber;
|
|
1221
|
+
private callToken;
|
|
515
1222
|
/** Reads symbol/decimals on-chain, marks unverified, persists; throws when the calls fail. */
|
|
516
1223
|
addToken(network: string, address: string): Promise<void>;
|
|
517
1224
|
private persistToken;
|
|
518
|
-
private rpc;
|
|
519
|
-
private rpcHex;
|
|
520
1225
|
/** BTC balance = confirmed spendable + own unconfirmed change; frozen 546/330 shown separately. */
|
|
521
1226
|
refreshBitcoin(xpub: string, network: string): Promise<void>;
|
|
522
1227
|
}
|
|
523
|
-
//#endregion
|
|
524
|
-
//#region src/backup/errors.d.ts
|
|
525
1228
|
/** BackupController error categories — never carry file contents, digests or secrets. */
|
|
526
1229
|
type BackupErrorCategory = "cloud" | "conflict" | "unavailable";
|
|
527
1230
|
export declare class BackupControllerError extends Error {
|
|
528
1231
|
readonly category: BackupErrorCategory;
|
|
529
1232
|
constructor(category: BackupErrorCategory, message: string);
|
|
530
1233
|
}
|
|
531
|
-
//#endregion
|
|
532
|
-
//#region src/backup/port.d.ts
|
|
533
1234
|
/**
|
|
534
1235
|
* Cloud-file storage port (design/backup.mdx "存储"): the cloud is an opaque key-value namespace —
|
|
535
1236
|
* names are file names (`qntx-wallet-backup-<id>.json`), contents are envelope texts. The kernel
|
|
@@ -547,8 +1248,6 @@ type CloudStore = {
|
|
|
547
1248
|
/** Deleting a missing file succeeds. */
|
|
548
1249
|
readonly delete: (name: string) => Promise<void>;
|
|
549
1250
|
};
|
|
550
|
-
//#endregion
|
|
551
|
-
//#region src/backup/controller.d.ts
|
|
552
1251
|
type BackupControllerState = {
|
|
553
1252
|
readonly status: "locked" | "unavailable" | "off" | "syncing" | "synced" | "conflict" | "error";
|
|
554
1253
|
/** The retained backup key's public summary from the wallet snapshot. */
|
|
@@ -556,7 +1255,6 @@ type BackupControllerState = {
|
|
|
556
1255
|
readonly uploadedAt: number | undefined;
|
|
557
1256
|
readonly unprotected: {
|
|
558
1257
|
readonly walletIds: ReadonlyArray<string>;
|
|
559
|
-
readonly nostrKeyIds: ReadonlyArray<string>;
|
|
560
1258
|
};
|
|
561
1259
|
readonly error: BackupErrorCategory | undefined;
|
|
562
1260
|
};
|
|
@@ -618,16 +1316,12 @@ export declare class BackupController extends Controller<BackupControllerState>
|
|
|
618
1316
|
private reconcile;
|
|
619
1317
|
private pass;
|
|
620
1318
|
}
|
|
621
|
-
//#endregion
|
|
622
|
-
//#region src/meta/errors.d.ts
|
|
623
1319
|
/** Meta-sync error categories — messages never carry event or document content. */
|
|
624
1320
|
type MetaSyncErrorCategory = "network" | "internal" | "unsupported" | "corrupt";
|
|
625
1321
|
export declare class MetaSyncError extends Error {
|
|
626
1322
|
readonly category: MetaSyncErrorCategory;
|
|
627
1323
|
constructor(category: MetaSyncErrorCategory, message: string, cause?: unknown);
|
|
628
1324
|
}
|
|
629
|
-
//#endregion
|
|
630
|
-
//#region src/meta/controller.d.ts
|
|
631
1325
|
type MetaSyncRelayPort = {
|
|
632
1326
|
readonly fetch: (filter: Filter) => Promise<ReadonlyArray<Event>>;
|
|
633
1327
|
readonly publish: (event: Event) => Promise<void>;
|
|
@@ -638,18 +1332,30 @@ type MetaSyncConfig = {
|
|
|
638
1332
|
readonly relays: MetaSyncRelayPort;
|
|
639
1333
|
};
|
|
640
1334
|
type MetaSyncWalletStatus = {
|
|
641
|
-
readonly status: "
|
|
1335
|
+
readonly status: "syncing" | "synced" | "error";
|
|
642
1336
|
readonly error?: MetaSyncErrorCategory;
|
|
643
1337
|
};
|
|
644
1338
|
type MetaSyncState = {
|
|
645
1339
|
readonly wallets: Readonly<Record<string, MetaSyncWalletStatus>>;
|
|
646
1340
|
};
|
|
1341
|
+
/** What the sync needs from the address book: its records, a merge, and a change subscription. */
|
|
1342
|
+
type AddressBookSync = {
|
|
1343
|
+
readonly syncEntries: () => ReadonlyArray<AddressBookRecord>;
|
|
1344
|
+
readonly merge: (remote: ReadonlyArray<AddressBookRecord>) => Promise<{
|
|
1345
|
+
readonly changed: boolean;
|
|
1346
|
+
readonly localNewer: boolean;
|
|
1347
|
+
}>;
|
|
1348
|
+
readonly store: {
|
|
1349
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
1350
|
+
};
|
|
1351
|
+
};
|
|
647
1352
|
type MetaSyncControllerOptions = {
|
|
648
1353
|
readonly wallet: Wallet;
|
|
649
1354
|
readonly accounts: AccountTreeController;
|
|
650
|
-
|
|
1355
|
+
readonly addressBook: AddressBookSync;
|
|
1356
|
+
/** `nostr(wallet).syncSigner` — each wallet signs metadata with its dedicated sync key. */
|
|
651
1357
|
readonly nostr: {
|
|
652
|
-
readonly
|
|
1358
|
+
readonly syncSigner: (walletId: string) => WalletSyncSigner;
|
|
653
1359
|
};
|
|
654
1360
|
readonly metaSync: MetaSyncConfig | undefined;
|
|
655
1361
|
readonly logger: EngineLogger;
|
|
@@ -657,9 +1363,10 @@ type MetaSyncControllerOptions = {
|
|
|
657
1363
|
};
|
|
658
1364
|
/**
|
|
659
1365
|
* Wallet-metadata sync over kind-30078 addressable events: one NIP-44-encrypted document per
|
|
660
|
-
* wallet, authored by its
|
|
661
|
-
* replaceable events would otherwise let a stale local tree overwrite a newer remote
|
|
662
|
-
* Debounced publishes are per wallet; a generation counter cancels in-flight write-backs
|
|
1366
|
+
* wallet, authored by its dedicated sync key (WD-070). Pull always precedes publish in an unlock
|
|
1367
|
+
* session — replaceable events would otherwise let a stale local tree overwrite a newer remote
|
|
1368
|
+
* document. Debounced publishes are per wallet; a generation counter cancels in-flight write-backs
|
|
1369
|
+
* on lock.
|
|
663
1370
|
*/
|
|
664
1371
|
export declare class MetaSyncController extends Controller<MetaSyncState> {
|
|
665
1372
|
private readonly options;
|
|
@@ -670,6 +1377,7 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
|
|
|
670
1377
|
private readonly timers;
|
|
671
1378
|
private readonly inflight;
|
|
672
1379
|
private accountsUnsubscribe;
|
|
1380
|
+
private addressBookUnsubscribe;
|
|
673
1381
|
constructor(options: MetaSyncControllerOptions);
|
|
674
1382
|
/** Unlocked: pull every wallet whose group-0 identity exists, then watch the tree. */
|
|
675
1383
|
init(): Promise<void>;
|
|
@@ -681,10 +1389,10 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
|
|
|
681
1389
|
/** Manual re-pull of every wallet that can sync. */
|
|
682
1390
|
sync(): Promise<void>;
|
|
683
1391
|
private pullAll;
|
|
684
|
-
private pubkeyFor;
|
|
685
|
-
private signerFor;
|
|
686
1392
|
private setStatus;
|
|
687
1393
|
private pullOne;
|
|
1394
|
+
/** The wallet's tree plus the shared address book — every wallet's document carries both. */
|
|
1395
|
+
private exportDoc;
|
|
688
1396
|
private filterFor;
|
|
689
1397
|
private acceptableEvent;
|
|
690
1398
|
/** Snapshot the wallet's exported doc — the debounce publishes only on a real change. */
|
|
@@ -692,245 +1400,6 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
|
|
|
692
1400
|
private onTreeChange;
|
|
693
1401
|
private publishNow;
|
|
694
1402
|
}
|
|
695
|
-
//#endregion
|
|
696
|
-
//#region src/payments/parse.d.ts
|
|
697
|
-
type PaymentOption = {
|
|
698
|
-
readonly kind: "spark";
|
|
699
|
-
readonly address: string;
|
|
700
|
-
} | {
|
|
701
|
-
readonly kind: "spark-invoice";
|
|
702
|
-
readonly invoice: string;
|
|
703
|
-
readonly amountSats?: number;
|
|
704
|
-
readonly memo?: string;
|
|
705
|
-
readonly expiresAt?: number;
|
|
706
|
-
} | {
|
|
707
|
-
readonly kind: "lightning";
|
|
708
|
-
readonly invoice: string;
|
|
709
|
-
readonly amountSats?: number;
|
|
710
|
-
readonly paymentHash: string;
|
|
711
|
-
readonly description?: string;
|
|
712
|
-
readonly expiresAt: number;
|
|
713
|
-
} | {
|
|
714
|
-
readonly kind: "lnurl-pay";
|
|
715
|
-
readonly request: LnurlPayRequest;
|
|
716
|
-
readonly address?: string;
|
|
717
|
-
} | {
|
|
718
|
-
readonly kind: "lnurl-withdraw";
|
|
719
|
-
readonly request: LnurlWithdrawRequest;
|
|
720
|
-
} | {
|
|
721
|
-
readonly kind: "bitcoin";
|
|
722
|
-
readonly address: string;
|
|
723
|
-
};
|
|
724
|
-
type PaymentRequest = {
|
|
725
|
-
readonly options: ReadonlyArray<PaymentOption>;
|
|
726
|
-
readonly amountSats?: number;
|
|
727
|
-
readonly label?: string;
|
|
728
|
-
readonly message?: string;
|
|
729
|
-
};
|
|
730
|
-
type PaymentParse = {
|
|
731
|
-
readonly kind: "request";
|
|
732
|
-
readonly request: PaymentRequest;
|
|
733
|
-
} | {
|
|
734
|
-
readonly kind: "lnurl";
|
|
735
|
-
readonly url: string;
|
|
736
|
-
readonly address?: string;
|
|
737
|
-
} | {
|
|
738
|
-
readonly kind: "unsupported";
|
|
739
|
-
readonly format: "bolt12" | "silent-payment" | "lnurl-auth" | "spark-token-invoice" | "nostr-wallet-connect";
|
|
740
|
-
} | {
|
|
741
|
-
readonly kind: "invalid";
|
|
742
|
-
readonly reason: "network" | "expired" | "amount-mismatch" | "malformed";
|
|
743
|
-
} | {
|
|
744
|
-
readonly kind: "unrecognized";
|
|
745
|
-
};
|
|
746
|
-
type ParseOptions = {
|
|
747
|
-
readonly network: SparkNetwork;
|
|
748
|
-
readonly now: number;
|
|
749
|
-
};
|
|
750
|
-
/** `input` → PaymentParse. Never throws: every failure is a structured result. */
|
|
751
|
-
export declare function parsePayment(input: string, options: ParseOptions): PaymentParse;
|
|
752
|
-
//#endregion
|
|
753
|
-
//#region src/payments/pay.d.ts
|
|
754
|
-
type PayParams = {
|
|
755
|
-
readonly account: SparkAccountRef;
|
|
756
|
-
readonly option: PaymentOption;
|
|
757
|
-
/** Caller-supplied amount — required by open invoices, the `spark` option, and LNURL flows. */
|
|
758
|
-
readonly amountSats?: number;
|
|
759
|
-
readonly comment?: string;
|
|
760
|
-
readonly maxFeeSats?: number;
|
|
761
|
-
readonly speed?: "FAST" | "MEDIUM" | "SLOW";
|
|
762
|
-
readonly verify: UnlockFactor;
|
|
763
|
-
};
|
|
764
|
-
type PayResult = {
|
|
765
|
-
readonly kind: "spark";
|
|
766
|
-
readonly transfer: SparkTransfer;
|
|
767
|
-
} | {
|
|
768
|
-
readonly kind: "lightning";
|
|
769
|
-
readonly payment: LightningPayment;
|
|
770
|
-
} | {
|
|
771
|
-
readonly kind: "withdraw";
|
|
772
|
-
readonly exit: CooperativeExitResult;
|
|
773
|
-
} | {
|
|
774
|
-
readonly kind: "lnurl-withdraw";
|
|
775
|
-
readonly invoice: LightningInvoice;
|
|
776
|
-
};
|
|
777
|
-
//#endregion
|
|
778
|
-
//#region src/payments/zap.d.ts
|
|
779
|
-
/** A profile zap names the recipient pubkey; an event zap carries the event it zaps. */
|
|
780
|
-
type ZapRecipient = {
|
|
781
|
-
readonly pubkey: string;
|
|
782
|
-
readonly lightning: string;
|
|
783
|
-
} | {
|
|
784
|
-
readonly event: Event;
|
|
785
|
-
readonly lightning: string;
|
|
786
|
-
};
|
|
787
|
-
type PrepareZapParams = {
|
|
788
|
-
/** Any `NostrSigner` — wallet key, external key, NIP-07/46 — signs the 9734. */
|
|
789
|
-
readonly signer: NostrSigner;
|
|
790
|
-
readonly recipient: ZapRecipient;
|
|
791
|
-
readonly amountSats: number;
|
|
792
|
-
readonly comment?: string | undefined;
|
|
793
|
-
readonly relays: ReadonlyArray<string>;
|
|
794
|
-
readonly network: SparkNetwork;
|
|
795
|
-
};
|
|
796
|
-
type PrepareZapContext = {
|
|
797
|
-
readonly fetch: typeof globalThis.fetch;
|
|
798
|
-
readonly now: () => number;
|
|
799
|
-
};
|
|
800
|
-
/** Everything a payer needs: the signed 9734, the invoice, and the note fields. */
|
|
801
|
-
type PreparedZap = {
|
|
802
|
-
readonly zapRequest: Event;
|
|
803
|
-
readonly invoice: string;
|
|
804
|
-
/** Hex payment hash decoded from the invoice. */
|
|
805
|
-
readonly paymentHash: string;
|
|
806
|
-
/** Millisecond expiry decoded from the invoice. */
|
|
807
|
-
readonly expiresAt: number;
|
|
808
|
-
readonly amountSats: number;
|
|
809
|
-
/** The LNURL service's 9735 signing pubkey. */
|
|
810
|
-
readonly receiptPubkey: string;
|
|
811
|
-
readonly recipientPubkey: string;
|
|
812
|
-
readonly eventId?: string;
|
|
813
|
-
readonly comment?: string;
|
|
814
|
-
/** The lud16 or LNURL as given. */
|
|
815
|
-
readonly lightning: string;
|
|
816
|
-
};
|
|
817
|
-
type PayZapOptions = {
|
|
818
|
-
readonly maxFeeSats: number;
|
|
819
|
-
readonly verify: UnlockFactor;
|
|
820
|
-
readonly now: () => number;
|
|
821
|
-
};
|
|
822
|
-
/** Everything up to payment: resolve LNURL, sign the 9734, request the invoice. */
|
|
823
|
-
export declare function prepareZap(params: PrepareZapParams, context: PrepareZapContext): Promise<PreparedZap>;
|
|
824
|
-
/**
|
|
825
|
-
* Pays a prepared zap through the controller's approve-first path. A nearly-expired invoice is
|
|
826
|
-
* rejected before approval — the user may have sat on the confirm screen since `prepareZap`.
|
|
827
|
-
*/
|
|
828
|
-
export declare function payZap(spark: SparkController, account: SparkAccountRef, prepared: PreparedZap, options: PayZapOptions): Promise<LightningPayment>;
|
|
829
|
-
//#endregion
|
|
830
|
-
//#region src/chains/evm.d.ts
|
|
831
|
-
type EvmFeeTier = "slow" | "normal" | "fast";
|
|
832
|
-
//#endregion
|
|
833
|
-
//#region src/chains/solana.d.ts
|
|
834
|
-
type SolanaFeeTier = "slow" | "normal" | "fast";
|
|
835
|
-
//#endregion
|
|
836
|
-
//#region src/transactions/route.d.ts
|
|
837
|
-
type SignParams = Parameters<ReturnType<typeof chains>["sign"]>[0];
|
|
838
|
-
type AccountRef = SignParams["request"]["account"];
|
|
839
|
-
type DisplayIntent = ReturnType<typeof decodeEvm>;
|
|
840
|
-
type TxState = "draft" | "signed" | "submitted" | "pending" | "confirmed" | "failed" | "rejected" | "dropped" | "replaced";
|
|
841
|
-
type TrackedTransaction = {
|
|
842
|
-
readonly id: string;
|
|
843
|
-
readonly family: "evm" | "solana" | "bitcoin";
|
|
844
|
-
readonly network: string;
|
|
845
|
-
readonly account: string;
|
|
846
|
-
readonly hash: string | undefined;
|
|
847
|
-
readonly state: TxState;
|
|
848
|
-
readonly intent: DisplayIntent | undefined;
|
|
849
|
-
readonly nonce: number;
|
|
850
|
-
/** Solana only — the blockhash expiry that turns an unconfirmed tx `dropped`. */
|
|
851
|
-
readonly lastValidBlockHeight?: number;
|
|
852
|
-
/** EVM replacement — the earlier transaction this one bumps or cancels. */
|
|
853
|
-
readonly replaces?: string;
|
|
854
|
-
/** CPFP — the unconfirmed parent this child pushes. */
|
|
855
|
-
readonly parentId?: string;
|
|
856
|
-
/** Bitcoin build record persisted at send for RBF/CPFP rebuilds. */
|
|
857
|
-
readonly btc?: {
|
|
858
|
-
readonly inputs: ReadonlyArray<{
|
|
859
|
-
readonly txid: string;
|
|
860
|
-
readonly vout: number;
|
|
861
|
-
readonly value: number;
|
|
862
|
-
readonly address: string;
|
|
863
|
-
}>;
|
|
864
|
-
readonly outputs: ReadonlyArray<{
|
|
865
|
-
readonly address: string;
|
|
866
|
-
readonly value: number;
|
|
867
|
-
readonly own: boolean;
|
|
868
|
-
}>;
|
|
869
|
-
readonly vsize: number;
|
|
870
|
-
readonly fee: number;
|
|
871
|
-
readonly feeRate: number;
|
|
872
|
-
};
|
|
873
|
-
readonly submittedAt: number;
|
|
874
|
-
readonly error: string | undefined;
|
|
875
|
-
};
|
|
876
|
-
type SendParams = {
|
|
877
|
-
readonly account: AccountRef;
|
|
878
|
-
readonly network: string;
|
|
879
|
-
readonly to: string;
|
|
880
|
-
readonly amount: bigint;
|
|
881
|
-
/** ERC-20 contract — when set, `to`/`amount` are the transfer recipient/units and value is 0. */
|
|
882
|
-
readonly token?: string;
|
|
883
|
-
readonly fee: EvmFeeTier | SolanaFeeTier;
|
|
884
|
-
/** SPL mint decimals — required when `token` is a Solana mint. */
|
|
885
|
-
readonly decimals?: number;
|
|
886
|
-
readonly verify: SignParams["verify"];
|
|
887
|
-
};
|
|
888
|
-
type Options = {
|
|
889
|
-
readonly wallet: Wallet;
|
|
890
|
-
readonly networks: NetworkController;
|
|
891
|
-
readonly openStore: () => Promise<EngineStore>;
|
|
892
|
-
readonly random: (n: number) => Uint8Array;
|
|
893
|
-
readonly setTimer: (ms: number, fn: () => unknown) => () => void;
|
|
894
|
-
readonly now: () => number;
|
|
895
|
-
readonly logger: EngineLogger;
|
|
896
|
-
readonly pollMs?: number;
|
|
897
|
-
/** Test seam — defaults to the wallet's real chains proxy. */
|
|
898
|
-
readonly chains?: ReturnType<typeof chains>;
|
|
899
|
-
};
|
|
900
|
-
//#endregion
|
|
901
|
-
//#region src/transactions/controller.d.ts
|
|
902
|
-
type TransactionControllerState = {
|
|
903
|
-
readonly txs: Record<string, TrackedTransaction>;
|
|
904
|
-
};
|
|
905
|
-
declare class TransactionController extends Controller<TransactionControllerState> {
|
|
906
|
-
private readonly options;
|
|
907
|
-
private engineStore?;
|
|
908
|
-
private readonly timers;
|
|
909
|
-
private evmRoute;
|
|
910
|
-
private readonly bitcoinRoute;
|
|
911
|
-
private locked;
|
|
912
|
-
constructor(options: Options);
|
|
913
|
-
init(): Promise<void>;
|
|
914
|
-
destroy(): Promise<void>;
|
|
915
|
-
lock(): void;
|
|
916
|
-
private persist;
|
|
917
|
-
private transition;
|
|
918
|
-
private routeCtx;
|
|
919
|
-
send(params: SendParams): Promise<TrackedTransaction>;
|
|
920
|
-
/**
|
|
921
|
-
* Speed up or cancel a pending/submitted EVM transaction at the same nonce — a fresh signature is
|
|
922
|
-
* required and a rejection leaves the original untouched.
|
|
923
|
-
*/
|
|
924
|
-
replace(id: string, mode: "speed-up" | "cancel", verify: SendParams["verify"]): Promise<TrackedTransaction>;
|
|
925
|
-
/**
|
|
926
|
-
* CPFP — spend an unconfirmed tx's own outputs into a higher-fee child so the package mines.
|
|
927
|
-
* Bitcoin only; the child is linked via `parentId`.
|
|
928
|
-
*/
|
|
929
|
-
bumpChild(id: string, targetRate: number, verify: SendParams["verify"]): Promise<TrackedTransaction>;
|
|
930
|
-
private track;
|
|
931
|
-
}
|
|
932
|
-
//#endregion
|
|
933
|
-
//#region src/engine.d.ts
|
|
934
1403
|
type EngineOptions = {
|
|
935
1404
|
readonly wallet: Wallet;
|
|
936
1405
|
/** Every Spark account the engine touches lives on this network. */
|
|
@@ -942,11 +1411,24 @@ type EngineOptions = {
|
|
|
942
1411
|
readonly openStore: () => Promise<EngineStore>;
|
|
943
1412
|
/** Cloud file transport for the backup controller; absent → `unavailable`. */
|
|
944
1413
|
readonly cloud?: CloudStore;
|
|
945
|
-
/**
|
|
1414
|
+
/**
|
|
1415
|
+
* Host endpoints per network (CAIP-2), ordered by preference, for all three chain families: EVM
|
|
1416
|
+
* and Solana JSON-RPC URLs, and for Bitcoin the Esplora base URL.
|
|
1417
|
+
*/
|
|
946
1418
|
readonly rpc?: Readonly<Record<string, ReadonlyArray<string>>>;
|
|
1419
|
+
/**
|
|
1420
|
+
* The wallet gateway: tried first for the networks it serves (read at each unlock) unless a
|
|
1421
|
+
* network has custom endpoints. The install id is sent only to the gateway's origin.
|
|
1422
|
+
*/
|
|
1423
|
+
readonly gateway?: {
|
|
1424
|
+
readonly url: string;
|
|
1425
|
+
readonly installId: string;
|
|
1426
|
+
};
|
|
947
1427
|
/** Injected timer for transaction polling; defaults to setTimeout. */
|
|
1428
|
+
/** Development builds: also accept `http://localhost` as a dApp origin. */
|
|
1429
|
+
readonly allowLocalhostOrigins?: boolean;
|
|
948
1430
|
readonly setTimer?: (ms: number, fn: () => void) => () => void;
|
|
949
|
-
/** Kind-30078 wallet-metadata sync; absent →
|
|
1431
|
+
/** Kind-30078 wallet-metadata sync; absent → no wallet metadata is synced. */
|
|
950
1432
|
readonly metaSync?: MetaSyncConfig;
|
|
951
1433
|
/** Test seam — defaults to the wallet's real spark proxy. */
|
|
952
1434
|
readonly sparkApis?: SparkControllerOptions["spark"];
|
|
@@ -955,52 +1437,50 @@ type WalletEngine = {
|
|
|
955
1437
|
readonly networks: NetworkController;
|
|
956
1438
|
readonly assets: AssetsController;
|
|
957
1439
|
readonly transactions: TransactionController;
|
|
958
|
-
readonly
|
|
1440
|
+
readonly requests: RequestController;
|
|
1441
|
+
readonly addressBook: AddressBookController;
|
|
1442
|
+
readonly connections: ConnectionController;
|
|
1443
|
+
readonly eip1193: Eip1193Handler;
|
|
1444
|
+
/** Read and receive surface; every payment goes through `requests`. */
|
|
1445
|
+
readonly spark: Omit<SparkController, "send" | "payInvoice" | "paySparkInvoice" | "withdraw">;
|
|
959
1446
|
readonly accounts: AccountTreeController;
|
|
960
1447
|
readonly metaSync: MetaSyncController;
|
|
961
1448
|
readonly backup: BackupController;
|
|
962
1449
|
readonly zaps: {
|
|
963
1450
|
readonly prepare: (params: PrepareZapParams) => Promise<PreparedZap>;
|
|
964
|
-
readonly pay: (account: SparkAccountRef, prepared: PreparedZap, options: Omit<PayZapOptions, "now">) => Promise<LightningPayment>;
|
|
965
1451
|
};
|
|
966
1452
|
readonly payments: {
|
|
967
1453
|
readonly parse: (input: string, network: SparkNetwork) => PaymentParse;
|
|
968
1454
|
readonly resolve: (input: string, network: SparkNetwork) => Promise<PaymentParse>;
|
|
969
|
-
|
|
1455
|
+
/** Receives funds from an LNURL-withdraw service; needs no verification factor. */
|
|
1456
|
+
readonly withdrawLnurl: (params: WithdrawLnurlParams) => Promise<{
|
|
1457
|
+
readonly kind: "lnurl-withdraw";
|
|
1458
|
+
readonly invoice: LightningInvoice;
|
|
1459
|
+
}>;
|
|
970
1460
|
};
|
|
971
1461
|
readonly unsubscribe: () => void;
|
|
972
1462
|
};
|
|
973
1463
|
export declare function createWalletEngine(options: EngineOptions): WalletEngine;
|
|
974
|
-
//#endregion
|
|
975
|
-
//#region src/backup/memory.d.ts
|
|
976
1464
|
/** In-memory CloudStore for tests and the playground; swap the Map for cross-engine sharing. */
|
|
977
1465
|
export declare function createMemoryCloudStore(backing?: Map<string, string>): CloudStore;
|
|
978
|
-
//#endregion
|
|
979
|
-
//#region src/spark/errors.d.ts
|
|
980
1466
|
/** SparkController error categories — never carry request bytes or secrets. */
|
|
981
1467
|
type SparkErrorCategory = "network" | "approval-required" | "insufficient-funds" | "rejected" | "internal";
|
|
982
1468
|
export declare class SparkControllerError extends Error {
|
|
983
1469
|
readonly category: SparkErrorCategory;
|
|
984
1470
|
constructor(category: SparkErrorCategory, message: string, cause?: unknown);
|
|
985
1471
|
}
|
|
986
|
-
//#endregion
|
|
987
|
-
//#region src/accounts/errors.d.ts
|
|
988
1472
|
/** Account-tree error categories — messages never carry secrets. */
|
|
989
1473
|
type AccountTreeErrorCategory = "invalid-input" | "rejected" | "not-found" | "locked";
|
|
990
1474
|
export declare class AccountTreeError extends Error {
|
|
991
1475
|
readonly category: AccountTreeErrorCategory;
|
|
992
1476
|
constructor(category: AccountTreeErrorCategory, message: string, cause?: unknown);
|
|
993
1477
|
}
|
|
994
|
-
//#endregion
|
|
995
|
-
//#region src/payments/errors.d.ts
|
|
996
1478
|
/** Payment layer error categories — messages never carry remote or secret content. */
|
|
997
1479
|
type PaymentErrorCategory = "invalid-input" | "network" | "rejected";
|
|
998
1480
|
export declare class PaymentError extends Error {
|
|
999
1481
|
readonly category: PaymentErrorCategory;
|
|
1000
1482
|
constructor(category: PaymentErrorCategory, message: string, cause?: unknown);
|
|
1001
1483
|
}
|
|
1002
|
-
//#endregion
|
|
1003
|
-
//#region src/payments/resolve.d.ts
|
|
1004
1484
|
type ResolveOptions = ParseOptions & {
|
|
1005
1485
|
readonly fetch: typeof globalThis.fetch;
|
|
1006
1486
|
};
|
|
@@ -1010,10 +1490,7 @@ type ResolveOptions = ParseOptions & {
|
|
|
1010
1490
|
* failures throw `PaymentError("network")` — remote error bodies never enter the message.
|
|
1011
1491
|
*/
|
|
1012
1492
|
export declare function resolvePayment(input: string, options: ResolveOptions): Promise<PaymentParse>;
|
|
1013
|
-
//#endregion
|
|
1014
|
-
//#region src/spark/exit-chain-codec.d.ts
|
|
1015
1493
|
export declare function encodeExitChain(chain: SparkExitChain): Uint8Array;
|
|
1016
1494
|
export declare function decodeExitChain(bytes: Uint8Array): SparkExitChain;
|
|
1017
|
-
|
|
1018
|
-
export type { AccountGroup, AccountTreeState, BackupControllerState, BackupErrorCategory, CloudStore, ControllerOptions, EngineCollection, EngineErrorCode, EngineLogger, EngineOptions, EngineStore, EventBus, MetaDoc, MetaDocGroup, MetaDocWallet, MetaSyncConfig, MetaSyncRelayPort, MetaSyncState, MetaSyncWalletStatus, PayParams, PayResult, PayZapOptions, PaymentNote, PaymentOption, PaymentParse, PaymentRequest, PrepareZapContext, PrepareZapParams, PreparedZap, SparkAccountState, SparkActivity, SparkClientFactory, SparkControllerOptions, SparkControllerState, SparkErrorCategory, WalletEngine, ZapRecipient };
|
|
1495
|
+
export type { AccountGroup, AccountTreeState, AddressBookEntry, AddressBookErrorCategory, AddressBookState, AddressFamily, BackupControllerState, BackupErrorCategory, BrowserOrigin, CloudStore, AccountGroup$1 as ConnectionAccountGroup, ConnectionOrigin, ConnectionScope, ConnectionSession, ConnectionState, ControllerOptions, Eip1193Event, Eip1193Request, EngineCollection, EngineErrorCode, EngineLogger, EngineOptions, EngineStore, EventBus, EvmSignInput, MetaDoc, MetaDocGroup, MetaDocTree, MetaDocWallet, MetaSyncConfig, MetaSyncRelayPort, MetaSyncState, MetaSyncWalletStatus, PayInput, PayParams, PaymentNote, PaymentOption, PaymentParse, PaymentRequest, PendingConnection, PendingRequest, PrepareZapContext, PrepareZapParams, PreparedSparkAction, PreparedZap, RequestCheckCode, RequestControllerState, RequestInput, RequestMethod, RequestOrigin, RequestStage, RiskFinding, SignLogEntry, SignLogOutcome, SignatureResult, SparkAccountState, SparkActivity, SparkClientFactory, SparkControllerOptions, SparkControllerState, SparkDepositInput, SparkDisplay, SparkErrorCategory, SparkExitInput, SparkResult, WalletEngine, WithdrawLnurlParams, ZapRecipient };
|
|
1019
1496
|
//# sourceMappingURL=index.d.mts.map
|