@arkade-os/sdk 0.4.15 → 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 +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 +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 +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 +125 -67
- 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 +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 +125 -67
- 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 +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
|
@@ -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,18 +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") ||
|
|
579
619
|
e.message.includes("VTXO_ALREADY_SPENT") ||
|
|
580
620
|
e.message.includes("duplicated input")) {
|
|
581
|
-
//
|
|
621
|
+
// Virtual output is already being used in a concurrent
|
|
582
622
|
// user-initiated operation. Skip silently — the
|
|
583
623
|
// wallet's tx lock serializes these, but the
|
|
584
624
|
// renewal will retry on the next cycle.
|
|
@@ -614,8 +654,8 @@ export class VtxoManager {
|
|
|
614
654
|
}
|
|
615
655
|
/**
|
|
616
656
|
* Starts a polling loop that:
|
|
617
|
-
* 1. Auto-settles new boarding
|
|
618
|
-
* 2. Sweeps expired boarding
|
|
657
|
+
* 1. Auto-settles new boarding inputs into Arkade
|
|
658
|
+
* 2. Sweeps expired boarding inputs (when boardingUtxoSweep is enabled)
|
|
619
659
|
*
|
|
620
660
|
* Uses setTimeout chaining (not setInterval) so a slow/blocked poll
|
|
621
661
|
* cannot stack up and the next delay can incorporate backoff.
|
|
@@ -633,7 +673,7 @@ export class VtxoManager {
|
|
|
633
673
|
this.pollTimeoutId = setTimeout(() => this.pollBoardingUtxos(), delay);
|
|
634
674
|
}
|
|
635
675
|
async pollBoardingUtxos() {
|
|
636
|
-
// Guard: wallet must support boarding
|
|
676
|
+
// Guard: wallet must support boarding input + sweep operations
|
|
637
677
|
if (!isSweepCapable(this.wallet))
|
|
638
678
|
return;
|
|
639
679
|
// Skip if disposed or a previous poll is still running
|
|
@@ -648,11 +688,11 @@ export class VtxoManager {
|
|
|
648
688
|
this.pollDone = { promise, resolve: resolve };
|
|
649
689
|
let hadError = false;
|
|
650
690
|
try {
|
|
651
|
-
// Fetch boarding
|
|
691
|
+
// Fetch boarding inputs once for the entire poll cycle so that
|
|
652
692
|
// settle and sweep don't each hit the network independently.
|
|
653
693
|
const boardingUtxos = await this.wallet.getBoardingUtxos();
|
|
654
|
-
// Settle new (unexpired)
|
|
655
|
-
// 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.
|
|
656
696
|
try {
|
|
657
697
|
await this.settleBoardingUtxos(boardingUtxos);
|
|
658
698
|
}
|
|
@@ -694,16 +734,16 @@ export class VtxoManager {
|
|
|
694
734
|
}
|
|
695
735
|
}
|
|
696
736
|
/**
|
|
697
|
-
* Auto-settle new (unexpired) boarding
|
|
737
|
+
* Auto-settle new (unexpired) boarding inputs into Arkade.
|
|
698
738
|
* Skips UTXOs that are already expired (those are handled by sweep).
|
|
699
739
|
* Only settles UTXOs not already in-flight (tracked in knownBoardingUtxos).
|
|
700
740
|
* UTXOs are marked as known only after a successful settle, so failed
|
|
701
741
|
* attempts will be retried on the next poll.
|
|
702
742
|
*/
|
|
703
743
|
async settleBoardingUtxos(boardingUtxos) {
|
|
704
|
-
// Exclude expired
|
|
744
|
+
// Exclude expired boarding inputs — those should be swept, not settled.
|
|
705
745
|
// If we can't determine expired status, bail out entirely to avoid
|
|
706
|
-
// accidentally settling expired
|
|
746
|
+
// accidentally settling expired inputs (which would conflict with sweep).
|
|
707
747
|
let expiredSet;
|
|
708
748
|
try {
|
|
709
749
|
const boardingTimelock = this.getBoardingTimelock();
|