UTxO Manager
The UTxO Manager provides smart coin selection and UTxO management capabilities.
Overview
Cardano uses the UTxO (Unspent Transaction Output) model. The UTxO Manager helps you:
- Select optimal UTxOs for transactions
- Track and manage your UTxO set
- Prevent double-spending with locking
- Find consolidation candidates
- Analyze UTxO statistics
Installation
import {
createUTxOManager,
selectCoins,
formatUTxOStats,
estimateInputCount,
UTxOManager,
} from 'cardano-devkit';
Creating a UTxO Manager
// From wallet UTxOs
const utxos = await lucid.wallet().getUtxos();
const manager = createUTxOManager(utxos);
// Empty manager
const emptyManager = createUTxOManager();
Coin Selection
Basic Selection
// Select UTxOs for 10 ADA
const result = manager.select(10_000_000n);
if (result.success) {
console.log("Selected UTxOs:", result.selected);
console.log("Total value:", result.totalValue);
console.log("Change:", result.change);
console.log("Input count:", result.inputCount);
} else {
console.log("Selection failed:", result.error);
}
Selection Strategies
// Largest-first: Minimizes input count
const largestFirst = manager.select(10_000_000n, {
strategy: "largest-first",
});
// Smallest-first: Uses up dust UTxOs
const smallestFirst = manager.select(10_000_000n, {
strategy: "smallest-first",
});
// Optimal: Balances input count and change
const optimal = manager.select(10_000_000n, {
strategy: "optimal",
});
Selection Options
const result = manager.select(10_000_000n, {
strategy: "optimal", // Selection strategy
minChange: 1_000_000n, // Minimum change to return
maxInputs: 20, // Maximum number of inputs
exclude: new Set(["hash#0"]), // UTxOs to exclude
requiredAssets: { // Required native assets
[policyId + assetName]: 100n,
},
});
Selecting Specific Assets
// Select UTxOs containing a specific token
const result = manager.selectAsset(
policyId,
assetName,
100n, // Required amount
{ maxInputs: 5 }
);
UTxO Filtering
By Asset
// Find UTxOs with any token from a policy
const policyUtxos = manager.findByAsset(policyId);
// Find UTxOs with a specific token
const tokenUtxos = manager.findByAsset(policyId, assetName);
Pure ADA UTxOs
// Find UTxOs with only ADA (no native assets)
const pureAdaUtxos = manager.findPureAda();
With Datum
// Find UTxOs with datum (script outputs)
const datumUtxos = manager.findWithDatum();
Custom Filter
// Custom filter function
const largeUtxos = manager.filter(
(utxo) => (utxo.assets?.lovelace ?? 0n) > 100_000_000n
);
UTxO Locking
Prevent UTxOs from being selected (useful for pending transactions):
// Lock specific UTxOs
manager.lock([utxo1, utxo2]);
// Check available vs total
console.log("Total:", manager.getAll().length);
console.log("Available:", manager.getAvailable().length);
console.log("Locked:", manager.getLocked().length);
// Unlock specific UTxOs
manager.unlock([utxo1]);
// Unlock all
manager.unlockAll();
Balance Queries
// Total balance (all UTxOs)
const total = manager.getTotalBalance();
// Available balance (excluding locked)
const available = manager.getAvailableBalance();
Statistics
const stats = manager.getStats();
console.log("Total UTxOs:", stats.total);
console.log("Available:", stats.available);
console.log("Locked:", stats.locked);
console.log("Pure ADA:", stats.pureAda);
console.log("With Assets:", stats.withAssets);
console.log("Total Lovelace:", stats.totalLovelace);
console.log("Available Lovelace:", stats.availableLovelace);
console.log("Average:", stats.averageLovelace);
console.log("Median:", stats.medianLovelace);
console.log("Smallest:", stats.smallestLovelace);
console.log("Largest:", stats.largestLovelace);
// Format for display
console.log(formatUTxOStats(stats));
Consolidation
Find small UTxOs that should be consolidated:
// Find UTxOs smaller than 5 ADA
const dustUtxos = manager.findConsolidationCandidates(5_000_000n);
console.log(`Found ${dustUtxos.length} dust UTxOs to consolidate`);
Updating the UTxO Set
// Replace all UTxOs
manager.setUtxos(newUtxos);
// Add new UTxOs
manager.addUtxos([newUtxo1, newUtxo2]);
// Remove spent UTxOs
manager.removeUtxos([spentUtxo1, spentUtxo2]);
Standalone Coin Selection
For quick one-off selection without creating a manager:
import { selectCoins } from 'cardano-devkit';
const result = selectCoins(utxos, 10_000_000n, {
strategy: "largest-first",
});
Estimating Input Count
Estimate how many inputs are needed for a target amount:
import { estimateInputCount } from 'cardano-devkit';
const count = estimateInputCount(utxos, 100_000_000n);
console.log(`Approximately ${count} inputs needed`);
Types
SelectionResult
interface SelectionResult {
selected: UTxO[];
totalValue: bigint;
change: bigint;
success: boolean;
error?: string;
inputCount: number;
}
SelectionOptions
interface SelectionOptions {
strategy?: "largest-first" | "smallest-first" | "optimal";
minChange?: bigint;
maxInputs?: number;
exclude?: Set<string>;
requiredAssets?: Record<string, bigint>;
}
UTxOStats
interface UTxOStats {
total: number;
available: number;
locked: number;
pureAda: number;
withAssets: number;
totalLovelace: bigint;
availableLovelace: bigint;
averageLovelace: bigint;
medianLovelace: bigint;
smallestLovelace: bigint;
largestLovelace: bigint;
}
CLI Usage
# Analyze UTxOs from a JSON file
cardano-devkit utxo analyze utxos.json
# Select UTxOs for a target amount
cardano-devkit utxo select utxos.json 10000000 --strategy optimal
# Output as JSON
cardano-devkit utxo analyze utxos.json --json
Best Practices
- Lock UTxOs during transaction building to prevent double-spending
- Use optimal strategy for most cases - it balances input count and change
- Consolidate dust UTxOs periodically to reduce wallet fragmentation
- Refresh UTxO set after transactions are confirmed
- Handle selection failures gracefully with user feedback