Skip to main content
Version: Next

Transaction building

TxBuilder builds Cardano transactions by collecting inputs, outputs, script data, metadata, and protocol parameters before producing a complete transaction.

Most applications use it through Blaze:

const tx = await blaze
.newTransaction()
.payLovelace(receiverAddress, 5_000_000n)
.complete();

You can also construct TxBuilder directly if you already have protocol parameters and want to manage wallet, provider, and signing code yourself.

Paying ada and assets​

Use payLovelace for ada payments and payAssets when the output contains a full Value.

import { makeValue } from "@blaze-cardano/tx";

const assetId = policyId + assetName;

const tx = await blaze
.newTransaction()
.payLovelace(receiverAddress, 5_000_000n)
.payAssets(receiverAddress, makeValue(2_000_000n, [assetId, 1n]))
.complete();

The builder checks that payment outputs use a payment address. If the transaction needs change, Blaze.newTransaction() sets the change address from the wallet before completion.

Attaching metadata​

Use setMetadata to attach transaction metadata. The builder stores it in auxiliary data and updates the auxiliary data hash on the transaction body.

import { Core } from "@blaze-cardano/sdk";

const labels = new Map([[674n, Core.Metadatum.newText("order:1234")]]);

const tx = await blaze
.newTransaction()
.payLovelace(receiverAddress, 5_000_000n)
.setMetadata(new Core.Metadata(labels))
.complete();

Use metadata for data that belongs to the transaction as a whole. Use datums for data that belongs to a script output.

Locking assets at scripts​

Use lockLovelace or lockAssets when an output belongs to a script address. A script lock needs a datum. The datum can be inline PlutusData or a datum hash, depending on how the script expects to read it.

import { Core, makeValue } from "@blaze-cardano/sdk";

const datum = Core.PlutusData.newInteger(42n);

const tx = await blaze
.newTransaction()
.lockAssets(scriptAddress, makeValue(2_000_000n), datum)
.complete();

lockLovelace is a convenience method for ada-only script outputs:

const tx = await blaze
.newTransaction()
.lockLovelace(scriptAddress, 2_000_000n, datum)
.complete();

If the output should carry a reference script, pass the script as the final argument.

const tx = await blaze
.newTransaction()
.lockAssets(scriptAddress, makeValue(2_000_000n), datum, validatorScript)
.complete();

Spending script UTxOs​

Use addInput to spend a UTxO. For a script UTxO, pass the redeemer as the second argument.

const tx = await blaze
.newTransaction()
.addInput(scriptUtxo, redeemer)
.provideScript(validatorScript)
.payLovelace(receiverAddress, 1_500_000n)
.complete();

If the UTxO has an inline datum, the builder reads it from the output. If the UTxO only has a datum hash, pass the unhashed datum as the third argument.

const tx = await blaze
.newTransaction()
.addInput(scriptUtxo, redeemer, datum)
.provideScript(validatorScript)
.payLovelace(receiverAddress, 1_500_000n)
.complete();

The datum is attached to the locked output. The redeemer is used later when spending that output.

Providing scripts and datums​

Use provideScript when the transaction must carry the script witness itself. You usually need this when the script is not available through a reference script.

const tx = await blaze
.newTransaction()
.addInput(scriptUtxo, redeemer)
.provideScript(validatorScript)
.complete();

Use provideDatum for extra Plutus data that the transaction needs as witness data but does not attach directly to an output.

const tx = await blaze
.newTransaction()
.provideDatum(extraDatum)
.addInput(scriptUtxo, redeemer)
.provideScript(validatorScript)
.complete();

Deploying reference scripts​

Use deployScript to create an output that carries a script reference. Pass an address when your application needs to keep control of that output.

const tx = await blaze
.newTransaction()
.deployScript(validatorScript, ownerAddress)
.complete();

If you do not pass an address, the builder locks the reference script at a burn address. This is useful in testing when your application wants to guarantee the ref-script utxo won't be spent by accident.

const tx = await blaze
.newTransaction()
.deployScript(validatorScript)
.complete();

Later transactions can spend script UTxOs by referencing these UTxOs instead of attaching the full script again.

Completing and submitting​

complete() selects inputs, calculates fees, evaluates scripts when an evaluator is configured, adds collateral when needed, and returns a transaction.

const tx = await blaze
.newTransaction()
.payLovelace(receiverAddress, 5_000_000n)
.complete();

Sign the completed transaction, then submit it through Blaze.

const signed = await blaze.signTransaction(tx);
const txId = await blaze.submitTransaction(signed);

submitTransaction(tx) uses the wallet submission path. Pass true as the second argument to submit through the configured provider instead.

const txId = await blaze.submitTransaction(signed, true);

For tests, the emulator provider accepts the same completed and signed transaction through postTransactionToChain.