Mesh LogoMesh
ResourcesSolutions

Transaction Builder

Build Cardano transactions with automatic UTXO selection, fee calculation, and change handling using Mesh SDK.

MeshTxBuilder simplifies Cardano transaction construction. Specify outputs, and Mesh handles UTXO selection, fee calculation, and change management automatically.

Quick start

npm install @meshsdk/core @meshsdk/react

Basic transaction

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: "5000000" }])
  .changeAddress(await wallet.getChangeAddressBech32())
  .selectUtxosFrom(await wallet.getUtxosMesh())
  .complete();

const signedTx = await wallet.signTx(unsignedTx, false);
const txHash = await wallet.submitTx(signedTx);

Features

FeatureDescription
Automatic UTXO selectionOptimal input selection based on outputs
Fee calculationPrecise fee using protocol parameters
Change handlingAutomatic change output with correct address
Native token supportSend tokens with automatic minimum ADA
MetadataAttach transaction metadata
Smart contractsInteract with Plutus scripts
Multi-signatureCreate transactions requiring multiple signers
Validity intervalsSet transaction validity windows

Common patterns

Send ADA

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

Send native tokens

const tx = await txBuilder
  .txOut(recipientAddress, [
    { unit: policyId + assetName, quantity: "1" },
    { unit: "lovelace", quantity: "2000000" }
  ])
  .changeAddress(changeAddress)
  .selectUtxosFrom(utxos)
  .complete();

Send to multiple recipients

const tx = await txBuilder
  .txOut(address1, [{ unit: "lovelace", quantity: "5000000" }])
  .txOut(address2, [{ unit: "lovelace", quantity: "3000000" }])
  .txOut(address3, [{ unit: "lovelace", quantity: "7000000" }])
  .changeAddress(changeAddress)
  .selectUtxosFrom(utxos)
  .complete();

Add metadata

const tx = await txBuilder
  .txOut(recipientAddress, [{ unit: "lovelace", quantity: "5000000" }])
  .metadataValue("674", { msg: ["Transaction message"] })
  .changeAddress(changeAddress)
  .selectUtxosFrom(utxos)
  .complete();

Mint tokens

const tx = await txBuilder
  .mint("1", policyId, tokenName)
  .mintingScript(mintingScript)
  .mintRedeemerValue(redeemer)
  .txOut(recipientAddress, [
    { unit: policyId + tokenName, quantity: "1" },
    { unit: "lovelace", quantity: "2000000" }
  ])
  .changeAddress(changeAddress)
  .selectUtxosFrom(utxos)
  .complete();

Interact with smart contracts

const tx = await txBuilder
  .spendingPlutusScriptV2()
  .txIn(scriptUtxo.input.txHash, scriptUtxo.input.outputIndex)
  .txInInlineDatumPresent()
  .txInRedeemerValue(redeemer)
  .txInScript(script)
  .txOut(recipientAddress, scriptUtxo.output.amount)
  .txOutInlineDatumValue(newDatum)
  .requiredSignerHash(signerPkh)
  .changeAddress(changeAddress)
  .txInCollateral(collateralUtxo.input.txHash, collateralUtxo.input.outputIndex)
  .selectUtxosFrom(utxos)
  .complete();

Advanced patterns

Manual UTXO selection

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

Validity intervals

const slot = await provider.resolveSlotNo("now");

const tx = await txBuilder
  .txOut(recipientAddress, [{ unit: "lovelace", quantity: "5000000" }])
  .invalidBefore(slot)
  .invalidHereafter(slot + 600) // Valid for ~10 minutes
  .changeAddress(changeAddress)
  .selectUtxosFrom(utxos)
  .complete();

Required signers

const tx = await txBuilder
  .txOut(recipientAddress, [{ unit: "lovelace", quantity: "5000000" }])
  .requiredSignerHash(additionalSignerPkh)
  .changeAddress(changeAddress)
  .selectUtxosFrom(utxos)
  .complete();

Error handling

try {
  const tx = await txBuilder
    .txOut(recipientAddress, amount)
    .changeAddress(changeAddress)
    .selectUtxosFrom(utxos)
    .complete();

  const signedTx = await wallet.signTx(tx);
  const txHash = await wallet.submitTx(signedTx);
  console.log("Transaction submitted:", txHash);
} catch (error) {
  if (error.message.includes("Insufficient")) {
    showError("Not enough ADA to complete this transaction");
  } else if (error.message.includes("User")) {
    showInfo("Transaction cancelled");
  } else {
    showError("Transaction failed. Please try again.");
  }
}

Integration with React

import { useWallet } from "@meshsdk/react";
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";

function SendButton({ recipient, amount }) {
  const { wallet } = useWallet();
  const provider = new BlockfrostProvider("<api-key>");

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

    const tx = await txBuilder
      .txOut(recipient, [{ unit: "lovelace", quantity: amount }])
      .changeAddress(await wallet.getChangeAddress())
      .selectUtxosFrom(await wallet.getUtxos())
      .complete();

    const signedTx = await wallet.signTx(tx);
    const txHash = await wallet.submitTx(signedTx);
    return txHash;
  }

  return <button onClick={handleSend}>Send {Number(amount) / 1_000_000} ADA</button>;
}

Why MeshTxBuilder

BenefitDetails
Eliminates UTXO complexityDescribe what to send, not how
Prevents common errorsValidates before submission
Simplifies smart contractsHigh-level APIs for scripts
Protocol-awareStays current with updates

On this page