@arkade-os/sdk 0.4.5 → 0.4.7
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 +67 -6
- package/dist/cjs/utils/arkTransaction.js +7 -3
- package/dist/cjs/wallet/expo/wallet.js +1 -0
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +14 -0
- package/dist/cjs/wallet/vtxo-manager.js +391 -6
- package/dist/cjs/wallet/wallet.js +85 -3
- package/dist/esm/utils/arkTransaction.js +7 -3
- package/dist/esm/wallet/expo/wallet.js +1 -0
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +14 -0
- package/dist/esm/wallet/vtxo-manager.js +390 -5
- package/dist/esm/wallet/wallet.js +86 -4
- package/dist/types/index.d.ts +2 -1
- package/dist/types/utils/arkTransaction.d.ts +1 -1
- package/dist/types/wallet/index.d.ts +12 -6
- package/dist/types/wallet/vtxo-manager.d.ts +166 -3
- package/dist/types/wallet/wallet.d.ts +12 -1
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ import { createAssetPacket, selectedCoinsToAssetInputs, selectCoinsWithAsset, }
|
|
|
15
15
|
import { VtxoScript } from '../script/base.js';
|
|
16
16
|
import { CSVMultisigTapscript } from '../script/tapscript.js';
|
|
17
17
|
import { buildOffchainTx, hasBoardingTxExpired, isValidArkAddress, } from '../utils/arkTransaction.js';
|
|
18
|
-
import { DEFAULT_RENEWAL_CONFIG } from './vtxo-manager.js';
|
|
18
|
+
import { DEFAULT_RENEWAL_CONFIG, DEFAULT_SETTLEMENT_CONFIG, VtxoManager, } from './vtxo-manager.js';
|
|
19
19
|
import { ArkNote } from '../arknote/index.js';
|
|
20
20
|
import { Intent } from '../intent/index.js';
|
|
21
21
|
import { RestIndexerProvider } from '../providers/indexer.js';
|
|
@@ -611,6 +611,18 @@ export class ReadonlyWallet {
|
|
|
611
611
|
}
|
|
612
612
|
return manager;
|
|
613
613
|
}
|
|
614
|
+
async dispose() {
|
|
615
|
+
const manager = this._contractManager ??
|
|
616
|
+
(this._contractManagerInitializing
|
|
617
|
+
? await this._contractManagerInitializing.catch(() => undefined)
|
|
618
|
+
: undefined);
|
|
619
|
+
manager?.dispose();
|
|
620
|
+
this._contractManager = undefined;
|
|
621
|
+
this._contractManagerInitializing = undefined;
|
|
622
|
+
}
|
|
623
|
+
async [Symbol.asyncDispose]() {
|
|
624
|
+
await this.dispose();
|
|
625
|
+
}
|
|
614
626
|
}
|
|
615
627
|
/**
|
|
616
628
|
* Main wallet implementation for Bitcoin transactions with Ark protocol support.
|
|
@@ -646,7 +658,9 @@ export class ReadonlyWallet {
|
|
|
646
658
|
* ```
|
|
647
659
|
*/
|
|
648
660
|
export class Wallet extends ReadonlyWallet {
|
|
649
|
-
constructor(identity, network, networkName, onchainProvider, arkProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, serverUnrollScript, forfeitOutputScript, forfeitPubkey, dustAmount, walletRepository, contractRepository,
|
|
661
|
+
constructor(identity, network, networkName, onchainProvider, arkProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, serverUnrollScript, forfeitOutputScript, forfeitPubkey, dustAmount, walletRepository, contractRepository,
|
|
662
|
+
/** @deprecated Use settlementConfig */
|
|
663
|
+
renewalConfig, delegatorProvider, watcherConfig, settlementConfig) {
|
|
650
664
|
super(identity, network, onchainProvider, indexerProvider, arkServerPublicKey, offchainTapscript, boardingTapscript, dustAmount, walletRepository, contractRepository, delegatorProvider, watcherConfig);
|
|
651
665
|
this.networkName = networkName;
|
|
652
666
|
this.arkProvider = arkProvider;
|
|
@@ -654,11 +668,31 @@ export class Wallet extends ReadonlyWallet {
|
|
|
654
668
|
this.forfeitOutputScript = forfeitOutputScript;
|
|
655
669
|
this.forfeitPubkey = forfeitPubkey;
|
|
656
670
|
this.identity = identity;
|
|
671
|
+
// Backwards-compatible: keep renewalConfig populated for any code reading it
|
|
657
672
|
this.renewalConfig = {
|
|
658
673
|
enabled: renewalConfig?.enabled ?? false,
|
|
659
674
|
...DEFAULT_RENEWAL_CONFIG,
|
|
660
675
|
...renewalConfig,
|
|
661
676
|
};
|
|
677
|
+
// Normalize: prefer settlementConfig, fall back to renewalConfig, default to enabled
|
|
678
|
+
if (settlementConfig !== undefined) {
|
|
679
|
+
this.settlementConfig = settlementConfig;
|
|
680
|
+
}
|
|
681
|
+
else if (renewalConfig && this.renewalConfig.enabled) {
|
|
682
|
+
this.settlementConfig = {
|
|
683
|
+
vtxoThreshold: renewalConfig.thresholdMs
|
|
684
|
+
? renewalConfig.thresholdMs / 1000
|
|
685
|
+
: undefined,
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
else if (renewalConfig) {
|
|
689
|
+
// renewalConfig provided but not enabled → disabled
|
|
690
|
+
this.settlementConfig = false;
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
// No config at all → enabled by default
|
|
694
|
+
this.settlementConfig = { ...DEFAULT_SETTLEMENT_CONFIG };
|
|
695
|
+
}
|
|
662
696
|
this._delegatorManager = delegatorProvider
|
|
663
697
|
? new DelegatorManagerImpl(delegatorProvider, arkProvider, identity)
|
|
664
698
|
: undefined;
|
|
@@ -667,6 +701,46 @@ export class Wallet extends ReadonlyWallet {
|
|
|
667
701
|
this._walletAssetManager ?? (this._walletAssetManager = new AssetManager(this));
|
|
668
702
|
return this._walletAssetManager;
|
|
669
703
|
}
|
|
704
|
+
async getVtxoManager() {
|
|
705
|
+
if (this._vtxoManager) {
|
|
706
|
+
return this._vtxoManager;
|
|
707
|
+
}
|
|
708
|
+
if (this._vtxoManagerInitializing) {
|
|
709
|
+
return this._vtxoManagerInitializing;
|
|
710
|
+
}
|
|
711
|
+
this._vtxoManagerInitializing = Promise.resolve(new VtxoManager(this, this.renewalConfig, this.settlementConfig));
|
|
712
|
+
try {
|
|
713
|
+
const manager = await this._vtxoManagerInitializing;
|
|
714
|
+
this._vtxoManager = manager;
|
|
715
|
+
return manager;
|
|
716
|
+
}
|
|
717
|
+
catch (error) {
|
|
718
|
+
this._vtxoManagerInitializing = undefined;
|
|
719
|
+
throw error;
|
|
720
|
+
}
|
|
721
|
+
finally {
|
|
722
|
+
this._vtxoManagerInitializing = undefined;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
async dispose() {
|
|
726
|
+
const manager = this._vtxoManager ??
|
|
727
|
+
(this._vtxoManagerInitializing
|
|
728
|
+
? await this._vtxoManagerInitializing.catch(() => undefined)
|
|
729
|
+
: undefined);
|
|
730
|
+
try {
|
|
731
|
+
if (manager) {
|
|
732
|
+
await manager.dispose();
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
catch {
|
|
736
|
+
// best-effort teardown; ensure super.dispose() still runs
|
|
737
|
+
}
|
|
738
|
+
finally {
|
|
739
|
+
this._vtxoManager = undefined;
|
|
740
|
+
this._vtxoManagerInitializing = undefined;
|
|
741
|
+
await super.dispose();
|
|
742
|
+
}
|
|
743
|
+
}
|
|
670
744
|
static async create(config) {
|
|
671
745
|
const pubkey = await config.identity.xOnlyPublicKey();
|
|
672
746
|
if (!pubkey) {
|
|
@@ -688,7 +762,9 @@ export class Wallet extends ReadonlyWallet {
|
|
|
688
762
|
const forfeitPubkey = hex.decode(setup.info.forfeitPubkey).slice(1);
|
|
689
763
|
const forfeitAddress = Address(setup.network).decode(setup.info.forfeitAddress);
|
|
690
764
|
const forfeitOutputScript = OutScript.encode(forfeitAddress);
|
|
691
|
-
|
|
765
|
+
const wallet = new Wallet(config.identity, setup.network, setup.networkName, setup.onchainProvider, setup.arkProvider, setup.indexerProvider, setup.serverPubKey, setup.offchainTapscript, setup.boardingTapscript, serverUnrollScript, forfeitOutputScript, forfeitPubkey, setup.dustAmount, setup.walletRepository, setup.contractRepository, config.renewalConfig, config.delegatorProvider, config.watcherConfig, config.settlementConfig);
|
|
766
|
+
await wallet.getVtxoManager();
|
|
767
|
+
return wallet;
|
|
692
768
|
}
|
|
693
769
|
/**
|
|
694
770
|
* Convert this wallet to a readonly wallet.
|
|
@@ -791,7 +867,13 @@ export class Wallet extends ReadonlyWallet {
|
|
|
791
867
|
let amount = 0;
|
|
792
868
|
const exitScript = CSVMultisigTapscript.decode(hex.decode(this.boardingTapscript.exitScript));
|
|
793
869
|
const boardingTimelock = exitScript.params.timelock;
|
|
794
|
-
|
|
870
|
+
// For block-based timelocks, fetch the chain tip height
|
|
871
|
+
let chainTipHeight;
|
|
872
|
+
if (boardingTimelock.type === "blocks") {
|
|
873
|
+
const tip = await this.onchainProvider.getChainTip();
|
|
874
|
+
chainTipHeight = tip.height;
|
|
875
|
+
}
|
|
876
|
+
const boardingUtxos = (await this.getBoardingUtxos()).filter((utxo) => !hasBoardingTxExpired(utxo, boardingTimelock, chainTipHeight));
|
|
795
877
|
const filteredBoardingUtxos = [];
|
|
796
878
|
for (const utxo of boardingUtxos) {
|
|
797
879
|
const inputFee = estimator.evalOnchainInput({
|
package/dist/types/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { TxTree, TxTreeNode } from "./tree/txTree";
|
|
|
16
16
|
import { SignerSession, TreeNonces, TreePartialSigs } from "./tree/signingSession";
|
|
17
17
|
import { Ramps } from "./wallet/ramps";
|
|
18
18
|
import { isVtxoExpiringSoon, VtxoManager } from "./wallet/vtxo-manager";
|
|
19
|
+
import type { SettlementConfig } from "./wallet/vtxo-manager";
|
|
19
20
|
import { ServiceWorkerWallet, ServiceWorkerReadonlyWallet } from "./wallet/serviceWorker/wallet";
|
|
20
21
|
import { OnchainWallet } from "./wallet/onchain";
|
|
21
22
|
import { setupServiceWorker } from "./worker/browser/utils";
|
|
@@ -48,4 +49,4 @@ import { IContractManager } from "./contracts/contractManager";
|
|
|
48
49
|
import { closeDatabase, openDatabase } from "./repositories/indexedDB/manager";
|
|
49
50
|
import { WalletMessageHandler } from "./wallet/serviceWorker/wallet-message-handler";
|
|
50
51
|
export { Wallet, ReadonlyWallet, SingleKey, ReadonlySingleKey, SeedIdentity, MnemonicIdentity, ReadonlyDescriptorIdentity, OnchainWallet, Ramps, VtxoManager, DelegatorManagerImpl, RestDelegatorProvider, ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, DelegateVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, MessageBus, WalletMessageHandler, ServiceWorkerWallet, ServiceWorkerReadonlyWallet, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, TapTreeCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, combineTapscriptSigs, isVtxoExpiringSoon, isValidArkAddress, ArkNote, networks, closeDatabase, openDatabase, IndexedDBWalletRepository, IndexedDBContractRepository, InMemoryWalletRepository, InMemoryContractRepository, MIGRATION_KEY, migrateWalletRepository, requiresMigration, getMigrationStatus, rollbackMigration, WalletRepositoryImpl, ContractRepositoryImpl, Intent, BIP322, TxTree, P2A, Unroll, Transaction, ArkError, maybeArkError, Batch, validateVtxoTxGraph, validateConnectorsTxGraph, buildForfeitTx, isRecoverable, isSpendable, isSubdust, isExpired, getSequence, ContractManager, ContractWatcher, contractHandlers, DefaultContractHandler, DelegateContractHandler, VHTLCContractHandler, encodeArkContract, decodeArkContract, contractFromArkContract, contractFromArkContractWithAddress, isArkContract, };
|
|
51
|
-
export type { Identity, ReadonlyIdentity, IWallet, IReadonlyWallet, BaseWalletConfig, WalletConfig, ReadonlyWalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, SeedIdentityOptions, MnemonicOptions, NetworkOptions, DescriptorOptions, IndexerProvider, PageResponse, BatchInfo, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, FeeInfo, 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, Asset, Recipient, IssuanceParams, IssuanceResult, ReissuanceParams, BurnParams, AssetDetails, AssetMetadata, KnownMetadata, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, StorageConfig, Contract, ContractVtxo, ContractState, ContractEvent, ContractEventCallback, ContractBalance, ContractWithVtxos, ContractHandler, IContractManager, PathSelection, PathContext, ContractManagerConfig, CreateContractParams, ContractWatcherConfig, ParsedArkContract, DefaultContractParams, DelegateContractParams, VHTLCContractParams, MessageHandler, RequestEnvelope, ResponseEnvelope, IDelegatorManager, DelegatorProvider, DelegateInfo, DelegateOptions, WalletRepository, ContractRepository, MigrationStatus, };
|
|
52
|
+
export type { Identity, ReadonlyIdentity, IWallet, IReadonlyWallet, BaseWalletConfig, WalletConfig, ReadonlyWalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, SeedIdentityOptions, MnemonicOptions, NetworkOptions, DescriptorOptions, IndexerProvider, PageResponse, BatchInfo, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, FeeInfo, 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, SettlementConfig, Asset, Recipient, IssuanceParams, IssuanceResult, ReissuanceParams, BurnParams, AssetDetails, AssetMetadata, KnownMetadata, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, StorageConfig, Contract, ContractVtxo, ContractState, ContractEvent, ContractEventCallback, ContractBalance, ContractWithVtxos, ContractHandler, IContractManager, PathSelection, PathContext, ContractManagerConfig, CreateContractParams, ContractWatcherConfig, ParsedArkContract, DefaultContractParams, DelegateContractParams, VHTLCContractParams, MessageHandler, RequestEnvelope, ResponseEnvelope, IDelegatorManager, DelegatorProvider, DelegateInfo, DelegateOptions, WalletRepository, ContractRepository, MigrationStatus, };
|
|
@@ -24,7 +24,7 @@ export type OffchainTx = {
|
|
|
24
24
|
* @returns Object containing the virtual transaction and checkpoint transactions
|
|
25
25
|
*/
|
|
26
26
|
export declare function buildOffchainTx(inputs: ArkTxInput[], outputs: TransactionOutput[], serverUnrollScript: CSVMultisigTapscript.Type): OffchainTx;
|
|
27
|
-
export declare function hasBoardingTxExpired(coin: ExtendedCoin, boardingTimelock: RelativeTimelock): boolean;
|
|
27
|
+
export declare function hasBoardingTxExpired(coin: ExtendedCoin, boardingTimelock: RelativeTimelock, chainTipHeight?: number): boolean;
|
|
28
28
|
/**
|
|
29
29
|
* Verify tapscript signatures on a transaction input
|
|
30
30
|
* @param tx Transaction to verify
|
|
@@ -3,7 +3,7 @@ import { ArkProvider, Output, SettlementEvent } from "../providers/ark";
|
|
|
3
3
|
import { Identity, ReadonlyIdentity } from "../identity";
|
|
4
4
|
import { RelativeTimelock } from "../script/tapscript";
|
|
5
5
|
import { EncodedVtxoScript, TapLeafScript } from "../script/base";
|
|
6
|
-
import { RenewalConfig } from "./vtxo-manager";
|
|
6
|
+
import { RenewalConfig, SettlementConfig } from "./vtxo-manager";
|
|
7
7
|
import { IndexerProvider } from "../providers/indexer";
|
|
8
8
|
import { OnchainProvider } from "../providers/onchain";
|
|
9
9
|
import { ContractWatcherConfig } from "../contracts/contractWatcher";
|
|
@@ -96,20 +96,26 @@ export interface ReadonlyWalletConfig extends BaseWalletConfig {
|
|
|
96
96
|
* onchainProvider: new EsploraProvider('https://mempool.space/api')
|
|
97
97
|
* });
|
|
98
98
|
*
|
|
99
|
-
* // With
|
|
99
|
+
* // With settlement configuration
|
|
100
100
|
* const wallet = await Wallet.create({
|
|
101
101
|
* identity: SingleKey.fromHex('...'),
|
|
102
102
|
* arkServerUrl: 'https://ark.example.com',
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* }
|
|
103
|
+
* settlementConfig: {
|
|
104
|
+
* vtxoThreshold: 86400, // 24 hours in seconds
|
|
105
|
+
* boardingUtxoSweep: true,
|
|
106
|
+
* },
|
|
107
107
|
* });
|
|
108
108
|
* ```
|
|
109
109
|
*/
|
|
110
110
|
export interface WalletConfig extends ReadonlyWalletConfig {
|
|
111
111
|
identity: Identity;
|
|
112
|
+
/** @deprecated Use settlementConfig instead */
|
|
112
113
|
renewalConfig?: RenewalConfig;
|
|
114
|
+
/**
|
|
115
|
+
* Configuration for automatic settlement and renewal.
|
|
116
|
+
* `false` = explicitly disabled, `undefined` = enabled by default, `{}` = enabled with defaults.
|
|
117
|
+
*/
|
|
118
|
+
settlementConfig?: SettlementConfig | false;
|
|
113
119
|
}
|
|
114
120
|
export type StorageConfig = {
|
|
115
121
|
walletRepository: WalletRepository;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { ExtendedVirtualCoin, IWallet } from ".";
|
|
1
|
+
import { ExtendedCoin, ExtendedVirtualCoin, IWallet } from ".";
|
|
2
2
|
import { SettlementEvent } from "../providers/ark";
|
|
3
3
|
export declare const DEFAULT_THRESHOLD_MS: number;
|
|
4
|
+
export declare const DEFAULT_THRESHOLD_SECONDS: number;
|
|
4
5
|
/**
|
|
5
6
|
* Configuration options for automatic VTXO renewal
|
|
7
|
+
* @deprecated Use SettlementConfig instead
|
|
6
8
|
*/
|
|
7
9
|
export interface RenewalConfig {
|
|
8
10
|
/**
|
|
@@ -14,13 +16,81 @@ export interface RenewalConfig {
|
|
|
14
16
|
* Threshold in milliseconds to use as threshold for renewal
|
|
15
17
|
* E.g., 86400000 means renew when 24 hours until expiry remains
|
|
16
18
|
* @default 86400000 (24 hours)
|
|
19
|
+
* @deprecated Use SettlementConfig.vtxoThreshold (in seconds) instead
|
|
17
20
|
*/
|
|
18
21
|
thresholdMs?: number;
|
|
19
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Configuration for automatic settlement and renewal.
|
|
25
|
+
*
|
|
26
|
+
* Controls two behaviors:
|
|
27
|
+
* 1. **VTXO renewal**: Automatically renew VTXOs that are close to expiry
|
|
28
|
+
* 2. **Boarding UTXO sweep**: Sweep expired boarding UTXOs back to a fresh boarding address
|
|
29
|
+
* via the unilateral exit path (on-chain self-spend to restart the timelock)
|
|
30
|
+
*
|
|
31
|
+
* Enabled by default when no config is provided.
|
|
32
|
+
* Pass `false` to explicitly disable all settlement behavior.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* // Default behavior: VTXO renewal at 3 days + boarding sweep enabled
|
|
37
|
+
* const wallet = await Wallet.create({
|
|
38
|
+
* identity: SingleKey.fromHex('...'),
|
|
39
|
+
* arkServerUrl: 'https://ark.example.com',
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* // Custom threshold
|
|
43
|
+
* const wallet = await Wallet.create({
|
|
44
|
+
* identity: SingleKey.fromHex('...'),
|
|
45
|
+
* arkServerUrl: 'https://ark.example.com',
|
|
46
|
+
* settlementConfig: {
|
|
47
|
+
* vtxoThreshold: 86400, // 24 hours in seconds
|
|
48
|
+
* },
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* // Explicitly disable
|
|
52
|
+
* const wallet = await Wallet.create({
|
|
53
|
+
* identity: SingleKey.fromHex('...'),
|
|
54
|
+
* arkServerUrl: 'https://ark.example.com',
|
|
55
|
+
* settlementConfig: false,
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export interface SettlementConfig {
|
|
60
|
+
/**
|
|
61
|
+
* Seconds before VTXO expiry to trigger renewal.
|
|
62
|
+
* @default 259200 (3 days)
|
|
63
|
+
*/
|
|
64
|
+
vtxoThreshold?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Sweep expired boarding UTXOs back to a fresh boarding address
|
|
67
|
+
* via the unilateral exit path (on-chain self-spend to restart the timelock).
|
|
68
|
+
*
|
|
69
|
+
* When enabled, expired boarding UTXOs are batched into a single on-chain transaction
|
|
70
|
+
* with multiple inputs and one output. A dust check ensures the sweep is only
|
|
71
|
+
* performed when the output after fees is above dust.
|
|
72
|
+
*
|
|
73
|
+
* @default true
|
|
74
|
+
*/
|
|
75
|
+
boardingUtxoSweep?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Polling interval in milliseconds for checking boarding UTXOs.
|
|
78
|
+
* The poll loop auto-settles new boarding UTXOs into Ark and
|
|
79
|
+
* sweeps expired ones (when boardingUtxoSweep is enabled).
|
|
80
|
+
*
|
|
81
|
+
* @default 60000 (1 minute)
|
|
82
|
+
*/
|
|
83
|
+
pollIntervalMs?: number;
|
|
84
|
+
}
|
|
20
85
|
/**
|
|
21
86
|
* Default renewal configuration values
|
|
87
|
+
* @deprecated Use DEFAULT_SETTLEMENT_CONFIG instead
|
|
22
88
|
*/
|
|
23
89
|
export declare const DEFAULT_RENEWAL_CONFIG: Required<Omit<RenewalConfig, "enabled">>;
|
|
90
|
+
/**
|
|
91
|
+
* Default settlement configuration values
|
|
92
|
+
*/
|
|
93
|
+
export declare const DEFAULT_SETTLEMENT_CONFIG: Required<SettlementConfig>;
|
|
24
94
|
/**
|
|
25
95
|
* Check if a VTXO is expiring soon based on threshold
|
|
26
96
|
*
|
|
@@ -75,10 +145,21 @@ export declare function getExpiringAndRecoverableVtxos(vtxos: ExtendedVirtualCoi
|
|
|
75
145
|
* }
|
|
76
146
|
* ```
|
|
77
147
|
*/
|
|
78
|
-
export declare class VtxoManager {
|
|
148
|
+
export declare class VtxoManager implements AsyncDisposable {
|
|
79
149
|
readonly wallet: IWallet;
|
|
150
|
+
/** @deprecated Use settlementConfig instead */
|
|
80
151
|
readonly renewalConfig?: RenewalConfig | undefined;
|
|
81
|
-
|
|
152
|
+
readonly settlementConfig: SettlementConfig | false;
|
|
153
|
+
private contractEventsSubscription?;
|
|
154
|
+
private readonly contractEventsSubscriptionReady;
|
|
155
|
+
private disposePromise?;
|
|
156
|
+
private pollIntervalId?;
|
|
157
|
+
private knownBoardingUtxos;
|
|
158
|
+
private sweptBoardingUtxos;
|
|
159
|
+
private pollInProgress;
|
|
160
|
+
constructor(wallet: IWallet,
|
|
161
|
+
/** @deprecated Use settlementConfig instead */
|
|
162
|
+
renewalConfig?: RenewalConfig | undefined, settlementConfig?: SettlementConfig | false);
|
|
82
163
|
/**
|
|
83
164
|
* Recover swept/expired VTXOs by settling them back to the wallet's Ark address.
|
|
84
165
|
*
|
|
@@ -177,4 +258,86 @@ export declare class VtxoManager {
|
|
|
177
258
|
* ```
|
|
178
259
|
*/
|
|
179
260
|
renewVtxos(eventCallback?: (event: SettlementEvent) => void): Promise<string>;
|
|
261
|
+
/**
|
|
262
|
+
* Get boarding UTXOs whose timelock has expired.
|
|
263
|
+
*
|
|
264
|
+
* These UTXOs can no longer be onboarded cooperatively via `settle()` and
|
|
265
|
+
* must be swept back to a fresh boarding address using the unilateral exit path.
|
|
266
|
+
*
|
|
267
|
+
* @returns Array of expired boarding UTXOs
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```typescript
|
|
271
|
+
* const manager = new VtxoManager(wallet);
|
|
272
|
+
* const expired = await manager.getExpiredBoardingUtxos();
|
|
273
|
+
* if (expired.length > 0) {
|
|
274
|
+
* console.log(`${expired.length} expired boarding UTXOs to sweep`);
|
|
275
|
+
* }
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
getExpiredBoardingUtxos(): Promise<ExtendedCoin[]>;
|
|
279
|
+
/**
|
|
280
|
+
* Sweep expired boarding UTXOs back to a fresh boarding address via
|
|
281
|
+
* the unilateral exit path (on-chain self-spend).
|
|
282
|
+
*
|
|
283
|
+
* This builds a raw on-chain transaction that:
|
|
284
|
+
* - Uses all expired boarding UTXOs as inputs (spent via the CSV exit script path)
|
|
285
|
+
* - Has a single output to the wallet's boarding address (restarts the timelock)
|
|
286
|
+
* - Batches multiple expired UTXOs into one transaction
|
|
287
|
+
* - Skips the sweep if the output after fees would be below dust
|
|
288
|
+
*
|
|
289
|
+
* No Ark server involvement is needed — this is a pure on-chain transaction.
|
|
290
|
+
*
|
|
291
|
+
* @returns The broadcast transaction ID
|
|
292
|
+
* @throws Error if no expired boarding UTXOs found
|
|
293
|
+
* @throws Error if output after fees is below dust (not economical to sweep)
|
|
294
|
+
* @throws Error if boarding UTXO sweep is not enabled in settlementConfig
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* const manager = new VtxoManager(wallet, undefined, {
|
|
299
|
+
* boardingUtxoSweep: true,
|
|
300
|
+
* });
|
|
301
|
+
*
|
|
302
|
+
* try {
|
|
303
|
+
* const txid = await manager.sweepExpiredBoardingUtxos();
|
|
304
|
+
* console.log('Swept expired boarding UTXOs:', txid);
|
|
305
|
+
* } catch (e) {
|
|
306
|
+
* console.log('No sweep needed or not economical');
|
|
307
|
+
* }
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
sweepExpiredBoardingUtxos(): Promise<string>;
|
|
311
|
+
/** Asserts sweep capability and returns the typed wallet. */
|
|
312
|
+
private getSweepWallet;
|
|
313
|
+
/** Decodes the boarding tapscript exit path to extract the CSV timelock. */
|
|
314
|
+
private getBoardingTimelock;
|
|
315
|
+
/** Returns the TapLeafScript for the boarding tapscript's exit (CSV) path. */
|
|
316
|
+
private getBoardingExitLeaf;
|
|
317
|
+
/** Returns the pkScript (output script) of the boarding tapscript. */
|
|
318
|
+
private getBoardingOutputScript;
|
|
319
|
+
/** Returns the on-chain provider for fee estimation and broadcasting. */
|
|
320
|
+
private getOnchainProvider;
|
|
321
|
+
/** Returns the Bitcoin network configuration from the wallet. */
|
|
322
|
+
private getNetwork;
|
|
323
|
+
/** Returns the wallet's identity for transaction signing. */
|
|
324
|
+
private getIdentity;
|
|
325
|
+
private initializeSubscription;
|
|
326
|
+
/**
|
|
327
|
+
* Starts a polling loop that:
|
|
328
|
+
* 1. Auto-settles new boarding UTXOs into Ark
|
|
329
|
+
* 2. Sweeps expired boarding UTXOs (when boardingUtxoSweep is enabled)
|
|
330
|
+
*/
|
|
331
|
+
private startBoardingUtxoPoll;
|
|
332
|
+
private pollBoardingUtxos;
|
|
333
|
+
/**
|
|
334
|
+
* Auto-settle new (unexpired) boarding UTXOs into the Ark.
|
|
335
|
+
* Skips UTXOs that are already expired (those are handled by sweep).
|
|
336
|
+
* Only settles UTXOs not already in-flight (tracked in knownBoardingUtxos).
|
|
337
|
+
* UTXOs are marked as known only after a successful settle, so failed
|
|
338
|
+
* attempts will be retried on the next poll.
|
|
339
|
+
*/
|
|
340
|
+
private settleBoardingUtxos;
|
|
341
|
+
dispose(): Promise<void>;
|
|
342
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
180
343
|
}
|
|
@@ -9,6 +9,7 @@ import { SignerSession } from "../tree/signingSession";
|
|
|
9
9
|
import { Identity, ReadonlyIdentity } from "../identity";
|
|
10
10
|
import { ArkTransaction, Recipient, Coin, ExtendedCoin, ExtendedVirtualCoin, GetVtxosFilter, IReadonlyWallet, IWallet, ReadonlyWalletConfig, SendBitcoinParams, SettleParams, WalletBalance, WalletConfig, IAssetManager, IReadonlyAssetManager } from ".";
|
|
11
11
|
import { CSVMultisigTapscript } from "../script/tapscript";
|
|
12
|
+
import { SettlementConfig, VtxoManager } from "./vtxo-manager";
|
|
12
13
|
import { Intent } from "../intent";
|
|
13
14
|
import { IndexerProvider } from "../providers/indexer";
|
|
14
15
|
import { WalletRepository } from "../repositories/walletRepository";
|
|
@@ -122,6 +123,8 @@ export declare class ReadonlyWallet implements IReadonlyWallet {
|
|
|
122
123
|
*/
|
|
123
124
|
getContractManager(): Promise<ContractManager>;
|
|
124
125
|
private initializeContractManager;
|
|
126
|
+
dispose(): Promise<void>;
|
|
127
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
125
128
|
}
|
|
126
129
|
/**
|
|
127
130
|
* Main wallet implementation for Bitcoin transactions with Ark protocol support.
|
|
@@ -165,13 +168,21 @@ export declare class Wallet extends ReadonlyWallet implements IWallet {
|
|
|
165
168
|
static MIN_FEE_RATE: number;
|
|
166
169
|
readonly identity: Identity;
|
|
167
170
|
private readonly _delegatorManager?;
|
|
171
|
+
private _vtxoManager?;
|
|
172
|
+
private _vtxoManagerInitializing?;
|
|
168
173
|
private _walletAssetManager?;
|
|
174
|
+
/** @deprecated Use settlementConfig instead */
|
|
169
175
|
readonly renewalConfig: Required<Omit<WalletConfig["renewalConfig"], "enabled">> & {
|
|
170
176
|
enabled: boolean;
|
|
171
177
|
thresholdMs: number;
|
|
172
178
|
};
|
|
173
|
-
|
|
179
|
+
readonly settlementConfig: SettlementConfig | false;
|
|
180
|
+
protected constructor(identity: Identity, network: Network, networkName: NetworkName, onchainProvider: OnchainProvider, arkProvider: ArkProvider, indexerProvider: IndexerProvider, arkServerPublicKey: Bytes, offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script, boardingTapscript: DefaultVtxo.Script, serverUnrollScript: CSVMultisigTapscript.Type, forfeitOutputScript: Bytes, forfeitPubkey: Bytes, dustAmount: bigint, walletRepository: WalletRepository, contractRepository: ContractRepository,
|
|
181
|
+
/** @deprecated Use settlementConfig */
|
|
182
|
+
renewalConfig?: WalletConfig["renewalConfig"], delegatorProvider?: DelegatorProvider, watcherConfig?: WalletConfig["watcherConfig"], settlementConfig?: WalletConfig["settlementConfig"]);
|
|
174
183
|
get assetManager(): IAssetManager;
|
|
184
|
+
getVtxoManager(): Promise<VtxoManager>;
|
|
185
|
+
dispose(): Promise<void>;
|
|
175
186
|
static create(config: WalletConfig): Promise<Wallet>;
|
|
176
187
|
/**
|
|
177
188
|
* Convert this wallet to a readonly wallet.
|