@arkade-os/sdk 0.4.14 → 0.4.16
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 +287 -215
- 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 +40 -24
- 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 +25 -1
- package/dist/cjs/contracts/handlers/vhtlc.js +2 -4
- 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/index.js +6 -0
- package/dist/cjs/identity/seedIdentity.js +5 -5
- package/dist/cjs/identity/singleKey.js +4 -0
- package/dist/cjs/index.js +5 -3
- 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 +25 -4
- 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 +123 -82
- package/dist/cjs/wallet/wallet.js +231 -98
- 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 +40 -24
- 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 +24 -1
- package/dist/esm/contracts/handlers/vhtlc.js +3 -5
- 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/index.js +5 -0
- package/dist/esm/identity/seedIdentity.js +5 -5
- package/dist/esm/identity/singleKey.js +4 -0
- package/dist/esm/index.js +3 -2
- 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 +25 -4
- 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 +122 -81
- package/dist/esm/wallet/wallet.js +232 -99
- 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 +40 -63
- 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 +11 -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 +36 -0
- package/dist/types/identity/seedIdentity.d.ts +10 -8
- package/dist/types/identity/singleKey.d.ts +4 -0
- package/dist/types/index.d.ts +3 -3
- 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 +18 -10
|
@@ -179,6 +179,13 @@ export class ServiceWorkerReadonlyWallet {
|
|
|
179
179
|
getTimeoutForRequest(request) {
|
|
180
180
|
return this.messageTimeouts[request.type] ?? 30000;
|
|
181
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Create a readonly service-worker wallet bound to an already-registered worker.
|
|
184
|
+
*
|
|
185
|
+
* @param options - Service worker, identity, and backend configuration
|
|
186
|
+
* @returns Initialized readonly service-worker wallet
|
|
187
|
+
* @throws Error if service-worker initialization fails
|
|
188
|
+
*/
|
|
182
189
|
static async create(options) {
|
|
183
190
|
const walletRepository = options.storage?.walletRepository ??
|
|
184
191
|
new IndexedDBWalletRepository();
|
|
@@ -239,23 +246,17 @@ export class ServiceWorkerReadonlyWallet {
|
|
|
239
246
|
return wallet;
|
|
240
247
|
}
|
|
241
248
|
/**
|
|
242
|
-
* Simplified setup method that handles service worker registration
|
|
243
|
-
*
|
|
249
|
+
* Simplified setup method that handles service worker registration
|
|
250
|
+
* and wallet initialization automatically.
|
|
251
|
+
*
|
|
252
|
+
* @see ServiceWorkerReadonlyWallet.create
|
|
244
253
|
*
|
|
245
254
|
* @example
|
|
246
255
|
* ```typescript
|
|
247
|
-
* // One-liner setup - handles everything automatically!
|
|
248
256
|
* const wallet = await ServiceWorkerReadonlyWallet.setup({
|
|
249
257
|
* serviceWorkerPath: '/service-worker.js',
|
|
250
|
-
* arkServerUrl: 'https://
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* // With custom readonly identity
|
|
254
|
-
* const identity = ReadonlySingleKey.fromPublicKey('your_public_key_hex');
|
|
255
|
-
* const wallet = await ServiceWorkerReadonlyWallet.setup({
|
|
256
|
-
* serviceWorkerPath: '/service-worker.js',
|
|
257
|
-
* arkServerUrl: 'https://mutinynet.arkade.sh',
|
|
258
|
-
* identity
|
|
258
|
+
* arkServerUrl: 'https://arkade.computer',
|
|
259
|
+
* identity: ReadonlySingleKey.fromPublicKey('your_public_key_hex')
|
|
259
260
|
* });
|
|
260
261
|
* ```
|
|
261
262
|
*/
|
|
@@ -457,6 +458,7 @@ export class ServiceWorkerReadonlyWallet {
|
|
|
457
458
|
});
|
|
458
459
|
return this.reinitPromise;
|
|
459
460
|
}
|
|
461
|
+
/** Clear cached wallet state from both the page and service worker storage. */
|
|
460
462
|
async clear() {
|
|
461
463
|
const message = {
|
|
462
464
|
id: getRandomId(),
|
|
@@ -529,6 +531,11 @@ export class ServiceWorkerReadonlyWallet {
|
|
|
529
531
|
throw new Error(`Failed to get boarding UTXOs: ${error}`);
|
|
530
532
|
}
|
|
531
533
|
}
|
|
534
|
+
/**
|
|
535
|
+
* Return service-worker wallet status, including connectivity and sync state.
|
|
536
|
+
*
|
|
537
|
+
* @returns Current service-worker wallet status payload including `walletInitalized` and `xOnlyPublicKey`
|
|
538
|
+
*/
|
|
532
539
|
async getStatus() {
|
|
533
540
|
const message = {
|
|
534
541
|
id: getRandomId(),
|
|
@@ -573,6 +580,11 @@ export class ServiceWorkerReadonlyWallet {
|
|
|
573
580
|
throw new Error(`Failed to get vtxos: ${error}`);
|
|
574
581
|
}
|
|
575
582
|
}
|
|
583
|
+
/**
|
|
584
|
+
* Trigger a wallet reload inside the service worker.
|
|
585
|
+
*
|
|
586
|
+
* @returns `true` when the wallet was reloaded
|
|
587
|
+
*/
|
|
576
588
|
async reload() {
|
|
577
589
|
const message = {
|
|
578
590
|
id: getRandomId(),
|
|
@@ -851,23 +863,15 @@ export class ServiceWorkerWallet extends ServiceWorkerReadonlyWallet {
|
|
|
851
863
|
return wallet;
|
|
852
864
|
}
|
|
853
865
|
/**
|
|
854
|
-
* Simplified setup method that handles service worker registration
|
|
855
|
-
*
|
|
866
|
+
* Simplified setup method that handles service worker registration
|
|
867
|
+
* and wallet initialization automatically.
|
|
856
868
|
*
|
|
857
869
|
* @example
|
|
858
870
|
* ```typescript
|
|
859
|
-
* // One-liner setup - handles everything automatically!
|
|
860
|
-
* const wallet = await ServiceWorkerWallet.setup({
|
|
861
|
-
* serviceWorkerPath: '/service-worker.js',
|
|
862
|
-
* arkServerUrl: 'https://mutinynet.arkade.sh'
|
|
863
|
-
* });
|
|
864
|
-
*
|
|
865
|
-
* // With custom identity
|
|
866
|
-
* const identity = SingleKey.fromHex('your_private_key_hex');
|
|
867
871
|
* const wallet = await ServiceWorkerWallet.setup({
|
|
868
872
|
* serviceWorkerPath: '/service-worker.js',
|
|
869
|
-
* arkServerUrl: 'https://
|
|
870
|
-
* identity
|
|
873
|
+
* arkServerUrl: 'https://arkade.computer',
|
|
874
|
+
* identity: MnemonicIdentity.fromMnemonic('abandon abandon...')
|
|
871
875
|
* });
|
|
872
876
|
* ```
|
|
873
877
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { base64, hex } from "@scure/base";
|
|
2
2
|
import { SigHash, TaprootControlBlock } from "@scure/btc-signer";
|
|
3
|
+
import { timelockToSequence } from '../contracts/handlers/helpers.js';
|
|
3
4
|
import { ChainTxType } from '../providers/indexer.js';
|
|
4
5
|
import { VtxoScript } from '../script/base.js';
|
|
5
6
|
import { TxWeightEstimator } from '../utils/txSizeEstimator.js';
|
|
@@ -15,7 +16,7 @@ export var Unroll;
|
|
|
15
16
|
StepType[StepType["DONE"] = 2] = "DONE";
|
|
16
17
|
})(StepType = Unroll.StepType || (Unroll.StepType = {}));
|
|
17
18
|
/**
|
|
18
|
-
* Manages the unrolling process of a
|
|
19
|
+
* Manages the unrolling process of a virtual output back to the Bitcoin blockchain.
|
|
19
20
|
*
|
|
20
21
|
* The Session class implements an async iterator that processes the unrolling steps:
|
|
21
22
|
* 1. **WAIT**: Waits for a transaction to be confirmed onchain (if it's in mempool)
|
|
@@ -39,19 +40,21 @@ export var Unroll;
|
|
|
39
40
|
* console.log(`Broadcasting transaction ${doneStep.tx.id}`);
|
|
40
41
|
* break;
|
|
41
42
|
* case Unroll.StepType.DONE:
|
|
42
|
-
* console.log(`Unrolling complete for
|
|
43
|
+
* console.log(`Unrolling complete for virtual output ${doneStep.vtxoTxid}`);
|
|
43
44
|
* break;
|
|
44
45
|
* }
|
|
45
46
|
* }
|
|
46
47
|
* ```
|
|
47
48
|
**/
|
|
48
49
|
class Session {
|
|
50
|
+
/** Create an unroll session from a virtual output outpoint and its dependency chain. */
|
|
49
51
|
constructor(toUnroll, bumper, explorer, indexer) {
|
|
50
52
|
this.toUnroll = toUnroll;
|
|
51
53
|
this.bumper = bumper;
|
|
52
54
|
this.explorer = explorer;
|
|
53
55
|
this.indexer = indexer;
|
|
54
56
|
}
|
|
57
|
+
/** Create an unroll session by loading the virtual output chain from the indexer. */
|
|
55
58
|
static async create(toUnroll, bumper, explorer, indexer) {
|
|
56
59
|
const { chain } = await indexer.getVtxoChain(toUnroll);
|
|
57
60
|
return new Session({ ...toUnroll, chain }, bumper, explorer, indexer);
|
|
@@ -120,7 +123,7 @@ export var Unroll;
|
|
|
120
123
|
});
|
|
121
124
|
}
|
|
122
125
|
else {
|
|
123
|
-
// finalize
|
|
126
|
+
// finalize Arkade transaction
|
|
124
127
|
tx.finalize();
|
|
125
128
|
}
|
|
126
129
|
return {
|
|
@@ -150,11 +153,11 @@ export var Unroll;
|
|
|
150
153
|
}
|
|
151
154
|
Unroll.Session = Session;
|
|
152
155
|
/**
|
|
153
|
-
* Complete the unroll of a
|
|
154
|
-
* @param wallet the wallet owning the
|
|
155
|
-
* @param vtxoTxids the txids of the
|
|
156
|
+
* Complete the unroll of a virtual output by broadcasting the transaction that spends the CSV path.
|
|
157
|
+
* @param wallet the wallet owning the virtual output(s)
|
|
158
|
+
* @param vtxoTxids the txids of the virtual output(s) to complete unroll
|
|
156
159
|
* @param outputAddress the address to send the unrolled funds to
|
|
157
|
-
* @throws if the
|
|
160
|
+
* @throws if the virtual output(s) are not fully unrolled, if the txids are not found, if the tx is not confirmed, if no exit path is found or not available
|
|
158
161
|
* @returns the txid of the transaction spending the unrolled funds
|
|
159
162
|
*/
|
|
160
163
|
async function completeUnroll(wallet, vtxoTxids, outputAddress) {
|
|
@@ -184,11 +187,12 @@ export var Unroll;
|
|
|
184
187
|
throw new Error(`spending leaf not found for vtxo ${vtxo.txid}:${vtxo.vout}`);
|
|
185
188
|
}
|
|
186
189
|
totalAmount += BigInt(vtxo.value);
|
|
190
|
+
const sequence = timelockToSequence(exit.params.timelock);
|
|
187
191
|
inputs.push({
|
|
188
192
|
txid: vtxo.txid,
|
|
189
193
|
index: vtxo.vout,
|
|
190
194
|
tapLeafScript: [spendingLeaf],
|
|
191
|
-
sequence
|
|
195
|
+
sequence,
|
|
192
196
|
witnessUtxo: {
|
|
193
197
|
amount: BigInt(vtxo.value),
|
|
194
198
|
script: VtxoScript.decode(vtxo.tapTree).pkScript,
|
package/dist/esm/wallet/utils.js
CHANGED
|
@@ -52,7 +52,7 @@ export function validateRecipients(recipients, dustAmount) {
|
|
|
52
52
|
address = ArkAddress.decode(recipient.address);
|
|
53
53
|
}
|
|
54
54
|
catch (e) {
|
|
55
|
-
throw new Error(`Invalid
|
|
55
|
+
throw new Error(`Invalid Arkade address: ${recipient.address}`);
|
|
56
56
|
}
|
|
57
57
|
const amount = recipient.amount || dustAmount;
|
|
58
58
|
if (amount <= 0) {
|
|
@@ -5,29 +5,57 @@ import { hex } from "@scure/base";
|
|
|
5
5
|
import { getSequence } from '../script/base.js';
|
|
6
6
|
import { Transaction } from '../utils/transaction.js';
|
|
7
7
|
import { TxWeightEstimator } from '../utils/txSizeEstimator.js';
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Return whether a wallet exposes the properties required for boarding input sweep operations.
|
|
10
|
+
*
|
|
11
|
+
* @param wallet - Wallet to inspect
|
|
12
|
+
* @returns `true` when the wallet supports boarding input sweep operations.
|
|
13
|
+
*/
|
|
9
14
|
function isSweepCapable(wallet) {
|
|
10
15
|
return ("boardingTapscript" in wallet &&
|
|
11
16
|
"onchainProvider" in wallet &&
|
|
12
17
|
"network" in wallet);
|
|
13
18
|
}
|
|
14
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Assert that the wallet supports boarding input sweep operations.
|
|
21
|
+
*
|
|
22
|
+
* @param wallet - Wallet to inspect
|
|
23
|
+
* @throws Error if the wallet does not support boarding input sweep operations.
|
|
24
|
+
*/
|
|
15
25
|
function assertSweepCapable(wallet) {
|
|
16
26
|
if (!isSweepCapable(wallet)) {
|
|
17
27
|
throw new Error("Boarding UTXO sweep requires a Wallet instance with boardingTapscript, onchainProvider, and network");
|
|
18
28
|
}
|
|
19
29
|
}
|
|
20
|
-
|
|
21
|
-
export const DEFAULT_THRESHOLD_SECONDS = 3 * 24 * 60 * 60;
|
|
30
|
+
/** Default renewal threshold in seconds (3 days). */
|
|
31
|
+
export const DEFAULT_THRESHOLD_SECONDS = 3 * 24 * 60 * 60;
|
|
22
32
|
/**
|
|
23
|
-
* Default renewal
|
|
24
|
-
|
|
33
|
+
* Default renewal threshold in milliseconds (3 days).
|
|
34
|
+
*/
|
|
35
|
+
export const DEFAULT_THRESHOLD_MS = DEFAULT_THRESHOLD_SECONDS * 1000;
|
|
36
|
+
/**
|
|
37
|
+
* Default renewal configuration values.
|
|
38
|
+
*
|
|
39
|
+
* @see RenewalConfig
|
|
40
|
+
* @deprecated Leave `renewalConfig` undefined and use `settlementConfig` instead.
|
|
41
|
+
* @see SettlementConfig
|
|
25
42
|
*/
|
|
26
43
|
export const DEFAULT_RENEWAL_CONFIG = {
|
|
27
44
|
thresholdMs: DEFAULT_THRESHOLD_MS, // 3 days
|
|
28
45
|
};
|
|
29
46
|
/**
|
|
30
|
-
* Default settlement configuration values
|
|
47
|
+
* Default settlement configuration values.
|
|
48
|
+
*
|
|
49
|
+
* @see SettlementConfig
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const wallet = await Wallet.create({
|
|
54
|
+
* identity,
|
|
55
|
+
* arkServerUrl: 'https://arkade.computer',
|
|
56
|
+
* settlementConfig: DEFAULT_SETTLEMENT_CONFIG,
|
|
57
|
+
* })
|
|
58
|
+
* ```
|
|
31
59
|
*/
|
|
32
60
|
export const DEFAULT_SETTLEMENT_CONFIG = {
|
|
33
61
|
vtxoThreshold: DEFAULT_THRESHOLD_SECONDS,
|
|
@@ -39,23 +67,23 @@ function getDustAmount(wallet) {
|
|
|
39
67
|
return "dustAmount" in wallet ? wallet.dustAmount : 330n;
|
|
40
68
|
}
|
|
41
69
|
/**
|
|
42
|
-
* Filter
|
|
70
|
+
* Filter virtual outputs that are recoverable (swept and still spendable, or preconfirmed subdust)
|
|
43
71
|
*
|
|
44
72
|
* Recovery strategy:
|
|
45
|
-
* - Always recover swept
|
|
46
|
-
* - Only recover subdust preconfirmed
|
|
73
|
+
* - Always recover swept virtual outputs (they've been taken by the server)
|
|
74
|
+
* - Only recover subdust preconfirmed virtual outputs (to avoid locking liquidity on settled virtual outputs with long expiry)
|
|
47
75
|
*
|
|
48
|
-
* @param vtxos - Array of virtual
|
|
76
|
+
* @param vtxos - Array of virtual outputs to check
|
|
49
77
|
* @param dustAmount - Dust threshold to identify subdust
|
|
50
|
-
* @returns Array of recoverable
|
|
78
|
+
* @returns Array of recoverable virtual outputs
|
|
51
79
|
*/
|
|
52
80
|
function getRecoverableVtxos(vtxos, dustAmount) {
|
|
53
81
|
return vtxos.filter((vtxo) => {
|
|
54
|
-
// Always recover swept
|
|
82
|
+
// Always recover swept virtual outputs
|
|
55
83
|
if (isRecoverable(vtxo)) {
|
|
56
84
|
return true;
|
|
57
85
|
}
|
|
58
|
-
// also include
|
|
86
|
+
// also include virtual outputs that are not swept but expired
|
|
59
87
|
if (isSpendable(vtxo) && isExpired(vtxo)) {
|
|
60
88
|
return true;
|
|
61
89
|
}
|
|
@@ -68,14 +96,14 @@ function getRecoverableVtxos(vtxos, dustAmount) {
|
|
|
68
96
|
});
|
|
69
97
|
}
|
|
70
98
|
/**
|
|
71
|
-
* Get recoverable
|
|
99
|
+
* Get recoverable virtual outputs including subdust outputs if the total value exceeds dust threshold.
|
|
72
100
|
*
|
|
73
|
-
* Decision is based on the combined total of ALL recoverable
|
|
101
|
+
* Decision is based on the combined total of ALL recoverable virtual outputs (regular + subdust),
|
|
74
102
|
* not just the subdust portion alone.
|
|
75
103
|
*
|
|
76
|
-
* @param vtxos - Array of virtual
|
|
104
|
+
* @param vtxos - Array of virtual outputs to check
|
|
77
105
|
* @param dustAmount - Dust threshold amount in satoshis
|
|
78
|
-
* @returns Object containing recoverable
|
|
106
|
+
* @returns Object containing recoverable virtual outputs and whether subdust should be included
|
|
79
107
|
*/
|
|
80
108
|
function getRecoverableWithSubdust(vtxos, dustAmount) {
|
|
81
109
|
const recoverableVtxos = getRecoverableVtxos(vtxos, dustAmount);
|
|
@@ -105,11 +133,11 @@ function getRecoverableWithSubdust(vtxos, dustAmount) {
|
|
|
105
133
|
};
|
|
106
134
|
}
|
|
107
135
|
/**
|
|
108
|
-
* Check if a
|
|
136
|
+
* Check if a virtual output is expiring soon based on threshold
|
|
109
137
|
*
|
|
110
|
-
* @param vtxo - The virtual
|
|
138
|
+
* @param vtxo - The virtual output to check
|
|
111
139
|
* @param thresholdMs - Threshold in milliseconds from now
|
|
112
|
-
* @returns true if
|
|
140
|
+
* @returns true if virtual output expires within threshold, false otherwise
|
|
113
141
|
*/
|
|
114
142
|
export function isVtxoExpiringSoon(vtxo, thresholdMs // in milliseconds
|
|
115
143
|
) {
|
|
@@ -130,12 +158,12 @@ export function isVtxoExpiringSoon(vtxo, thresholdMs // in milliseconds
|
|
|
130
158
|
return batchExpiry - now <= realThresholdMs;
|
|
131
159
|
}
|
|
132
160
|
/**
|
|
133
|
-
* Filter
|
|
161
|
+
* Filter virtual outputs that are expiring soon or are recoverable/subdust
|
|
134
162
|
*
|
|
135
|
-
* @param vtxos - Array of virtual
|
|
163
|
+
* @param vtxos - Array of virtual outputs to check
|
|
136
164
|
* @param thresholdMs - Threshold in milliseconds from now
|
|
137
165
|
* @param dustAmount - Dust threshold amount in satoshis
|
|
138
|
-
* @returns Array of
|
|
166
|
+
* @returns Array of virtual outputs expiring within threshold
|
|
139
167
|
*/
|
|
140
168
|
export function getExpiringAndRecoverableVtxos(vtxos, thresholdMs, dustAmount) {
|
|
141
169
|
return vtxos.filter((vtxo) => isVtxoExpiringSoon(vtxo, thresholdMs) ||
|
|
@@ -185,24 +213,24 @@ export class VtxoManager {
|
|
|
185
213
|
}
|
|
186
214
|
// ========== Recovery Methods ==========
|
|
187
215
|
/**
|
|
188
|
-
* Recover swept/expired
|
|
216
|
+
* Recover swept/expired virtual outputs by settling them back to the wallet's Arkade address.
|
|
189
217
|
*
|
|
190
218
|
* This method:
|
|
191
|
-
* 1. Fetches all
|
|
192
|
-
* 2. Filters for swept but still spendable
|
|
193
|
-
* 3. Includes subdust
|
|
194
|
-
* 4. Settles everything back to the wallet's
|
|
219
|
+
* 1. Fetches all virtual outputs (including recoverable ones)
|
|
220
|
+
* 2. Filters for swept but still spendable virtual outputs and preconfirmed subdust
|
|
221
|
+
* 3. Includes subdust virtual outputs if the total value >= dust threshold
|
|
222
|
+
* 4. Settles everything back to the wallet's Arkade address
|
|
195
223
|
*
|
|
196
|
-
* Note: Settled
|
|
224
|
+
* Note: Settled virtual outputs with long expiry are NOT recovered to avoid locking liquidity unnecessarily.
|
|
197
225
|
* Only preconfirmed subdust is recovered to consolidate small amounts.
|
|
198
226
|
*
|
|
199
227
|
* @param eventCallback - Optional callback to receive settlement events
|
|
200
228
|
* @returns Settlement transaction ID
|
|
201
|
-
* @throws Error if no recoverable
|
|
229
|
+
* @throws Error if no recoverable virtual outputs found
|
|
202
230
|
*
|
|
203
231
|
* @example
|
|
204
232
|
* ```typescript
|
|
205
|
-
* const manager =
|
|
233
|
+
* const manager = await wallet.getVtxoManager();
|
|
206
234
|
*
|
|
207
235
|
* // Simple recovery
|
|
208
236
|
* const txid = await manager.recoverVtxos();
|
|
@@ -214,20 +242,20 @@ export class VtxoManager {
|
|
|
214
242
|
* ```
|
|
215
243
|
*/
|
|
216
244
|
async recoverVtxos(eventCallback) {
|
|
217
|
-
// Get all
|
|
245
|
+
// Get all virtual outputs including recoverable ones
|
|
218
246
|
const allVtxos = await this.wallet.getVtxos({
|
|
219
247
|
withRecoverable: true,
|
|
220
248
|
withUnrolled: false,
|
|
221
249
|
});
|
|
222
250
|
// Get dust amount from wallet
|
|
223
251
|
const dustAmount = getDustAmount(this.wallet);
|
|
224
|
-
// Filter recoverable
|
|
252
|
+
// Filter recoverable virtual outputs and handle subdust logic
|
|
225
253
|
const { vtxosToRecover, totalAmount } = getRecoverableWithSubdust(allVtxos, dustAmount);
|
|
226
254
|
if (vtxosToRecover.length === 0) {
|
|
227
255
|
throw new Error("No recoverable VTXOs found");
|
|
228
256
|
}
|
|
229
257
|
const arkAddress = await this.wallet.getAddress();
|
|
230
|
-
// Settle all recoverable
|
|
258
|
+
// Settle all recoverable virtual outputs back to the wallet
|
|
231
259
|
return this.wallet.settle({
|
|
232
260
|
inputs: vtxosToRecover,
|
|
233
261
|
outputs: [
|
|
@@ -247,13 +275,13 @@ export class VtxoManager {
|
|
|
247
275
|
*
|
|
248
276
|
* @example
|
|
249
277
|
* ```typescript
|
|
250
|
-
* const manager =
|
|
278
|
+
* const manager = await wallet.getVtxoManager();
|
|
251
279
|
* const balance = await manager.getRecoverableBalance();
|
|
252
280
|
*
|
|
253
281
|
* if (balance.recoverable > 0n) {
|
|
254
282
|
* console.log(`You can recover ${balance.recoverable} sats`);
|
|
255
283
|
* if (balance.includesSubdust) {
|
|
256
|
-
* console.log(`This includes ${balance.subdust} sats from subdust
|
|
284
|
+
* console.log(`This includes ${balance.subdust} sats from subdust virtual outputs`);
|
|
257
285
|
* }
|
|
258
286
|
* }
|
|
259
287
|
* ```
|
|
@@ -278,17 +306,24 @@ export class VtxoManager {
|
|
|
278
306
|
}
|
|
279
307
|
// ========== Renewal Methods ==========
|
|
280
308
|
/**
|
|
281
|
-
* Get
|
|
309
|
+
* Get virtual outputs that are expiring soon based on renewal configuration
|
|
282
310
|
*
|
|
283
311
|
* @param thresholdMs - Optional override for threshold in milliseconds
|
|
284
|
-
* @returns Array of expiring
|
|
312
|
+
* @returns Array of expiring virtual outputs, empty array if renewal is disabled or no virtual outputs expiring
|
|
285
313
|
*
|
|
286
314
|
* @example
|
|
287
315
|
* ```typescript
|
|
288
|
-
* const
|
|
316
|
+
* const wallet = await Wallet.create({
|
|
317
|
+
* identity,
|
|
318
|
+
* arkServerUrl: 'https://arkade.computer',
|
|
319
|
+
* settlementConfig: {
|
|
320
|
+
* vtxoThreshold: 86_400 // 24 hours
|
|
321
|
+
* },
|
|
322
|
+
* });
|
|
323
|
+
* const manager = await wallet.getVtxoManager();
|
|
289
324
|
* const expiringVtxos = await manager.getExpiringVtxos();
|
|
290
325
|
* if (expiringVtxos.length > 0) {
|
|
291
|
-
* console.log(`${expiringVtxos.length}
|
|
326
|
+
* console.log(`${expiringVtxos.length} virtual outputs expiring soon`);
|
|
292
327
|
* }
|
|
293
328
|
* ```
|
|
294
329
|
*/
|
|
@@ -316,20 +351,20 @@ export class VtxoManager {
|
|
|
316
351
|
return getExpiringAndRecoverableVtxos(vtxos, threshold, getDustAmount(this.wallet));
|
|
317
352
|
}
|
|
318
353
|
/**
|
|
319
|
-
* Renew expiring
|
|
354
|
+
* Renew expiring virtual outputs by settling them back to the wallet's address
|
|
320
355
|
*
|
|
321
|
-
* This method collects all expiring spendable
|
|
356
|
+
* This method collects all expiring spendable virtual outputs (including recoverable ones) and settles
|
|
322
357
|
* them back to the wallet, effectively refreshing their expiration time. This is the
|
|
323
|
-
* primary way to prevent
|
|
358
|
+
* primary way to prevent virtual outputs from expiring.
|
|
324
359
|
*
|
|
325
360
|
* @param eventCallback - Optional callback for settlement events
|
|
326
361
|
* @returns Settlement transaction ID
|
|
327
|
-
* @throws Error if no
|
|
362
|
+
* @throws Error if no virtual outputs available to renew
|
|
328
363
|
* @throws Error if total amount is below dust threshold
|
|
329
364
|
*
|
|
330
365
|
* @example
|
|
331
366
|
* ```typescript
|
|
332
|
-
* const manager =
|
|
367
|
+
* const manager = await wallet.getVtxoManager();
|
|
333
368
|
*
|
|
334
369
|
* // Simple renewal
|
|
335
370
|
* const txid = await manager.renewVtxos();
|
|
@@ -346,7 +381,7 @@ export class VtxoManager {
|
|
|
346
381
|
}
|
|
347
382
|
this.renewalInProgress = true;
|
|
348
383
|
try {
|
|
349
|
-
// Get all
|
|
384
|
+
// Get all virtual outputs (including recoverable ones)
|
|
350
385
|
// Use default threshold to bypass settlementConfig gate (manual API should always work)
|
|
351
386
|
const vtxos = await this.getExpiringVtxos(this.settlementConfig !== false &&
|
|
352
387
|
this.settlementConfig?.vtxoThreshold !== undefined
|
|
@@ -379,21 +414,21 @@ export class VtxoManager {
|
|
|
379
414
|
this.renewalInProgress = false;
|
|
380
415
|
}
|
|
381
416
|
}
|
|
382
|
-
// ========== Boarding
|
|
417
|
+
// ========== Boarding Input Sweep Methods ==========
|
|
383
418
|
/**
|
|
384
|
-
* Get boarding
|
|
419
|
+
* Get boarding inputs whose timelock has expired.
|
|
385
420
|
*
|
|
386
|
-
* These
|
|
421
|
+
* These inputs can no longer be onboarded cooperatively via `settle()` and
|
|
387
422
|
* must be swept back to a fresh boarding address using the unilateral exit path.
|
|
388
423
|
*
|
|
389
|
-
* @returns Array of expired boarding
|
|
424
|
+
* @returns Array of expired boarding inputs
|
|
390
425
|
*
|
|
391
426
|
* @example
|
|
392
427
|
* ```typescript
|
|
393
|
-
* const manager =
|
|
428
|
+
* const manager = await wallet.getVtxoManager();
|
|
394
429
|
* const expired = await manager.getExpiredBoardingUtxos();
|
|
395
430
|
* if (expired.length > 0) {
|
|
396
|
-
* console.log(`${expired.length} expired boarding
|
|
431
|
+
* console.log(`${expired.length} expired boarding inputs to sweep`);
|
|
397
432
|
* }
|
|
398
433
|
* ```
|
|
399
434
|
*/
|
|
@@ -409,31 +444,36 @@ export class VtxoManager {
|
|
|
409
444
|
return boardingUtxos.filter((utxo) => hasBoardingTxExpired(utxo, boardingTimelock, chainTipHeight));
|
|
410
445
|
}
|
|
411
446
|
/**
|
|
412
|
-
* Sweep expired boarding
|
|
413
|
-
* the unilateral exit path (
|
|
447
|
+
* Sweep expired boarding inputs back to a fresh boarding address via
|
|
448
|
+
* the unilateral exit path (onchain self-spend).
|
|
414
449
|
*
|
|
415
|
-
* This builds a raw
|
|
416
|
-
* - Uses all expired boarding
|
|
450
|
+
* This builds a raw onchain transaction that:
|
|
451
|
+
* - Uses all expired boarding inputs as inputs (spent via the CSV exit script path)
|
|
417
452
|
* - Has a single output to the wallet's boarding address (restarts the timelock)
|
|
418
|
-
* - Batches multiple expired
|
|
453
|
+
* - Batches multiple expired boarding inputs into one transaction
|
|
419
454
|
* - Skips the sweep if the output after fees would be below dust
|
|
420
455
|
*
|
|
421
|
-
* No
|
|
456
|
+
* No Arkade server involvement is needed — this is a pure onchain transaction.
|
|
422
457
|
*
|
|
423
458
|
* @returns The broadcast transaction ID
|
|
424
|
-
* @throws Error if no expired boarding
|
|
459
|
+
* @throws Error if no expired boarding inputs are found
|
|
425
460
|
* @throws Error if output after fees is below dust (not economical to sweep)
|
|
426
|
-
* @throws Error if boarding
|
|
461
|
+
* @throws Error if boarding input sweep is not enabled in settlementConfig
|
|
427
462
|
*
|
|
428
463
|
* @example
|
|
429
464
|
* ```typescript
|
|
430
|
-
* const
|
|
431
|
-
*
|
|
465
|
+
* const wallet = await Wallet.create({
|
|
466
|
+
* identity,
|
|
467
|
+
* arkServerUrl: 'https://arkade.computer',
|
|
468
|
+
* settlementConfig: {
|
|
469
|
+
* boardingUtxoSweep: true,
|
|
470
|
+
* },
|
|
432
471
|
* });
|
|
472
|
+
* const manager = await wallet.getVtxoManager();
|
|
433
473
|
*
|
|
434
474
|
* try {
|
|
435
475
|
* const txid = await manager.sweepExpiredBoardingUtxos();
|
|
436
|
-
* console.log('Swept expired boarding
|
|
476
|
+
* console.log('Swept expired boarding inputs:', txid);
|
|
437
477
|
* } catch (e) {
|
|
438
478
|
* console.log('No sweep needed or not economical');
|
|
439
479
|
* }
|
|
@@ -447,7 +487,7 @@ export class VtxoManager {
|
|
|
447
487
|
throw new Error("Boarding UTXO sweep is not enabled in settlementConfig");
|
|
448
488
|
}
|
|
449
489
|
const allExpired = await this.getExpiredBoardingUtxos(prefetchedUtxos);
|
|
450
|
-
// Filter out
|
|
490
|
+
// Filter out inputs already swept (tx broadcast but not yet confirmed).
|
|
451
491
|
const expiredUtxos = allExpired.filter((u) => !this.sweptBoardingUtxos.has(`${u.txid}:${u.vout}`));
|
|
452
492
|
if (expiredUtxos.length === 0) {
|
|
453
493
|
throw new Error("No expired boarding UTXOs to sweep");
|
|
@@ -498,12 +538,12 @@ export class VtxoManager {
|
|
|
498
538
|
signedTx.finalize();
|
|
499
539
|
// Broadcast
|
|
500
540
|
const txid = await this.getOnchainProvider().broadcastTransaction(signedTx.hex);
|
|
501
|
-
// Mark
|
|
541
|
+
// Mark boarding inputs as swept to prevent duplicate broadcasts on next poll
|
|
502
542
|
for (const u of expiredUtxos) {
|
|
503
543
|
this.sweptBoardingUtxos.add(`${u.txid}:${u.vout}`);
|
|
504
544
|
}
|
|
505
545
|
// Mark the sweep output as "known" so the next poll doesn't try to
|
|
506
|
-
// auto-settle it back into
|
|
546
|
+
// auto-settle it back into Arkade (it lands at the same boarding address).
|
|
507
547
|
this.knownBoardingUtxos.add(`${txid}:0`);
|
|
508
548
|
return txid;
|
|
509
549
|
}
|
|
@@ -527,7 +567,7 @@ export class VtxoManager {
|
|
|
527
567
|
getBoardingOutputScript() {
|
|
528
568
|
return this.getSweepWallet().boardingTapscript.pkScript;
|
|
529
569
|
}
|
|
530
|
-
/** Returns the
|
|
570
|
+
/** Returns the onchain provider for fee estimation and broadcasting. */
|
|
531
571
|
getOnchainProvider() {
|
|
532
572
|
return this.getSweepWallet().onchainProvider;
|
|
533
573
|
}
|
|
@@ -543,7 +583,7 @@ export class VtxoManager {
|
|
|
543
583
|
if (this.settlementConfig === false) {
|
|
544
584
|
return undefined;
|
|
545
585
|
}
|
|
546
|
-
// Start polling for boarding
|
|
586
|
+
// Start polling for boarding inputs independently of contract manager
|
|
547
587
|
// SSE setup. Use a short delay to let the wallet finish construction.
|
|
548
588
|
this.startupPollTimeoutId = setTimeout(() => {
|
|
549
589
|
if (this.disposed)
|
|
@@ -567,17 +607,18 @@ export class VtxoManager {
|
|
|
567
607
|
this.renewVtxos().catch((e) => {
|
|
568
608
|
if (e instanceof Error) {
|
|
569
609
|
if (e.message.includes("No VTXOs available to renew")) {
|
|
570
|
-
// Not an error, just no
|
|
610
|
+
// Not an error, just no virtual outputs eligible for renewal.
|
|
571
611
|
return;
|
|
572
612
|
}
|
|
573
613
|
if (e.message.includes("is below dust threshold")) {
|
|
574
614
|
// Not an error, just below dust threshold.
|
|
575
|
-
// As more
|
|
615
|
+
// As more virtual outputs are received, the threshold will be raised.
|
|
576
616
|
return;
|
|
577
617
|
}
|
|
578
618
|
if (e.message.includes("VTXO_ALREADY_REGISTERED") ||
|
|
619
|
+
e.message.includes("VTXO_ALREADY_SPENT") ||
|
|
579
620
|
e.message.includes("duplicated input")) {
|
|
580
|
-
//
|
|
621
|
+
// Virtual output is already being used in a concurrent
|
|
581
622
|
// user-initiated operation. Skip silently — the
|
|
582
623
|
// wallet's tx lock serializes these, but the
|
|
583
624
|
// renewal will retry on the next cycle.
|
|
@@ -613,8 +654,8 @@ export class VtxoManager {
|
|
|
613
654
|
}
|
|
614
655
|
/**
|
|
615
656
|
* Starts a polling loop that:
|
|
616
|
-
* 1. Auto-settles new boarding
|
|
617
|
-
* 2. Sweeps expired boarding
|
|
657
|
+
* 1. Auto-settles new boarding inputs into Arkade
|
|
658
|
+
* 2. Sweeps expired boarding inputs (when boardingUtxoSweep is enabled)
|
|
618
659
|
*
|
|
619
660
|
* Uses setTimeout chaining (not setInterval) so a slow/blocked poll
|
|
620
661
|
* cannot stack up and the next delay can incorporate backoff.
|
|
@@ -632,7 +673,7 @@ export class VtxoManager {
|
|
|
632
673
|
this.pollTimeoutId = setTimeout(() => this.pollBoardingUtxos(), delay);
|
|
633
674
|
}
|
|
634
675
|
async pollBoardingUtxos() {
|
|
635
|
-
// Guard: wallet must support boarding
|
|
676
|
+
// Guard: wallet must support boarding input + sweep operations
|
|
636
677
|
if (!isSweepCapable(this.wallet))
|
|
637
678
|
return;
|
|
638
679
|
// Skip if disposed or a previous poll is still running
|
|
@@ -647,11 +688,11 @@ export class VtxoManager {
|
|
|
647
688
|
this.pollDone = { promise, resolve: resolve };
|
|
648
689
|
let hadError = false;
|
|
649
690
|
try {
|
|
650
|
-
// Fetch boarding
|
|
691
|
+
// Fetch boarding inputs once for the entire poll cycle so that
|
|
651
692
|
// settle and sweep don't each hit the network independently.
|
|
652
693
|
const boardingUtxos = await this.wallet.getBoardingUtxos();
|
|
653
|
-
// Settle new (unexpired)
|
|
654
|
-
// Sequential to avoid racing for the same
|
|
694
|
+
// Settle new (unexpired) boarding inputs first, then sweep expired ones.
|
|
695
|
+
// Sequential to avoid racing for the same inputs.
|
|
655
696
|
try {
|
|
656
697
|
await this.settleBoardingUtxos(boardingUtxos);
|
|
657
698
|
}
|
|
@@ -693,16 +734,16 @@ export class VtxoManager {
|
|
|
693
734
|
}
|
|
694
735
|
}
|
|
695
736
|
/**
|
|
696
|
-
* Auto-settle new (unexpired) boarding
|
|
737
|
+
* Auto-settle new (unexpired) boarding inputs into Arkade.
|
|
697
738
|
* Skips UTXOs that are already expired (those are handled by sweep).
|
|
698
739
|
* Only settles UTXOs not already in-flight (tracked in knownBoardingUtxos).
|
|
699
740
|
* UTXOs are marked as known only after a successful settle, so failed
|
|
700
741
|
* attempts will be retried on the next poll.
|
|
701
742
|
*/
|
|
702
743
|
async settleBoardingUtxos(boardingUtxos) {
|
|
703
|
-
// Exclude expired
|
|
744
|
+
// Exclude expired boarding inputs — those should be swept, not settled.
|
|
704
745
|
// If we can't determine expired status, bail out entirely to avoid
|
|
705
|
-
// accidentally settling expired
|
|
746
|
+
// accidentally settling expired inputs (which would conflict with sweep).
|
|
706
747
|
let expiredSet;
|
|
707
748
|
try {
|
|
708
749
|
const boardingTimelock = this.getBoardingTimelock();
|