@arkade-os/sdk 0.5.0-rc.2 → 0.5.0-rc.21
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 +90 -83
- package/dist/adapters/expo.cjs +5 -6
- package/dist/adapters/expo.d.cts +4 -4
- package/dist/adapters/expo.d.ts +4 -4
- package/dist/adapters/expo.js +3 -4
- package/dist/{asyncStorageTaskQueue-C5rBYlru.d.ts → asyncStorageTaskQueue-aL7K14e4.d.ts} +2 -2
- package/dist/{asyncStorageTaskQueue-BuDvgWh6.d.cts → asyncStorageTaskQueue-x8ok3tJy.d.cts} +2 -2
- package/dist/{chunk-ISO4TI5J.js → chunk-4FDNOLBO.js} +566 -459
- package/dist/chunk-4FDNOLBO.js.map +1 -0
- package/dist/{chunk-JZWLXNHV.cjs → chunk-5XBH5SAL.cjs} +574 -464
- package/dist/chunk-5XBH5SAL.cjs.map +1 -0
- package/dist/{chunk-3R476TDV.js → chunk-CXHJGED6.js} +293 -1071
- package/dist/chunk-CXHJGED6.js.map +1 -0
- package/dist/{chunk-ZRNQV6HV.js → chunk-EXFU6MTA.js} +4578 -4396
- package/dist/chunk-EXFU6MTA.js.map +1 -0
- package/dist/{chunk-43FKNLX4.cjs → chunk-GVF4OCTL.cjs} +357 -1114
- package/dist/chunk-GVF4OCTL.cjs.map +1 -0
- package/dist/{chunk-HLCGYOIH.cjs → chunk-HIZNPHB2.cjs} +37 -36
- package/dist/chunk-HIZNPHB2.cjs.map +1 -0
- package/dist/{chunk-4PKLULWT.js → chunk-JZAEFOE4.js} +109 -246
- package/dist/chunk-JZAEFOE4.js.map +1 -0
- package/dist/{chunk-ZOTXDOS5.js → chunk-LNJPVLIC.js} +30 -29
- package/dist/chunk-LNJPVLIC.js.map +1 -0
- package/dist/{chunk-NVZJSKZS.cjs → chunk-Q7PC3NHX.cjs} +121 -257
- package/dist/chunk-Q7PC3NHX.cjs.map +1 -0
- package/dist/{chunk-GMZZQXV5.cjs → chunk-R5OFJ23O.cjs} +4961 -4767
- package/dist/chunk-R5OFJ23O.cjs.map +1 -0
- package/dist/{chunk-6DNR46C7.js → chunk-S2WWOVFC.js} +7 -5
- package/dist/chunk-S2WWOVFC.js.map +1 -0
- package/dist/{chunk-D25O4EGY.cjs → chunk-VZMLADXQ.cjs} +12 -10
- package/dist/chunk-VZMLADXQ.cjs.map +1 -0
- package/dist/contracts/handlers/index.cjs +9 -10
- package/dist/contracts/handlers/index.d.cts +5 -5
- package/dist/contracts/handlers/index.d.ts +5 -5
- package/dist/contracts/handlers/index.js +2 -3
- package/dist/{delegate-BAX5QftB.d.ts → delegate-BT5iON1T.d.ts} +1 -1
- package/dist/{delegate-1yp1HyP7.d.cts → delegate-u6kXTtWY.d.cts} +1 -1
- package/dist/index-BCnhItOQ.d.cts +639 -0
- package/dist/{index-DUxufw76.d.cts → index-CK5QbTmZ.d.cts} +1387 -2404
- package/dist/{index-DUxufw76.d.ts → index-CK5QbTmZ.d.ts} +1387 -2404
- package/dist/index-D1D4cR-G.d.ts +639 -0
- package/dist/index.cjs +375 -340
- package/dist/index.d.cts +784 -1197
- package/dist/index.d.ts +784 -1197
- package/dist/index.js +4 -5
- package/dist/repositories/realm/index.cjs +201 -106
- package/dist/repositories/realm/index.cjs.map +1 -1
- package/dist/repositories/realm/index.d.cts +28 -16
- package/dist/repositories/realm/index.d.ts +28 -16
- package/dist/repositories/realm/index.js +190 -95
- package/dist/repositories/realm/index.js.map +1 -1
- package/dist/repositories/sqlite/index.cjs +301 -189
- package/dist/repositories/sqlite/index.cjs.map +1 -1
- package/dist/repositories/sqlite/index.d.cts +32 -21
- package/dist/repositories/sqlite/index.d.ts +32 -21
- package/dist/repositories/sqlite/index.js +294 -182
- package/dist/repositories/sqlite/index.js.map +1 -1
- package/dist/{taskRunner-D_iPiZIi.d.ts → taskRunner-BeYR6NpQ.d.ts} +2 -2
- package/dist/{taskRunner-Dr3NStc0.d.cts → taskRunner-Csey3EYJ.d.cts} +2 -2
- package/dist/wallet/expo/background.cjs +14 -15
- package/dist/wallet/expo/background.cjs.map +1 -1
- package/dist/wallet/expo/background.d.cts +10 -16
- package/dist/wallet/expo/background.d.ts +10 -16
- package/dist/wallet/expo/background.js +6 -7
- package/dist/wallet/expo/background.js.map +1 -1
- package/dist/wallet/expo/index.cjs +16 -23
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +6 -9
- package/dist/wallet/expo/index.d.ts +6 -9
- package/dist/wallet/expo/index.js +8 -15
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/wallet-DG3Qmbmt.d.cts +1848 -0
- package/dist/wallet-DzSLMxBZ.d.ts +1848 -0
- package/dist/worker/expo/index.cjs +9 -10
- package/dist/worker/expo/index.cjs.map +1 -1
- package/dist/worker/expo/index.d.cts +6 -6
- package/dist/worker/expo/index.d.ts +6 -6
- package/dist/worker/expo/index.js +5 -6
- package/dist/worker/expo/index.js.map +1 -1
- package/package.json +12 -51
- package/dist/adapters/asyncStorage.cjs +0 -48
- package/dist/adapters/asyncStorage.cjs.map +0 -1
- package/dist/adapters/asyncStorage.d.cts +0 -16
- package/dist/adapters/asyncStorage.d.ts +0 -16
- package/dist/adapters/asyncStorage.js +0 -46
- package/dist/adapters/asyncStorage.js.map +0 -1
- package/dist/adapters/fileSystem.cjs +0 -116
- package/dist/adapters/fileSystem.cjs.map +0 -1
- package/dist/adapters/fileSystem.d.cts +0 -17
- package/dist/adapters/fileSystem.d.ts +0 -17
- package/dist/adapters/fileSystem.js +0 -93
- package/dist/adapters/fileSystem.js.map +0 -1
- package/dist/adapters/indexedDB.cjs +0 -103
- package/dist/adapters/indexedDB.cjs.map +0 -1
- package/dist/adapters/indexedDB.d.cts +0 -18
- package/dist/adapters/indexedDB.d.ts +0 -18
- package/dist/adapters/indexedDB.js +0 -101
- package/dist/adapters/indexedDB.js.map +0 -1
- package/dist/adapters/localStorage.cjs +0 -50
- package/dist/adapters/localStorage.cjs.map +0 -1
- package/dist/adapters/localStorage.d.cts +0 -14
- package/dist/adapters/localStorage.d.ts +0 -14
- package/dist/adapters/localStorage.js +0 -48
- package/dist/adapters/localStorage.js.map +0 -1
- package/dist/chunk-3R476TDV.js.map +0 -1
- package/dist/chunk-43FKNLX4.cjs.map +0 -1
- package/dist/chunk-4PKLULWT.js.map +0 -1
- package/dist/chunk-5BLDMQED.cjs +0 -18
- package/dist/chunk-5BLDMQED.cjs.map +0 -1
- package/dist/chunk-6DNR46C7.js.map +0 -1
- package/dist/chunk-D25O4EGY.cjs.map +0 -1
- package/dist/chunk-GMZZQXV5.cjs.map +0 -1
- package/dist/chunk-HLCGYOIH.cjs.map +0 -1
- package/dist/chunk-ISO4TI5J.js.map +0 -1
- package/dist/chunk-JZWLXNHV.cjs.map +0 -1
- package/dist/chunk-NSBPE2FW.js +0 -15
- package/dist/chunk-NSBPE2FW.js.map +0 -1
- package/dist/chunk-NVZJSKZS.cjs.map +0 -1
- package/dist/chunk-ZOTXDOS5.js.map +0 -1
- package/dist/chunk-ZRNQV6HV.js.map +0 -1
- package/dist/hdWalletCapable-CmEU0NP1.d.ts +0 -2232
- package/dist/hdWalletCapable-eJgaT-ec.d.cts +0 -2232
- package/dist/index-Bem5vKzX.d.ts +0 -850
- package/dist/index-C0IanN1m.d.cts +0 -11
- package/dist/index-C0IanN1m.d.ts +0 -11
- package/dist/index-W_oMcOmG.d.cts +0 -850
|
@@ -0,0 +1,1848 @@
|
|
|
1
|
+
import { W as WalletRepository, P as PageRequest, O as Outpoint, D as PageResult, B as ExtendedVirtualCoin, F as ScriptVtxoCursor, H as ScriptVtxoPageOptions, J as StoredVtxo, K as VtxoRepositoryKey, E as ExtendedCoin, L as TransactionHistoryPageFilter, M as TransactionHistoryPageCursor, h as ArkTransaction, Q as WalletState, a2 as DescriptorProvider, a3 as DescriptorSigningRequest, a4 as Transaction, l as GetNewAddressesOptions, m as NewAddress, a as Identity, w as RelativeTimelock, a5 as Network, a6 as CSVMultisigTapscript, a7 as BatchStartedEvent, a8 as TreeSigningStartedEvent, a9 as TxTree, aa as TreeNoncesEvent, ab as BatchFinalizationEvent, ac as BatchFinalizedEvent, ad as BatchFailedEvent, ae as TreeTxEvent, af as TreeSignatureEvent, o as SettlementEvent, b as WalletConfig, C as ContractRepository, k as IContractManager, ag as IReadonlyWallet, ah as ReadonlyIdentity, ai as OnchainProvider, u as ArkProvider, v as IndexerProvider, aj as DelegateProvider, ak as ReadonlyWalletConfig, X as IntentRepository, _ as VirtualTxRepository, al as ExitCaptureMode, am as ExitDataSource, i as ActivityRegistry, an as IReadonlyAssetManager, ao as ContractSyncState, ap as RecipientArkadeAddressContext, G as GetArkadeInfoOptions, A as ArkadeInfo, c as ArkadeReader, aq as NetworkName, ar as ArkAddress, e as WalletBalance, f as GetVtxosFilter, N as NormalizedExtendedVirtualCoin, g as GetSpendableVtxosFilter, as as ContractWithVtxos, at as selectPendingRecoveryOutpoints, j as Activity, au as Coin, av as ContractManager, aw as ContractManagerConfig, I as IWallet, ax as SettlementConfig, d as ArkadeBroadcaster, q as IAssetManager, ay as VtxoManager, n as IDelegateManager, S as SettleParams, R as Recipient, az as SignerSession, aA as SignedIntent, aB as Intent, p as SendParams, aC as TimeHeight } from './index-CK5QbTmZ.js';
|
|
2
|
+
import { TransactionOutput } from '@scure/btc-signer/psbt.js';
|
|
3
|
+
import { Bytes } from '@scure/btc-signer/utils.js';
|
|
4
|
+
import { D as DefaultVtxo, a as DelegateVtxo } from './delegate-BT5iON1T.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* IndexedDB-based implementation of WalletRepository.
|
|
8
|
+
*/
|
|
9
|
+
declare class IndexedDBWalletRepository implements WalletRepository {
|
|
10
|
+
readonly version: 2;
|
|
11
|
+
private readonly connection;
|
|
12
|
+
constructor(dbName?: string);
|
|
13
|
+
clear(): Promise<void>;
|
|
14
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
15
|
+
getVtxosPage(address: string, page: PageRequest<Outpoint>): Promise<PageResult<ExtendedVirtualCoin, Outpoint>>;
|
|
16
|
+
saveVtxos(address: string, vtxos: ExtendedVirtualCoin[]): Promise<void>;
|
|
17
|
+
deleteVtxos(address: string): Promise<void>;
|
|
18
|
+
getVtxosForScriptPage(script: string, page: PageRequest<ScriptVtxoCursor>, options?: ScriptVtxoPageOptions): Promise<PageResult<StoredVtxo, ScriptVtxoCursor>>;
|
|
19
|
+
saveVtxosForScript(key: VtxoRepositoryKey, vtxos: ExtendedVirtualCoin[]): Promise<void>;
|
|
20
|
+
deleteVtxosForScript(script: string): Promise<void>;
|
|
21
|
+
getUtxosPage(address: string, page: PageRequest<Outpoint>): Promise<PageResult<ExtendedCoin, Outpoint>>;
|
|
22
|
+
private pageByAddress;
|
|
23
|
+
saveUtxos(addressOrBatch: string | ReadonlyMap<string, ExtendedCoin[]>, utxos?: ExtendedCoin[]): Promise<void>;
|
|
24
|
+
deleteUtxos(address: string): Promise<void>;
|
|
25
|
+
getTransactionHistoryPage(filter: TransactionHistoryPageFilter, page: PageRequest<TransactionHistoryPageCursor>): Promise<PageResult<ArkTransaction, TransactionHistoryPageCursor>>;
|
|
26
|
+
saveTransactions(address: string, txs: ArkTransaction[]): Promise<void>;
|
|
27
|
+
deleteTransactions(address: string): Promise<void>;
|
|
28
|
+
getWalletState(): Promise<WalletState | null>;
|
|
29
|
+
saveWalletState(state: WalletState): Promise<void>;
|
|
30
|
+
private getDB;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A {@link DescriptorProvider} decorator that adds a **keyring**: raw
|
|
35
|
+
* private keys imported from outside the wallet's derivation tree, each
|
|
36
|
+
* addressed by a `tr(<pubkey>)` descriptor.
|
|
37
|
+
*
|
|
38
|
+
* Resolution is union-shaped — `signWithDescriptor` /
|
|
39
|
+
* `signMessageWithDescriptor` serve a descriptor from the wrapped
|
|
40
|
+
* provider's derivation tree *or* from the keyring, whichever owns it —
|
|
41
|
+
* so the wallet's existing descriptor routing
|
|
42
|
+
* (`InputSignerRouter`) signs foreign-key contracts with no changes: an
|
|
43
|
+
* imported contract carrying `metadata.signingDescriptor` is signable by
|
|
44
|
+
* construction rather than throwing `MissingSigningDescriptorError`.
|
|
45
|
+
*
|
|
46
|
+
* Allocation is *not* extended: `getNextSigningDescriptor` always
|
|
47
|
+
* delegates to the wrapped provider. The keyring holds foreign keys the
|
|
48
|
+
* wallet was handed; it never mints receive addresses.
|
|
49
|
+
*
|
|
50
|
+
* Lifecycle: entries persist under
|
|
51
|
+
* `WalletRepository.getWalletState().settings.keyring` (same
|
|
52
|
+
* no-migration pattern as `HDDescriptorProvider`), so an import survives
|
|
53
|
+
* the restarts a recovery spans, and {@link deleteKey} purges it when
|
|
54
|
+
* recovery completes. The repository is the source of truth: the async
|
|
55
|
+
* signing/purge APIs converge on sibling instances' imports and purges
|
|
56
|
+
* (see {@link refresh}), so any tab/worker sharing the repo can complete
|
|
57
|
+
* a recovery another one started.
|
|
58
|
+
*
|
|
59
|
+
* **Keys are stored unencrypted.** This is a deliberate, scoped
|
|
60
|
+
* decision: the intended use is a short-lived, purge-on-completion hold
|
|
61
|
+
* of a key that guards funds already destined for this wallet. At-rest
|
|
62
|
+
* encryption is a possible hardening follow-up. Do not use this to hold
|
|
63
|
+
* long-lived key material.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const provider = await KeyringDescriptorProvider.create(hdProvider, walletRepo);
|
|
68
|
+
* const descriptor = await provider.importKey(foreignPrivKey);
|
|
69
|
+
* // descriptor: tr(<x-only pubkey hex>)
|
|
70
|
+
* // ... import a contract with metadata.signingDescriptor = descriptor,
|
|
71
|
+
* // let the wallet's recovery machinery settle it, then:
|
|
72
|
+
* await provider.deleteKey(descriptor);
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare class KeyringDescriptorProvider implements DescriptorProvider {
|
|
76
|
+
/**
|
|
77
|
+
* The wrapped provider. Exposed so callers that need to reach a
|
|
78
|
+
* concrete provider type behind the decorator (e.g. the wallet's
|
|
79
|
+
* restore path, which branches on `HDDescriptorProvider`) can
|
|
80
|
+
* unwrap it rather than mis-classify the decorator.
|
|
81
|
+
*/
|
|
82
|
+
readonly base: DescriptorProvider;
|
|
83
|
+
private readonly walletRepository;
|
|
84
|
+
/**
|
|
85
|
+
* In-memory mirror of the persisted keyring, keyed by x-only pubkey
|
|
86
|
+
* hex. Required because {@link isOurs} is synchronous while
|
|
87
|
+
* persistence is not. The **repository is the source of truth**: the
|
|
88
|
+
* async APIs write through to it and {@link refresh} re-seeds this
|
|
89
|
+
* mirror from it when a signing request names a foreign key the
|
|
90
|
+
* mirror doesn't know — a sibling instance (another tab/worker on
|
|
91
|
+
* the same repo) may have imported it after this instance was
|
|
92
|
+
* constructed. The sync views ({@link isOurs}, {@link hasKey},
|
|
93
|
+
* {@link listKeyringDescriptors}) answer from the last-known
|
|
94
|
+
* snapshot.
|
|
95
|
+
*/
|
|
96
|
+
private readonly keys;
|
|
97
|
+
private constructor();
|
|
98
|
+
/**
|
|
99
|
+
* Wrap `base` with a keyring, loading any previously imported keys
|
|
100
|
+
* from the repository. Unlike `HDDescriptorProvider.create`, this
|
|
101
|
+
* *does* read at construction: `isOurs` is synchronous and must be
|
|
102
|
+
* able to answer for persisted keys from the first call.
|
|
103
|
+
*/
|
|
104
|
+
static create(base: DescriptorProvider, walletRepository: WalletRepository): Promise<KeyringDescriptorProvider>;
|
|
105
|
+
/**
|
|
106
|
+
* Import a raw private key into the keyring and return its
|
|
107
|
+
* `tr(<x-only pubkey>)` descriptor handle. Idempotent: re-importing
|
|
108
|
+
* the same key returns the same descriptor and leaves storage
|
|
109
|
+
* unchanged.
|
|
110
|
+
*/
|
|
111
|
+
importKey(privateKey: Uint8Array): Promise<string>;
|
|
112
|
+
/**
|
|
113
|
+
* Purge a keyring entry. Returns `true` when an entry was removed,
|
|
114
|
+
* `false` when the descriptor was not in the keyring (already
|
|
115
|
+
* purged, or never ours) — so a repeated purge is a safe no-op.
|
|
116
|
+
*
|
|
117
|
+
* Always goes through storage, never trusting the in-memory mirror:
|
|
118
|
+
* the entry may have been imported by a sibling instance after this
|
|
119
|
+
* one was constructed, and skipping the persistent purge on a memory
|
|
120
|
+
* miss would leave that key at rest forever.
|
|
121
|
+
*/
|
|
122
|
+
deleteKey(descriptor: string): Promise<boolean>;
|
|
123
|
+
/** True iff `descriptor` resolves to a key held in the keyring. */
|
|
124
|
+
hasKey(descriptor: string): boolean;
|
|
125
|
+
/** The `tr(<pubkey>)` descriptors of every key currently held. */
|
|
126
|
+
listKeyringDescriptors(): string[];
|
|
127
|
+
/** Allocation is the wrapped provider's job; the keyring never mints. */
|
|
128
|
+
getNextSigningDescriptor(): Promise<string>;
|
|
129
|
+
/** Ours iff the wrapped provider claims it, or the keyring holds it. */
|
|
130
|
+
isOurs(descriptor: string): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Signs each request with the key its descriptor resolves to.
|
|
133
|
+
* Keyring-owned requests are signed here; every other request is
|
|
134
|
+
* handed to the wrapped provider in a single batched call, so a
|
|
135
|
+
* batch-signing identity behind a `StaticDescriptorProvider` still
|
|
136
|
+
* sees one interaction.
|
|
137
|
+
*
|
|
138
|
+
* Results are returned in request order regardless of how the
|
|
139
|
+
* requests split across the two signers.
|
|
140
|
+
*/
|
|
141
|
+
signWithDescriptor(requests: DescriptorSigningRequest[]): Promise<Transaction[]>;
|
|
142
|
+
/** Signs a message with the keyring key, or delegates to the base. */
|
|
143
|
+
signMessageWithDescriptor(descriptor: string, message: Uint8Array, type?: "schnorr" | "ecdsa"): Promise<Uint8Array>;
|
|
144
|
+
/**
|
|
145
|
+
* Split requests into keyring-owned and base-delegated buckets.
|
|
146
|
+
* `mayBeStale` is set when a delegated descriptor is foreign-shaped —
|
|
147
|
+
* a sibling instance may have imported its key after this instance
|
|
148
|
+
* seeded the mirror, so the caller should {@link refresh} once and
|
|
149
|
+
* re-split before trusting the delegation.
|
|
150
|
+
*/
|
|
151
|
+
private splitRequests;
|
|
152
|
+
/**
|
|
153
|
+
* True when `descriptor` is a bare `tr(<pubkey>)` the base provider
|
|
154
|
+
* does not own — the only shape a keyring entry can have, so the only
|
|
155
|
+
* kind of miss a {@link refresh} could turn into a hit.
|
|
156
|
+
*/
|
|
157
|
+
private isForeignShaped;
|
|
158
|
+
/**
|
|
159
|
+
* Re-seed the in-memory mirror from the repository, converging on
|
|
160
|
+
* imports and purges made by sibling instances on the same repo.
|
|
161
|
+
* Full replacement, not a merge, so sibling *deletions* propagate
|
|
162
|
+
* too. Corrupt persisted settings throw, same as {@link create}.
|
|
163
|
+
*
|
|
164
|
+
* Only a *miss* triggers a refresh, so that convergence is one-sided:
|
|
165
|
+
* an entry this instance still believes it holds is never
|
|
166
|
+
* revalidated, and a sibling's purge can linger in this mirror until
|
|
167
|
+
* some unrelated foreign-shaped miss re-seeds it. Harmless today —
|
|
168
|
+
* `deleteKey`'s caller also deletes the contract row carrying the
|
|
169
|
+
* descriptor, so no signing request can name the stale entry — but it
|
|
170
|
+
* means the at-rest purge is not a memory purge for siblings.
|
|
171
|
+
*/
|
|
172
|
+
private refresh;
|
|
173
|
+
/**
|
|
174
|
+
* The keyring key for `descriptor`, or `undefined` when the request
|
|
175
|
+
* belongs to the base provider. Base ownership wins on collision:
|
|
176
|
+
* a key already in the derivation tree keeps its established signing
|
|
177
|
+
* path, so importing it cannot reroute existing contracts.
|
|
178
|
+
*/
|
|
179
|
+
private resolveKey;
|
|
180
|
+
/**
|
|
181
|
+
* Read-modify-write the keyring settings through `updateWalletState`,
|
|
182
|
+
* whose in-process mutex plus cross-context Web Lock keep concurrent
|
|
183
|
+
* imports/purges — including ones driven from other tabs/workers
|
|
184
|
+
* sharing the store — from clobbering each other's entries.
|
|
185
|
+
*/
|
|
186
|
+
private mutate;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Capability a wallet exposes so descriptor-blind consumers (Boltz swaps, other plugins) can bind
|
|
191
|
+
* artifacts to the wallet's current HD index and later enumerate every used index. Probed
|
|
192
|
+
* structurally ({@link isHDWalletCapable}) rather than widening `IWallet`, so plugins keep working
|
|
193
|
+
* against older wallets; a static wallet answers "no HD state" through the same methods.
|
|
194
|
+
*/
|
|
195
|
+
interface HDWalletCapable {
|
|
196
|
+
/**
|
|
197
|
+
* The descriptor at the wallet's current receive index, or `undefined` for
|
|
198
|
+
* static / `auto` wallets and HD wallets that have never rotated. Callers
|
|
199
|
+
* fall back to the identity key.
|
|
200
|
+
*/
|
|
201
|
+
getCurrentSigningDescriptor(): Promise<string | undefined>;
|
|
202
|
+
/**
|
|
203
|
+
* Every descriptor the wallet may hold keys under, ascending by index: the allocation
|
|
204
|
+
* watermark's band plus any descriptor persisted on a contract. Empty for static wallets.
|
|
205
|
+
* `lookAhead` appends that many past the watermark without advancing it, for restore probing.
|
|
206
|
+
*/
|
|
207
|
+
getUsedSigningDescriptors(opts?: {
|
|
208
|
+
lookAhead?: number;
|
|
209
|
+
}): Promise<string[]>;
|
|
210
|
+
/**
|
|
211
|
+
* An {@link Identity} whose keys and signatures are those of `descriptor`; the wallet
|
|
212
|
+
* identity itself when `descriptor` is the identity's own key.
|
|
213
|
+
*
|
|
214
|
+
* Throws {@link ForeignDescriptorError} for a descriptor this wallet cannot sign for — never
|
|
215
|
+
* substitutes another key, which would sign happily and surface only as a rejected tx or a
|
|
216
|
+
* dead script. The returned identity must actually sign (`sign`, `signMessage`,
|
|
217
|
+
* `signerSession`): `contractSigner` refuses a watch-only one as `WalletCannotSignError`,
|
|
218
|
+
* which would otherwise pass every check and throw after the contract is funded.
|
|
219
|
+
*/
|
|
220
|
+
signerForDescriptor(descriptor: string): Promise<Identity>;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Thrown by {@link HDWalletCapable.signerForDescriptor} when the wallet holds no key for the
|
|
224
|
+
* descriptor, so callers can tell "not my key" from transient signing failures.
|
|
225
|
+
*/
|
|
226
|
+
declare class ForeignDescriptorError extends Error {
|
|
227
|
+
readonly descriptor: string;
|
|
228
|
+
readonly name = "ForeignDescriptorError";
|
|
229
|
+
constructor(descriptor: string, options?: {
|
|
230
|
+
cause?: unknown;
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Thrown by `Wallet.getNewAddresses({ forceNew: true })` when there is no HD stream to advance
|
|
235
|
+
* (`walletMode: 'static'` / `'auto'`, or a {@link DescriptorProvider} that declined). Typed
|
|
236
|
+
* rather than a silent repeat, which would surface only as two payers sharing a script.
|
|
237
|
+
*/
|
|
238
|
+
declare class WalletCannotAllocateAddressError extends Error {
|
|
239
|
+
readonly name = "WalletCannotAllocateAddressError";
|
|
240
|
+
constructor(reason: string, options?: {
|
|
241
|
+
cause?: unknown;
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/** Anything that can derive and sign for a descriptor it claims. */
|
|
245
|
+
type DescriptorOwner = Pick<DescriptorProvider, "isOurs" | "signWithDescriptor" | "signMessageWithDescriptor">;
|
|
246
|
+
/**
|
|
247
|
+
* The identity that signs `descriptor`, or {@link ForeignDescriptorError}. Shared by every
|
|
248
|
+
* {@link HDWalletCapable.signerForDescriptor} so page- and worker-side wallets cannot drift into
|
|
249
|
+
* a signer that passes a pubkey check and then throws on every signature, after funding.
|
|
250
|
+
*/
|
|
251
|
+
declare function resolveDescriptorSigner(descriptor: string, identity: Identity, provider?: DescriptorOwner): Promise<Identity>;
|
|
252
|
+
/** Structural type guard for {@link HDWalletCapable}. */
|
|
253
|
+
declare function isHDWalletCapable(value: unknown): value is HDWalletCapable;
|
|
254
|
+
/**
|
|
255
|
+
* Allocating a *fresh* index — strictly more than {@link HDWalletCapable}'s descriptor awareness.
|
|
256
|
+
* A separate probe because widening that guard would silently demote every wallet implementing
|
|
257
|
+
* only its original surface (including older SDKs') from HD-capable to static.
|
|
258
|
+
*/
|
|
259
|
+
interface HDAllocationCapable {
|
|
260
|
+
/**
|
|
261
|
+
* The signing descriptor a new artifact (swap, invoice, contract) should bind to. **The
|
|
262
|
+
* wallet decides**: an HD wallet allocates a fresh index, advancing the watermark; a static
|
|
263
|
+
* wallet answers with its one `tr(pubkey)` every time. Consumers must not probe the wallet's
|
|
264
|
+
* shape or mint key material; they use the answer with
|
|
265
|
+
* {@link HDWalletCapable.signerForDescriptor}.
|
|
266
|
+
*
|
|
267
|
+
* `undefined` only for implementations that genuinely cannot answer (`Wallet` always
|
|
268
|
+
* answers); callers then fall back to the identity key — never a random one.
|
|
269
|
+
*
|
|
270
|
+
* Unlike {@link HDWalletCapable.getCurrentSigningDescriptor}, which peeks (two artifacts bound
|
|
271
|
+
* to a peek share a key). Per-call uniqueness is a wallet property, so anything deriving
|
|
272
|
+
* per-artifact secrets must check the descriptor's shape, not the wallet's.
|
|
273
|
+
*/
|
|
274
|
+
getNextSigningDescriptor(): Promise<string | undefined>;
|
|
275
|
+
/**
|
|
276
|
+
* Move the allocation watermark to `descriptor`'s index so later allocations cannot reissue
|
|
277
|
+
* it. Monotonic; a static wallet accepts its own descriptor as a no-op.
|
|
278
|
+
*
|
|
279
|
+
* Throws on a descriptor this wallet cannot derive, or an HD descriptor with no parseable
|
|
280
|
+
* trailing index: mapping those to index 0 would let a restored artifact's index be reissued.
|
|
281
|
+
*/
|
|
282
|
+
advanceSigningDescriptorWatermark(descriptor: string): Promise<void>;
|
|
283
|
+
}
|
|
284
|
+
/** Structural type guard for {@link HDAllocationCapable}. */
|
|
285
|
+
declare function isHDAllocationCapable(value: unknown): value is HDAllocationCapable;
|
|
286
|
+
/**
|
|
287
|
+
* Minting addresses to hand out: beyond {@link HDAllocationCapable}'s bare index, the wallet
|
|
288
|
+
* builds the scripts, persists them as watched contracts, and reports the rows. A third probe
|
|
289
|
+
* for the same no-silent-demotion reason.
|
|
290
|
+
*/
|
|
291
|
+
interface AddressAllocationCapable {
|
|
292
|
+
/**
|
|
293
|
+
* Fresh addresses of each requested type from one newly allocated HD index, persisted and
|
|
294
|
+
* watched. An HD wallet burns an index; a wallet with no stream answers with its existing
|
|
295
|
+
* display addresses or, under `forceNew`, throws {@link WalletCannotAllocateAddressError}.
|
|
296
|
+
*
|
|
297
|
+
* Unlike {@link HDAllocationCapable.getNextSigningDescriptor}, allocation and script
|
|
298
|
+
* registration happen together: split across a process boundary, a failed registration
|
|
299
|
+
* leaves a burnt index and an unwatched address.
|
|
300
|
+
*/
|
|
301
|
+
getNewAddresses(opts?: GetNewAddressesOptions): Promise<NewAddress[]>;
|
|
302
|
+
}
|
|
303
|
+
/** Structural type guard for {@link AddressAllocationCapable}. */
|
|
304
|
+
declare function isAddressAllocationCapable(value: unknown): value is AddressAllocationCapable;
|
|
305
|
+
|
|
306
|
+
/** Wall-clock floor for `batchExpiry` outside regtest. */
|
|
307
|
+
declare const DEFAULT_MIN_BATCH_EXPIRY_SECONDS = 86400n;
|
|
308
|
+
/** Wall-clock floor for `batchExpiry` on regtest (~10 blocks). */
|
|
309
|
+
declare const REGTEST_MIN_BATCH_EXPIRY_SECONDS = 6000n;
|
|
310
|
+
/** Bounds applied to a server-supplied `BatchStartedEvent.batchExpiry`. */
|
|
311
|
+
type BatchExpiryPolicy = {
|
|
312
|
+
/** Minimum wall-clock delay in seconds, after normalization. */
|
|
313
|
+
minSeconds: bigint;
|
|
314
|
+
/**
|
|
315
|
+
* Reject block-typed timelocks. Mirrors arkd, which allows a block-typed
|
|
316
|
+
* vtxo tree expiry only on regtest.
|
|
317
|
+
*/
|
|
318
|
+
requireSeconds: boolean;
|
|
319
|
+
/** When advertised by the operator, `batchExpiry` must equal it exactly. */
|
|
320
|
+
advertisedVtxoTreeExpiry?: bigint;
|
|
321
|
+
};
|
|
322
|
+
/**
|
|
323
|
+
* Default policy for a network.
|
|
324
|
+
*
|
|
325
|
+
* Derive it from the locally held {@link Network} — pinned at wallet setup —
|
|
326
|
+
* rather than from a per-round server field, so the permissive regtest branch
|
|
327
|
+
* can't be selected by the operator at event time.
|
|
328
|
+
*/
|
|
329
|
+
declare function defaultBatchExpiryPolicy(network: Network): BatchExpiryPolicy;
|
|
330
|
+
/** Resolve a policy for `network`, applying any caller overrides on top. */
|
|
331
|
+
declare function resolveBatchExpiryPolicy(network: Network, overrides?: Partial<BatchExpiryPolicy>): BatchExpiryPolicy;
|
|
332
|
+
/**
|
|
333
|
+
* Check a server-supplied batch expiry against `policy` and return the timelock
|
|
334
|
+
* to commit to.
|
|
335
|
+
*
|
|
336
|
+
* The sweep leaf of the shared batch output is derived from this value, so it
|
|
337
|
+
* is never reconstructible from anything else the server sends: validating the
|
|
338
|
+
* tree only proves it is consistent with whatever value was chosen. Callers
|
|
339
|
+
* must encode the returned timelock rather than re-deriving their own.
|
|
340
|
+
*
|
|
341
|
+
* @throws {ServerResponseMismatchError} if the value is out of policy.
|
|
342
|
+
*/
|
|
343
|
+
declare function assertValidBatchExpiry(batchExpiry: bigint, policy: BatchExpiryPolicy): RelativeTimelock;
|
|
344
|
+
|
|
345
|
+
/** Wall-clock floor for the checkpoint exit delay outside regtest. Matches arkd's own default. */
|
|
346
|
+
declare const DEFAULT_MIN_CHECKPOINT_EXIT_DELAY_SECONDS = 86400n;
|
|
347
|
+
/**
|
|
348
|
+
* Wall-clock floor for the checkpoint exit delay on regtest (~2 blocks nominal).
|
|
349
|
+
*
|
|
350
|
+
* Deliberately lower than {@link REGTEST_MIN_BATCH_EXPIRY_SECONDS "../wallet/batchExpiry"}: sized
|
|
351
|
+
* to clear a 5-block `ARKD_CHECKPOINT_EXIT_DELAY` while still rejecting a 1-block attack. Could be
|
|
352
|
+
* tightened once no external regtest deployment is known to rely on the lower bound.
|
|
353
|
+
*/
|
|
354
|
+
declare const REGTEST_MIN_CHECKPOINT_EXIT_DELAY_SECONDS = 1200n;
|
|
355
|
+
/**
|
|
356
|
+
* Wall-clock floor for the checkpoint exit delay on mutinynet: exactly the hosted Arkade Service's
|
|
357
|
+
* advertised 4096s (8 * 512) CSV, sized for ~30s blocks.
|
|
358
|
+
*/
|
|
359
|
+
declare const MUTINYNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS = 4096n;
|
|
360
|
+
/**
|
|
361
|
+
* Wall-clock floor for the checkpoint exit delay on signet: the hosted Arkade Service's advertised
|
|
362
|
+
* 86016s (168 * 512), i.e. 24h rounded down to BIP-68's 512s granularity (86400 is not a multiple
|
|
363
|
+
* of 512, so it cannot be encoded). That is 384s under the default floor.
|
|
364
|
+
*/
|
|
365
|
+
declare const SIGNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS = 86016n;
|
|
366
|
+
/** Bounds applied to a server-supplied `ArkadeInfo.checkpointTapscript`. */
|
|
367
|
+
type CheckpointExitDelayPolicy = {
|
|
368
|
+
/** Minimum wall-clock delay in seconds, after normalization. */
|
|
369
|
+
minSeconds: bigint;
|
|
370
|
+
/** Reject block-typed timelocks. Mirrors arkd, which allows them only on regtest. */
|
|
371
|
+
requireSeconds: boolean;
|
|
372
|
+
/**
|
|
373
|
+
* When set, the script's embedded pubkey must equal this x-only key.
|
|
374
|
+
*
|
|
375
|
+
* arkd always builds the checkpoint tapscript from its own `forfeitPubkey`, so pass the one the
|
|
376
|
+
* caller already trusts: pinned wallet state where it exists, otherwise the same `ArkadeInfo`
|
|
377
|
+
* response's `forfeitPubkey` as a self-consistency check.
|
|
378
|
+
*/
|
|
379
|
+
advertisedForfeitPubkey?: Bytes;
|
|
380
|
+
};
|
|
381
|
+
/**
|
|
382
|
+
* Default policy for a network. Derived from the locally pinned {@link Network}, not server data,
|
|
383
|
+
* so the operator cannot select the permissive regtest branch.
|
|
384
|
+
*/
|
|
385
|
+
declare function defaultCheckpointExitDelayPolicy(network: Network): CheckpointExitDelayPolicy;
|
|
386
|
+
/** Resolve a policy for `network`, applying any caller overrides on top. */
|
|
387
|
+
declare function resolveCheckpointExitDelayPolicy(network: Network, overrides?: Partial<CheckpointExitDelayPolicy>): CheckpointExitDelayPolicy;
|
|
388
|
+
/**
|
|
389
|
+
* Decode and validate a server-supplied `checkpointTapscript` against `policy`.
|
|
390
|
+
*
|
|
391
|
+
* Every offchain send/claim builds its checkpoint outputs' server-claim leaf from this script, so
|
|
392
|
+
* a sub-floor or wrong-pubkey value lets the operator sweep an in-flight checkpoint before it
|
|
393
|
+
* settles. This is the sole gate: callers must use the returned script, not decode their own.
|
|
394
|
+
*
|
|
395
|
+
* @throws {ServerResponseMismatchError} if the script fails to decode, its
|
|
396
|
+
* timelock is out of policy, or its pubkey does not match
|
|
397
|
+
* `policy.advertisedForfeitPubkey` (when set).
|
|
398
|
+
*/
|
|
399
|
+
declare function assertValidServerUnrollScript(checkpointTapscript: string, policy: CheckpointExitDelayPolicy): CSVMultisigTapscript.Type;
|
|
400
|
+
|
|
401
|
+
declare class ArkError extends Error {
|
|
402
|
+
readonly code: number;
|
|
403
|
+
readonly message: string;
|
|
404
|
+
readonly name: string;
|
|
405
|
+
readonly metadata?: Record<string, string> | undefined;
|
|
406
|
+
constructor(code: number, message: string, name: string, metadata?: Record<string, string> | undefined);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Structured arkd error `name`s the SDK branches on, centralized so call sites don't
|
|
410
|
+
* hardcode string literals. Not an exhaustive mirror of the server's codes — only the
|
|
411
|
+
* ones the SDK acts on.
|
|
412
|
+
*/
|
|
413
|
+
declare const ArkErrorName: {
|
|
414
|
+
readonly DIGEST_MISMATCH: "DIGEST_MISMATCH";
|
|
415
|
+
readonly VTXO_ALREADY_SPENT: "VTXO_ALREADY_SPENT";
|
|
416
|
+
readonly INVALID_TX_FILTER: "INVALID_TX_FILTER";
|
|
417
|
+
readonly TX_FILTERS_LIMIT_EXCEEDED: "TX_FILTERS_LIMIT_EXCEEDED";
|
|
418
|
+
/**
|
|
419
|
+
* A CLTV closure was spent before its absolute locktime matured. `submitTx` only, with
|
|
420
|
+
* metadata `{ locktime, current_locktime, type: "height" | "time" }`. Self-healing, so defer
|
|
421
|
+
* and retry: the server matures a seconds-locktime against the **chain tip block's
|
|
422
|
+
* timestamp**, not wall clock, so a prompt spend is rejected until a later block lands.
|
|
423
|
+
*/
|
|
424
|
+
readonly FORFEIT_CLOSURE_LOCKED: "FORFEIT_CLOSURE_LOCKED";
|
|
425
|
+
readonly INVALID_INTENT_PROOF: "INVALID_INTENT_PROOF";
|
|
426
|
+
};
|
|
427
|
+
type ArkErrorName = (typeof ArkErrorName)[keyof typeof ArkErrorName];
|
|
428
|
+
/**
|
|
429
|
+
* Type guard for a structured {@link ArkError}, optionally narrowing to a cataloged
|
|
430
|
+
* {@link ArkErrorName}; for an uncataloged name, add it there or compare `err.name` after the
|
|
431
|
+
* one-argument form.
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* if (isArkError(maybeArkError(err), ArkErrorName.DIGEST_MISMATCH)) { ... }
|
|
435
|
+
*/
|
|
436
|
+
declare function isArkError(error: unknown, name?: ArkErrorName): error is ArkError;
|
|
437
|
+
/**
|
|
438
|
+
* Which remote dependency an availability failure refers to; labels the
|
|
439
|
+
* {@link ProviderUnavailableError} message and `ProviderConnectionState`. Deliberately *not* a
|
|
440
|
+
* field on the error: structured clone across the service-worker `postMessage` boundary keeps
|
|
441
|
+
* `message`, `stack` and `cause` but drops own-properties and normalizes a custom `name` to
|
|
442
|
+
* `"Error"`.
|
|
443
|
+
*/
|
|
444
|
+
type ProviderKind = "arkade" | "indexer";
|
|
445
|
+
/**
|
|
446
|
+
* A remote provider (Arkade operator or its indexer) is temporarily unreachable: transport
|
|
447
|
+
* failure, timeout, or a 5xx/429. Retryable, unlike terminal config/auth/schema errors, which
|
|
448
|
+
* stay a plain `Error`/{@link ArkError}. The low-level error is kept as {@link Error.cause}.
|
|
449
|
+
*/
|
|
450
|
+
declare class ProviderUnavailableError extends Error {
|
|
451
|
+
/** Always `true`: this error type only ever wraps retryable conditions. */
|
|
452
|
+
readonly retryable = true;
|
|
453
|
+
constructor(message: string, options?: {
|
|
454
|
+
cause?: unknown;
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* A response doesn't reconcile with what the SDK submitted or validated (a checkpoint txid not
|
|
459
|
+
* among those submitted, a commitment tx differing from the one validated at tree signing).
|
|
460
|
+
* Terminal: the two are equal by construction in a well-formed exchange. `retryable` and `name`
|
|
461
|
+
* don't cross the SW boundary (see {@link ProviderKind}), so every distinguishing detail belongs
|
|
462
|
+
* in `message`.
|
|
463
|
+
*/
|
|
464
|
+
declare class ServerResponseMismatchError extends Error {
|
|
465
|
+
readonly retryable = false;
|
|
466
|
+
constructor(message: string, options?: {
|
|
467
|
+
cause?: unknown;
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Try to convert an error to an ArkError class, returning undefined if the error is not an ArkError
|
|
472
|
+
* @param error - The error to parse
|
|
473
|
+
* @returns The parsed ArkError, or undefined if the error is not an ArkError
|
|
474
|
+
*/
|
|
475
|
+
declare function maybeArkError(error: any): ArkError | undefined;
|
|
476
|
+
|
|
477
|
+
/** Where the {@link ArkadeInfo} used to construct a wallet came from. */
|
|
478
|
+
type ServerInfoSource = "live" | "cache";
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Batch namespace provides utilities for joining and processing batch session.
|
|
482
|
+
* The batch settlement process involves multiple events, this namespace provides abstractions and types to handle them.
|
|
483
|
+
* @see https://docs.arkadeos.com/learn/pillars/batch-swaps
|
|
484
|
+
* @example
|
|
485
|
+
* ```typescript
|
|
486
|
+
* // use wallet handler or create a custom one
|
|
487
|
+
* const handler = wallet.createBatchHandler(intentId, inputs, expectedRecipients, musig2session);
|
|
488
|
+
*
|
|
489
|
+
* const abortController = new AbortController();
|
|
490
|
+
* // Get event stream from the Arkade provider
|
|
491
|
+
* const eventStream = arkProvider.getEventStream(
|
|
492
|
+
* abortController.signal,
|
|
493
|
+
* ['your-topic-1', 'your-topic-2']
|
|
494
|
+
* );
|
|
495
|
+
*
|
|
496
|
+
* // Join the batch and process events
|
|
497
|
+
* try {
|
|
498
|
+
* const commitmentTxid = await Batch.join(eventStream, handler);
|
|
499
|
+
* console.log('Batch completed with commitment:', commitmentTxid);
|
|
500
|
+
* } catch (error) {
|
|
501
|
+
* console.error('Batch processing failed:', error);
|
|
502
|
+
* } finally {
|
|
503
|
+
* abortController.abort();
|
|
504
|
+
* }
|
|
505
|
+
* ```
|
|
506
|
+
*/
|
|
507
|
+
declare namespace Batch {
|
|
508
|
+
interface Handler {
|
|
509
|
+
/**
|
|
510
|
+
* Called on BatchStarted event.
|
|
511
|
+
* @returns { skip: boolean } indicating whether the batch should be skipped or not.
|
|
512
|
+
*/
|
|
513
|
+
onBatchStarted(event: BatchStartedEvent): Promise<{
|
|
514
|
+
skip: boolean;
|
|
515
|
+
}>;
|
|
516
|
+
/**
|
|
517
|
+
* Called when tree signing starts.
|
|
518
|
+
* @param event The tree signing started event.
|
|
519
|
+
* @param vtxoTree The unsigned virtual output tree, reconstructed from the TreeTxEvent events.
|
|
520
|
+
* @returns Promise resolving to a boolean indicating whether to continue processing.
|
|
521
|
+
*/
|
|
522
|
+
onTreeSigningStarted(event: TreeSigningStartedEvent, vtxoTree: TxTree): Promise<{
|
|
523
|
+
skip: boolean;
|
|
524
|
+
}>;
|
|
525
|
+
/**
|
|
526
|
+
* Called when tree nonces are received.
|
|
527
|
+
* @param event The tree nonces event.
|
|
528
|
+
* @returns Promise resolving to a boolean indicating whether signing is complete.
|
|
529
|
+
*/
|
|
530
|
+
onTreeNonces(event: TreeNoncesEvent): Promise<{
|
|
531
|
+
fullySigned: boolean;
|
|
532
|
+
}>;
|
|
533
|
+
/**
|
|
534
|
+
* Called during batch finalization.
|
|
535
|
+
* @param event The batch finalization event.
|
|
536
|
+
* @param vtxoTree The signed virtual output tree, reconstructed from the TreeTxEvent events.
|
|
537
|
+
* @param connectorTree The connector transaction tree, reconstructed from the TreeTxEvent events.
|
|
538
|
+
*/
|
|
539
|
+
onBatchFinalization(event: BatchFinalizationEvent, vtxoTree?: TxTree, connectorTree?: TxTree): Promise<void>;
|
|
540
|
+
/**
|
|
541
|
+
* Called when batch finalization completes successfully.
|
|
542
|
+
*
|
|
543
|
+
* @param event - Batch finalized event
|
|
544
|
+
*/
|
|
545
|
+
onBatchFinalized?(event: BatchFinalizedEvent): Promise<void>;
|
|
546
|
+
/**
|
|
547
|
+
* Called when batch processing fails.
|
|
548
|
+
*
|
|
549
|
+
* @param event - Batch failed event
|
|
550
|
+
*/
|
|
551
|
+
onBatchFailed?(event: BatchFailedEvent): Promise<void>;
|
|
552
|
+
/**
|
|
553
|
+
* Called for each virtual output tree transaction chunk received during batch processing.
|
|
554
|
+
*
|
|
555
|
+
* @param event - Tree transaction event
|
|
556
|
+
*/
|
|
557
|
+
onTreeTxEvent?(event: TreeTxEvent): Promise<void>;
|
|
558
|
+
/**
|
|
559
|
+
* Called for each tree signature event received during batch processing.
|
|
560
|
+
*
|
|
561
|
+
* @param event - Tree signature event
|
|
562
|
+
*/
|
|
563
|
+
onTreeSignatureEvent?(event: TreeSignatureEvent): Promise<void>;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Options for the join function.
|
|
567
|
+
*
|
|
568
|
+
* @property abortController - Abort controller used to cancel batch processing.
|
|
569
|
+
* @property skipVtxoTreeSigning - Ignore events related to the virtual output tree musig2 signing session.
|
|
570
|
+
* @property eventCallback - Callback invoked for each settlement event received while joining the batch.
|
|
571
|
+
*/
|
|
572
|
+
type JoinOptions = Partial<{
|
|
573
|
+
abortController: AbortController;
|
|
574
|
+
skipVtxoTreeSigning: boolean;
|
|
575
|
+
eventCallback: (event: SettlementEvent) => Promise<void>;
|
|
576
|
+
}>;
|
|
577
|
+
/**
|
|
578
|
+
* Start the state machine that will process the batch events and join a batch.
|
|
579
|
+
* @param eventIterator - The events stream to process.
|
|
580
|
+
* @param handler - How to react to events.
|
|
581
|
+
* @param options - Options.
|
|
582
|
+
*/
|
|
583
|
+
function join(eventIterator: AsyncIterableIterator<SettlementEvent>, handler: Handler, options?: JoinOptions): Promise<string>;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Inputs a {@link ReceiveRotatorFactory} gets at boot to find the current display contract or
|
|
588
|
+
* allocate a fresh descriptor. Allocation only: `resolveBoot` rebuilds the tapscript afterwards.
|
|
589
|
+
*/
|
|
590
|
+
interface ReceiveRotatorBootOpts {
|
|
591
|
+
walletRepository: WalletRepository;
|
|
592
|
+
contractRepository: ContractRepository;
|
|
593
|
+
serverPubKey: Uint8Array;
|
|
594
|
+
/** When set, only this contract family is considered for the current display contract. */
|
|
595
|
+
expectedContractType?: "default" | "delegate";
|
|
596
|
+
/**
|
|
597
|
+
* The wallet's baseline (index-0) x-only receive pubkey, used by {@link
|
|
598
|
+
* WalletReceiveRotator.defaultBoot} when no tagged receive row exists. Such a wallet never
|
|
599
|
+
* rotated L2, and the raw watermark can't be used: boarding shares the HD index stream, so a
|
|
600
|
+
* boarding-only allocation may have advanced it.
|
|
601
|
+
*/
|
|
602
|
+
baselineReceivePubKey?: Uint8Array;
|
|
603
|
+
/** Receives rotation-failure and backoff diagnostics. Defaults to `console`. */
|
|
604
|
+
logger?: Logger;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Output of {@link ReceiveRotatorFactory.createReceiveRotator}: the rotator plus the receive
|
|
608
|
+
* pubkey resolved at boot (existing tagged display contract's, or freshly allocated).
|
|
609
|
+
*/
|
|
610
|
+
interface ReceiveRotatorBoot {
|
|
611
|
+
rotator: WalletReceiveRotator;
|
|
612
|
+
receivePubkey: Uint8Array;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* What {@link WalletReceiveRotator.resolveBoot} returns: the rotator, the offchain tapscript to
|
|
616
|
+
* use (rebuilt to the boot pubkey if it differs), and the provider, which the wallet keeps so
|
|
617
|
+
* spends route per-input signing through {@link DescriptorProvider.signWithDescriptor}.
|
|
618
|
+
*/
|
|
619
|
+
interface ReceiveRotatorBootResult {
|
|
620
|
+
rotator: WalletReceiveRotator;
|
|
621
|
+
offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script;
|
|
622
|
+
provider: DescriptorProvider;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Opt-in {@link DescriptorProvider} extension for providers driving HD receive rotation
|
|
626
|
+
* (implemented by {@link HDDescriptorProvider}). Kept out of the core interface so
|
|
627
|
+
* allocate-and-sign providers needn't know the receive lifecycle; without it the wallet uses
|
|
628
|
+
* {@link WalletReceiveRotator.defaultBoot}.
|
|
629
|
+
*/
|
|
630
|
+
interface ReceiveRotatorFactory {
|
|
631
|
+
createReceiveRotator(opts: ReceiveRotatorBootOpts): Promise<ReceiveRotatorBoot | undefined>;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Parse the trailing HD child index from a materialized signing descriptor
|
|
635
|
+
* (`tr(...xpub.../0/<index>)`). Returns 0 when absent or unparseable: restore registers the
|
|
636
|
+
* index-0 baseline untagged, so a missing descriptor legitimately means 0.
|
|
637
|
+
*/
|
|
638
|
+
declare function signingDescriptorIndex(descriptor: unknown): number;
|
|
639
|
+
/**
|
|
640
|
+
* Strict {@link signingDescriptorIndex}: `undefined` instead of the 0 fallback, for callers
|
|
641
|
+
* (e.g. watermark moves) where mapping "unparseable" to 0 would silently do nothing.
|
|
642
|
+
*/
|
|
643
|
+
declare function strictSigningDescriptorIndex(descriptor: string): number | undefined;
|
|
644
|
+
/** Minimal logging surface the rotator needs; `console` or any structured logger satisfies it. */
|
|
645
|
+
interface Logger {
|
|
646
|
+
error(message: string, ...args: unknown[]): void;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* The wallet surface the rotator needs at runtime. An interface to avoid a circular dependency on
|
|
650
|
+
* `wallet.ts`; `Wallet` satisfies it structurally.
|
|
651
|
+
*/
|
|
652
|
+
interface RotatableWallet {
|
|
653
|
+
readonly defaultContractScript: string;
|
|
654
|
+
readonly network: {
|
|
655
|
+
hrp: string;
|
|
656
|
+
};
|
|
657
|
+
readonly arkServerPublicKey: Uint8Array;
|
|
658
|
+
readonly offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script;
|
|
659
|
+
/**
|
|
660
|
+
* @internal Sole sanctioned write path for `offchainTapscript` after construction; called
|
|
661
|
+
* once per rotation after the new display contract is persisted.
|
|
662
|
+
*/
|
|
663
|
+
setOffchainTapscriptForRotation(tapscript: DefaultVtxo.Script | DelegateVtxo.Script): void;
|
|
664
|
+
getContractManager(): Promise<IContractManager>;
|
|
665
|
+
getAddress(): Promise<string>;
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Owns the wallet's HD receive-rotation lifecycle; exists only when `walletMode` resolves to a
|
|
669
|
+
* {@link DescriptorProvider}.
|
|
670
|
+
*
|
|
671
|
+
* 1. `resolveBoot()` (before Wallet construction): reuse the display contract's pubkey or
|
|
672
|
+
* allocate the first descriptor.
|
|
673
|
+
* 2. `install(wallet)`: subscribe to `vtxo_received` and rotate on matching events.
|
|
674
|
+
* 3. `dispose()`: unsubscribe and drain any in-flight rotation.
|
|
675
|
+
*
|
|
676
|
+
* NArk parity: the provider is a pure allocator; the current address comes from the contract
|
|
677
|
+
* repository, not the provider.
|
|
678
|
+
*/
|
|
679
|
+
declare class WalletReceiveRotator {
|
|
680
|
+
private readonly provider;
|
|
681
|
+
private unsubscribe?;
|
|
682
|
+
private chain;
|
|
683
|
+
/**
|
|
684
|
+
* Script of the latest tagged display contract, retired by the next `rotate()`. `undefined`
|
|
685
|
+
* means the untagged index-0 baseline is displayed, which must NOT be deactivated.
|
|
686
|
+
*/
|
|
687
|
+
private currentTaggedScript;
|
|
688
|
+
/** Drives exponential backoff so a broken provider isn't hammered on every inbound VTXO. */
|
|
689
|
+
private consecutiveFailures;
|
|
690
|
+
/** Unix ms before which `vtxo_received` events skip rotation; 0 = no backoff. */
|
|
691
|
+
private nextRotationAllowedAt;
|
|
692
|
+
private readonly logger;
|
|
693
|
+
private constructor();
|
|
694
|
+
/**
|
|
695
|
+
* Resolve `walletMode` to a provider and build the rotator (via its
|
|
696
|
+
* {@link ReceiveRotatorFactory}, else {@link defaultBoot}). Returns `undefined` for the
|
|
697
|
+
* static path.
|
|
698
|
+
*
|
|
699
|
+
* Resolution errors propagate for `'hd'` and explicit providers (degrading would hide
|
|
700
|
+
* misconfig); a {@link NonRangeableDescriptorError} is swallowed only under `'auto'`, for
|
|
701
|
+
* back-compat with identities whose descriptor isn't rangeable.
|
|
702
|
+
*/
|
|
703
|
+
static resolveBoot(config: WalletConfig, setup: ReceiveRotatorBootOpts & {
|
|
704
|
+
offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script;
|
|
705
|
+
}): Promise<ReceiveRotatorBootResult | undefined>;
|
|
706
|
+
/**
|
|
707
|
+
* Default boot any {@link ReceiveRotatorFactory.createReceiveRotator} can delegate to: take
|
|
708
|
+
* the current display contract from the repository, else allocate/derive the receive pubkey.
|
|
709
|
+
* Tapscript construction is deliberately left to `resolveBoot`.
|
|
710
|
+
*/
|
|
711
|
+
static defaultBoot(provider: DescriptorProvider, opts: ReceiveRotatorBootOpts): Promise<ReceiveRotatorBoot>;
|
|
712
|
+
/**
|
|
713
|
+
* Subscribe to `vtxo_received` and rotate whenever the current display contract receives
|
|
714
|
+
* funds. Old display contracts stay watched, so earlier shared addresses keep crediting.
|
|
715
|
+
*/
|
|
716
|
+
install(wallet: RotatableWallet): Promise<void>;
|
|
717
|
+
/**
|
|
718
|
+
* One rotation attempt with exponential backoff. Errors are logged, not rethrown, so `chain`
|
|
719
|
+
* never rejects and the next `vtxo_received` still runs.
|
|
720
|
+
*/
|
|
721
|
+
private runRotateWithBackoff;
|
|
722
|
+
/** Wait for any in-flight rotation to complete (mainly for tests). */
|
|
723
|
+
drain(): Promise<void>;
|
|
724
|
+
/**
|
|
725
|
+
* Run `fn` on the rotation chain. {@link Wallet.rotateServerSigner} uses it because both it
|
|
726
|
+
* and `rotate()` swap `offchainTapscript`; interleaving could tear the visible receive state.
|
|
727
|
+
* The chain advances even if `fn` rejects (the caller still sees the rejection).
|
|
728
|
+
*/
|
|
729
|
+
runExclusive<T>(fn: () => Promise<T>): Promise<T>;
|
|
730
|
+
/**
|
|
731
|
+
* Unsubscribe first so no late event queues work, then drain so an in-flight
|
|
732
|
+
* `createContract` finishes before the contract manager disposes.
|
|
733
|
+
*/
|
|
734
|
+
dispose(): Promise<void>;
|
|
735
|
+
/**
|
|
736
|
+
* Allocate the next descriptor, register it as the new tagged display contract (same
|
|
737
|
+
* default/delegate shape), swap it in, and mark the previous tagged one `inactive` (still
|
|
738
|
+
* watched; it just stops being advertised). The untagged index-0 baseline is never retired.
|
|
739
|
+
*/
|
|
740
|
+
private rotate;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Cap on HD descriptors getUsedSigningDescriptors() materializes past the watermark (bounds
|
|
745
|
+
* plugin/restore probes; the watermark itself is not moved).
|
|
746
|
+
*/
|
|
747
|
+
declare const MAX_USED_SIGNING_DESCRIPTORS_LOOK_AHEAD = 1000;
|
|
748
|
+
type IncomingFunds = {
|
|
749
|
+
type: "utxo";
|
|
750
|
+
coins: Coin[];
|
|
751
|
+
} | {
|
|
752
|
+
type: "vtxo";
|
|
753
|
+
newVtxos: ExtendedVirtualCoin[];
|
|
754
|
+
spentVtxos: ExtendedVirtualCoin[];
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* Structural rather than {@link ContractWithVtxos} so the worker's repository-built snapshot
|
|
759
|
+
* (VTXOs without `contractScript`) classifies without a parallel array.
|
|
760
|
+
*/
|
|
761
|
+
type PendingRecoverySnapshot = Parameters<typeof selectPendingRecoveryOutpoints>[0];
|
|
762
|
+
/**
|
|
763
|
+
* Boarding UTXOs grouped by boarding address, with that address's signer. A flat
|
|
764
|
+
* {@link ExtendedCoin} can't carry it: it keeps only the encoded leaves, not the owning script's
|
|
765
|
+
* `serverPubKey` or CSV delay, which deprecated-signer classification needs.
|
|
766
|
+
*/
|
|
767
|
+
interface BoardingUtxoGroup {
|
|
768
|
+
/** Tapscript of the boarding address the coins sit on. */
|
|
769
|
+
tapscript: DefaultVtxo.Script;
|
|
770
|
+
/** Server key of that address, normalized x-only hex. */
|
|
771
|
+
serverPubKey: string;
|
|
772
|
+
/** CSV exit timelock decoded from THIS tapscript's exit leaf. */
|
|
773
|
+
csvTimelock: RelativeTimelock;
|
|
774
|
+
coins: ExtendedCoin[];
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Why a VTXO at an arkadeCash address could neither be swept nor imported for
|
|
778
|
+
* recovery by {@link Wallet.claimCash}.
|
|
779
|
+
*
|
|
780
|
+
* - `subdust` — below dust, so it sits at an OP_RETURN script with no spendable
|
|
781
|
+
* leaf. Unspendable as cash; `createCash` prevents minting these.
|
|
782
|
+
* - `already-spent` — someone else claimed it first.
|
|
783
|
+
* - `exited` — unilaterally exited onchain, so the offchain sweep cannot reach it;
|
|
784
|
+
* `Unroll.completeUnroll` is the remedy.
|
|
785
|
+
* - `has-assets` — asset-bearing; the BTC-only sweep would burn the assets.
|
|
786
|
+
* - `sweep-failed` — spendable, but its own sweep was rejected.
|
|
787
|
+
* - `recovery-failed` — server-swept and recoverable in principle, but the
|
|
788
|
+
* import that hands it to the wallet's recovery machinery failed.
|
|
789
|
+
*
|
|
790
|
+
* A server-swept VTXO whose import *succeeds* is not reported here — it lands
|
|
791
|
+
* in {@link ArkadeCashClaimResult.recovering} instead.
|
|
792
|
+
*/
|
|
793
|
+
type ArkadeCashUnclaimedReason = "subdust" | "already-spent" | "exited" | "has-assets" | "sweep-failed" | "recovery-failed";
|
|
794
|
+
/** Minimal outpoint + value identifying a VTXO in a claim report. */
|
|
795
|
+
interface ArkadeCashVtxoRef {
|
|
796
|
+
txid: string;
|
|
797
|
+
vout: number;
|
|
798
|
+
/** Value in satoshis. */
|
|
799
|
+
value: number;
|
|
800
|
+
}
|
|
801
|
+
/** A VTXO {@link Wallet.claimCash} left behind, with the reason why. */
|
|
802
|
+
interface ArkadeCashUnclaimedVtxo extends ArkadeCashVtxoRef {
|
|
803
|
+
reason: ArkadeCashUnclaimedReason;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Outcome of {@link Wallet.claimCash}: what was swept instantly, what was
|
|
807
|
+
* imported for background recovery, and what was left behind.
|
|
808
|
+
*
|
|
809
|
+
* The shape is open — further buckets may be added as more of the
|
|
810
|
+
* non-sweepable states become claimable.
|
|
811
|
+
*/
|
|
812
|
+
interface ArkadeCashClaimResult {
|
|
813
|
+
/** Satoshis swept to this wallet instantly (the thin single-key sweep). */
|
|
814
|
+
swept: number;
|
|
815
|
+
/**
|
|
816
|
+
* Server-swept VTXOs imported for recovery. These funds are not in the
|
|
817
|
+
* wallet yet: a swept VTXO can only move through a settlement, so
|
|
818
|
+
* `claimCash` imports it as a signable contract and hands it to the
|
|
819
|
+
* wallet's own recovery machinery, which settles it back (rotation-aware)
|
|
820
|
+
* on the normal retry cadence. The amount arrives as a fresh VTXO once
|
|
821
|
+
* that settlement finalizes.
|
|
822
|
+
*/
|
|
823
|
+
recovering: {
|
|
824
|
+
/** Satoshis imported for recovery. */
|
|
825
|
+
amount: number;
|
|
826
|
+
vtxos: ArkadeCashVtxoRef[];
|
|
827
|
+
};
|
|
828
|
+
unclaimed: {
|
|
829
|
+
/** Satoshis left behind. */
|
|
830
|
+
amount: number;
|
|
831
|
+
vtxos: ArkadeCashUnclaimedVtxo[];
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Thrown when {@link Wallet.createCash}'s `send` fails after the transaction may already have been
|
|
836
|
+
* submitted. `cash` carries the private key of the funded output: discard it and the sats may be
|
|
837
|
+
* stranded. Persist it; {@link Wallet.claimCash} recovers the funds whether or not the send landed.
|
|
838
|
+
*/
|
|
839
|
+
declare class ArkadeCashCreateError extends Error {
|
|
840
|
+
/** The encoded arkadeCash token controlling the funded output. */
|
|
841
|
+
readonly cash: string;
|
|
842
|
+
/** The original failure from `send`. */
|
|
843
|
+
readonly cause: unknown;
|
|
844
|
+
constructor(
|
|
845
|
+
/** The encoded arkadeCash token controlling the funded output. */
|
|
846
|
+
cash: string,
|
|
847
|
+
/** The original failure from `send`. */
|
|
848
|
+
cause: unknown);
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Freshness of provider-backed sync (server-info source + indexer-sync health). Balances/VTXOs
|
|
852
|
+
* are always served from the repository regardless.
|
|
853
|
+
*/
|
|
854
|
+
type ProviderConnectionState = {
|
|
855
|
+
mode: "online";
|
|
856
|
+
source: "live";
|
|
857
|
+
lastOnlineAt: number;
|
|
858
|
+
} | {
|
|
859
|
+
mode: "degraded";
|
|
860
|
+
source: "cache" | "repository";
|
|
861
|
+
provider: ProviderKind;
|
|
862
|
+
reason: string;
|
|
863
|
+
lastOnlineAt?: number;
|
|
864
|
+
};
|
|
865
|
+
declare class ReadonlyWallet implements IReadonlyWallet {
|
|
866
|
+
readonly identity: ReadonlyIdentity;
|
|
867
|
+
readonly network: Network;
|
|
868
|
+
readonly onchainProvider: OnchainProvider;
|
|
869
|
+
/** Narrowed so a readonly wallet can't grow a `submitTx` use; `Wallet` re-widens it. */
|
|
870
|
+
protected readonly arkProvider: Pick<ArkProvider, "getInfo">;
|
|
871
|
+
readonly indexerProvider: IndexerProvider;
|
|
872
|
+
readonly dustAmount: bigint;
|
|
873
|
+
readonly walletRepository: WalletRepository;
|
|
874
|
+
readonly contractRepository: ContractRepository;
|
|
875
|
+
readonly delegateProvider?: DelegateProvider | undefined;
|
|
876
|
+
private _contractManager?;
|
|
877
|
+
private _contractManagerInitializing?;
|
|
878
|
+
protected readonly watcherConfig?: ReadonlyWalletConfig["watcherConfig"];
|
|
879
|
+
protected vtxoSyncOverlapMs?: number;
|
|
880
|
+
protected copySyncOverlapTo(wallet: ReadonlyWallet): void;
|
|
881
|
+
/** Opt-in intent-lifecycle repository; `undefined` ⇒ intent persistence is a no-op. */
|
|
882
|
+
intentRepository?: IntentRepository;
|
|
883
|
+
/**
|
|
884
|
+
* **Experimental / inert.** Opt-in virtual-tx repository, exposed so callers can pass it to
|
|
885
|
+
* {@link Unroll.Session.create} as a best-effort raw-tx cache. Normal sync never writes it.
|
|
886
|
+
*/
|
|
887
|
+
virtualTxRepository?: VirtualTxRepository;
|
|
888
|
+
/** Opt-in exit-data capture settings; see {@link StorageConfig.exitDataCapture}. */
|
|
889
|
+
exitDataCapture?: {
|
|
890
|
+
mode?: ExitCaptureMode;
|
|
891
|
+
minExitWorthSats?: number;
|
|
892
|
+
sources?: ExitDataSource[];
|
|
893
|
+
};
|
|
894
|
+
private readonly _assetManager;
|
|
895
|
+
readonly walletContractTimelocks: RelativeTimelock[];
|
|
896
|
+
protected _pendingSpendOutpoints: Set<string>;
|
|
897
|
+
/** Activity resolvers consumed by {@link getActivityHistory}. */
|
|
898
|
+
readonly activity: ActivityRegistry;
|
|
899
|
+
get assetManager(): IReadonlyAssetManager;
|
|
900
|
+
/**
|
|
901
|
+
* Active receive tapscript; written only by {@link Wallet.setOffchainTapscriptForRotation}
|
|
902
|
+
* (sole intended caller: {@link WalletReceiveRotator.rotate}).
|
|
903
|
+
*/
|
|
904
|
+
protected _offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script;
|
|
905
|
+
/**
|
|
906
|
+
* Current boarding tapscript (QR / onboarding target); written only by
|
|
907
|
+
* {@link Wallet.setBoardingTapscriptForRotation}. Static / `auto` wallets never rotate it.
|
|
908
|
+
*/
|
|
909
|
+
protected _boardingTapscript: DefaultVtxo.Script;
|
|
910
|
+
/**
|
|
911
|
+
* Active server signer (x-only); written only by
|
|
912
|
+
* {@link Wallet.setArkServerPublicKeyForRotation} when arkd rotates its signer mid-session.
|
|
913
|
+
*/
|
|
914
|
+
protected _arkServerPublicKey: Bytes;
|
|
915
|
+
/**
|
|
916
|
+
* Whether the LATEST server-info resolution was live or fell back to the cached snapshot.
|
|
917
|
+
* Updated on every {@link getArkadeInfo} read so recovery (or a fresh fallback) is reflected.
|
|
918
|
+
*/
|
|
919
|
+
protected _serverInfoSource: ServerInfoSource;
|
|
920
|
+
/**
|
|
921
|
+
* Epoch-ms of the last live operator contact, or the cached snapshot's `savedAt` when the
|
|
922
|
+
* latest resolution fell back.
|
|
923
|
+
*/
|
|
924
|
+
protected _serverInfoLastOnlineAt?: number;
|
|
925
|
+
/** @see {@link _serverInfoSource} */
|
|
926
|
+
get serverInfoSource(): ServerInfoSource;
|
|
927
|
+
/**
|
|
928
|
+
* Composed provider-connection freshness: degraded on `arkade` (`cache`) when the latest
|
|
929
|
+
* server-info resolution fell back, else degraded on `indexer` (`repository`) when an
|
|
930
|
+
* initialized contract manager has, else online. Never forces a `ContractManager` to
|
|
931
|
+
* construct, so it is safe for readonly callers.
|
|
932
|
+
*/
|
|
933
|
+
getProviderConnectionState(): ProviderConnectionState;
|
|
934
|
+
/**
|
|
935
|
+
* The contract manager's sync health **without initializing it** (`online` if none exists),
|
|
936
|
+
* so unlike {@link getContractManager} it never triggers a remote sync.
|
|
937
|
+
*/
|
|
938
|
+
getContractSyncState(): ContractSyncState;
|
|
939
|
+
protected constructor(identity: ReadonlyIdentity, network: Network, onchainProvider: OnchainProvider,
|
|
940
|
+
/** Narrowed so a readonly wallet can't grow a `submitTx` use; `Wallet` re-widens it. */
|
|
941
|
+
arkProvider: Pick<ArkProvider, "getInfo">, indexerProvider: IndexerProvider, arkServerPublicKey: Bytes, offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script, boardingTapscript: DefaultVtxo.Script, dustAmount: bigint, walletRepository: WalletRepository, contractRepository: ContractRepository, delegateProvider?: DelegateProvider | undefined, watcherConfig?: ReadonlyWalletConfig["watcherConfig"], walletContractTimelocks?: RelativeTimelock[]);
|
|
942
|
+
/**
|
|
943
|
+
* x-only hex → cutoff of the operator's deprecated signers, cached for OFFLINE read/watch.
|
|
944
|
+
* Boarding watch/history fan out over {current} ∪ this set so deposits at addresses minted
|
|
945
|
+
* under a rotated signer stay watched. Deliberately NOT used by the spend path:
|
|
946
|
+
* {@link getBoardingUtxos} stays current-signer-only (a deprecated-signer input in a plain
|
|
947
|
+
* settle() is rejected; recovery goes through the migration API).
|
|
948
|
+
*/
|
|
949
|
+
protected _deprecatedSigners: Map<string, bigint>;
|
|
950
|
+
/**
|
|
951
|
+
* Refresh the cached deprecated-signer set from server info; feeds
|
|
952
|
+
* {@link pendingRecoveryOutpoints}. Lenient: a malformed entry is skipped, never fatal.
|
|
953
|
+
*/
|
|
954
|
+
refreshDeprecatedSigners(info: {
|
|
955
|
+
deprecatedSigners?: readonly {
|
|
956
|
+
pubkey?: string;
|
|
957
|
+
cutoffDate?: bigint;
|
|
958
|
+
}[];
|
|
959
|
+
}): void;
|
|
960
|
+
/** Boarding WATCH/HISTORY signer set: current ∪ deprecated (spend stays current-only). */
|
|
961
|
+
protected watchedBoardingSigners(): Set<string>;
|
|
962
|
+
/**
|
|
963
|
+
* `serverPubKey` defaults to the live key; spend paths that snapshot it
|
|
964
|
+
* against mid-flight rotation pass their snapshot, so the check reads from
|
|
965
|
+
* one rotation epoch.
|
|
966
|
+
*/
|
|
967
|
+
protected recipientAddressContext(serverPubKey?: Bytes): RecipientArkadeAddressContext;
|
|
968
|
+
/** Currently-active receive tapscript; changes only on receive rotation. */
|
|
969
|
+
get offchainTapscript(): DefaultVtxo.Script | DelegateVtxo.Script;
|
|
970
|
+
/** Current active server signer (x-only, 32 bytes); changes only on server-signer rotation. */
|
|
971
|
+
get arkServerPublicKey(): Bytes;
|
|
972
|
+
/**
|
|
973
|
+
* Server info for the connected Arkade server: live wins, a retryable failure falls back to
|
|
974
|
+
* the boot snapshot, a terminal one propagates. Live because `signerPubkey`,
|
|
975
|
+
* `checkpointTapscript` and `fees` move on rotation, and a covenant built against a
|
|
976
|
+
* superseded signer is unspendable.
|
|
977
|
+
*
|
|
978
|
+
* @remarks Reading does NOT re-pin the wallet ({@link arkServerPublicKey}, {@link dustAmount},
|
|
979
|
+
* tapscripts), so inside a rotation window this can report epoch N+1 while the wallet spends
|
|
980
|
+
* on N; the provider's `onServerInfoChanged` closes the window. Pass `{ requireLive: true }`
|
|
981
|
+
* before binding the answer into a covenant to fail closed instead of getting the snapshot.
|
|
982
|
+
*
|
|
983
|
+
* @returns The Arkade server's info
|
|
984
|
+
* @see ArkadeInfo
|
|
985
|
+
*/
|
|
986
|
+
getArkadeInfo(opts?: GetArkadeInfoOptions): Promise<ArkadeInfo>;
|
|
987
|
+
/**
|
|
988
|
+
* Chain reads against this wallet's server for scripts it does not own, bound to the wallet's
|
|
989
|
+
* own (possibly Expo/injected) `indexerProvider`. `getVtxos` normalizes via
|
|
990
|
+
* {@link getNormalizedVtxos}. A bound object, not the provider, so an `IReadonlyWallet`
|
|
991
|
+
* holder gets these two reads and nothing else.
|
|
992
|
+
*/
|
|
993
|
+
getArkadeReader(): Promise<ArkadeReader>;
|
|
994
|
+
/**
|
|
995
|
+
* Current boarding tapscript (on-chain onboarding target); changes only when a fresh boarding
|
|
996
|
+
* address is explicitly allocated.
|
|
997
|
+
*/
|
|
998
|
+
get boardingTapscript(): DefaultVtxo.Script;
|
|
999
|
+
/**
|
|
1000
|
+
* Fired after boarding rotation so a live {@link notifyIncomingFunds} watcher re-subscribes
|
|
1001
|
+
* to the fresh address in-session instead of missing deposits until its next re-init.
|
|
1002
|
+
*/
|
|
1003
|
+
private readonly _boardingRotationListeners;
|
|
1004
|
+
/** Register a listener invoked synchronously after each boarding rotation. */
|
|
1005
|
+
protected onBoardingRotation(listener: () => void): () => void;
|
|
1006
|
+
/** A throwing listener is isolated: it can't break the rotation or starve siblings. */
|
|
1007
|
+
protected notifyBoardingRotation(): void;
|
|
1008
|
+
/** Shared setup for ReadonlyWallet.create() and Wallet.create(). */
|
|
1009
|
+
protected static setupWalletConfig(config: ReadonlyWalletConfig, pubKey: Uint8Array): Promise<{
|
|
1010
|
+
arkProvider: ArkProvider;
|
|
1011
|
+
indexerProvider: IndexerProvider;
|
|
1012
|
+
onchainProvider: OnchainProvider;
|
|
1013
|
+
network: Network;
|
|
1014
|
+
networkName: NetworkName;
|
|
1015
|
+
serverPubKey: Uint8Array<ArrayBufferLike>;
|
|
1016
|
+
offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script;
|
|
1017
|
+
boardingTapscript: DefaultVtxo.Script;
|
|
1018
|
+
dustAmount: bigint;
|
|
1019
|
+
walletRepository: WalletRepository | IndexedDBWalletRepository;
|
|
1020
|
+
contractRepository: ContractRepository;
|
|
1021
|
+
info: ArkadeInfo;
|
|
1022
|
+
serverInfoSource: ServerInfoSource;
|
|
1023
|
+
serverInfoLastOnlineAt: number | undefined;
|
|
1024
|
+
delegateProvider: DelegateProvider | undefined;
|
|
1025
|
+
walletContractTimelocks: RelativeTimelock[];
|
|
1026
|
+
}>;
|
|
1027
|
+
/**
|
|
1028
|
+
* Create a readonly wallet for querying balances, addresses, and history.
|
|
1029
|
+
*
|
|
1030
|
+
* @param config - Readonly wallet configuration
|
|
1031
|
+
* @returns A readonly wallet instance
|
|
1032
|
+
*/
|
|
1033
|
+
static create<T extends ReadonlyWallet>(this: {
|
|
1034
|
+
prototype: T;
|
|
1035
|
+
}, config: ReadonlyWalletConfig): Promise<T>;
|
|
1036
|
+
static create(config: ReadonlyWalletConfig): Promise<ReadonlyWallet>;
|
|
1037
|
+
get arkAddress(): ArkAddress;
|
|
1038
|
+
/**
|
|
1039
|
+
* Get the pkScript hex for the wallet's primary offchain address.
|
|
1040
|
+
* For the full wallet-owned script set registered in ContractManager, use getWalletScripts().
|
|
1041
|
+
*/
|
|
1042
|
+
get defaultContractScript(): string;
|
|
1043
|
+
/** Returns the wallet's Arkade address. */
|
|
1044
|
+
getAddress(): Promise<string>;
|
|
1045
|
+
/** Returns the onchain boarding address used to move funds into Arkade. */
|
|
1046
|
+
getBoardingAddress(): Promise<string>;
|
|
1047
|
+
/**
|
|
1048
|
+
* Return the wallet's combined onchain and offchain balances.
|
|
1049
|
+
*/
|
|
1050
|
+
getBalance(): Promise<WalletBalance>;
|
|
1051
|
+
/**
|
|
1052
|
+
* Return virtual outputs tracked by the wallet, including escrowed, locked and
|
|
1053
|
+
* awaiting-recovery funds. Coin selection must use {@link getSpendableVtxos}: feeding this
|
|
1054
|
+
* into `settle({ inputs })` or `send({ selectedVtxos })` bypasses the generic-spending gate.
|
|
1055
|
+
*
|
|
1056
|
+
* @param filter - Optional flags controlling whether recoverable or unrolled VTXOs are included
|
|
1057
|
+
*/
|
|
1058
|
+
getVtxos(filter?: GetVtxosFilter): Promise<NormalizedExtendedVirtualCoin[]>;
|
|
1059
|
+
/** @inheritdoc */
|
|
1060
|
+
getSpendableVtxos(filter?: GetSpendableVtxosFilter): Promise<NormalizedExtendedVirtualCoin[]>;
|
|
1061
|
+
/**
|
|
1062
|
+
* Debug-log any explicit input generic selection would have excluded. Explicit-input APIs stay
|
|
1063
|
+
* ungated on purpose (naming an outpoint *is* the intent, and is how an escrowed deposit is
|
|
1064
|
+
* recovered), so this only makes the crossing visible — notably
|
|
1065
|
+
* `settle({ inputs: await wallet.getVtxos() })`. Never throws. Public for worker and plugins.
|
|
1066
|
+
*/
|
|
1067
|
+
logUngatedInputs(source: string, inputs: readonly {
|
|
1068
|
+
txid: string;
|
|
1069
|
+
vout: number;
|
|
1070
|
+
script?: string;
|
|
1071
|
+
}[]): Promise<void>;
|
|
1072
|
+
/**
|
|
1073
|
+
* Past-cutoff-signer contracts as a script-level exclusion: the `pendingRecovery` answer for a
|
|
1074
|
+
* caller-supplied input without a synced snapshot (a swept outpoint is unspendable anyway).
|
|
1075
|
+
*/
|
|
1076
|
+
private expiredSignerExclusion;
|
|
1077
|
+
/** The intent store's lock set. Fails open, like every other read of it. */
|
|
1078
|
+
private lockedOutpoints;
|
|
1079
|
+
/**
|
|
1080
|
+
* One contract+VTXO read (which may sync against the indexer). Callers needing several views
|
|
1081
|
+
* derive them all from one snapshot so they answer about the same instant.
|
|
1082
|
+
*/
|
|
1083
|
+
protected contractSnapshot(filter?: GetSpendableVtxosFilter, options?: {
|
|
1084
|
+
unspentOnly?: boolean;
|
|
1085
|
+
}): Promise<ContractWithVtxos[]>;
|
|
1086
|
+
/**
|
|
1087
|
+
* The two exclusion sets the gate is made of, derived from one snapshot so
|
|
1088
|
+
* {@link getSpendableVtxos} and the balance answer about the same instant.
|
|
1089
|
+
*/
|
|
1090
|
+
private spendabilityView;
|
|
1091
|
+
/** The capability probes {@link computeOffchainBalance} needs, over one snapshot. */
|
|
1092
|
+
private balanceCapabilities;
|
|
1093
|
+
/**
|
|
1094
|
+
* Outpoints of not-yet-swept VTXOs whose deprecated signer is past its cutoff (EXPIRED) —
|
|
1095
|
+
* unspendable until they recover; excluded by {@link getBalance} and {@link getSpendableVtxos}.
|
|
1096
|
+
* Takes a fresh (syncing) snapshot; callers that hold one or must not sync use
|
|
1097
|
+
* {@link pendingRecoveryOutpointsIn}.
|
|
1098
|
+
*/
|
|
1099
|
+
pendingRecoveryOutpoints(): Promise<Set<string>>;
|
|
1100
|
+
/** {@link pendingRecoveryOutpoints} over a caller-held snapshot; no I/O of its own. */
|
|
1101
|
+
pendingRecoveryOutpointsIn(snapshot: PendingRecoverySnapshot): Set<string>;
|
|
1102
|
+
private selectPendingRecovery;
|
|
1103
|
+
/**
|
|
1104
|
+
* Return wallet transaction history derived from Arkade state and boarding transactions.
|
|
1105
|
+
*/
|
|
1106
|
+
getTransactionHistory(): Promise<ArkTransaction[]>;
|
|
1107
|
+
/**
|
|
1108
|
+
* Wallet history grouped by registered activity resolvers. With no resolver match,
|
|
1109
|
+
* rows bucket by transaction key so send/change pairs stay together.
|
|
1110
|
+
*/
|
|
1111
|
+
getActivityHistory(): Promise<Activity[]>;
|
|
1112
|
+
/**
|
|
1113
|
+
* Clear the global VTXO sync cursor, forcing a full re-bootstrap on next sync.
|
|
1114
|
+
* Useful for recovery after indexer reprocessing or debugging.
|
|
1115
|
+
*/
|
|
1116
|
+
clearSyncCursor(): Promise<void>;
|
|
1117
|
+
/**
|
|
1118
|
+
* Wipe all locally persisted wallet data (VTXOs, UTXOs, history, sync
|
|
1119
|
+
* cursor, contracts, intents). Create a fresh wallet instance afterward.
|
|
1120
|
+
* Intents are kept while any may still be held by arkd, so a later
|
|
1121
|
+
* reconciliation can release them with their stored proofs.
|
|
1122
|
+
*/
|
|
1123
|
+
clear(): Promise<void>;
|
|
1124
|
+
private clearIntents;
|
|
1125
|
+
/**
|
|
1126
|
+
* On-chain (P2TR) addresses of every boarding tapscript this wallet uses, current plus
|
|
1127
|
+
* historical rotated, so deposits at old addresses still surface; {@link getBoardingAddress}
|
|
1128
|
+
* stays single-valued.
|
|
1129
|
+
*/
|
|
1130
|
+
getBoardingAddresses(): Promise<string[]>;
|
|
1131
|
+
/** Transaction history across the wallet's boarding addresses (current + historical). */
|
|
1132
|
+
getBoardingTxs(): Promise<{
|
|
1133
|
+
boardingTxs: ArkTransaction[];
|
|
1134
|
+
commitmentsToIgnore: Set<string>;
|
|
1135
|
+
}>;
|
|
1136
|
+
/**
|
|
1137
|
+
* Every boarding tapscript whose UTXOs belong to this wallet (rotation spreads them over
|
|
1138
|
+
* several addresses), deduplicated by scriptPubKey. Always includes the index-0 baseline,
|
|
1139
|
+
* which covers the equal-delay case where that row coalesced onto `default`.
|
|
1140
|
+
*
|
|
1141
|
+
* @param allowedSigners - x-only server keys whose persisted boarding rows are included;
|
|
1142
|
+
* defaults to the current signer (the foreign-ASP guard). Migration widens it to old signers.
|
|
1143
|
+
* The baseline and current display tapscript are included regardless.
|
|
1144
|
+
*/
|
|
1145
|
+
protected getBoardingTapscripts(allowedSigners?: Set<string>): Promise<DefaultVtxo.Script[]>;
|
|
1146
|
+
/**
|
|
1147
|
+
* Fetch and cache boarding UTXOs for the given signer set, grouped per address (see
|
|
1148
|
+
* {@link BoardingUtxoGroup} for why), saving every group in one `saveUtxos`. No
|
|
1149
|
+
* `getInfo()`: the only network calls are the per-address `getCoins`.
|
|
1150
|
+
*
|
|
1151
|
+
* @param allowedSigners - x-only-hex server keys whose boarding addresses to
|
|
1152
|
+
* fetch (passed through to {@link getBoardingTapscripts}).
|
|
1153
|
+
*/
|
|
1154
|
+
getBoardingUtxosForSigners(allowedSigners: Set<string>): Promise<BoardingUtxoGroup[]>;
|
|
1155
|
+
/**
|
|
1156
|
+
* Fetch and cache boarding UTXOs at current and historical boarding addresses, each annotated
|
|
1157
|
+
* with its own address's tapscript so spends use the right per-index leaves. Current-signer
|
|
1158
|
+
* only: old-signer inputs would make a plain `settle()` the server must reject, so their
|
|
1159
|
+
* recovery goes through the deprecated-signer migration API.
|
|
1160
|
+
*/
|
|
1161
|
+
getBoardingUtxos(): Promise<ExtendedCoin[]>;
|
|
1162
|
+
/**
|
|
1163
|
+
* Subscribe to onchain and offchain notifications for newly received funds.
|
|
1164
|
+
*
|
|
1165
|
+
* The onchain watcher tracks every boarding address (current + historical) and re-subscribes
|
|
1166
|
+
* automatically when boarding rotates after subscribing, so deposits to a fresh address fire
|
|
1167
|
+
* within the same session.
|
|
1168
|
+
*
|
|
1169
|
+
* @param eventCallback - Callback invoked when matching funds are detected
|
|
1170
|
+
* @returns A function that stops the subscriptions
|
|
1171
|
+
*/
|
|
1172
|
+
notifyIncomingFunds(eventCallback: (coins: IncomingFunds) => void): Promise<() => void>;
|
|
1173
|
+
/** Fetch Arkade transaction ids that are still pending final settlement. */
|
|
1174
|
+
fetchPendingTxs(): Promise<string[]>;
|
|
1175
|
+
/**
|
|
1176
|
+
* Get all pkScript hex strings for the wallet's own addresses
|
|
1177
|
+
* (both delegate and non-delegate, current and historical).
|
|
1178
|
+
*/
|
|
1179
|
+
getWalletScripts(): Promise<string[]>;
|
|
1180
|
+
/**
|
|
1181
|
+
* Build a map of scriptHex → VtxoScript for all wallet contracts,
|
|
1182
|
+
* so virtual outputs can be extended with the correct tapscript per contract.
|
|
1183
|
+
*/
|
|
1184
|
+
getScriptMap(): Promise<Map<string, DefaultVtxo.Script | DelegateVtxo.Script>>;
|
|
1185
|
+
/**
|
|
1186
|
+
* Get the ContractManager, which manages the wallet's own receive contracts and external ones
|
|
1187
|
+
* (Boltz swaps, HTLCs, …) with resilient multi-contract watching.
|
|
1188
|
+
*
|
|
1189
|
+
* @example
|
|
1190
|
+
* ```typescript
|
|
1191
|
+
* const manager = await wallet.getContractManager();
|
|
1192
|
+
*
|
|
1193
|
+
* // Create a contract for a Boltz swap
|
|
1194
|
+
* const contract = await manager.createContract({
|
|
1195
|
+
* label: "Boltz Swap",
|
|
1196
|
+
* type: "vhtlc",
|
|
1197
|
+
* params: { ... },
|
|
1198
|
+
* script: swapScript,
|
|
1199
|
+
* address: swapAddress,
|
|
1200
|
+
* });
|
|
1201
|
+
*
|
|
1202
|
+
* // Start watching for events (includes wallet's default address)
|
|
1203
|
+
* const stop = await manager.onContractEvent((event) => {
|
|
1204
|
+
* console.log(`${event.type} on ${event.contractScript}`);
|
|
1205
|
+
* });
|
|
1206
|
+
* ```
|
|
1207
|
+
*/
|
|
1208
|
+
getContractManager(): Promise<ContractManager>;
|
|
1209
|
+
/**
|
|
1210
|
+
* HD look-ahead configuration for the contract manager. Readonly wallets
|
|
1211
|
+
* have no descriptor provider, hence no watermark to look ahead of.
|
|
1212
|
+
* @see Wallet.lookAheadConfig
|
|
1213
|
+
*/
|
|
1214
|
+
protected lookAheadConfig(): ContractManagerConfig["lookAhead"];
|
|
1215
|
+
/** Readonly wallets never settle, so they neither release nor own server intents. */
|
|
1216
|
+
protected intentReconciliationConfig(): ContractManagerConfig["intentReconciliation"];
|
|
1217
|
+
private initializeContractManager;
|
|
1218
|
+
/** Dispose wallet-owned managers and release background resources. */
|
|
1219
|
+
dispose(): Promise<void>;
|
|
1220
|
+
/** Async-dispose hook that forwards to `dispose()`. */
|
|
1221
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Main wallet implementation for Bitcoin transactions with Arkade protocol support.
|
|
1225
|
+
*
|
|
1226
|
+
* @example
|
|
1227
|
+
* ```typescript
|
|
1228
|
+
* // Create a wallet with providers
|
|
1229
|
+
* const wallet = await Wallet.create({
|
|
1230
|
+
* identity: MnemonicIdentity.fromMnemonic('abandon abandon...'),
|
|
1231
|
+
* arkProvider: new RestArkProvider(),
|
|
1232
|
+
* onchainProvider: new EsploraProvider()
|
|
1233
|
+
* });
|
|
1234
|
+
*
|
|
1235
|
+
* // Use custom providers and/or URLs (e.g., for Expo/React Native)
|
|
1236
|
+
* const wallet = await Wallet.create({
|
|
1237
|
+
* identity: MnemonicIdentity.fromMnemonic('abandon abandon...'),
|
|
1238
|
+
* arkProvider: new ExpoArkProvider('https://arkade.computer'),
|
|
1239
|
+
* indexerProvider: new ExpoIndexerProvider('https://arkade.computer'),
|
|
1240
|
+
* onchainProvider: new EsploraProvider('https://mempool.space/api')
|
|
1241
|
+
* });
|
|
1242
|
+
*
|
|
1243
|
+
* // Get addresses
|
|
1244
|
+
* const arkAddress = await wallet.getAddress();
|
|
1245
|
+
* const boardingAddress = await wallet.getBoardingAddress();
|
|
1246
|
+
*
|
|
1247
|
+
* // Send bitcoin
|
|
1248
|
+
* const txid = await wallet.send({
|
|
1249
|
+
* address: 'ark1q...',
|
|
1250
|
+
* amount: 50000,
|
|
1251
|
+
* });
|
|
1252
|
+
* ```
|
|
1253
|
+
*/
|
|
1254
|
+
declare class Wallet extends ReadonlyWallet implements IWallet, HDWalletCapable, AddressAllocationCapable {
|
|
1255
|
+
readonly forfeitOutputScript: Bytes;
|
|
1256
|
+
readonly forfeitPubkey: Bytes;
|
|
1257
|
+
/** Overrides for the `batchExpiry` bounds; defaults derive from `network`. */
|
|
1258
|
+
protected readonly batchExpiryPolicy?: Partial<BatchExpiryPolicy> | undefined;
|
|
1259
|
+
/** Overrides for the checkpoint exit delay bounds; defaults derive from `network`. */
|
|
1260
|
+
protected readonly checkpointExitDelayPolicy?: Partial<CheckpointExitDelayPolicy> | undefined;
|
|
1261
|
+
static MIN_FEE_RATE: number;
|
|
1262
|
+
readonly identity: Identity;
|
|
1263
|
+
private readonly _delegateManager?;
|
|
1264
|
+
private _vtxoManager?;
|
|
1265
|
+
private _vtxoManagerInitializing?;
|
|
1266
|
+
private _walletAssetManager?;
|
|
1267
|
+
/**
|
|
1268
|
+
* HD receive rotator; absent for `static` and SingleKey-under-`auto` wallets. Its subscription
|
|
1269
|
+
* installs lazily on first `getVtxoManager()` so the contract manager is up first.
|
|
1270
|
+
*/
|
|
1271
|
+
private _receiveRotator?;
|
|
1272
|
+
/** Unsubscribe for `onServerInfoChanged` (mid-session signer rotation). */
|
|
1273
|
+
private _serverInfoUnsub?;
|
|
1274
|
+
/**
|
|
1275
|
+
* Tail of the serialized {@link handleServerInfoChanged} chain; {@link dispose} awaits it so an
|
|
1276
|
+
* in-flight rotation settles before the contract manager is torn down.
|
|
1277
|
+
*/
|
|
1278
|
+
private _serverInfoInFlight;
|
|
1279
|
+
/**
|
|
1280
|
+
* React to a mid-session server-info change (`DIGEST_MISMATCH`): refresh deprecated signers
|
|
1281
|
+
* first so boarding watch widens immediately, then rotate via {@link rotateServerSigner} only
|
|
1282
|
+
* if the active signer changed. Old-signer rows stay active. Never throws into the emit loop.
|
|
1283
|
+
*/
|
|
1284
|
+
private handleServerInfoChanged;
|
|
1285
|
+
/**
|
|
1286
|
+
* Await an `onServerInfoChanged` handler still applying a rotation. {@link rotateServerSigner}
|
|
1287
|
+
* persists the new signer's rows *before* committing the tapscripts, so a path that refreshes
|
|
1288
|
+
* server info then reads signer-derived state must drain first or it reads torn state and
|
|
1289
|
+
* races the handler. Resolves once idle; handler rejections are swallowed (already logged).
|
|
1290
|
+
*
|
|
1291
|
+
* @internal Invoked by {@link dispose} and the {@link VtxoManager} migration
|
|
1292
|
+
* pass; not part of the stable public API.
|
|
1293
|
+
*/
|
|
1294
|
+
settleServerInfoChanges(): Promise<void>;
|
|
1295
|
+
private _receiveRotatorInstalled;
|
|
1296
|
+
/**
|
|
1297
|
+
* Descriptor-aware signer for inputs locked by rotated pubkeys (the rotator's instance).
|
|
1298
|
+
* Undefined for static / non-HD wallets, which only sign with the identity.
|
|
1299
|
+
*/
|
|
1300
|
+
private readonly _descriptorProvider?;
|
|
1301
|
+
/**
|
|
1302
|
+
* Keyring holding foreign private keys imported outside the wallet's
|
|
1303
|
+
* derivation tree (see {@link KeyringDescriptorProvider}). Wraps
|
|
1304
|
+
* {@link _descriptorProvider} (or a {@link StaticDescriptorProvider}
|
|
1305
|
+
* over the wallet identity when there is no HD provider) and is the
|
|
1306
|
+
* descriptor provider {@link _signerRouter} actually signs through, so
|
|
1307
|
+
* a contract carrying `metadata.signingDescriptor` for an imported key
|
|
1308
|
+
* is signable by construction.
|
|
1309
|
+
*
|
|
1310
|
+
* Kept separate from {@link _descriptorProvider} on purpose: the latter
|
|
1311
|
+
* still gates HD boarding/receive rotation (a `!provider` check means
|
|
1312
|
+
* "static wallet, no rotation"), and wrapping it with a keyring for
|
|
1313
|
+
* every wallet would break that gate. The keyring is orthogonal — it
|
|
1314
|
+
* only ever adds foreign signable keys, never receive addresses.
|
|
1315
|
+
*
|
|
1316
|
+
* Populated for every {@link Wallet.create}d wallet; the constructor's
|
|
1317
|
+
* param is optional so the router degrades to {@link _descriptorProvider}
|
|
1318
|
+
* if a caller ever omits it.
|
|
1319
|
+
*/
|
|
1320
|
+
private readonly _keyring?;
|
|
1321
|
+
/**
|
|
1322
|
+
* The built-in HD provider behind any keyring wrapping, or `undefined` when there is none.
|
|
1323
|
+
* Every HD-specific branch goes through this: a wrapped HD provider (a public `walletMode`
|
|
1324
|
+
* shape) fails `instanceof HDDescriptorProvider` and would silently take the non-HD path.
|
|
1325
|
+
*/
|
|
1326
|
+
private get _hdProvider();
|
|
1327
|
+
/** Per-side width of the HD look-ahead band. @see WalletConfig.lookAheadWindow */
|
|
1328
|
+
private readonly _lookAheadWindow;
|
|
1329
|
+
protected intentReconciliationConfig(): ContractManagerConfig["intentReconciliation"];
|
|
1330
|
+
/**
|
|
1331
|
+
* Watch a band of receive scripts around the HD watermark so payments to an externally-issued
|
|
1332
|
+
* address land without a `restore()`. HD only. `candidateDeps` is read at refill time, so a
|
|
1333
|
+
* band rebuilt after {@link rotateServerSigner} fans the new signer set.
|
|
1334
|
+
*/
|
|
1335
|
+
protected lookAheadConfig(): ContractManagerConfig["lookAhead"];
|
|
1336
|
+
/**
|
|
1337
|
+
* Every axis an externally issued receive script could use: an issuer sharing the seed (NArk,
|
|
1338
|
+
* a merchant backend) picks its own contract type. From cached state (no `getInfo`) to stay
|
|
1339
|
+
* synchronous and offline-safe.
|
|
1340
|
+
*/
|
|
1341
|
+
private receiveCandidateDeps;
|
|
1342
|
+
private readonly _signerRouter;
|
|
1343
|
+
/**
|
|
1344
|
+
* @internal Sole write path for `offchainTapscript`; called by
|
|
1345
|
+
* {@link WalletReceiveRotator.rotate} after the rotated contract is persisted.
|
|
1346
|
+
*/
|
|
1347
|
+
setOffchainTapscriptForRotation(tapscript: DefaultVtxo.Script | DelegateVtxo.Script): void;
|
|
1348
|
+
/**
|
|
1349
|
+
* @internal Sole write path for `boardingTapscript`; called by
|
|
1350
|
+
* {@link Wallet.getNewBoardingAddress} after the rotated contract is persisted.
|
|
1351
|
+
*/
|
|
1352
|
+
setBoardingTapscriptForRotation(tapscript: DefaultVtxo.Script): void;
|
|
1353
|
+
/**
|
|
1354
|
+
* @internal Sole write path for `arkServerPublicKey`; called by
|
|
1355
|
+
* {@link Wallet.rotateServerSigner} after the rotated rows are persisted.
|
|
1356
|
+
*/
|
|
1357
|
+
setArkServerPublicKeyForRotation(serverPubKey: Bytes): void;
|
|
1358
|
+
/**
|
|
1359
|
+
* Checkpoint output script from the server's `checkpointTapscript`; pinned at construction,
|
|
1360
|
+
* re-sourced only via {@link setServerUnrollScriptForRotation}.
|
|
1361
|
+
*/
|
|
1362
|
+
protected _serverUnrollScript: CSVMultisigTapscript.Type;
|
|
1363
|
+
get serverUnrollScript(): CSVMultisigTapscript.Type;
|
|
1364
|
+
/**
|
|
1365
|
+
* @internal Sole write path for `serverUnrollScript`; called by
|
|
1366
|
+
* {@link Wallet._doRotateServerSigner} with the rotating `ArkadeInfo`'s checkpoint script.
|
|
1367
|
+
*/
|
|
1368
|
+
setServerUnrollScriptForRotation(script: CSVMultisigTapscript.Type): void;
|
|
1369
|
+
/**
|
|
1370
|
+
* Serializes {@link rotateServerSigner} for static / non-HD wallets so two callers can't both
|
|
1371
|
+
* swap the tapscripts; HD wallets use {@link WalletReceiveRotator.runExclusive} instead.
|
|
1372
|
+
*/
|
|
1373
|
+
private _serverRotationChain;
|
|
1374
|
+
/**
|
|
1375
|
+
* Allocate a *fresh* on-chain boarding address at the next index of the shared HD stream and
|
|
1376
|
+
* make it the displayed one (NArk: `GetNextContract(NextContractPurpose.Boarding)`).
|
|
1377
|
+
* Persists an `active` `boarding` contract tagged {@link WALLET_RECEIVE_SOURCE} so it is
|
|
1378
|
+
* watched, restored at boot and signable per index.
|
|
1379
|
+
*
|
|
1380
|
+
* A static / `auto` wallet returns {@link getBoardingAddress} unchanged (no index burned). A
|
|
1381
|
+
* custom {@link DescriptorProvider} wallet burns an index per call, including via
|
|
1382
|
+
* {@link maybeRotateBoardingAfterBoard} on every settle consuming a boarding UTXO; retired
|
|
1383
|
+
* addresses stay reachable through {@link getBoardingUtxos}.
|
|
1384
|
+
*
|
|
1385
|
+
* @deprecated Use {@link getNewAddresses} — it mints any combination of
|
|
1386
|
+
* address types at one shared index, and reports the contract row behind
|
|
1387
|
+
* each. Note the difference in display behaviour: this method *swaps* the
|
|
1388
|
+
* advertised boarding address, where `getNewAddresses` mints side
|
|
1389
|
+
* addresses and leaves {@link getBoardingAddress} alone. To keep this
|
|
1390
|
+
* method's behaviour, keep calling this method.
|
|
1391
|
+
*/
|
|
1392
|
+
getNewBoardingAddress(): Promise<string>;
|
|
1393
|
+
/**
|
|
1394
|
+
* Allocate a *fresh* address of each requested type, all at **one** new HD index. The way to
|
|
1395
|
+
* issue a second address before the first is paid ({@link getAddress} only advances on
|
|
1396
|
+
* receipt). Each is persisted `active` with its `signingDescriptor`, so it is watched,
|
|
1397
|
+
* counted, and signable via {@link signerForDescriptor}; the look-ahead band slides.
|
|
1398
|
+
*
|
|
1399
|
+
* Rows are deliberately **untagged**: boot adopts the newest {@link WALLET_RECEIVE_SOURCE} row
|
|
1400
|
+
* as the display address, and a side address must not become what the wallet advertises.
|
|
1401
|
+
* {@link getAddress} and {@link getBoardingAddress} are unchanged.
|
|
1402
|
+
*
|
|
1403
|
+
* A wallet with no HD stream (`static` / `auto`) returns its persisted display rows, or with
|
|
1404
|
+
* `forceNew` throws {@link WalletCannotAllocateAddressError} rather than return a stale one.
|
|
1405
|
+
*
|
|
1406
|
+
* @example
|
|
1407
|
+
* ```typescript
|
|
1408
|
+
* const [invoice] = await wallet.getNewAddresses({ forceNew: true });
|
|
1409
|
+
* // hand `invoice.address` to Alice, keep the descriptor with the invoice
|
|
1410
|
+
* const signer = await wallet.signerForDescriptor(invoice.signingDescriptor);
|
|
1411
|
+
* ```
|
|
1412
|
+
*/
|
|
1413
|
+
getNewAddresses(opts?: GetNewAddressesOptions): Promise<NewAddress[]>;
|
|
1414
|
+
/**
|
|
1415
|
+
* Shared core of {@link getNewAddresses} and {@link getNewBoardingAddress}.
|
|
1416
|
+
*
|
|
1417
|
+
* @param tagSource - Tag rows {@link WALLET_RECEIVE_SOURCE} so boot adopts them as the display
|
|
1418
|
+
* address; only the deprecated boarding allocator passes `true`.
|
|
1419
|
+
*/
|
|
1420
|
+
private allocateAddresses;
|
|
1421
|
+
/**
|
|
1422
|
+
* The wallet's existing display addresses as persisted rows, each minted from the descriptor
|
|
1423
|
+
* that owns its display script ({@link displayDescriptor}) so it signs for `address`.
|
|
1424
|
+
*/
|
|
1425
|
+
private currentAddresses;
|
|
1426
|
+
/**
|
|
1427
|
+
* The descriptor owning the current display script for `type`, from its persisted row. Not
|
|
1428
|
+
* derived from the identity: on a rotated wallet that would pair the address with a signer
|
|
1429
|
+
* holding the wrong key. Falls back to the identity's `tr(pubkey)` when no row carries one
|
|
1430
|
+
* (static / `auto`; index-0 baselines have no `signingDescriptor`).
|
|
1431
|
+
*/
|
|
1432
|
+
private displayDescriptor;
|
|
1433
|
+
/**
|
|
1434
|
+
* Build, persist and shape one address of `type` owned by `descriptor`. The descriptor is the
|
|
1435
|
+
* sole source of the owner key in both branches, so `address` and `signingDescriptor` can't
|
|
1436
|
+
* drift apart.
|
|
1437
|
+
*/
|
|
1438
|
+
private mintAddress;
|
|
1439
|
+
/**
|
|
1440
|
+
* Boarding contract owned by `pubKey`, keeping the current tapscript's other options
|
|
1441
|
+
* (offchain analogue: {@link buildReceiveContract}).
|
|
1442
|
+
*/
|
|
1443
|
+
private buildBoardingContract;
|
|
1444
|
+
/**
|
|
1445
|
+
* @see HDWalletCapable.getCurrentSigningDescriptor
|
|
1446
|
+
*/
|
|
1447
|
+
getCurrentSigningDescriptor(): Promise<string | undefined>;
|
|
1448
|
+
/**
|
|
1449
|
+
* @see HDAllocationCapable.getNextSigningDescriptor
|
|
1450
|
+
*
|
|
1451
|
+
* Every `Wallet` answers, so consumers never branch on wallet shape: HD allocates through the
|
|
1452
|
+
* contract manager; otherwise the identity key as `tr(pubkey)`, the same every call.
|
|
1453
|
+
*/
|
|
1454
|
+
getNextSigningDescriptor(): Promise<string | undefined>;
|
|
1455
|
+
/**
|
|
1456
|
+
* @see HDAllocationCapable.advanceSigningDescriptorWatermark
|
|
1457
|
+
*/
|
|
1458
|
+
advanceSigningDescriptorWatermark(descriptor: string): Promise<void>;
|
|
1459
|
+
/**
|
|
1460
|
+
* @see HDWalletCapable.getUsedSigningDescriptors
|
|
1461
|
+
*
|
|
1462
|
+
* Union of the watermark band (covers indices allocated for unpersisted things, e.g. swaps)
|
|
1463
|
+
* and descriptors persisted on contracts (covers rows a restore scan wrote).
|
|
1464
|
+
*/
|
|
1465
|
+
getUsedSigningDescriptors(opts?: {
|
|
1466
|
+
lookAhead?: number;
|
|
1467
|
+
}): Promise<string[]>;
|
|
1468
|
+
/**
|
|
1469
|
+
* @see HDWalletCapable.signerForDescriptor
|
|
1470
|
+
*
|
|
1471
|
+
* Fail-loud: a descriptor this wallet can't sign for throws {@link ForeignDescriptorError}
|
|
1472
|
+
* rather than substituting the baseline identity, which would sign with the wrong key.
|
|
1473
|
+
*/
|
|
1474
|
+
signerForDescriptor(descriptor: string): Promise<Identity>;
|
|
1475
|
+
/**
|
|
1476
|
+
* Mid-session server-signer rotation. A wallet built before arkd rotated keeps deriving
|
|
1477
|
+
* old-signer receive addresses, and a migration output to one yields a VTXO the server must
|
|
1478
|
+
* reject, so receive state is re-derived under the new signer first.
|
|
1479
|
+
*
|
|
1480
|
+
* Same write-path as {@link WalletReceiveRotator.rotate} with the server key swapped: build the
|
|
1481
|
+
* new tapscripts, register their rows (carrying signing metadata so a descriptor-backed
|
|
1482
|
+
* pubkey still signs), and only then commit visible state. Old-signer rows stay `active` for
|
|
1483
|
+
* the migration pass to drain. Idempotent; serialized against HD receive rotation.
|
|
1484
|
+
*
|
|
1485
|
+
* @internal Invoked by the {@link VtxoManager} migration pass; not part of
|
|
1486
|
+
* the stable public API.
|
|
1487
|
+
*/
|
|
1488
|
+
rotateServerSigner(newServerPubKey: Bytes, checkpointTapscript: string): Promise<void>;
|
|
1489
|
+
private _doRotateServerSigner;
|
|
1490
|
+
/**
|
|
1491
|
+
* Serializes `settle`/`send` so VtxoManager's background renewal can't race user
|
|
1492
|
+
* transactions for the same inputs.
|
|
1493
|
+
*/
|
|
1494
|
+
private _txLock;
|
|
1495
|
+
private readonly _settlingOutpoints;
|
|
1496
|
+
/** Coalesces concurrent {@link restore} calls into one scan; cleared on settle. */
|
|
1497
|
+
private _restoreInFlight?;
|
|
1498
|
+
private _addPendingSpends;
|
|
1499
|
+
private _removePendingSpends;
|
|
1500
|
+
private _withTxLock;
|
|
1501
|
+
/**
|
|
1502
|
+
* Explicitly recover this wallet's contracts and balance on a fresh repo: a gap-limit scan
|
|
1503
|
+
* for HD wallets, the single default pubkey otherwise. Throws on operational failure (a
|
|
1504
|
+
* truncated restore is loud), never because of identity/mode. Idempotent.
|
|
1505
|
+
*
|
|
1506
|
+
* Ordering: scan → advance the HD watermark → inline VTXO pull → only THEN surface handler
|
|
1507
|
+
* errors, so safely-discovered funds are recovered even when one handler failed.
|
|
1508
|
+
*
|
|
1509
|
+
* @param opts.gapLimit - Consecutive-unused-index window. Default 20. A non-positive /
|
|
1510
|
+
* non-integer value throws synchronously.
|
|
1511
|
+
*
|
|
1512
|
+
* @note Concurrent calls coalesce onto the running scan; their `gapLimit` is ignored.
|
|
1513
|
+
*/
|
|
1514
|
+
restore(opts?: {
|
|
1515
|
+
gapLimit?: number;
|
|
1516
|
+
}): Promise<void>;
|
|
1517
|
+
private _runRestore;
|
|
1518
|
+
readonly settlementConfig: SettlementConfig | false;
|
|
1519
|
+
/** Public here; `ReadonlyWallet` keeps it protected so a readonly view can't submit. */
|
|
1520
|
+
readonly arkProvider: ArkProvider;
|
|
1521
|
+
/**
|
|
1522
|
+
* Broadcast access bound to this wallet's server, so a plugin needs only the wallet. Not on
|
|
1523
|
+
* {@link ReadonlyWallet}: a readonly wallet or `toReadonly()` view must not be able to submit.
|
|
1524
|
+
*/
|
|
1525
|
+
getArkadeBroadcaster(): Promise<ArkadeBroadcaster>;
|
|
1526
|
+
protected constructor(identity: Identity, network: Network, onchainProvider: OnchainProvider, arkProvider: ArkProvider, indexerProvider: IndexerProvider, arkServerPublicKey: Bytes, offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script, boardingTapscript: DefaultVtxo.Script, serverUnrollScript: CSVMultisigTapscript.Type, forfeitOutputScript: Bytes, forfeitPubkey: Bytes, dustAmount: bigint, walletRepository: WalletRepository, contractRepository: ContractRepository, delegateProvider?: DelegateProvider, watcherConfig?: WalletConfig["watcherConfig"], settlementConfig?: WalletConfig["settlementConfig"], walletContractTimelocks?: RelativeTimelock[], receiveRotator?: WalletReceiveRotator, descriptorProvider?: DescriptorProvider, keyring?: KeyringDescriptorProvider, lookAheadWindow?: number,
|
|
1527
|
+
/** Overrides for the `batchExpiry` bounds; defaults derive from `network`. */
|
|
1528
|
+
batchExpiryPolicy?: Partial<BatchExpiryPolicy> | undefined,
|
|
1529
|
+
/** Overrides for the checkpoint exit delay bounds; defaults derive from `network`. */
|
|
1530
|
+
checkpointExitDelayPolicy?: Partial<CheckpointExitDelayPolicy> | undefined);
|
|
1531
|
+
get assetManager(): IAssetManager;
|
|
1532
|
+
getVtxoManager(): Promise<VtxoManager>;
|
|
1533
|
+
dispose(): Promise<void>;
|
|
1534
|
+
/**
|
|
1535
|
+
* Create a full wallet and initialize its background managers.
|
|
1536
|
+
*
|
|
1537
|
+
* @param config - Wallet configuration
|
|
1538
|
+
* @returns A wallet ready to query balances and send transactions
|
|
1539
|
+
* @example
|
|
1540
|
+
* ```typescript
|
|
1541
|
+
* const wallet = await Wallet.create({
|
|
1542
|
+
* identity,
|
|
1543
|
+
* arkProvider: new RestArkProvider(),
|
|
1544
|
+
* });
|
|
1545
|
+
* ```
|
|
1546
|
+
*/
|
|
1547
|
+
static create<T extends Wallet>(this: {
|
|
1548
|
+
prototype: T;
|
|
1549
|
+
}, config: WalletConfig): Promise<T>;
|
|
1550
|
+
static create(config: WalletConfig): Promise<Wallet>;
|
|
1551
|
+
/**
|
|
1552
|
+
* Convert this wallet to a readonly wallet.
|
|
1553
|
+
*
|
|
1554
|
+
* @returns A readonly wallet with the same configuration but readonly identity
|
|
1555
|
+
* @example
|
|
1556
|
+
* ```typescript
|
|
1557
|
+
* const wallet = await Wallet.create({ identity: MnemonicIdentity.fromMnemonic('abandon abandon...'), ... });
|
|
1558
|
+
* const readonlyWallet = await wallet.toReadonly();
|
|
1559
|
+
*
|
|
1560
|
+
* // Can query balance and addresses
|
|
1561
|
+
* const balance = await readonlyWallet.getBalance();
|
|
1562
|
+
* const address = await readonlyWallet.getAddress();
|
|
1563
|
+
*
|
|
1564
|
+
* // But cannot send transactions (type error)
|
|
1565
|
+
* // readonlyWallet.send(...); // TypeScript error
|
|
1566
|
+
* ```
|
|
1567
|
+
*/
|
|
1568
|
+
toReadonly(): Promise<ReadonlyWallet>;
|
|
1569
|
+
/** Returns the delegate manager when delegation support is configured. */
|
|
1570
|
+
getDelegateManager(): Promise<IDelegateManager | undefined>;
|
|
1571
|
+
/**
|
|
1572
|
+
* Settle boarding inputs and/or virtual outputs into a finalized mainnet transaction.
|
|
1573
|
+
*
|
|
1574
|
+
* `params.inputs` is **ungated** (how an escrowed deposit is recovered by hand), so
|
|
1575
|
+
* `settle({ inputs: await wallet.getVtxos() })` bypasses the gate; pass
|
|
1576
|
+
* {@link getSpendableVtxos} to settle "whatever is spendable".
|
|
1577
|
+
*
|
|
1578
|
+
* @param params - Optional settlement inputs and outputs. When omitted, the wallet settles all eligible funds.
|
|
1579
|
+
* @param eventCallback - Optional callback invoked for settlement stream events.
|
|
1580
|
+
* @returns The finalized Arkade transaction id
|
|
1581
|
+
*/
|
|
1582
|
+
settle(params?: SettleParams, eventCallback?: (event: SettlementEvent) => void): Promise<string>;
|
|
1583
|
+
private _settleImpl;
|
|
1584
|
+
/**
|
|
1585
|
+
* Rotate-on-board: the boarding analogue of {@link WalletReceiveRotator}'s L2 rotation.
|
|
1586
|
+
* Boarding has no on-chain receive event (the watcher sees only the L2 indexer), so a settle
|
|
1587
|
+
* consuming a boarding UTXO (a non-VTXO, non-arknote input) is the trigger. No-op without a
|
|
1588
|
+
* descriptor provider. Best-effort: the settle has committed, so failures are only logged.
|
|
1589
|
+
*/
|
|
1590
|
+
private maybeRotateBoardingAfterBoard;
|
|
1591
|
+
private handleSettlementFinalizationEvent;
|
|
1592
|
+
private unsignableBoardingInputError;
|
|
1593
|
+
/**
|
|
1594
|
+
* Create a batch event handler for settlement flows.
|
|
1595
|
+
*
|
|
1596
|
+
* @param intentId - The intent ID.
|
|
1597
|
+
* @param inputs - Inputs used by the intent.
|
|
1598
|
+
* @param expectedRecipients - Expected recipients to validate in the virtual output tree.
|
|
1599
|
+
* @param session - Optional musig2 signing session. When omitted, signing steps are skipped.
|
|
1600
|
+
*/
|
|
1601
|
+
createBatchHandler(intentId: string, inputs: ExtendedCoin[], expectedRecipients: Recipient[], session?: SignerSession): Batch.Handler;
|
|
1602
|
+
/**
|
|
1603
|
+
* Signing jobs keyed by each input's own `witnessUtxo.script`; inputs without one
|
|
1604
|
+
* (cosigner/connector) are silently omitted.
|
|
1605
|
+
*/
|
|
1606
|
+
private inputSigningJobsFromWitnessUtxos;
|
|
1607
|
+
/**
|
|
1608
|
+
* Best-effort upsert into {@link intentRepository}; never throws into the settle path.
|
|
1609
|
+
* Preserves fields the event reducer already wrote.
|
|
1610
|
+
*/
|
|
1611
|
+
private persistIntentSnapshot;
|
|
1612
|
+
signInputsByWitnessScript(tx: Transaction): Promise<Transaction>;
|
|
1613
|
+
signOnchainBoardingTx(tx: Transaction): Promise<Transaction>;
|
|
1614
|
+
safeRegisterIntent(intent: SignedIntent<Intent.RegisterMessage>, inputs: ExtendedCoin[]): Promise<string>;
|
|
1615
|
+
makeRegisterIntentSignature(coins: ExtendedCoin[], outputs: TransactionOutput[], onchainOutputsIndexes: number[], cosignerPubKeys: string[], validAt?: number): Promise<SignedIntent<Intent.RegisterMessage>>;
|
|
1616
|
+
makeDeleteIntentSignature(coins: ExtendedCoin[]): Promise<SignedIntent<Intent.DeleteMessage>>;
|
|
1617
|
+
makeGetPendingTxIntentSignature(coins: ExtendedVirtualCoin[]): Promise<SignedIntent<Intent.GetPendingTxMessage>>;
|
|
1618
|
+
/**
|
|
1619
|
+
* Finalizes pending transactions by retrieving them from the server and finalizing each one.
|
|
1620
|
+
* Skips the server check entirely when no send was interrupted (no pending tx flag set).
|
|
1621
|
+
* @param vtxos - Optional list of virtual outputs to use instead of retrieving them from the server
|
|
1622
|
+
* @returns Array of transaction IDs that were finalized
|
|
1623
|
+
*/
|
|
1624
|
+
finalizePendingTxs(vtxos?: ExtendedVirtualCoin[]): Promise<{
|
|
1625
|
+
finalized: string[];
|
|
1626
|
+
pending: string[];
|
|
1627
|
+
}>;
|
|
1628
|
+
/**
|
|
1629
|
+
* Server unroll scripts a pending checkpoint may have been built under: configured, current,
|
|
1630
|
+
* and one per deprecated signer — else a pre-rotation tx would stay pending forever.
|
|
1631
|
+
*/
|
|
1632
|
+
private checkpointUnrollCandidates;
|
|
1633
|
+
private hasPendingTxFlag;
|
|
1634
|
+
private setPendingTxFlag;
|
|
1635
|
+
/**
|
|
1636
|
+
* Create an ArkadeCash bearer instrument: sends `amount` to a DefaultVtxo controlled by a fresh
|
|
1637
|
+
* key and returns the encoded token, claimable via `claimCash()` without sharing an address.
|
|
1638
|
+
*
|
|
1639
|
+
* Short-lived: it carries a private key, so hand it over and claim it promptly. Unclaimed past
|
|
1640
|
+
* its batch expiry it is swept, and `claimCash` can only report it.
|
|
1641
|
+
*
|
|
1642
|
+
* @param amount - Whole sats at or above dust (below dust mints an unspendable OP_RETURN).
|
|
1643
|
+
* @returns The encoded arkadeCash string (e.g., "arkadecash1...")
|
|
1644
|
+
*/
|
|
1645
|
+
createCash(amount: number): Promise<string>;
|
|
1646
|
+
/**
|
|
1647
|
+
* Claim an ArkadeCash bearer instrument: sweep what can be swept, recover what
|
|
1648
|
+
* was swept by the server, report the rest.
|
|
1649
|
+
*
|
|
1650
|
+
* Every spendable VTXO at the arkadeCash address is swept to this wallet in
|
|
1651
|
+
* its own offchain transaction, signed with the key carried by the arkadeCash
|
|
1652
|
+
* string. A VTXO the server already swept at batch expiry cannot move
|
|
1653
|
+
* through the thin sweep — only a settlement can lift it — so it is
|
|
1654
|
+
* **imported** as a signable `default` contract (the arkadeCash key is filed
|
|
1655
|
+
* in the keyring) and handed to the wallet's own recovery machinery, which
|
|
1656
|
+
* settles it back on the normal retry cadence. That import is the only
|
|
1657
|
+
* thing `claimCash` persists, and the key is purged once recovery
|
|
1658
|
+
* completes. Anything neither sweepable nor recoverable — subdust, already
|
|
1659
|
+
* claimed, or asset-bearing — is returned in `unclaimed` with a per-VTXO
|
|
1660
|
+
* reason and otherwise ignored.
|
|
1661
|
+
*
|
|
1662
|
+
* The arkadeCash string is the recovery token: a claim interrupted between
|
|
1663
|
+
* submit and finalize is completed by simply re-running `claimCash`, which
|
|
1664
|
+
* drains any pending arkadeCash transaction on the server before sweeping.
|
|
1665
|
+
* The import is idempotent, so re-running is always safe.
|
|
1666
|
+
*
|
|
1667
|
+
* @param cashStr - The encoded arkadeCash string (e.g., "arkadecash1...")
|
|
1668
|
+
* @returns What was swept instantly, what was imported for recovery, and
|
|
1669
|
+
* what was left behind. The shape is open: further buckets may be added.
|
|
1670
|
+
*/
|
|
1671
|
+
claimCash(cashStr: string): Promise<ArkadeCashClaimResult>;
|
|
1672
|
+
/**
|
|
1673
|
+
* Import an arkadeCash instrument as a signable, recovery-only contract so the
|
|
1674
|
+
* wallet's own recovery machinery can settle its server-swept VTXOs back.
|
|
1675
|
+
*
|
|
1676
|
+
* Two writes, both idempotent so a re-run (or a resumed claim) is safe:
|
|
1677
|
+
* - the arkadeCash private key is filed in the keyring, returning its
|
|
1678
|
+
* `tr(<pubkey>)` descriptor;
|
|
1679
|
+
* - a `default` contract for the arkadeCash script is registered carrying that
|
|
1680
|
+
* descriptor as `metadata.signingDescriptor` (so the signer router can
|
|
1681
|
+
* sign the swept inputs) and `metadata.recoveryOnly` (so the contract is
|
|
1682
|
+
* settled in its own isolated intent, never bundled into the wallet's own
|
|
1683
|
+
* renewal/recovery — a persistently rejected input then dents only its
|
|
1684
|
+
* own recovery, never the wallet's funds).
|
|
1685
|
+
*
|
|
1686
|
+
* A row may already exist at the script WITHOUT the recovery flags — the
|
|
1687
|
+
* public `createContract` surface lets a consumer register the cash
|
|
1688
|
+
* address (e.g. to watch a note it issued) — and `createContract`'s
|
|
1689
|
+
* same-type idempotency keeps such a row as-is. It is then promoted:
|
|
1690
|
+
* presenting the bearer key IS the authorization to claim, and left
|
|
1691
|
+
* unflagged the row would feed unsignable swept VTXOs into the wallet's
|
|
1692
|
+
* own settles while being invisible to both the isolated recovery pass
|
|
1693
|
+
* and `removeRecoveryContract`'s purge.
|
|
1694
|
+
*/
|
|
1695
|
+
private importArkadeCashForRecovery;
|
|
1696
|
+
/** Best-effort, non-blocking trigger of the isolated imported-recovery pass. */
|
|
1697
|
+
private kickImportedRecovery;
|
|
1698
|
+
/**
|
|
1699
|
+
* Retire a contract imported for recovery once its funds have been settled
|
|
1700
|
+
* back: purge the keyring key that backed it, then delete the contract row.
|
|
1701
|
+
* Ends the key-at-rest window opened by {@link importArkadeCashForRecovery}.
|
|
1702
|
+
*
|
|
1703
|
+
* Scoped to recovery-only contracts as a safety guard — it will not touch a
|
|
1704
|
+
* regular wallet contract — and idempotent: a second call (the contract
|
|
1705
|
+
* already gone) is a no-op. Invoked by the isolated recovery pass in
|
|
1706
|
+
* `VtxoManager` (see its `RecoveryContractCapableWallet` capability).
|
|
1707
|
+
*
|
|
1708
|
+
* The write order is load-bearing; do not swap it. The two repositories
|
|
1709
|
+
* cannot be written atomically, so one of them leaks on a partial failure.
|
|
1710
|
+
* Purging the key first leaves a contract row with a dangling descriptor:
|
|
1711
|
+
* visible, harmless, and retried to completion by the next recovery pass
|
|
1712
|
+
* (its VTXOs read back spent, so nothing is signed). The reverse leaves an
|
|
1713
|
+
* unencrypted key that nothing references — the descriptor lived only in
|
|
1714
|
+
* the row just deleted — so no retry can ever find it, breaking the
|
|
1715
|
+
* purge-on-completion bound that justifies storing it in the clear.
|
|
1716
|
+
*/
|
|
1717
|
+
removeRecoveryContract(script: string): Promise<void>;
|
|
1718
|
+
/**
|
|
1719
|
+
* Split the VTXOs at an arkadeCash address into three buckets: the ones the
|
|
1720
|
+
* thin sweep can move (`spendable`), the server-swept ones that must go
|
|
1721
|
+
* through a recovery settlement (`recoverable`), and the ones that can
|
|
1722
|
+
* only be reported (`unclaimed`).
|
|
1723
|
+
*/
|
|
1724
|
+
private classifyCashVtxos;
|
|
1725
|
+
/** Read every page of an unfiltered VTXO query for the given scripts. */
|
|
1726
|
+
private fetchAllVtxos;
|
|
1727
|
+
/**
|
|
1728
|
+
* Complete sweeps a previous `claimCash` registered but never finalized: a thin
|
|
1729
|
+
* {@link finalizePendingTxs} signed with the arkadeCash key. A drained tx pays whoever
|
|
1730
|
+
* registered it, so finalizing is still right, but only value paid to `myPkScript` counts.
|
|
1731
|
+
*
|
|
1732
|
+
* @param vtxos - VTXOs at the cash contract's own pkScript, spent included; any other
|
|
1733
|
+
* outpoint (subdust above all) would invalidate the proof.
|
|
1734
|
+
* @returns Txs finalized, sats paid to this wallet, and the outpoints consumed to pay it.
|
|
1735
|
+
*/
|
|
1736
|
+
private finalizePendingCashTxs;
|
|
1737
|
+
/** Sum the outputs of an ark tx PSBT that pay the given scriptPubKey. */
|
|
1738
|
+
private arkTxAmountPaidTo;
|
|
1739
|
+
/**
|
|
1740
|
+
* Send BTC and/or assets to one or more recipients, passed either as
|
|
1741
|
+
* variadic `Recipient`s or as a single `SendParams` object — the latter
|
|
1742
|
+
* also carries the virtual outputs to spend.
|
|
1743
|
+
*
|
|
1744
|
+
* @param args - Recipients, or a `SendParams` object
|
|
1745
|
+
* @returns Promise resolving to the Arkade transaction ID
|
|
1746
|
+
* @see SendParams
|
|
1747
|
+
*
|
|
1748
|
+
* @example
|
|
1749
|
+
* ```typescript
|
|
1750
|
+
* const txid = await wallet.send({
|
|
1751
|
+
* address: 'ark1q...',
|
|
1752
|
+
* amount: 1000, // (optional, default to dust) btc amount to send to the output
|
|
1753
|
+
* assets: [{ assetId: 'abc123...', amount: 50n }] // (optional) list of assets to send
|
|
1754
|
+
* });
|
|
1755
|
+
*
|
|
1756
|
+
* // choosing the inputs as well as the outputs
|
|
1757
|
+
* const txid = await wallet.send({
|
|
1758
|
+
* recipients: [{ address: 'ark1q...', amount: 1000 }],
|
|
1759
|
+
* selectedVtxos: mine, // spent as given, nothing added
|
|
1760
|
+
* });
|
|
1761
|
+
* ```
|
|
1762
|
+
*/
|
|
1763
|
+
send(...args: [SendParams] | [Recipient, ...Recipient[]]): Promise<string>;
|
|
1764
|
+
private _sendImpl;
|
|
1765
|
+
/**
|
|
1766
|
+
* Shared submit/persist tail of `send` and {@link sendSelectedVtxosToSelf}; callers own coin
|
|
1767
|
+
* selection, outputs and the synchronous epoch snapshot.
|
|
1768
|
+
*/
|
|
1769
|
+
private _submitOffchainSpend;
|
|
1770
|
+
/**
|
|
1771
|
+
* @internal Migration primitive for {@link VtxoManager}: spend the wallet's own
|
|
1772
|
+
* deprecated-signer VTXOs into one full-value output on the *active* signer, via the Ark send
|
|
1773
|
+
* path (not `settle`) so arkd builds checkpoints against the active epoch. No boarding inputs.
|
|
1774
|
+
* The caller must already be on the active signer and have sized the batch. Preserves all
|
|
1775
|
+
* input assets; records no `TxSent` history.
|
|
1776
|
+
*/
|
|
1777
|
+
sendSelectedVtxosToSelf(inputs: ExtendedVirtualCoin[], now?: TimeHeight): Promise<string>;
|
|
1778
|
+
/**
|
|
1779
|
+
* Build an offchain transaction from the given inputs and outputs,
|
|
1780
|
+
* sign it, submit to the Arkade provider, and finalize.
|
|
1781
|
+
*
|
|
1782
|
+
* Signs whatever it is handed, ungated — see {@link settle} for the trade.
|
|
1783
|
+
*
|
|
1784
|
+
* @returns The Arkade transaction id and server-signed checkpoint PSBTs (for bookkeeping)
|
|
1785
|
+
*/
|
|
1786
|
+
buildAndSubmitOffchainTx(inputs: ExtendedVirtualCoin[], outputs: TransactionOutput[], serverUnrollScript?: CSVMultisigTapscript.Type): Promise<{
|
|
1787
|
+
arkTxid: string;
|
|
1788
|
+
signedCheckpointTxs: string[];
|
|
1789
|
+
}>;
|
|
1790
|
+
private updateDbAfterOffchainTx;
|
|
1791
|
+
private updateDbAfterSettle;
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1794
|
+
* Select virtual outputs to reach a target amount, prioritizing those closer to expiry
|
|
1795
|
+
* @param coins List of virtual outputs to select from
|
|
1796
|
+
* @param targetAmount Target amount to reach in satoshis
|
|
1797
|
+
* @returns Selected virtual outputs and change amount
|
|
1798
|
+
*/
|
|
1799
|
+
declare function selectVirtualCoins(coins: ExtendedVirtualCoin[], targetAmount: number): {
|
|
1800
|
+
inputs: ExtendedVirtualCoin[];
|
|
1801
|
+
changeAmount: bigint;
|
|
1802
|
+
};
|
|
1803
|
+
/**
|
|
1804
|
+
* Raised when a wait is cancelled through its `AbortSignal` or `timeoutMs`. `name` is
|
|
1805
|
+
* `"AbortError"`, so DOM and SDK aborts can be handled identically.
|
|
1806
|
+
*/
|
|
1807
|
+
declare class AbortError extends Error {
|
|
1808
|
+
constructor(message?: string);
|
|
1809
|
+
}
|
|
1810
|
+
/** Options for {@link waitForIncomingFunds}. */
|
|
1811
|
+
interface WaitForIncomingFundsOptions {
|
|
1812
|
+
/**
|
|
1813
|
+
* Cancels the wait. On abort the underlying subscription is stopped and
|
|
1814
|
+
* the returned promise rejects — with the signal's `reason` when the
|
|
1815
|
+
* caller supplied an `Error`, otherwise an {@link AbortError}.
|
|
1816
|
+
*/
|
|
1817
|
+
signal?: AbortSignal;
|
|
1818
|
+
/**
|
|
1819
|
+
* Cancels the wait after this many milliseconds, rejecting with an
|
|
1820
|
+
* {@link AbortError}. Equivalent to passing an `AbortSignal.timeout`
|
|
1821
|
+
* signal, without requiring that API on the target platform.
|
|
1822
|
+
*/
|
|
1823
|
+
timeoutMs?: number;
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* Wait for incoming funds to the wallet.
|
|
1827
|
+
*
|
|
1828
|
+
* Keeps live network watchers open until it settles. **Cancel it if you won't await it to
|
|
1829
|
+
* completion** (`signal` / `timeoutMs`): a `Promise.race` against a timer abandons the loser
|
|
1830
|
+
* without stopping its watchers, and in a loop stacks subscriptions until the process exits.
|
|
1831
|
+
*
|
|
1832
|
+
* @param wallet - The wallet to wait for incoming funds
|
|
1833
|
+
* @param options - Cancellation options; see {@link WaitForIncomingFundsOptions}
|
|
1834
|
+
* @returns A promise that resolves the next new coins received by the wallet's address
|
|
1835
|
+
* @throws {AbortError} If cancelled via `signal` or `timeoutMs`
|
|
1836
|
+
* @example
|
|
1837
|
+
* ```typescript
|
|
1838
|
+
* // Wake early on a deposit, but give up after 30s and release the watchers.
|
|
1839
|
+
* try {
|
|
1840
|
+
* const funds = await waitForIncomingFunds(wallet, { timeoutMs: 30_000 })
|
|
1841
|
+
* } catch (e) {
|
|
1842
|
+
* if ((e as Error).name !== "AbortError") throw e
|
|
1843
|
+
* }
|
|
1844
|
+
* ```
|
|
1845
|
+
*/
|
|
1846
|
+
declare function waitForIncomingFunds(wallet: Wallet, options?: WaitForIncomingFundsOptions): Promise<IncomingFunds>;
|
|
1847
|
+
|
|
1848
|
+
export { waitForIncomingFunds as $, type AddressAllocationCapable as A, type BatchExpiryPolicy as B, type CheckpointExitDelayPolicy as C, DEFAULT_MIN_BATCH_EXPIRY_SECONDS as D, assertValidServerUnrollScript as E, ForeignDescriptorError as F, defaultBatchExpiryPolicy as G, type HDWalletCapable as H, type IncomingFunds as I, defaultCheckpointExitDelayPolicy as J, KeyringDescriptorProvider as K, isAddressAllocationCapable as L, MAX_USED_SIGNING_DESCRIPTORS_LOOK_AHEAD as M, isArkError as N, isHDAllocationCapable as O, type ProviderConnectionState as P, isHDWalletCapable as Q, ReadonlyWallet as R, SIGNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS as S, maybeArkError as T, resolveBatchExpiryPolicy as U, resolveCheckpointExitDelayPolicy as V, Wallet as W, resolveDescriptorSigner as X, selectVirtualCoins as Y, signingDescriptorIndex as Z, strictSigningDescriptorIndex as _, type HDAllocationCapable as a, type ReceiveRotatorFactory as b, type ReceiveRotatorBootOpts as c, type ReceiveRotatorBoot as d, Batch as e, AbortError as f, ArkError as g, ArkErrorName as h, type ArkadeCashClaimResult as i, ArkadeCashCreateError as j, type ArkadeCashUnclaimedReason as k, type ArkadeCashUnclaimedVtxo as l, type ArkadeCashVtxoRef as m, type BoardingUtxoGroup as n, DEFAULT_MIN_CHECKPOINT_EXIT_DELAY_SECONDS as o, IndexedDBWalletRepository as p, MUTINYNET_MIN_CHECKPOINT_EXIT_DELAY_SECONDS as q, type ProviderKind as r, ProviderUnavailableError as s, REGTEST_MIN_BATCH_EXPIRY_SECONDS as t, REGTEST_MIN_CHECKPOINT_EXIT_DELAY_SECONDS as u, type ServerInfoSource as v, ServerResponseMismatchError as w, type WaitForIncomingFundsOptions as x, WalletCannotAllocateAddressError as y, assertValidBatchExpiry as z };
|