@arkade-os/sdk 0.3.1-alpha.4 → 0.3.1-alpha.6

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.
Files changed (47) hide show
  1. package/README.md +11 -27
  2. package/dist/cjs/forfeit.js +2 -5
  3. package/dist/cjs/identity/singleKey.js +4 -5
  4. package/dist/cjs/index.js +5 -4
  5. package/dist/cjs/intent/index.js +3 -8
  6. package/dist/cjs/providers/onchain.js +19 -20
  7. package/dist/cjs/repositories/walletRepository.js +64 -2
  8. package/dist/cjs/script/base.js +14 -5
  9. package/dist/cjs/utils/arkTransaction.js +3 -5
  10. package/dist/cjs/utils/transaction.js +28 -0
  11. package/dist/cjs/wallet/onchain.js +4 -4
  12. package/dist/cjs/wallet/serviceWorker/worker.js +19 -2
  13. package/dist/cjs/wallet/unroll.js +3 -4
  14. package/dist/cjs/wallet/utils.js +9 -0
  15. package/dist/cjs/wallet/vtxo-manager.js +31 -89
  16. package/dist/cjs/wallet/wallet.js +11 -13
  17. package/dist/esm/forfeit.js +1 -4
  18. package/dist/esm/identity/singleKey.js +3 -4
  19. package/dist/esm/index.js +3 -3
  20. package/dist/esm/intent/index.js +2 -7
  21. package/dist/esm/providers/onchain.js +19 -20
  22. package/dist/esm/repositories/walletRepository.js +64 -2
  23. package/dist/esm/script/base.js +11 -2
  24. package/dist/esm/utils/arkTransaction.js +3 -5
  25. package/dist/esm/utils/transaction.js +24 -0
  26. package/dist/esm/wallet/onchain.js +3 -3
  27. package/dist/esm/wallet/serviceWorker/worker.js +21 -4
  28. package/dist/esm/wallet/unroll.js +4 -5
  29. package/dist/esm/wallet/utils.js +8 -0
  30. package/dist/esm/wallet/vtxo-manager.js +30 -85
  31. package/dist/esm/wallet/wallet.js +12 -14
  32. package/dist/types/forfeit.d.ts +1 -1
  33. package/dist/types/identity/index.d.ts +1 -1
  34. package/dist/types/identity/singleKey.d.ts +1 -1
  35. package/dist/types/index.d.ts +3 -3
  36. package/dist/types/intent/index.d.ts +1 -1
  37. package/dist/types/providers/onchain.d.ts +6 -2
  38. package/dist/types/repositories/walletRepository.d.ts +9 -1
  39. package/dist/types/script/base.d.ts +2 -0
  40. package/dist/types/utils/arkTransaction.d.ts +1 -3
  41. package/dist/types/utils/transaction.d.ts +13 -0
  42. package/dist/types/wallet/onchain.d.ts +1 -1
  43. package/dist/types/wallet/serviceWorker/worker.d.ts +4 -0
  44. package/dist/types/wallet/unroll.d.ts +1 -1
  45. package/dist/types/wallet/utils.d.ts +2 -1
  46. package/dist/types/wallet/vtxo-manager.d.ts +7 -35
  47. package/package.json +1 -1
@@ -1,9 +1,10 @@
1
1
  import { base64, hex } from "@scure/base";
2
- import { SigHash, Transaction, TaprootControlBlock } from "@scure/btc-signer";
2
+ import { SigHash, TaprootControlBlock } from "@scure/btc-signer";
3
3
  import { ChainTxType } from '../providers/indexer.js';
4
4
  import { VtxoScript } from '../script/base.js';
5
5
  import { TxWeightEstimator } from '../utils/txSizeEstimator.js';
6
6
  import { Wallet } from './wallet.js';
7
+ import { Transaction } from '../utils/transaction.js';
7
8
  export var Unroll;
8
9
  (function (Unroll) {
9
10
  let StepType;
@@ -102,9 +103,7 @@ export var Unroll;
102
103
  if (virtualTxs.txs.length === 0) {
103
104
  throw new Error(`Tx ${nextTxToBroadcast.txid} not found`);
104
105
  }
105
- const tx = Transaction.fromPSBT(base64.decode(virtualTxs.txs[0]), {
106
- allowUnknownInputs: true,
107
- });
106
+ const tx = Transaction.fromPSBT(base64.decode(virtualTxs.txs[0]));
108
107
  // finalize the tree transaction
109
108
  if (nextTxToBroadcast.type === ChainTxType.TREE) {
110
109
  const input = tx.getInput(0);
@@ -197,7 +196,7 @@ export var Unroll;
197
196
  });
198
197
  txWeightEstimator.addTapscriptInput(64, spendingLeaf[1].length, TaprootControlBlock.encode(spendingLeaf[0]).length);
199
198
  }
200
- const tx = new Transaction({ allowUnknownInputs: true, version: 2 });
199
+ const tx = new Transaction({ version: 2 });
201
200
  for (const input of inputs) {
202
201
  tx.addInput(input);
203
202
  }
@@ -6,3 +6,11 @@ export function extendVirtualCoin(wallet, vtxo) {
6
6
  tapTree: wallet.offchainTapscript.encode(),
7
7
  };
8
8
  }
9
+ export function extendCoin(wallet, utxo) {
10
+ return {
11
+ ...utxo,
12
+ forfeitTapLeafScript: wallet.boardingTapscript.forfeit(),
13
+ intentTapLeafScript: wallet.boardingTapscript.exit(),
14
+ tapTree: wallet.boardingTapscript.encode(),
15
+ };
16
+ }
@@ -5,6 +5,9 @@ import { isRecoverable, isSubdust } from './index.js';
5
5
  export const DEFAULT_RENEWAL_CONFIG = {
6
6
  thresholdPercentage: 10,
7
7
  };
8
+ function getDustAmount(wallet) {
9
+ return "dustAmount" in wallet ? wallet.dustAmount : 330n;
10
+ }
8
11
  /**
9
12
  * Filter VTXOs that are recoverable (swept and still spendable, or preconfirmed subdust)
10
13
  *
@@ -74,80 +77,35 @@ function getRecoverableWithSubdust(vtxos, dustAmount) {
74
77
  * @param thresholdMs - Threshold in milliseconds from now
75
78
  * @returns true if VTXO expires within threshold, false otherwise
76
79
  */
77
- export function isVtxoExpiringSoon(vtxo, thresholdMs) {
80
+ export function isVtxoExpiringSoon(vtxo, percentage) {
78
81
  const { batchExpiry } = vtxo.virtualStatus;
79
- // No expiry set means it doesn't expire
80
82
  if (!batchExpiry) {
81
- return false;
83
+ return false; // it doesn't expire
82
84
  }
83
85
  const now = Date.now();
84
- const timeUntilExpiry = batchExpiry - now;
85
- return timeUntilExpiry > 0 && timeUntilExpiry <= thresholdMs;
86
+ if (batchExpiry <= now) {
87
+ return false; // already expired
88
+ }
89
+ // It shouldn't happen, but let's be safe
90
+ if (!vtxo.createdAt) {
91
+ return false;
92
+ }
93
+ const duration = batchExpiry - vtxo.createdAt.getTime();
94
+ const softExpiry = batchExpiry - (duration * percentage) / 100;
95
+ return softExpiry > 0 && softExpiry <= now;
86
96
  }
87
97
  /**
88
- * Filter VTXOs that are expiring soon
98
+ * Filter VTXOs that are expiring soon or are recoverable/subdust
89
99
  *
90
100
  * @param vtxos - Array of virtual coins to check
91
101
  * @param thresholdMs - Threshold in milliseconds from now
102
+ * @param dustAmount - Dust threshold amount in satoshis
92
103
  * @returns Array of VTXOs expiring within threshold
93
104
  */
94
- export function getExpiringVtxos(vtxos, thresholdMs) {
95
- return vtxos.filter((vtxo) => isVtxoExpiringSoon(vtxo, thresholdMs));
96
- }
97
- /**
98
- * Calculate expiry threshold in milliseconds based on batch expiry and percentage
99
- *
100
- * @param batchExpiry - Batch expiry timestamp in milliseconds
101
- * @param percentage - Percentage of total time (0-100)
102
- * @returns Threshold timestamp in milliseconds from now
103
- *
104
- * @example
105
- * // VTXO expires in 10 days, threshold is 10%
106
- * const expiry = Date.now() + 10 * 24 * 60 * 60 * 1000;
107
- * const threshold = calculateExpiryThreshold(expiry, 10);
108
- * // Returns 1 day in milliseconds (10% of 10 days)
109
- */
110
- export function calculateExpiryThreshold(batchExpiry, percentage) {
111
- if (percentage < 0 || percentage > 100) {
112
- throw new Error("Percentage must be between 0 and 100");
113
- }
114
- const now = Date.now();
115
- const totalTime = batchExpiry - now;
116
- if (totalTime <= 0) {
117
- // Already expired
118
- return 0;
119
- }
120
- // Calculate threshold as percentage of total time
121
- return Math.floor((totalTime * percentage) / 100);
122
- }
123
- /**
124
- * Get the minimum expiry time from a list of VTXOs
125
- *
126
- * @param vtxos - Array of virtual coins
127
- * @returns Minimum batch expiry timestamp, or undefined if no VTXOs have expiry
128
- */
129
- export function getMinimumExpiry(vtxos) {
130
- const expiries = vtxos
131
- .map((v) => v.virtualStatus.batchExpiry)
132
- .filter((e) => e !== undefined);
133
- if (expiries.length === 0) {
134
- return undefined;
135
- }
136
- return Math.min(...expiries);
137
- }
138
- /**
139
- * Calculate dynamic threshold based on the earliest expiring VTXO
140
- *
141
- * @param vtxos - Array of virtual coins
142
- * @param percentage - Percentage of time until expiry (0-100)
143
- * @returns Threshold in milliseconds, or undefined if no VTXOs have expiry
144
- */
145
- export function calculateDynamicThreshold(vtxos, percentage) {
146
- const minExpiry = getMinimumExpiry(vtxos);
147
- if (!minExpiry) {
148
- return undefined;
149
- }
150
- return calculateExpiryThreshold(minExpiry, percentage);
105
+ export function getExpiringAndRecoverableVtxos(vtxos, percentage, dustAmount) {
106
+ return vtxos.filter((vtxo) => isVtxoExpiringSoon(vtxo, percentage) ||
107
+ isRecoverable(vtxo) ||
108
+ isSubdust(vtxo, dustAmount));
151
109
  }
152
110
  /**
153
111
  * VtxoManager is a unified class for managing VTXO lifecycle operations including
@@ -228,9 +186,7 @@ export class VtxoManager {
228
186
  withUnrolled: false,
229
187
  });
230
188
  // Get dust amount from wallet
231
- const dustAmount = "dustAmount" in this.wallet
232
- ? this.wallet.dustAmount
233
- : 1000n;
189
+ const dustAmount = getDustAmount(this.wallet);
234
190
  // Filter recoverable VTXOs and handle subdust logic
235
191
  const { vtxosToRecover, includesSubdust, totalAmount } = getRecoverableWithSubdust(allVtxos, dustAmount);
236
192
  if (vtxosToRecover.length === 0) {
@@ -273,9 +229,7 @@ export class VtxoManager {
273
229
  withRecoverable: true,
274
230
  withUnrolled: false,
275
231
  });
276
- const dustAmount = "dustAmount" in this.wallet
277
- ? this.wallet.dustAmount
278
- : 1000n;
232
+ const dustAmount = getDustAmount(this.wallet);
279
233
  const { vtxosToRecover, includesSubdust, totalAmount } = getRecoverableWithSubdust(allVtxos, dustAmount);
280
234
  // Calculate subdust amount separately for reporting
281
235
  const subdustAmount = vtxosToRecover
@@ -305,23 +259,16 @@ export class VtxoManager {
305
259
  * ```
306
260
  */
307
261
  async getExpiringVtxos(thresholdPercentage) {
308
- if (!this.renewalConfig?.enabled) {
309
- return [];
310
- }
311
- const vtxos = await this.wallet.getVtxos();
262
+ const vtxos = await this.wallet.getVtxos({ withRecoverable: true });
312
263
  const percentage = thresholdPercentage ??
313
- this.renewalConfig.thresholdPercentage ??
264
+ this.renewalConfig?.thresholdPercentage ??
314
265
  DEFAULT_RENEWAL_CONFIG.thresholdPercentage;
315
- const threshold = calculateDynamicThreshold(vtxos, percentage);
316
- if (!threshold) {
317
- return [];
318
- }
319
- return getExpiringVtxos(vtxos, threshold);
266
+ return getExpiringAndRecoverableVtxos(vtxos, percentage, getDustAmount(this.wallet));
320
267
  }
321
268
  /**
322
- * Renew VTXOs by settling them back to the wallet's address
269
+ * Renew expiring VTXOs by settling them back to the wallet's address
323
270
  *
324
- * This method collects all spendable VTXOs (including recoverable ones) and settles
271
+ * This method collects all expiring spendable VTXOs (including recoverable ones) and settles
325
272
  * them back to the wallet, effectively refreshing their expiration time. This is the
326
273
  * primary way to prevent VTXOs from expiring.
327
274
  *
@@ -345,15 +292,13 @@ export class VtxoManager {
345
292
  */
346
293
  async renewVtxos(eventCallback) {
347
294
  // Get all VTXOs (including recoverable ones)
348
- const vtxos = await this.wallet.getVtxos({ withRecoverable: true });
295
+ const vtxos = await this.getExpiringVtxos();
349
296
  if (vtxos.length === 0) {
350
297
  throw new Error("No VTXOs available to renew");
351
298
  }
352
299
  const totalAmount = vtxos.reduce((sum, vtxo) => sum + vtxo.value, 0);
353
300
  // Get dust amount from wallet
354
- const dustAmount = "dustAmount" in this.wallet
355
- ? this.wallet.dustAmount
356
- : 1000n;
301
+ const dustAmount = getDustAmount(this.wallet);
357
302
  // Check if total amount is above dust threshold
358
303
  if (BigInt(totalAmount) < dustAmount) {
359
304
  throw new Error(`Total amount ${totalAmount} is below dust threshold ${dustAmount}`);
@@ -24,7 +24,7 @@ import { ConditionWitness, VtxoTaprootTree } from '../utils/unknownFields.js';
24
24
  import { InMemoryStorageAdapter } from '../storage/inMemory.js';
25
25
  import { WalletRepositoryImpl, } from '../repositories/walletRepository.js';
26
26
  import { ContractRepositoryImpl, } from '../repositories/contractRepository.js';
27
- import { extendVirtualCoin } from './utils.js';
27
+ import { extendCoin, extendVirtualCoin } from './utils.js';
28
28
  /**
29
29
  * Main wallet implementation for Bitcoin transactions with Ark protocol support.
30
30
  * The wallet does not store any data locally and relies on Ark and onchain
@@ -333,15 +333,12 @@ export class Wallet {
333
333
  async getBoardingUtxos() {
334
334
  const boardingAddress = await this.getBoardingAddress();
335
335
  const boardingUtxos = await this.onchainProvider.getCoins(boardingAddress);
336
- const encodedBoardingTapscript = this.boardingTapscript.encode();
337
- const forfeit = this.boardingTapscript.forfeit();
338
- const exit = this.boardingTapscript.exit();
339
- return boardingUtxos.map((utxo) => ({
340
- ...utxo,
341
- forfeitTapLeafScript: forfeit,
342
- intentTapLeafScript: exit,
343
- tapTree: encodedBoardingTapscript,
344
- }));
336
+ const utxos = boardingUtxos.map((utxo) => {
337
+ return extendCoin(this, utxo);
338
+ });
339
+ // Save boardingUtxos using unified repository
340
+ await this.walletRepository.saveUtxos(boardingAddress, utxos);
341
+ return utxos;
345
342
  }
346
343
  async sendBitcoin(params) {
347
344
  if (params.amount <= 0) {
@@ -761,8 +758,6 @@ export class Wallet {
761
758
  const vtxo = vtxos.find((vtxo) => vtxo.txid === input.txid && vtxo.vout === input.vout);
762
759
  // boarding utxo, we need to sign the settlement tx
763
760
  if (!vtxo) {
764
- hasBoardingUtxos = true;
765
- const inputIndexes = [];
766
761
  for (let i = 0; i < settlementPsbt.inputsLength; i++) {
767
762
  const settlementInput = settlementPsbt.getInput(i);
768
763
  if (!settlementInput.txid ||
@@ -778,9 +773,12 @@ export class Wallet {
778
773
  settlementPsbt.updateInput(i, {
779
774
  tapLeafScript: [input.forfeitTapLeafScript],
780
775
  });
781
- inputIndexes.push(i);
776
+ settlementPsbt = await this.identity.sign(settlementPsbt, [
777
+ i,
778
+ ]);
779
+ hasBoardingUtxos = true;
780
+ break;
782
781
  }
783
- settlementPsbt = await this.identity.sign(settlementPsbt, inputIndexes);
784
782
  continue;
785
783
  }
786
784
  if (isRecoverable(vtxo) || isSubdust(vtxo, this.dustAmount)) {
@@ -1,3 +1,3 @@
1
- import { Transaction } from "@scure/btc-signer";
1
+ import { Transaction } from "./utils/transaction";
2
2
  import { TransactionInputUpdate } from "@scure/btc-signer/psbt.js";
3
3
  export declare function buildForfeitTx(inputs: TransactionInputUpdate[], forfeitPkScript: Uint8Array, txLocktime?: number): Transaction;
@@ -1,4 +1,4 @@
1
- import { Transaction } from "@scure/btc-signer/transaction.js";
1
+ import { Transaction } from "../utils/transaction";
2
2
  import { SignerSession } from "../tree/signingSession";
3
3
  export interface Identity {
4
4
  signerSession(): SignerSession;
@@ -1,5 +1,5 @@
1
- import { Transaction } from "@scure/btc-signer/transaction.js";
2
1
  import { Identity } from ".";
2
+ import { Transaction } from "../utils/transaction";
3
3
  import { SignerSession } from "../tree/signingSession";
4
4
  /**
5
5
  * In-memory single key implementation for Bitcoin transaction signing.
@@ -1,10 +1,10 @@
1
- import { Transaction } from "@scure/btc-signer/transaction.js";
1
+ import { Transaction } from "./utils/transaction";
2
2
  import { SingleKey } from "./identity/singleKey";
3
3
  import { Identity } from "./identity";
4
4
  import { ArkAddress } from "./script/address";
5
5
  import { VHTLC } from "./script/vhtlc";
6
6
  import { DefaultVtxo } from "./script/default";
7
- import { VtxoScript, EncodedVtxoScript, TapLeafScript } from "./script/base";
7
+ import { VtxoScript, EncodedVtxoScript, TapLeafScript, TapTreeCoder } from "./script/base";
8
8
  import { TxType, IWallet, WalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, GetVtxosFilter, TapLeaves } from "./wallet";
9
9
  import { Wallet, waitForIncomingFunds, IncomingFunds } from "./wallet/wallet";
10
10
  import { TxTree, TxTreeNode } from "./tree/txTree";
@@ -33,5 +33,5 @@ import { Unroll } from "./wallet/unroll";
33
33
  import { WalletRepositoryImpl } from "./repositories/walletRepository";
34
34
  import { ContractRepositoryImpl } from "./repositories/contractRepository";
35
35
  import { ArkError, maybeArkError } from "./providers/errors";
36
- export { Wallet, SingleKey, OnchainWallet, Ramps, VtxoManager, ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, Worker, ServiceWorkerWallet, Request, Response, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, ArkNote, networks, WalletRepositoryImpl, ContractRepositoryImpl, Intent, TxTree, P2A, Unroll, Transaction, ArkError, maybeArkError, };
36
+ export { Wallet, SingleKey, OnchainWallet, Ramps, VtxoManager, ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, Worker, ServiceWorkerWallet, Request, Response, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, TapTreeCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, ArkNote, networks, WalletRepositoryImpl, ContractRepositoryImpl, Intent, TxTree, P2A, Unroll, Transaction, ArkError, maybeArkError, };
37
37
  export type { Identity, IWallet, WalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, IndexerProvider, PageResponse, Batch, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, ArkInfo, SignedIntent, Output, TxNotification, ExplorerTransaction, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, };
@@ -1,5 +1,5 @@
1
- import { Transaction } from "@scure/btc-signer";
2
1
  import { TransactionInput, TransactionOutput } from "@scure/btc-signer/psbt.js";
2
+ import { Transaction } from "../utils/transaction";
3
3
  /**
4
4
  * Intent proof implementation for Bitcoin message signing.
5
5
  *
@@ -49,8 +49,12 @@ export interface OnchainProvider {
49
49
  */
50
50
  export declare class EsploraProvider implements OnchainProvider {
51
51
  private baseUrl;
52
- private polling;
53
- constructor(baseUrl: string);
52
+ readonly pollingInterval: number;
53
+ readonly forcePolling: boolean;
54
+ constructor(baseUrl: string, opts?: {
55
+ pollingInterval?: number;
56
+ forcePolling?: boolean;
57
+ });
54
58
  getCoins(address: string): Promise<Coin[]>;
55
59
  getFeeRate(): Promise<number | undefined>;
56
60
  broadcastTransaction(...txs: string[]): Promise<string>;
@@ -1,5 +1,5 @@
1
1
  import { StorageAdapter } from "../storage";
2
- import { ArkTransaction, ExtendedVirtualCoin } from "../wallet";
2
+ import { ArkTransaction, ExtendedCoin, ExtendedVirtualCoin } from "../wallet";
3
3
  export interface WalletState {
4
4
  lastSyncTime?: number;
5
5
  settings?: Record<string, any>;
@@ -9,6 +9,10 @@ export interface WalletRepository {
9
9
  saveVtxos(address: string, vtxos: ExtendedVirtualCoin[]): Promise<void>;
10
10
  removeVtxo(address: string, vtxoId: string): Promise<void>;
11
11
  clearVtxos(address: string): Promise<void>;
12
+ getUtxos(address: string): Promise<ExtendedCoin[]>;
13
+ saveUtxos(address: string, utxos: ExtendedCoin[]): Promise<void>;
14
+ removeUtxo(address: string, utxoId: string): Promise<void>;
15
+ clearUtxos(address: string): Promise<void>;
12
16
  getTransactionHistory(address: string): Promise<ArkTransaction[]>;
13
17
  saveTransactions(address: string, txs: ArkTransaction[]): Promise<void>;
14
18
  clearTransactions(address: string): Promise<void>;
@@ -23,6 +27,10 @@ export declare class WalletRepositoryImpl implements WalletRepository {
23
27
  saveVtxos(address: string, vtxos: ExtendedVirtualCoin[]): Promise<void>;
24
28
  removeVtxo(address: string, vtxoId: string): Promise<void>;
25
29
  clearVtxos(address: string): Promise<void>;
30
+ getUtxos(address: string): Promise<ExtendedCoin[]>;
31
+ saveUtxos(address: string, utxos: ExtendedCoin[]): Promise<void>;
32
+ removeUtxo(address: string, utxoId: string): Promise<void>;
33
+ clearUtxos(address: string): Promise<void>;
26
34
  getTransactionHistory(address: string): Promise<ArkTransaction[]>;
27
35
  saveTransactions(address: string, txs: ArkTransaction[]): Promise<void>;
28
36
  clearTransactions(address: string): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import { NETWORK } from "@scure/btc-signer";
2
+ import { PSBTOutput } from "@scure/btc-signer/psbt.js";
2
3
  import { Bytes } from "@scure/btc-signer/utils.js";
3
4
  import { ArkAddress } from "./address";
4
5
  import { ConditionCSVMultisigTapscript, CSVMultisigTapscript } from "./tapscript";
@@ -10,6 +11,7 @@ export type TapLeafScript = [
10
11
  },
11
12
  Bytes
12
13
  ];
14
+ export declare const TapTreeCoder: (typeof PSBTOutput.tapTree)[2];
13
15
  export declare function scriptFromTapLeafScript(leaf: TapLeafScript): Bytes;
14
16
  /**
15
17
  * VtxoScript is a script that contains a list of tapleaf scripts.
@@ -1,13 +1,11 @@
1
- import { Transaction } from "@scure/btc-signer";
2
- import { Bytes } from "@scure/btc-signer/utils.js";
3
1
  import { TransactionOutput } from "@scure/btc-signer/psbt.js";
4
2
  import { ExtendedCoin, VirtualCoin } from "../wallet";
5
3
  import { RelativeTimelock } from "../script/tapscript";
6
4
  import { EncodedVtxoScript, TapLeafScript } from "../script/base";
7
5
  import { CSVMultisigTapscript } from "../script/tapscript";
6
+ import { Transaction } from "./transaction";
8
7
  export type ArkTxInput = {
9
8
  tapLeafScript: TapLeafScript;
10
- checkpointTapLeafScript?: Bytes;
11
9
  } & EncodedVtxoScript & Pick<VirtualCoin, "txid" | "vout" | "value">;
12
10
  export type OffchainTx = {
13
11
  arkTx: Transaction;
@@ -0,0 +1,13 @@
1
+ import { Transaction as BtcSignerTransaction } from "@scure/btc-signer";
2
+ import { TxOpts } from "@scure/btc-signer/transaction";
3
+ import { Bytes } from "@scure/btc-signer/utils";
4
+ /**
5
+ * Transaction is a wrapper around the @scure/btc-signer Transaction class.
6
+ * It adds the Ark protocol specific options to the transaction.
7
+ */
8
+ export declare class Transaction extends BtcSignerTransaction {
9
+ static ARK_TX_OPTS: TxOpts;
10
+ constructor(opts?: TxOpts);
11
+ static fromPSBT(psbt_: Bytes, opts?: TxOpts): Transaction;
12
+ static fromRaw(raw: Bytes, opts?: TxOpts): Transaction;
13
+ }
@@ -1,10 +1,10 @@
1
- import { Transaction } from "@scure/btc-signer";
2
1
  import { P2TR } from "@scure/btc-signer/payment.js";
3
2
  import { Coin, SendBitcoinParams } from ".";
4
3
  import { Identity } from "../identity";
5
4
  import { Network, NetworkName } from "../networks";
6
5
  import { OnchainProvider } from "../providers/onchain";
7
6
  import { AnchorBumper } from "../utils/anchor";
7
+ import { Transaction } from "../utils/transaction";
8
8
  /**
9
9
  * Onchain Bitcoin wallet implementation for traditional Bitcoin transactions.
10
10
  *
@@ -25,6 +25,10 @@ export declare class Worker {
25
25
  * Get all vtxos categorized by type
26
26
  */
27
27
  private getAllVtxos;
28
+ /**
29
+ * Get all boarding utxos from wallet repository
30
+ */
31
+ private getAllBoardingUtxos;
28
32
  start(withServiceWorkerUpdate?: boolean): Promise<void>;
29
33
  clear(): Promise<void>;
30
34
  reload(): Promise<void>;
@@ -1,9 +1,9 @@
1
- import { Transaction } from "@scure/btc-signer";
2
1
  import { ChainTx, IndexerProvider } from "../providers/indexer";
3
2
  import { AnchorBumper } from "../utils/anchor";
4
3
  import { OnchainProvider } from "../providers/onchain";
5
4
  import { Outpoint } from ".";
6
5
  import { Wallet } from "./wallet";
6
+ import { Transaction } from "../utils/transaction";
7
7
  export declare namespace Unroll {
8
8
  enum StepType {
9
9
  UNROLL = 0,
@@ -1,2 +1,3 @@
1
- import type { ExtendedVirtualCoin, VirtualCoin, Wallet } from "..";
1
+ import type { Coin, ExtendedCoin, ExtendedVirtualCoin, VirtualCoin, Wallet } from "..";
2
2
  export declare function extendVirtualCoin(wallet: Wallet, vtxo: VirtualCoin): ExtendedVirtualCoin;
3
+ export declare function extendCoin(wallet: Wallet, utxo: Coin): ExtendedCoin;
@@ -8,7 +8,7 @@ export interface RenewalConfig {
8
8
  * Enable automatic renewal monitoring
9
9
  * @default false
10
10
  */
11
- enabled: boolean;
11
+ enabled?: boolean;
12
12
  /**
13
13
  * Percentage of expiry time to use as threshold (0-100)
14
14
  * E.g., 10 means renew when 10% of time until expiry remains
@@ -27,44 +27,16 @@ export declare const DEFAULT_RENEWAL_CONFIG: Required<Omit<RenewalConfig, "enabl
27
27
  * @param thresholdMs - Threshold in milliseconds from now
28
28
  * @returns true if VTXO expires within threshold, false otherwise
29
29
  */
30
- export declare function isVtxoExpiringSoon(vtxo: ExtendedVirtualCoin, thresholdMs: number): boolean;
30
+ export declare function isVtxoExpiringSoon(vtxo: ExtendedVirtualCoin, percentage: number): boolean;
31
31
  /**
32
- * Filter VTXOs that are expiring soon
32
+ * Filter VTXOs that are expiring soon or are recoverable/subdust
33
33
  *
34
34
  * @param vtxos - Array of virtual coins to check
35
35
  * @param thresholdMs - Threshold in milliseconds from now
36
+ * @param dustAmount - Dust threshold amount in satoshis
36
37
  * @returns Array of VTXOs expiring within threshold
37
38
  */
38
- export declare function getExpiringVtxos(vtxos: ExtendedVirtualCoin[], thresholdMs: number): ExtendedVirtualCoin[];
39
- /**
40
- * Calculate expiry threshold in milliseconds based on batch expiry and percentage
41
- *
42
- * @param batchExpiry - Batch expiry timestamp in milliseconds
43
- * @param percentage - Percentage of total time (0-100)
44
- * @returns Threshold timestamp in milliseconds from now
45
- *
46
- * @example
47
- * // VTXO expires in 10 days, threshold is 10%
48
- * const expiry = Date.now() + 10 * 24 * 60 * 60 * 1000;
49
- * const threshold = calculateExpiryThreshold(expiry, 10);
50
- * // Returns 1 day in milliseconds (10% of 10 days)
51
- */
52
- export declare function calculateExpiryThreshold(batchExpiry: number, percentage: number): number;
53
- /**
54
- * Get the minimum expiry time from a list of VTXOs
55
- *
56
- * @param vtxos - Array of virtual coins
57
- * @returns Minimum batch expiry timestamp, or undefined if no VTXOs have expiry
58
- */
59
- export declare function getMinimumExpiry(vtxos: ExtendedVirtualCoin[]): number | undefined;
60
- /**
61
- * Calculate dynamic threshold based on the earliest expiring VTXO
62
- *
63
- * @param vtxos - Array of virtual coins
64
- * @param percentage - Percentage of time until expiry (0-100)
65
- * @returns Threshold in milliseconds, or undefined if no VTXOs have expiry
66
- */
67
- export declare function calculateDynamicThreshold(vtxos: ExtendedVirtualCoin[], percentage: number): number | undefined;
39
+ export declare function getExpiringAndRecoverableVtxos(vtxos: ExtendedVirtualCoin[], percentage: number, dustAmount: bigint): ExtendedVirtualCoin[];
68
40
  /**
69
41
  * VtxoManager is a unified class for managing VTXO lifecycle operations including
70
42
  * recovery of swept/expired VTXOs and renewal to prevent expiration.
@@ -179,9 +151,9 @@ export declare class VtxoManager {
179
151
  */
180
152
  getExpiringVtxos(thresholdPercentage?: number): Promise<ExtendedVirtualCoin[]>;
181
153
  /**
182
- * Renew VTXOs by settling them back to the wallet's address
154
+ * Renew expiring VTXOs by settling them back to the wallet's address
183
155
  *
184
- * This method collects all spendable VTXOs (including recoverable ones) and settles
156
+ * This method collects all expiring spendable VTXOs (including recoverable ones) and settles
185
157
  * them back to the wallet, effectively refreshing their expiration time. This is the
186
158
  * primary way to prevent VTXOs from expiring.
187
159
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/sdk",
3
- "version": "0.3.1-alpha.4",
3
+ "version": "0.3.1-alpha.6",
4
4
  "description": "Bitcoin wallet SDK with Taproot and Ark integration",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",