@arkade-os/sdk 0.4.15 → 0.4.17
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 +102 -96
- package/dist/cjs/arkfee/estimator.js +1 -1
- package/dist/cjs/arkfee/types.js +2 -1
- package/dist/cjs/arknote/index.js +43 -4
- package/dist/cjs/bip322/index.js +1 -1
- package/dist/cjs/contracts/arkcontract.js +1 -1
- package/dist/cjs/contracts/contractManager.js +60 -28
- package/dist/cjs/contracts/contractWatcher.js +29 -22
- package/dist/cjs/contracts/handlers/default.js +1 -1
- package/dist/cjs/contracts/handlers/delegate.js +1 -1
- package/dist/cjs/contracts/handlers/helpers.js +1 -1
- package/dist/cjs/extension/asset/assetGroup.js +92 -5
- package/dist/cjs/extension/asset/assetId.js +67 -3
- package/dist/cjs/extension/asset/assetInput.js +18 -0
- package/dist/cjs/extension/asset/assetOutput.js +15 -0
- package/dist/cjs/extension/asset/assetRef.js +66 -0
- package/dist/cjs/extension/asset/metadata.js +15 -0
- package/dist/cjs/extension/asset/packet.js +4 -1
- package/dist/cjs/extension/index.js +1 -1
- package/dist/cjs/forfeit.js +14 -0
- package/dist/cjs/identity/seedIdentity.js +2 -2
- package/dist/cjs/identity/singleKey.js +4 -0
- package/dist/cjs/intent/index.js +28 -12
- package/dist/cjs/providers/ark.js +3 -2
- package/dist/cjs/providers/delegator.js +20 -1
- package/dist/cjs/providers/expoArk.js +2 -2
- package/dist/cjs/providers/indexer.js +2 -2
- package/dist/cjs/providers/onchain.js +2 -1
- package/dist/cjs/repositories/realm/schemas.js +2 -2
- package/dist/cjs/repositories/realm/types.js +1 -1
- package/dist/cjs/script/address.js +37 -6
- package/dist/cjs/script/base.js +70 -1
- package/dist/cjs/script/default.js +3 -0
- package/dist/cjs/script/delegate.js +4 -0
- package/dist/cjs/script/tapscript.js +17 -2
- package/dist/cjs/script/vhtlc.js +35 -27
- package/dist/cjs/storage/fileSystem.js +1 -1
- package/dist/cjs/storage/inMemory.js +1 -1
- package/dist/cjs/storage/indexedDB.js +1 -1
- package/dist/cjs/storage/localStorage.js +1 -1
- package/dist/cjs/tree/validation.js +1 -1
- package/dist/cjs/utils/arkTransaction.js +5 -5
- package/dist/cjs/utils/bip21.js +16 -3
- package/dist/cjs/utils/syncCursors.js +4 -4
- package/dist/cjs/utils/transaction.js +1 -1
- package/dist/cjs/utils/transactionHistory.js +11 -11
- package/dist/cjs/utils/unknownFields.js +3 -3
- package/dist/cjs/wallet/asset-manager.js +4 -4
- package/dist/cjs/wallet/batch.js +5 -5
- package/dist/cjs/wallet/delegator.js +9 -8
- package/dist/cjs/wallet/expo/background.js +3 -3
- package/dist/cjs/wallet/expo/wallet.js +7 -7
- package/dist/cjs/wallet/index.js +43 -0
- package/dist/cjs/wallet/onchain.js +43 -5
- package/dist/cjs/wallet/ramps.js +44 -14
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +22 -22
- package/dist/cjs/wallet/serviceWorker/wallet.js +28 -24
- package/dist/cjs/wallet/unroll.js +12 -8
- package/dist/cjs/wallet/utils.js +1 -1
- package/dist/cjs/wallet/vtxo-manager.js +122 -82
- package/dist/cjs/wallet/wallet.js +140 -77
- package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +1 -1
- package/dist/cjs/worker/expo/processors/contractPollProcessor.js +2 -2
- package/dist/cjs/worker/expo/taskRunner.js +3 -3
- package/dist/cjs/worker/messageBus.js +3 -0
- package/dist/esm/arkfee/estimator.js +1 -1
- package/dist/esm/arkfee/types.js +2 -1
- package/dist/esm/arknote/index.js +43 -4
- package/dist/esm/bip322/index.js +1 -1
- package/dist/esm/contracts/arkcontract.js +1 -1
- package/dist/esm/contracts/contractManager.js +60 -28
- package/dist/esm/contracts/contractWatcher.js +29 -22
- package/dist/esm/contracts/handlers/default.js +1 -1
- package/dist/esm/contracts/handlers/delegate.js +1 -1
- package/dist/esm/contracts/handlers/helpers.js +1 -1
- package/dist/esm/extension/asset/assetGroup.js +92 -5
- package/dist/esm/extension/asset/assetId.js +67 -3
- package/dist/esm/extension/asset/assetInput.js +18 -0
- package/dist/esm/extension/asset/assetOutput.js +15 -0
- package/dist/esm/extension/asset/assetRef.js +66 -0
- package/dist/esm/extension/asset/metadata.js +15 -0
- package/dist/esm/extension/asset/packet.js +4 -1
- package/dist/esm/extension/index.js +1 -1
- package/dist/esm/forfeit.js +14 -0
- package/dist/esm/identity/seedIdentity.js +2 -2
- package/dist/esm/identity/singleKey.js +4 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/intent/index.js +28 -12
- package/dist/esm/providers/ark.js +3 -2
- package/dist/esm/providers/delegator.js +20 -1
- package/dist/esm/providers/expoArk.js +2 -2
- package/dist/esm/providers/indexer.js +2 -2
- package/dist/esm/providers/onchain.js +2 -1
- package/dist/esm/repositories/realm/schemas.js +2 -2
- package/dist/esm/repositories/realm/types.js +1 -1
- package/dist/esm/script/address.js +37 -6
- package/dist/esm/script/base.js +70 -1
- package/dist/esm/script/default.js +3 -0
- package/dist/esm/script/delegate.js +4 -0
- package/dist/esm/script/tapscript.js +17 -2
- package/dist/esm/script/vhtlc.js +35 -27
- package/dist/esm/storage/fileSystem.js +1 -1
- package/dist/esm/storage/inMemory.js +1 -1
- package/dist/esm/storage/indexedDB.js +1 -1
- package/dist/esm/storage/localStorage.js +1 -1
- package/dist/esm/tree/validation.js +1 -1
- package/dist/esm/utils/arkTransaction.js +5 -5
- package/dist/esm/utils/bip21.js +16 -3
- package/dist/esm/utils/syncCursors.js +4 -4
- package/dist/esm/utils/transaction.js +1 -1
- package/dist/esm/utils/transactionHistory.js +11 -11
- package/dist/esm/utils/unknownFields.js +3 -3
- package/dist/esm/wallet/asset-manager.js +4 -4
- package/dist/esm/wallet/batch.js +5 -5
- package/dist/esm/wallet/delegator.js +9 -8
- package/dist/esm/wallet/expo/background.js +3 -3
- package/dist/esm/wallet/expo/wallet.js +7 -7
- package/dist/esm/wallet/index.js +43 -0
- package/dist/esm/wallet/onchain.js +43 -5
- package/dist/esm/wallet/ramps.js +44 -14
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +22 -22
- package/dist/esm/wallet/serviceWorker/wallet.js +28 -24
- package/dist/esm/wallet/unroll.js +12 -8
- package/dist/esm/wallet/utils.js +1 -1
- package/dist/esm/wallet/vtxo-manager.js +121 -81
- package/dist/esm/wallet/wallet.js +140 -77
- package/dist/esm/worker/expo/asyncStorageTaskQueue.js +1 -1
- package/dist/esm/worker/expo/processors/contractPollProcessor.js +2 -2
- package/dist/esm/worker/expo/taskRunner.js +3 -3
- package/dist/esm/worker/messageBus.js +3 -0
- package/dist/types/arkfee/estimator.d.ts +1 -1
- package/dist/types/arkfee/types.d.ts +2 -1
- package/dist/types/arknote/index.d.ts +44 -4
- package/dist/types/bip322/index.d.ts +1 -1
- package/dist/types/contracts/arkcontract.d.ts +1 -1
- package/dist/types/contracts/contractManager.d.ts +39 -65
- package/dist/types/contracts/contractWatcher.d.ts +39 -18
- package/dist/types/contracts/handlers/default.d.ts +1 -1
- package/dist/types/contracts/handlers/delegate.d.ts +1 -1
- package/dist/types/contracts/handlers/helpers.d.ts +1 -1
- package/dist/types/contracts/types.d.ts +36 -26
- package/dist/types/extension/asset/assetGroup.d.ts +92 -1
- package/dist/types/extension/asset/assetId.d.ts +67 -3
- package/dist/types/extension/asset/assetInput.d.ts +18 -0
- package/dist/types/extension/asset/assetOutput.d.ts +15 -0
- package/dist/types/extension/asset/assetRef.d.ts +66 -0
- package/dist/types/extension/asset/metadata.d.ts +15 -0
- package/dist/types/extension/asset/packet.d.ts +4 -1
- package/dist/types/extension/index.d.ts +1 -1
- package/dist/types/forfeit.d.ts +14 -0
- package/dist/types/identity/index.d.ts +16 -0
- package/dist/types/identity/seedIdentity.d.ts +8 -6
- package/dist/types/identity/singleKey.d.ts +4 -0
- package/dist/types/intent/index.d.ts +19 -6
- package/dist/types/providers/ark.d.ts +40 -2
- package/dist/types/providers/delegator.d.ts +54 -1
- package/dist/types/providers/expoArk.d.ts +2 -2
- package/dist/types/providers/indexer.d.ts +105 -2
- package/dist/types/providers/onchain.d.ts +62 -1
- package/dist/types/repositories/realm/schemas.d.ts +2 -2
- package/dist/types/repositories/realm/types.d.ts +2 -2
- package/dist/types/repositories/walletRepository.d.ts +16 -0
- package/dist/types/script/address.d.ts +35 -2
- package/dist/types/script/base.d.ts +66 -1
- package/dist/types/script/default.d.ts +3 -0
- package/dist/types/script/delegate.d.ts +4 -0
- package/dist/types/script/tapscript.d.ts +17 -2
- package/dist/types/script/vhtlc.d.ts +35 -27
- package/dist/types/storage/fileSystem.d.ts +1 -1
- package/dist/types/storage/inMemory.d.ts +1 -1
- package/dist/types/storage/index.d.ts +1 -1
- package/dist/types/storage/indexedDB.d.ts +1 -1
- package/dist/types/storage/localStorage.d.ts +1 -1
- package/dist/types/utils/arkTransaction.d.ts +3 -3
- package/dist/types/utils/bip21.d.ts +17 -0
- package/dist/types/utils/syncCursors.d.ts +4 -4
- package/dist/types/utils/transaction.d.ts +1 -1
- package/dist/types/utils/transactionHistory.d.ts +3 -3
- package/dist/types/utils/unknownFields.d.ts +5 -5
- package/dist/types/wallet/asset-manager.d.ts +3 -3
- package/dist/types/wallet/batch.d.ts +27 -7
- package/dist/types/wallet/delegator.d.ts +10 -0
- package/dist/types/wallet/expo/background.d.ts +4 -4
- package/dist/types/wallet/expo/wallet.d.ts +10 -10
- package/dist/types/wallet/index.d.ts +457 -25
- package/dist/types/wallet/onchain.d.ts +42 -4
- package/dist/types/wallet/ramps.d.ts +40 -10
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +4 -4
- package/dist/types/wallet/serviceWorker/wallet.d.ts +71 -33
- package/dist/types/wallet/unroll.d.ts +8 -6
- package/dist/types/wallet/vtxo-manager.d.ts +146 -93
- package/dist/types/wallet/wallet.d.ts +91 -33
- package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +1 -1
- package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +1 -1
- package/dist/types/worker/expo/taskRunner.d.ts +6 -6
- package/dist/types/worker/messageBus.d.ts +5 -3
- package/package.json +1 -1
|
@@ -39,6 +39,10 @@ const contractManager_1 = require("../contracts/contractManager");
|
|
|
39
39
|
const handlers_1 = require("../contracts/handlers");
|
|
40
40
|
const helpers_1 = require("../contracts/handlers/helpers");
|
|
41
41
|
const syncCursors_1 = require("../utils/syncCursors");
|
|
42
|
+
// Hardcoded unilateral exit delay for mainnet (~7 days in seconds).
|
|
43
|
+
// Pinned here so that address derivation stays stable for existing mainnet
|
|
44
|
+
// wallets even after the server lowers the delay it advertises.
|
|
45
|
+
const MAINNET_UNILATERAL_EXIT_DELAY = 605184n;
|
|
42
46
|
/**
|
|
43
47
|
* Type guard function to check if an identity has a toReadonly method.
|
|
44
48
|
*/
|
|
@@ -113,12 +117,12 @@ class ReadonlyWallet {
|
|
|
113
117
|
const serverIsMainnet = info.network === "bitcoin";
|
|
114
118
|
if (identityIsMainnet && !serverIsMainnet) {
|
|
115
119
|
throw new Error(`Network mismatch: identity uses mainnet derivation (coin type 0) ` +
|
|
116
|
-
`but
|
|
120
|
+
`but the Arkade server is on ${info.network}. ` +
|
|
117
121
|
`Create identity with { isMainnet: false } to use testnet derivation.`);
|
|
118
122
|
}
|
|
119
123
|
if (!identityIsMainnet && serverIsMainnet) {
|
|
120
124
|
throw new Error(`Network mismatch: identity uses testnet derivation (coin type 1) ` +
|
|
121
|
-
`but
|
|
125
|
+
`but the Arkade server is on mainnet. ` +
|
|
122
126
|
`Create identity with { isMainnet: true } or omit isMainnet (defaults to mainnet).`);
|
|
123
127
|
}
|
|
124
128
|
}
|
|
@@ -134,10 +138,16 @@ class ReadonlyWallet {
|
|
|
134
138
|
throw new Error("invalid exitTimelock");
|
|
135
139
|
}
|
|
136
140
|
}
|
|
141
|
+
// On mainnet, pin the unilateral exit delay to the historical value so
|
|
142
|
+
// that addresses derived by existing wallets remain stable even if the
|
|
143
|
+
// server starts advertising a shorter delay.
|
|
144
|
+
const unilateralExitDelay = info.network === "bitcoin"
|
|
145
|
+
? MAINNET_UNILATERAL_EXIT_DELAY
|
|
146
|
+
: info.unilateralExitDelay;
|
|
137
147
|
// create unilateral exit timelock
|
|
138
148
|
const exitTimelock = config.exitTimelock ?? {
|
|
139
|
-
value:
|
|
140
|
-
type:
|
|
149
|
+
value: unilateralExitDelay,
|
|
150
|
+
type: unilateralExitDelay < 512n ? "blocks" : "seconds",
|
|
141
151
|
};
|
|
142
152
|
// validate boarding timelock passed in config if any
|
|
143
153
|
if (config.boardingTimelock) {
|
|
@@ -190,6 +200,12 @@ class ReadonlyWallet {
|
|
|
190
200
|
delegatorProvider: config.delegatorProvider,
|
|
191
201
|
};
|
|
192
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Create a readonly wallet for querying balances, addresses, and history.
|
|
205
|
+
*
|
|
206
|
+
* @param config - Readonly wallet configuration
|
|
207
|
+
* @returns A readonly wallet instance
|
|
208
|
+
*/
|
|
193
209
|
static async create(config) {
|
|
194
210
|
const pubkey = await config.identity.xOnlyPublicKey();
|
|
195
211
|
if (!pubkey) {
|
|
@@ -208,12 +224,17 @@ class ReadonlyWallet {
|
|
|
208
224
|
get defaultContractScript() {
|
|
209
225
|
return base_1.hex.encode(this.offchainTapscript.pkScript);
|
|
210
226
|
}
|
|
227
|
+
/** Returns the wallet's Arkade address. */
|
|
211
228
|
async getAddress() {
|
|
212
229
|
return this.arkAddress.encode();
|
|
213
230
|
}
|
|
231
|
+
/** Returns the onchain boarding address used to move funds into Arkade. */
|
|
214
232
|
async getBoardingAddress() {
|
|
215
233
|
return this.boardingTapscript.onchainAddress(this.network);
|
|
216
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Return the wallet's combined onchain and offchain balances.
|
|
237
|
+
*/
|
|
217
238
|
async getBalance() {
|
|
218
239
|
const [boardingUtxos, vtxos] = await Promise.all([
|
|
219
240
|
this.getBoardingUtxos(),
|
|
@@ -245,7 +266,7 @@ class ReadonlyWallet {
|
|
|
245
266
|
.reduce((sum, coin) => sum + coin.value, 0);
|
|
246
267
|
const totalBoarding = confirmed + unconfirmed;
|
|
247
268
|
const totalOffchain = settled + preconfirmed + recoverable;
|
|
248
|
-
// aggregate asset balances from spendable
|
|
269
|
+
// aggregate asset balances from spendable virtual outputs
|
|
249
270
|
const assetBalances = new Map();
|
|
250
271
|
for (const vtxo of vtxos) {
|
|
251
272
|
if (!(0, _1.isSpendable)(vtxo))
|
|
@@ -275,15 +296,16 @@ class ReadonlyWallet {
|
|
|
275
296
|
assets,
|
|
276
297
|
};
|
|
277
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Return virtual outputs tracked by the wallet.
|
|
301
|
+
*
|
|
302
|
+
* @param filter - Optional flags controlling whether recoverable or unrolled VTXOs are included
|
|
303
|
+
*/
|
|
278
304
|
async getVtxos(filter) {
|
|
279
|
-
const { isDelta, fetchedExtended, address } = await this.syncVtxos();
|
|
280
305
|
const f = filter ?? { withRecoverable: true, withUnrolled: false };
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
? await this.walletRepository.getVtxos(address)
|
|
285
|
-
: fetchedExtended;
|
|
286
|
-
return vtxos.filter((vtxo) => {
|
|
306
|
+
const contractManager = await this.getContractManager();
|
|
307
|
+
const contractsWithVtxos = await contractManager.getContractsWithVtxos();
|
|
308
|
+
return contractsWithVtxos.flatMap(({ vtxos }) => vtxos.filter((vtxo) => {
|
|
287
309
|
if ((0, _1.isSpendable)(vtxo)) {
|
|
288
310
|
if (!f.withRecoverable &&
|
|
289
311
|
((0, _1.isRecoverable)(vtxo) || (0, _1.isExpired)(vtxo))) {
|
|
@@ -292,10 +314,13 @@ class ReadonlyWallet {
|
|
|
292
314
|
return true;
|
|
293
315
|
}
|
|
294
316
|
return !!(f.withUnrolled && vtxo.isUnrolled);
|
|
295
|
-
});
|
|
317
|
+
}));
|
|
296
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* Return wallet transaction history derived from Arkade state and boarding transactions.
|
|
321
|
+
*/
|
|
297
322
|
async getTransactionHistory() {
|
|
298
|
-
// Delta-sync
|
|
323
|
+
// Delta-sync virtual outputs into cache, then build history from the cache.
|
|
299
324
|
const { isDelta, fetchedExtended, address } = await this.syncVtxos();
|
|
300
325
|
const allVtxos = isDelta
|
|
301
326
|
? await this.walletRepository.getVtxos(address)
|
|
@@ -307,7 +332,7 @@ class ReadonlyWallet {
|
|
|
307
332
|
return (0, transactionHistory_1.buildTransactionHistory)(allVtxos, boardingTxs, commitmentsToIgnore, getTxCreatedAt);
|
|
308
333
|
}
|
|
309
334
|
/**
|
|
310
|
-
* Delta-sync wallet
|
|
335
|
+
* Delta-sync wallet virtual outputs: fetch only changed virtual outputs since the last
|
|
311
336
|
* cursor, or do a full bootstrap when no cursor exists. Upserts
|
|
312
337
|
* the result into the cache and advances the sync cursors.
|
|
313
338
|
*
|
|
@@ -380,21 +405,21 @@ class ReadonlyWallet {
|
|
|
380
405
|
allVtxos.push(...response.vtxos);
|
|
381
406
|
}
|
|
382
407
|
}
|
|
383
|
-
// Extend every fetched
|
|
408
|
+
// Extend every fetched virtual output and upsert into the cache.
|
|
384
409
|
const fetchedExtended = [];
|
|
385
410
|
for (const vtxo of allVtxos) {
|
|
386
411
|
const extended = extendWithScript(vtxo);
|
|
387
412
|
if (extended)
|
|
388
413
|
fetchedExtended.push(extended);
|
|
389
414
|
}
|
|
390
|
-
// Save
|
|
415
|
+
// Save virtual outputs first, then advance cursors only on success.
|
|
391
416
|
const cutoff = (0, syncCursors_1.cursorCutoff)(requestStartedAt);
|
|
392
417
|
await this.walletRepository.saveVtxos(address, fetchedExtended);
|
|
393
418
|
await (0, syncCursors_1.advanceSyncCursors)(this.walletRepository, Object.fromEntries(allScripts.map((s) => [s, cutoff])));
|
|
394
419
|
// Delta-sync reconciliation: full re-fetch for delta scripts.
|
|
395
420
|
//
|
|
396
|
-
// The delta fetch (above) only returns
|
|
397
|
-
// cursor, so it can miss preconfirmed
|
|
421
|
+
// The delta fetch (above) only returns virtual outputs changed after the
|
|
422
|
+
// cursor, so it can miss preconfirmed virtual outputs that were consumed
|
|
398
423
|
// by a round between syncs. Rather than layering targeted
|
|
399
424
|
// queries (pendingOnly, spendableOnly) with pagination guards
|
|
400
425
|
// and set algebra, we perform a single unfiltered re-fetch for
|
|
@@ -402,8 +427,8 @@ class ReadonlyWallet {
|
|
|
402
427
|
// gives us complete, authoritative state in one call and keeps
|
|
403
428
|
// the reconciliation logic simple.
|
|
404
429
|
//
|
|
405
|
-
// Any cached non-spent
|
|
406
|
-
// result set is marked spent; any
|
|
430
|
+
// Any cached non-spent virtual output that is absent from the full
|
|
431
|
+
// result set is marked spent; any virtual output whose state changed
|
|
407
432
|
// (e.g. preconfirmed → settled) is updated in place.
|
|
408
433
|
if (hasDelta) {
|
|
409
434
|
const { vtxos: fullVtxos, page: fullPage } = await this.indexerProvider.getVtxos({
|
|
@@ -412,7 +437,7 @@ class ReadonlyWallet {
|
|
|
412
437
|
// Reconciliation is best-effort: if the response is
|
|
413
438
|
// paginated we don't have a complete picture, so we skip
|
|
414
439
|
// rather than act on partial data. Wallets with enough
|
|
415
|
-
//
|
|
440
|
+
// virtual outputs to exceed a single page rely solely on the
|
|
416
441
|
// cursor-based delta mechanism for state updates.
|
|
417
442
|
const fullSetComplete = !fullPage || fullPage.total <= 1;
|
|
418
443
|
if (fullSetComplete) {
|
|
@@ -429,7 +454,7 @@ class ReadonlyWallet {
|
|
|
429
454
|
const outpoint = `${cached.txid}:${cached.vout}`;
|
|
430
455
|
const fresh = fullOutpoints.get(outpoint);
|
|
431
456
|
if (!fresh) {
|
|
432
|
-
// Server no longer knows about this
|
|
457
|
+
// Server no longer knows about this virtual output —
|
|
433
458
|
// it was spent between syncs.
|
|
434
459
|
reconciledExtended.push({
|
|
435
460
|
...cached,
|
|
@@ -462,12 +487,15 @@ class ReadonlyWallet {
|
|
|
462
487
|
};
|
|
463
488
|
}
|
|
464
489
|
/**
|
|
465
|
-
* Clear all
|
|
490
|
+
* Clear all virtual output sync cursors, forcing a full re-bootstrap on next sync.
|
|
466
491
|
* Useful for recovery after indexer reprocessing or debugging.
|
|
467
492
|
*/
|
|
468
493
|
async clearSyncCursors() {
|
|
469
494
|
await (0, syncCursors_1.clearSyncCursors)(this.walletRepository);
|
|
470
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Build a transaction history view for the wallet's boarding address.
|
|
498
|
+
*/
|
|
471
499
|
async getBoardingTxs() {
|
|
472
500
|
const utxos = [];
|
|
473
501
|
const commitmentsToIgnore = new Set();
|
|
@@ -538,16 +566,25 @@ class ReadonlyWallet {
|
|
|
538
566
|
commitmentsToIgnore,
|
|
539
567
|
};
|
|
540
568
|
}
|
|
569
|
+
/**
|
|
570
|
+
* Fetch and cache onchain inputs (UTXOs) received at the boarding address.
|
|
571
|
+
*/
|
|
541
572
|
async getBoardingUtxos() {
|
|
542
573
|
const boardingAddress = await this.getBoardingAddress();
|
|
543
574
|
const boardingUtxos = await this.onchainProvider.getCoins(boardingAddress);
|
|
544
575
|
const utxos = boardingUtxos.map((utxo) => {
|
|
545
576
|
return (0, utils_1.extendCoin)(this, utxo);
|
|
546
577
|
});
|
|
547
|
-
// Save
|
|
578
|
+
// Save boarding inputs using unified repository
|
|
548
579
|
await this.walletRepository.saveUtxos(boardingAddress, utxos);
|
|
549
580
|
return utxos;
|
|
550
581
|
}
|
|
582
|
+
/**
|
|
583
|
+
* Subscribe to onchain and offchain notifications for newly received funds.
|
|
584
|
+
*
|
|
585
|
+
* @param eventCallback - Callback invoked when matching funds are detected
|
|
586
|
+
* @returns A function that stops the subscriptions
|
|
587
|
+
*/
|
|
551
588
|
async notifyIncomingFunds(eventCallback) {
|
|
552
589
|
const arkAddress = await this.getAddress();
|
|
553
590
|
const boardingAddress = await this.getBoardingAddress();
|
|
@@ -558,11 +595,11 @@ class ReadonlyWallet {
|
|
|
558
595
|
return tx.vout.findIndex((v) => v.scriptpubkey_address === boardingAddress);
|
|
559
596
|
};
|
|
560
597
|
onchainStopFunc = await this.onchainProvider.watchAddresses([boardingAddress], (txs) => {
|
|
561
|
-
// find all
|
|
598
|
+
// find all onchain outputs belonging to our boarding address
|
|
562
599
|
const coins = txs
|
|
563
600
|
// filter txs where address is in output
|
|
564
601
|
.filter((tx) => findVoutOnTx(tx) !== -1)
|
|
565
|
-
// return
|
|
602
|
+
// return boarding input as Coin
|
|
566
603
|
.map((tx) => {
|
|
567
604
|
const { txid, status } = tx;
|
|
568
605
|
const vout = findVoutOnTx(tx);
|
|
@@ -587,8 +624,8 @@ class ReadonlyWallet {
|
|
|
587
624
|
};
|
|
588
625
|
// Handle subscription updates asynchronously without blocking.
|
|
589
626
|
// Note: subscription covers all wallet scripts (default + delegate),
|
|
590
|
-
// but we can't determine which script each
|
|
591
|
-
// subscription event.
|
|
627
|
+
// but we can't determine which script each virtual output belongs to from the
|
|
628
|
+
// subscription event. Virtual outputs are extended with the current offchainTapscript;
|
|
592
629
|
// this is for notification/display only — not for spending.
|
|
593
630
|
// For correct extension metadata, use getVtxos() which queries per-script.
|
|
594
631
|
(async () => {
|
|
@@ -615,8 +652,9 @@ class ReadonlyWallet {
|
|
|
615
652
|
};
|
|
616
653
|
return stopFunc;
|
|
617
654
|
}
|
|
655
|
+
/** Fetch Arkade transaction ids that are still pending final settlement. */
|
|
618
656
|
async fetchPendingTxs() {
|
|
619
|
-
// get non-swept
|
|
657
|
+
// get non-swept virtual outputs, rely on the indexer only in case DB doesn't have the right state
|
|
620
658
|
const scripts = await this.getWalletScripts();
|
|
621
659
|
let { vtxos } = await this.indexerProvider.getVtxos({
|
|
622
660
|
scripts,
|
|
@@ -657,7 +695,7 @@ class ReadonlyWallet {
|
|
|
657
695
|
}
|
|
658
696
|
/**
|
|
659
697
|
* Build a map of scriptHex → VtxoScript for all wallet contracts,
|
|
660
|
-
* so
|
|
698
|
+
* so virtual outputs can be extended with the correct tapscript per contract.
|
|
661
699
|
*/
|
|
662
700
|
async getScriptMap() {
|
|
663
701
|
const map = new Map();
|
|
@@ -746,7 +784,6 @@ class ReadonlyWallet {
|
|
|
746
784
|
indexerProvider: this.indexerProvider,
|
|
747
785
|
contractRepository: this.contractRepository,
|
|
748
786
|
walletRepository: this.walletRepository,
|
|
749
|
-
getDefaultAddress: () => this.getAddress(),
|
|
750
787
|
watcherConfig: this.watcherConfig,
|
|
751
788
|
});
|
|
752
789
|
// Register the wallet's current address as a contract
|
|
@@ -770,7 +807,7 @@ class ReadonlyWallet {
|
|
|
770
807
|
address: await this.getAddress(),
|
|
771
808
|
state: "active",
|
|
772
809
|
});
|
|
773
|
-
// Also register the non-delegate version so old
|
|
810
|
+
// Also register the non-delegate version so old virtual outputs remain visible
|
|
774
811
|
const nonDelegateScript = new default_1.DefaultVtxo.Script({
|
|
775
812
|
pubKey: delegateScript.options.pubKey,
|
|
776
813
|
serverPubKey: delegateScript.options.serverPubKey,
|
|
@@ -808,6 +845,7 @@ class ReadonlyWallet {
|
|
|
808
845
|
}
|
|
809
846
|
return manager;
|
|
810
847
|
}
|
|
848
|
+
/** Dispose wallet-owned managers and release background resources. */
|
|
811
849
|
async dispose() {
|
|
812
850
|
const manager = this._contractManager ??
|
|
813
851
|
(this._contractManagerInitializing
|
|
@@ -817,30 +855,31 @@ class ReadonlyWallet {
|
|
|
817
855
|
this._contractManager = undefined;
|
|
818
856
|
this._contractManagerInitializing = undefined;
|
|
819
857
|
}
|
|
858
|
+
/** Async-dispose hook that forwards to `dispose()`. */
|
|
820
859
|
async [Symbol.asyncDispose]() {
|
|
821
860
|
await this.dispose();
|
|
822
861
|
}
|
|
823
862
|
}
|
|
824
863
|
exports.ReadonlyWallet = ReadonlyWallet;
|
|
825
864
|
/**
|
|
826
|
-
* Main wallet implementation for Bitcoin transactions with
|
|
827
|
-
* The wallet does not store any data locally and relies on
|
|
828
|
-
* providers to fetch
|
|
865
|
+
* Main wallet implementation for Bitcoin transactions with Arkade protocol support.
|
|
866
|
+
* The wallet does not store any data locally and relies on Arkade and onchain
|
|
867
|
+
* providers to fetch onchain and virtual outputs.
|
|
829
868
|
*
|
|
830
869
|
* @example
|
|
831
870
|
* ```typescript
|
|
832
871
|
* // Create a wallet with URL configuration
|
|
833
872
|
* const wallet = await Wallet.create({
|
|
834
|
-
* identity:
|
|
835
|
-
* arkServerUrl: 'https://
|
|
873
|
+
* identity: MnemonicIdentity.fromMnemonic('abandon abandon...'),
|
|
874
|
+
* arkServerUrl: 'https://arkade.computer',
|
|
836
875
|
* esploraUrl: 'https://mempool.space/api'
|
|
837
876
|
* });
|
|
838
877
|
*
|
|
839
878
|
* // Or with custom provider instances (e.g., for Expo/React Native)
|
|
840
879
|
* const wallet = await Wallet.create({
|
|
841
|
-
* identity:
|
|
842
|
-
* arkProvider: new ExpoArkProvider('https://
|
|
843
|
-
* indexerProvider: new ExpoIndexerProvider('https://
|
|
880
|
+
* identity: MnemonicIdentity.fromMnemonic('abandon abandon...'),
|
|
881
|
+
* arkProvider: new ExpoArkProvider('https://arkade.computer'),
|
|
882
|
+
* indexerProvider: new ExpoIndexerProvider('https://arkade.computer'),
|
|
844
883
|
* esploraUrl: 'https://mempool.space/api'
|
|
845
884
|
* });
|
|
846
885
|
*
|
|
@@ -849,9 +888,9 @@ exports.ReadonlyWallet = ReadonlyWallet;
|
|
|
849
888
|
* const boardingAddress = await wallet.getBoardingAddress();
|
|
850
889
|
*
|
|
851
890
|
* // Send bitcoin
|
|
852
|
-
* const txid = await wallet.
|
|
853
|
-
* address: '
|
|
854
|
-
* amount: 50000
|
|
891
|
+
* const txid = await wallet.send({
|
|
892
|
+
* address: 'ark1q...',
|
|
893
|
+
* amount: 50000,
|
|
855
894
|
* });
|
|
856
895
|
* ```
|
|
857
896
|
*/
|
|
@@ -880,7 +919,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
880
919
|
this.forfeitOutputScript = forfeitOutputScript;
|
|
881
920
|
this.forfeitPubkey = forfeitPubkey;
|
|
882
921
|
/**
|
|
883
|
-
* Async mutex that serializes all operations submitting VTXOs to the
|
|
922
|
+
* Async mutex that serializes all operations submitting VTXOs to the Arkade
|
|
884
923
|
* server (`settle`, `send`, `sendBitcoin`). This prevents VtxoManager's
|
|
885
924
|
* background renewal from racing with user-initiated transactions for the
|
|
886
925
|
* same VTXO inputs.
|
|
@@ -960,6 +999,19 @@ class Wallet extends ReadonlyWallet {
|
|
|
960
999
|
await super.dispose();
|
|
961
1000
|
}
|
|
962
1001
|
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Create a full wallet and initialize its background managers.
|
|
1004
|
+
*
|
|
1005
|
+
* @param config - Wallet configuration
|
|
1006
|
+
* @returns A wallet ready to query balances and send transactions
|
|
1007
|
+
* @example
|
|
1008
|
+
* ```typescript
|
|
1009
|
+
* const wallet = await Wallet.create({
|
|
1010
|
+
* identity,
|
|
1011
|
+
* arkServerUrl: 'https://arkade.computer',
|
|
1012
|
+
* });
|
|
1013
|
+
* ```
|
|
1014
|
+
*/
|
|
963
1015
|
static async create(config) {
|
|
964
1016
|
const pubkey = await config.identity.xOnlyPublicKey();
|
|
965
1017
|
if (!pubkey) {
|
|
@@ -991,7 +1043,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
991
1043
|
* @returns A readonly wallet with the same configuration but readonly identity
|
|
992
1044
|
* @example
|
|
993
1045
|
* ```typescript
|
|
994
|
-
* const wallet = await Wallet.create({ identity:
|
|
1046
|
+
* const wallet = await Wallet.create({ identity: MnemonicIdentity.fromMnemonic('abandon abandon...'), ... });
|
|
995
1047
|
* const readonlyWallet = await wallet.toReadonly();
|
|
996
1048
|
*
|
|
997
1049
|
* // Can query balance and addresses
|
|
@@ -999,7 +1051,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
999
1051
|
* const address = await readonlyWallet.getAddress();
|
|
1000
1052
|
*
|
|
1001
1053
|
* // But cannot send transactions (type error)
|
|
1002
|
-
* // readonlyWallet.
|
|
1054
|
+
* // readonlyWallet.send(...); // TypeScript error
|
|
1003
1055
|
* ```
|
|
1004
1056
|
*/
|
|
1005
1057
|
async toReadonly() {
|
|
@@ -1009,19 +1061,22 @@ class Wallet extends ReadonlyWallet {
|
|
|
1009
1061
|
: this.identity; // Identity extends ReadonlyIdentity, so this is safe
|
|
1010
1062
|
return new ReadonlyWallet(readonlyIdentity, this.network, this.onchainProvider, this.indexerProvider, this.arkServerPublicKey, this.offchainTapscript, this.boardingTapscript, this.dustAmount, this.walletRepository, this.contractRepository, this.delegatorProvider, this.watcherConfig);
|
|
1011
1063
|
}
|
|
1064
|
+
/** Returns the delegator manager when delegation support is configured. */
|
|
1012
1065
|
async getDelegatorManager() {
|
|
1013
1066
|
return this._delegatorManager;
|
|
1014
1067
|
}
|
|
1015
1068
|
/**
|
|
1016
|
-
*
|
|
1017
|
-
*
|
|
1069
|
+
* Send bitcoin to an Arkade address.
|
|
1070
|
+
*
|
|
1071
|
+
* @deprecated Use `send`.
|
|
1072
|
+
* @param params - Send parameters
|
|
1018
1073
|
*/
|
|
1019
1074
|
async sendBitcoin(params) {
|
|
1020
1075
|
if (params.amount <= 0) {
|
|
1021
1076
|
throw new Error("Amount must be positive");
|
|
1022
1077
|
}
|
|
1023
1078
|
if (!(0, arkTransaction_1.isValidArkAddress)(params.address)) {
|
|
1024
|
-
throw new Error("Invalid
|
|
1079
|
+
throw new Error("Invalid Arkade address " + params.address);
|
|
1025
1080
|
}
|
|
1026
1081
|
if (params.selectedVtxos && params.selectedVtxos.length > 0) {
|
|
1027
1082
|
return this._withTxLock(async () => {
|
|
@@ -1066,6 +1121,13 @@ class Wallet extends ReadonlyWallet {
|
|
|
1066
1121
|
amount: params.amount,
|
|
1067
1122
|
});
|
|
1068
1123
|
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Settle boarding inputs and/or virtual outputs into a finalized mainnet transaction.
|
|
1126
|
+
*
|
|
1127
|
+
* @param params - Optional settlement inputs and outputs. When omitted, the wallet settles all eligible funds.
|
|
1128
|
+
* @param eventCallback - Optional callback invoked for settlement stream events.
|
|
1129
|
+
* @returns The finalized Arkade transaction id
|
|
1130
|
+
*/
|
|
1069
1131
|
async settle(params, eventCallback) {
|
|
1070
1132
|
return this._withTxLock(() => this._settleImpl(params, eventCallback));
|
|
1071
1133
|
}
|
|
@@ -1083,7 +1145,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1083
1145
|
}
|
|
1084
1146
|
}
|
|
1085
1147
|
}
|
|
1086
|
-
// if no params are provided, use all non
|
|
1148
|
+
// if no params are provided, use all non-expired boarding inputs and offchain virtual outputs as inputs
|
|
1087
1149
|
// and send all to the offchain address
|
|
1088
1150
|
if (!params) {
|
|
1089
1151
|
const { fees } = await this.arkProvider.getInfo();
|
|
@@ -1104,7 +1166,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1104
1166
|
amount: BigInt(utxo.value),
|
|
1105
1167
|
});
|
|
1106
1168
|
if (inputFee.value >= utxo.value) {
|
|
1107
|
-
// skip if fees are greater than the
|
|
1169
|
+
// skip if fees are greater than the boarding input value
|
|
1108
1170
|
continue;
|
|
1109
1171
|
}
|
|
1110
1172
|
filteredBoardingUtxos.push(utxo);
|
|
@@ -1125,7 +1187,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1125
1187
|
: new Date(),
|
|
1126
1188
|
});
|
|
1127
1189
|
if (inputFee.value >= vtxo.value) {
|
|
1128
|
-
// skip if fees are greater than the
|
|
1190
|
+
// skip if fees are greater than the virtual output value
|
|
1129
1191
|
continue;
|
|
1130
1192
|
}
|
|
1131
1193
|
filteredVtxos.push(vtxo);
|
|
@@ -1216,7 +1278,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1216
1278
|
const assetPacket = (0, asset_1.createAssetPacket)(assetInputs, recipients);
|
|
1217
1279
|
outputs.push(extension_1.Extension.create([assetPacket]).txOut());
|
|
1218
1280
|
}
|
|
1219
|
-
// session holds the state of the musig2 signing process of the
|
|
1281
|
+
// session holds the state of the musig2 signing process of the virtual output tree
|
|
1220
1282
|
let session;
|
|
1221
1283
|
const signingPublicKeys = [];
|
|
1222
1284
|
if (hasOffchainOutputs) {
|
|
@@ -1267,7 +1329,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1267
1329
|
for (const input of inputs) {
|
|
1268
1330
|
// check if the input is an offchain "virtual" coin
|
|
1269
1331
|
const vtxo = vtxos.find((vtxo) => vtxo.txid === input.txid && vtxo.vout === input.vout);
|
|
1270
|
-
// boarding
|
|
1332
|
+
// boarding input, we need to sign the settlement tx
|
|
1271
1333
|
if (!vtxo) {
|
|
1272
1334
|
for (let i = 0; i < settlementPsbt.inputsLength; i++) {
|
|
1273
1335
|
const settlementInput = settlementPsbt.getInput(i);
|
|
@@ -1345,11 +1407,12 @@ class Wallet extends ReadonlyWallet {
|
|
|
1345
1407
|
}
|
|
1346
1408
|
}
|
|
1347
1409
|
/**
|
|
1348
|
-
*
|
|
1410
|
+
* Create a batch event handler for settlement flows.
|
|
1411
|
+
*
|
|
1349
1412
|
* @param intentId - The intent ID.
|
|
1350
|
-
* @param inputs -
|
|
1351
|
-
* @param
|
|
1352
|
-
* @param
|
|
1413
|
+
* @param inputs - Inputs used by the intent.
|
|
1414
|
+
* @param expectedRecipients - Expected recipients to validate in the virtual output tree.
|
|
1415
|
+
* @param session - Optional musig2 signing session. When omitted, signing steps are skipped.
|
|
1353
1416
|
*/
|
|
1354
1417
|
createBatchHandler(intentId, inputs, expectedRecipients, session) {
|
|
1355
1418
|
let sweepTapTreeRoot;
|
|
@@ -1363,7 +1426,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1363
1426
|
for (const idHash of event.intentIdHashes) {
|
|
1364
1427
|
if (idHash === intentIdHashStr) {
|
|
1365
1428
|
if (!this.arkProvider) {
|
|
1366
|
-
throw new Error("
|
|
1429
|
+
throw new Error("Arkade provider not configured");
|
|
1367
1430
|
}
|
|
1368
1431
|
await this.arkProvider.confirmRegistration(intentId);
|
|
1369
1432
|
skip = false;
|
|
@@ -1396,10 +1459,10 @@ class Wallet extends ReadonlyWallet {
|
|
|
1396
1459
|
// not a cosigner, skip the signing
|
|
1397
1460
|
return { skip: true };
|
|
1398
1461
|
}
|
|
1399
|
-
// validate the unsigned
|
|
1462
|
+
// validate the unsigned virtual output tree
|
|
1400
1463
|
const commitmentTx = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(event.unsignedCommitmentTx));
|
|
1401
1464
|
(0, validation_1.validateVtxoTxGraph)(vtxoTree, commitmentTx, sweepTapTreeRoot);
|
|
1402
|
-
// validate that all expected receivers are in the
|
|
1465
|
+
// validate that all expected receivers are in the virtual output tree with correct amounts and assets
|
|
1403
1466
|
if (expectedRecipients && expectedRecipients.length > 0) {
|
|
1404
1467
|
(0, validation_2.validateBatchRecipients)(commitmentTx, vtxoTree.leaves(), expectedRecipients, this.network);
|
|
1405
1468
|
}
|
|
@@ -1500,7 +1563,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1500
1563
|
/**
|
|
1501
1564
|
* Finalizes pending transactions by retrieving them from the server and finalizing each one.
|
|
1502
1565
|
* Skips the server check entirely when no send was interrupted (no pending tx flag set).
|
|
1503
|
-
* @param vtxos - Optional list of
|
|
1566
|
+
* @param vtxos - Optional list of virtual outputs to use instead of retrieving them from the server
|
|
1504
1567
|
* @returns Array of transaction IDs that were finalized
|
|
1505
1568
|
*/
|
|
1506
1569
|
async finalizePendingTxs(vtxos) {
|
|
@@ -1599,13 +1662,13 @@ class Wallet extends ReadonlyWallet {
|
|
|
1599
1662
|
/**
|
|
1600
1663
|
* Send BTC and/or assets to one or more recipients.
|
|
1601
1664
|
*
|
|
1602
|
-
* @param
|
|
1603
|
-
* @returns Promise resolving to the
|
|
1665
|
+
* @param args - Recipients with their addresses, BTC amounts, and assets
|
|
1666
|
+
* @returns Promise resolving to the Arkade transaction ID
|
|
1604
1667
|
*
|
|
1605
1668
|
* @example
|
|
1606
1669
|
* ```typescript
|
|
1607
1670
|
* const txid = await wallet.send({
|
|
1608
|
-
* address: '
|
|
1671
|
+
* address: 'ark1q...',
|
|
1609
1672
|
* amount: 1000, // (optional, default to dust) btc amount to send to the output
|
|
1610
1673
|
* assets: [{ assetId: 'abc123...', amount: 50 }] // (optional) list of assets to send
|
|
1611
1674
|
* });
|
|
@@ -1753,8 +1816,8 @@ class Wallet extends ReadonlyWallet {
|
|
|
1753
1816
|
}
|
|
1754
1817
|
/**
|
|
1755
1818
|
* Build an offchain transaction from the given inputs and outputs,
|
|
1756
|
-
* sign it, submit to the
|
|
1757
|
-
* @returns The
|
|
1819
|
+
* sign it, submit to the Arkade provider, and finalize.
|
|
1820
|
+
* @returns The Arkade transaction id and server-signed checkpoint PSBTs (for bookkeeping)
|
|
1758
1821
|
*/
|
|
1759
1822
|
async buildAndSubmitOffchainTx(inputs, outputs) {
|
|
1760
1823
|
const offchainTx = (0, arkTransaction_1.buildOffchainTx)(inputs.map((input) => {
|
|
@@ -1813,7 +1876,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1813
1876
|
}
|
|
1814
1877
|
return { arkTxid, signedCheckpointTxs };
|
|
1815
1878
|
}
|
|
1816
|
-
// mark
|
|
1879
|
+
// mark virtual outputs as spent, save change outputs if any
|
|
1817
1880
|
async updateDbAfterOffchainTx(inputs, arkTxid, signedCheckpointTxs, sentAmount, changeAmount, changeVout, changeAssets) {
|
|
1818
1881
|
try {
|
|
1819
1882
|
const spentVtxos = [];
|
|
@@ -1861,7 +1924,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1861
1924
|
}
|
|
1862
1925
|
const createdAt = Date.now();
|
|
1863
1926
|
const addr = this.arkAddress.encode();
|
|
1864
|
-
// Only save a change
|
|
1927
|
+
// Only save a change virtual output for preconfirmed coins (those with a batchExpiry).
|
|
1865
1928
|
// Inputs without a batchExpiry are already settled/unrolled and don't need tracking.
|
|
1866
1929
|
let changeVtxo;
|
|
1867
1930
|
if (changeAmount > 0n && batchExpiry !== Number.MAX_SAFE_INTEGER) {
|
|
@@ -1905,7 +1968,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1905
1968
|
console.warn("error saving offchain tx to repository", e);
|
|
1906
1969
|
}
|
|
1907
1970
|
}
|
|
1908
|
-
// mark
|
|
1971
|
+
// mark virtual outputs as spent/settled, remove boarding inputs
|
|
1909
1972
|
async updateDbAfterSettle(inputs, commitmentTxid) {
|
|
1910
1973
|
try {
|
|
1911
1974
|
const addr = this.arkAddress.encode();
|
|
@@ -1916,7 +1979,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1916
1979
|
const isVtxo = (input) => "virtualStatus" in input;
|
|
1917
1980
|
for (const input of inputs) {
|
|
1918
1981
|
if (isVtxo(input)) {
|
|
1919
|
-
//
|
|
1982
|
+
// virtual output = mark it settled
|
|
1920
1983
|
const vtxo = (0, utils_1.extendVirtualCoin)(this, input);
|
|
1921
1984
|
if (vtxo.arkTxId) {
|
|
1922
1985
|
inputArkTxIds.add(vtxo.arkTxId);
|
|
@@ -1932,7 +1995,7 @@ class Wallet extends ReadonlyWallet {
|
|
|
1932
1995
|
});
|
|
1933
1996
|
}
|
|
1934
1997
|
else {
|
|
1935
|
-
// boarding
|
|
1998
|
+
// boarding input = remove it
|
|
1936
1999
|
boardingUtxoToRemove.add(`${input.txid}:${input.vout}`);
|
|
1937
2000
|
}
|
|
1938
2001
|
}
|
|
@@ -1957,13 +2020,13 @@ class Wallet extends ReadonlyWallet {
|
|
|
1957
2020
|
exports.Wallet = Wallet;
|
|
1958
2021
|
Wallet.MIN_FEE_RATE = 1; // sats/vbyte
|
|
1959
2022
|
/**
|
|
1960
|
-
* Select virtual
|
|
1961
|
-
* @param coins List of virtual
|
|
2023
|
+
* Select virtual outputs to reach a target amount, prioritizing those closer to expiry
|
|
2024
|
+
* @param coins List of virtual outputs to select from
|
|
1962
2025
|
* @param targetAmount Target amount to reach in satoshis
|
|
1963
|
-
* @returns Selected
|
|
2026
|
+
* @returns Selected virtual outputs and change amount
|
|
1964
2027
|
*/
|
|
1965
2028
|
function selectVirtualCoins(coins, targetAmount) {
|
|
1966
|
-
// Sort
|
|
2029
|
+
// Sort virtual outputs by expiry (ascending) and amount (descending)
|
|
1967
2030
|
const sortedCoins = [...coins].sort((a, b) => {
|
|
1968
2031
|
// First sort by expiry if available
|
|
1969
2032
|
const expiryA = a.virtualStatus.batchExpiry || Number.MAX_SAFE_INTEGER;
|
|
@@ -52,7 +52,7 @@ class AsyncStorageTaskQueue {
|
|
|
52
52
|
// ── Config persistence (for background handler rehydration) ──────
|
|
53
53
|
/**
|
|
54
54
|
* Persist a config blob alongside the queue data.
|
|
55
|
-
* Used by
|
|
55
|
+
* Used by @see ExpoWallet.setup to store the wallet parameters
|
|
56
56
|
* that the background handler needs to reconstruct providers.
|
|
57
57
|
*/
|
|
58
58
|
async persistConfig(config) {
|
|
@@ -6,7 +6,7 @@ exports.CONTRACT_POLL_TASK_TYPE = "contract-poll";
|
|
|
6
6
|
* Polls the indexer for the latest VTXO state of every contract and
|
|
7
7
|
* persists the results to the wallet repository.
|
|
8
8
|
*
|
|
9
|
-
* Replicates the polling subset of
|
|
9
|
+
* Replicates the polling subset of @see ContractManager.initialize:
|
|
10
10
|
* 1. Load all contracts from the contract repository.
|
|
11
11
|
* 2. Mark expired active contracts as inactive.
|
|
12
12
|
* 3. Paginated fetch of spendable VTXOs from the indexer.
|
|
@@ -29,7 +29,7 @@ exports.contractPollProcessor = {
|
|
|
29
29
|
contract.state = "inactive";
|
|
30
30
|
await contractRepository.saveContract(contract);
|
|
31
31
|
}
|
|
32
|
-
// Paginated fetch of spendable
|
|
32
|
+
// Paginated fetch of spendable virtual outputs
|
|
33
33
|
const pageSize = 100;
|
|
34
34
|
let pageIndex = 0;
|
|
35
35
|
let hasMore = true;
|
|
@@ -8,7 +8,7 @@ const utils_1 = require("../../wallet/utils");
|
|
|
8
8
|
*
|
|
9
9
|
* For each task in the inbox:
|
|
10
10
|
* 1. Find the processor whose `taskType` matches `task.type`.
|
|
11
|
-
* 2. Execute it, producing a
|
|
11
|
+
* 2. Execute it, producing a @see TaskResult.
|
|
12
12
|
* 3. Push the result to the outbox and remove the task from the inbox.
|
|
13
13
|
*
|
|
14
14
|
* Tasks with no matching processor produce a `"noop"` result.
|
|
@@ -57,8 +57,8 @@ async function runTasks(queue, processors, deps) {
|
|
|
57
57
|
return results;
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
* Build the
|
|
61
|
-
* (e.g.
|
|
60
|
+
* Build the @see TaskDependencies needed by task processors
|
|
61
|
+
* (e.g. `src/worker/expo/processors/contractPollProcessor.ts`)
|
|
62
62
|
*
|
|
63
63
|
* This is the same construction that `defineExpoBackgroundTask` does
|
|
64
64
|
* internally, extracted so that consumers with custom schedulers
|