Mesh LogoMesh
ResourcesChallenges

Coin Selection

Fix UTXO selection errors in Cardano transactions with Mesh SDK's automatic coin selection.

Coin selection determines which UTXOs fund your transaction. Poor selection causes failures, oversized transactions, and wallet fragmentation. Mesh handles this automatically.

The challenge

Why coin selection fails

CauseDescription
Value distribution100 ADA as one UTXO vs 100 small UTXOs requires different strategies
Token couplingNative tokens lock ADA - you can't access ADA without moving the tokens
Minimum valuesEvery UTXO needs ~1-2 ADA minimum
Size limitsToo many inputs exceed 16KB transaction limit

Common mistakes

MistakeProblem
Greedy selectionLargest first may not create valid change
Random selectionUnpredictable sizes and frequent failures
Ignoring tokensSelecting UTXOs with unwanted tokens
Poor change strategyCreates many small UTXOs (fragmentation)

Change output complexity

Change calculation is not simple subtraction:

  • Must include tokens from inputs not being sent
  • Must meet minimum UTXO value requirements
  • May need multiple outputs for different token bundles
  • Fee calculation creates circular dependency

The solution

Mesh's selectUtxosFrom() handles all coin selection complexity.

Quick start

npm install @meshsdk/core @meshsdk/react

Basic usage

import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
import { MeshCardanoBrowserWallet } from "@meshsdk/wallet";

const provider = new BlockfrostProvider("<your-api-key>");
const wallet = await MeshCardanoBrowserWallet.enable("eternl");

const txBuilder = new MeshTxBuilder({
  fetcher: provider,
  submitter: provider,
});

const unsignedTx = await txBuilder
  .txOut(recipientAddress, [{ unit: "lovelace", quantity: "10000000" }])
  .changeAddress(await wallet.getChangeAddressBech32())
  .selectUtxosFrom(await wallet.getUtxosMesh())
  .complete();

What selectUtxosFrom does

ActionBenefit
Minimizes transaction sizeFewer inputs = lower fees
Avoids token entanglementPrefers ADA-only UTXOs when possible
Satisfies minimumsEnsures value covers outputs, fees, and valid change
Retries intelligentlyAlternative strategies if initial selection fails

Common patterns

Send multiple tokens

const tx = await txBuilder
  .txOut(recipient, [
    { unit: "lovelace", quantity: "3000000" },
    { unit: policyId1 + assetName1, quantity: "50" },
    { unit: policyId2 + assetName2, quantity: "1" }
  ])
  .changeAddress(changeAddress)
  .selectUtxosFrom(utxos)
  .complete();

Consolidate fragmented wallet

const allUtxos = await wallet.getUtxos();
const totalLovelace = allUtxos.reduce((sum, utxo) =>
  sum + BigInt(utxo.output.amount.find(a => a.unit === "lovelace")?.quantity || 0),
  BigInt(0)
);

const tx = await txBuilder
  .txOut(changeAddress, [{
    unit: "lovelace",
    quantity: (totalLovelace - BigInt(500000)).toString()
  }])
  .changeAddress(changeAddress)
  .selectUtxosFrom(allUtxos)
  .complete();

Manual UTXO selection

When you need specific UTXOs:

const specificUtxo = utxos.find(u => /* your criteria */);

const tx = await txBuilder
  .txIn(specificUtxo.input.txHash, specificUtxo.input.outputIndex)
  .txOut(recipient, [{ unit: "lovelace", quantity: "5000000" }])
  .changeAddress(changeAddress)
  .complete();

Handle selection failures

async function buildTransaction(amount: string) {
  try {
    const utxos = await wallet.getUtxos();
    return await txBuilder
      .txOut(recipient, [{ unit: "lovelace", quantity: amount }])
      .changeAddress(await wallet.getChangeAddress())
      .selectUtxosFrom(utxos)
      .complete();
  } catch (error) {
    if (error.message.includes("Insufficient")) {
      throw new Error("Unable to build transaction. Try a smaller amount.");
    }
    throw error;
  }
}

Prevent problems

Avoid fragmentation

  • Consolidate small UTXOs during low-fee periods
  • Avoid transactions with many small outputs
  • Use Mesh's automatic selection for efficient change

Best practices

PracticeReason
Fetch fresh UTXOsAvoid stale data
Handle errors gracefullyProvide clear user feedback
Test with various wallet statesEdge cases matter
Monitor wallet healthWatch for fragmentation

On this page