Skip to main content

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

  1. Lock UTxOs during transaction building to prevent double-spending
  2. Use optimal strategy for most cases - it balances input count and change
  3. Consolidate dust UTxOs periodically to reduce wallet fragmentation
  4. Refresh UTxO set after transactions are confirmed
  5. Handle selection failures gracefully with user feedback