VTXO Management automates the renewal and recovery of virtual coins to prevent expiration and loss of funds. VtxoManager is also accessible from ServiceWorkerWallet via wallet.getVtxoManager().
Overview
VTXOs can be in different states and have an expiration time based on the batch expiry . The VtxoManager class provides automated management for:
Renewal : Renew VTXOs before they expire to maintain unilateral control of your funds
Recovery : Reclaim expired and swept VTXOs back to your wallet
Creating a VTXO Manager
import { MnemonicIdentity , VtxoManager , Wallet } from '@arkade-os/sdk'
const identity = MnemonicIdentity . fromMnemonic ( mnemonic )
const wallet = await Wallet . create ({
identity ,
arkServerUrl: 'https://arkade.computer' ,
settlementConfig: {
vtxoThreshold: 259200 , // 3 days, in seconds
boardingUtxoSweep: true ,
},
})
// Use the wallet's settlementConfig when constructing a manager manually
const manager = new VtxoManager ( wallet , undefined , wallet . settlementConfig )
// Or let the wallet create one lazily
const sameManager = await wallet . getVtxoManager ()
renewalConfig with enabled and thresholdMs is deprecated. Prefer settlementConfig on the wallet, where vtxoThreshold is expressed in seconds.
VTXO Renewal
Renew VTXOs before they expire to keep your liquidity available. This settles all VTXOs (including recoverable ones) back to your wallet with a fresh expiration time.
Checking Expiring VTXOs
// Check which VTXOs are expiring soon
const expiringVtxos = await manager . getExpiringVtxos ()
if ( expiringVtxos . length > 0 ) {
console . log ( ` ${ expiringVtxos . length } VTXOs expiring soon` )
expiringVtxos . forEach ( vtxo => {
const timeLeft = vtxo . virtualStatus . batchExpiry ! - Date . now ()
const hoursLeft = Math . floor ( timeLeft / ( 1000 * 60 * 60 ))
console . log ( `VTXO ${ vtxo . txid } expires in ${ hoursLeft } hours` )
})
}
timeLeft: remaining time until expiry (batchExpiry - current time) in milliseconds
hoursLeft: remaining time in hours, derived from timeLeft
Renewing VTXOs
// Renew all VTXOs to prevent expiration
const txid = await manager . renewVtxos ()
console . log ( 'Renewed:' , txid )
Set up automatic renewal checks in your application to ensure VTXOs never expire. A good practice is to check daily and renew when the threshold is reached.
VTXO Recovery
Recover VTXOs that have been swept by the server or consolidate small amounts (sub-dust).
Checking Recoverable Balance
// Check what's recoverable
const balance = await manager . getRecoverableBalance ()
console . log ( `Recoverable: ${ balance . recoverable } sats` )
console . log ( `Subdust: ${ balance . subdust } sats` )
console . log ( `Subdust included: ${ balance . includesSubdust } ` )
console . log ( `VTXO count: ${ balance . vtxoCount } ` )
Response shape:
type RecoverableBalance = {
recoverable : bigint // total recoverable amount in satoshis
subdust : bigint // sub-dust amount included
includesSubdust : boolean // whether subdust is part of recoverable
vtxoCount : number // number of recoverable VTXOs
}
Recovering VTXOs
if ( balance . recoverable > 0 n ) {
// Recover swept VTXOs and preconfirmed subdust
const txid = await manager . recoverVtxos (( event ) => {
console . log ( 'Settlement event:' , event . type )
})
console . log ( 'Recovered:' , txid )
}
Best Practices
Implement automatic renewal checks in your application: // Check for expiring VTXOs daily
setInterval ( async () => {
const expiring = await manager . getExpiringVtxos ()
if ( expiring . length > 0 ) {
await manager . renewVtxos ()
}
}, 24 * 60 * 60 * 1000 ) // Once per day
Periodically check for recoverable funds: // Check for recoverable VTXOs weekly
setInterval ( async () => {
const balance = await manager . getRecoverableBalance ()
if ( balance . recoverable > 0 n ) {
await manager . recoverVtxos ()
}
}, 7 * 24 * 60 * 60 * 1000 ) // Once per week
The threshold specifies how much time must remain before a VTXO is flagged for renewal. Adjust the threshold based on your needs:
3 days (default) : Good balance between proactive renewal and transaction costs
1 day : More aggressive, suitable for high-value or frequently active wallets
7 days : More relaxed, suitable for infrequently used wallets
Complete Example
Here’s a complete example of VTXO management:
import { Wallet , MnemonicIdentity , VtxoManager } from '@arkade-os/sdk'
import { LocalStorageAdapter } from '@arkade-os/sdk/adapters/localStorage'
// Setup wallet
const storage = new LocalStorageAdapter ()
const mnemonic = await storage . getItem ( 'mnemonic' )
const identity = MnemonicIdentity . fromMnemonic ( mnemonic )
const wallet = await Wallet . create ({
identity ,
arkServerUrl: 'https://arkade.computer' ,
storage
})
// Create VTXO manager
const manager = new VtxoManager ( wallet , undefined , {
vtxoThreshold: 259200 ,
boardingUtxoSweep: true ,
})
// Check and renew expiring VTXOs
const expiringVtxos = await manager . getExpiringVtxos ()
if ( expiringVtxos . length > 0 ) {
console . log ( `Renewing ${ expiringVtxos . length } expiring VTXOs...` )
const renewTxid = await manager . renewVtxos ()
console . log ( 'Renewal transaction:' , renewTxid )
}
// Check and recover swept VTXOs
const balance = await manager . getRecoverableBalance ()
if ( balance . recoverable > 0 n ) {
console . log ( `Recovering ${ balance . recoverable } sats...` )
const recoverTxid = await manager . recoverVtxos (( event ) => {
console . log ( 'Settlement event:' , event . type )
})
console . log ( 'Recovery transaction:' , recoverTxid )
}
Next Steps