@hydra-sdk/transaction
Classes
TxBuilder
Main class for building and managing Cardano transactions with comprehensive support for all Cardano features.
TxBuilder.constructor(options?: TxBuilderOptions) → TxBuilder
Initializes a new transaction builder.
Parameters:
options?(TxBuilderOptions): Configuration optionsfetcher?: Custom fetchersubmitter?: Custom submitterevaluator?(IEvaluator): Optional script evaluator. When supplied and the transaction has Plutus redeemers,complete()runs a second build pass to write realexUnitsback into the redeemers so the fee is accurate.txEvaluationMultiplier?(number): Safety multiplier applied to evaluated exUnits before writing them back (e.g.1.1to over-provision by 10%). Default:1.isHydra?: Allows creating transactions for Hydra Headparams?: Custom protocol parametersverbose?: Enable verbose modeerrorLogger?: Strict/testing mode — throws instead of continuing when tx building hits an issue (default: false; not recommended for production)
Example:
import { TxBuilder } from '@hydra-sdk/transaction'
// Create a basic builder
const txBuilder = new TxBuilder()
// With custom protocol parameters
const txBuilder = new TxBuilder({
params: {
minFeeA: 44,
minFeeB: 155381,
maxTxSize: 16384
}
})
// For Hydra transactions
const txBuilder = new TxBuilder({
isHydra: true,
params: protocolParams,
verbose: true
})
Returns: TxBuilder
A new TxBuilder instance
TxBuilder.setInputs(utxos: UTxO[], options?: { strategy: CoinSelectionStrategy }) → TxBuilder
Provide the UTxOs the builder may spend and choose the coin-selection strategy. The builder selects which of these UTxOs to consume when it completes the transaction. This is the public entry point for coin selection.
Parameters:
utxos(UTxO): List of available UTxOsoptions?({ strategy: CoinSelectionStrategy }): Coin-selection options. Default:{ strategy: 'LargestFirstMultiAsset' }LargestFirst: Select largest coins firstRandomImprove: Random selection with improvementLargestFirstMultiAsset: Multi-asset friendly (default)RandomImproveMultiAsset: Multi-asset friendly random
Example:
const utxos = await wallet.queryUtxos()
// Default strategy (LargestFirstMultiAsset)
const tx1 = await txBuilder.setInputs(utxos).complete()
// Specific strategy
const tx2 = await txBuilder.setInputs(utxos, { strategy: 'RandomImprove' }).complete()
// Restrict selection to specific UTxOs
const specificUtxos = utxos.filter(utxo =>
utxo.output.amount.some(asset => asset.unit !== 'lovelace')
)
const tx3 = await txBuilder.setInputs(specificUtxos).complete()
Returns: TxBuilder
Returns the builder for method chaining
TxBuilder.txIn(txHash: string, outputIndex: number, amount?: Asset[], address?: string) → TxBuilder
Add a transaction input.
Parameters:
txHash(string): Transaction hashoutputIndex(number): Output indexamount?(Asset): Asset amounts (optional)address?(string): Address (optional)
Example:
txBuilder.txIn(
'a1b2c3d4e5f6...',
0,
[{ unit: 'lovelace', quantity: '2000000' }],
'addr_test1...'
)
Returns: TxBuilder
TxBuilder.txOut(address: string, amount: Asset[]) → TxBuilder
Add a transaction output.
Parameters:
address(string): Recipient addressamount(Asset): List of assets
Example:
// ADA only
txBuilder.txOut('addr_test1...', [
{ unit: 'lovelace', quantity: '2000000' }
])
// Multi-asset
txBuilder.txOut('addr_test1...', [
{ unit: 'lovelace', quantity: '2000000' },
{ unit: 'policyId.assetName', quantity: '100' }
])
Returns: TxBuilder
TxBuilder.changeAddress(address: string) → TxBuilder
Set the change address.
Parameters:
address(string): Change address
Example:
const account = wallet.getAccount(0, 0)
txBuilder.changeAddress(account.baseAddressBech32)
Returns: TxBuilder
Convenience aliases — addOutput, setChangeAddress, …
Object-form aliases used throughout the guides. They are thin wrappers over txOut / changeAddress (identical behaviour) — pick whichever style you prefer.
| Alias | Equivalent to |
|---|---|
addOutput({ address, amount }) | txOut(address, amount) |
addOutputs(outputs: TxOutput[]) | one txOut per output |
addLovelaceOutput(address, lovelace) | txOut(address, [{ unit: 'lovelace', quantity: lovelace }]) |
setChangeAddress(address) | changeAddress(address) |
// These two builders produce the same transaction:
txBuilder.addOutput({ address, amount: [{ unit: 'lovelace', quantity: '2000000' }] }).setChangeAddress(addr)
txBuilder.txOut(address, [{ unit: 'lovelace', quantity: '2000000' }]).changeAddress(addr)
TxOutput is { address: string; amount: Asset[] }.
TxBuilder.mint(quantity: string, policyId: string, assetName: string) → TxBuilder
Mint or burn assets.
Parameters:
quantity(string): Quantity (negative to burn)policyId(string): Policy IDassetName(string): Asset name
Example:
// Mint tokens
txBuilder.mint('1000', policyId, 'TokenName')
// Burn tokens
txBuilder.mint('-500', policyId, 'TokenName')
Returns: TxBuilder
TxBuilder.mintingScript(policy: PolicyScript) → TxBuilder
Attach the minting policy for the assets added with mint(). Required whenever you mint or burn.
Parameters:
policy(PolicyScript):{ type: 'Native' | 'PlutusV1' | 'PlutusV2' | 'PlutusV3'; scriptCborHex: string }
Example:
txBuilder
.mint('1000000', policyId, assetNameHex)
.mintingScript({ type: 'Native', scriptCborHex })
Returns: TxBuilder
TxBuilder.mintRedeemerValue(redeemer: Redeemer) → TxBuilder
Attach a redeemer to a Plutus minting policy (for PlutusV1/V2/V3 mints). Build the redeemer with buildRedeemer / RedeemerUtils.mkMintRedeemer.
Returns: TxBuilder
TxBuilder.txInScript(scriptCbor: string, version?: LanguageVersion) → TxBuilder
Attach a Plutus script to the last input.
Parameters:
scriptCbor(string): Script in CBOR hex formatversion?(LanguageVersion): Plutus language version —'V1' | 'V2' | 'V3'. Default:'V3'.
Example:
txBuilder.txIn(txHash, outputIndex)
.txInScript(scriptCbor) // defaults to Plutus V3
.txInScript(scriptCbor, 'V2') // or pin the version explicitly
Returns: TxBuilder
TxBuilder.txInDatumHash(datum: PlutusData) → TxBuilder
Add a datum hash for script input.
Parameters:
datum(PlutusData): Plutus data
Example:
const datum = CardanoWASM.PlutusData.from_hex('d87980')
txBuilder.txIn(txHash, outputIndex)
.txInDatumHash(datum)
Returns: TxBuilder
TxBuilder.txInInlineDatum(inlineDatum: PlutusData) → TxBuilder
Add an inline datum for script input.
Parameters:
inlineDatum(PlutusData): Plutus data
Example:
const inlineDatum = CardanoWASM.PlutusData.from_hex('d87980')
txBuilder.txIn(txHash, outputIndex)
.txInInlineDatum(inlineDatum)
Returns: TxBuilder
TxBuilder.txInEmptyRedeemer() → TxBuilder
Add an empty redeemer for script input.
Example:
txBuilder.txIn(txHash, outputIndex)
.txInScript(scriptCbor)
.txInEmptyRedeemer()
Returns: TxBuilder
TxBuilder.txInRedeemerValue(redeemer: Redeemer) → TxBuilder
Attach a redeemer to the last script input (the spend redeemer). Build it with buildRedeemer (below) or RedeemerUtils.mkRedeemer / mkSpendRedeemer from @hydra-sdk/core. Use this instead of txInEmptyRedeemer() when the script needs real redeemer data.
Parameters:
redeemer(Redeemer): The redeemer to attach
Example:
import { buildRedeemer } from '@hydra-sdk/transaction'
const redeemer = buildRedeemer({ action: 'claim' }, { tag: 'SPEND', index: 0 })
txBuilder.txIn(scriptHash, scriptIdx)
.txInScript(scriptCbor)
.txInRedeemerValue(redeemer)
Returns: TxBuilder
TxBuilder.txOutInlineDatumValue(inlineDatum: PlutusData) → TxBuilder
Add an inline datum for the last output.
Parameters:
inlineDatum(PlutusData): Plutus data
Example:
const datum = CardanoWASM.PlutusData.from_hex('d87980')
txBuilder.txOut('addr_test1...', amount)
.txOutInlineDatumValue(datum)
Returns: TxBuilder
TxBuilder.registerStake(rewardAddress: string) → TxBuilder
Register a stake address.
Parameters:
rewardAddress(string): Stake reward address
Example:
txBuilder.registerStake('stake_test1...')
set_certs). In earlier versions it was silently dropped at build time. An invalid reward address now throws.Returns: TxBuilder
TxBuilder.deregisterStake(rewardAddress: string) → TxBuilder
Deregister (retire) a stake address, reclaiming its key deposit.
Parameters:
rewardAddress(string): Stake reward address
Example:
txBuilder.deregisterStake('stake_test1...')
Returns: TxBuilder
TxBuilder.delegateStake(rewardAddress: string, poolKeyHash: string) → TxBuilder
Delegate stake to a pool.
Parameters:
rewardAddress(string): Stake reward addresspoolKeyHash(string): Pool key hash
Example:
txBuilder.delegateStake('stake_test1...', 'pool1...')
registerStake / deregisterStake, the delegation certificate is applied to the transaction body since v1.2.0. PoolRegistration / PoolRetirement are not supported yet and throw a clear error.Returns: TxBuilder
TxBuilder.withdrawal(rewardAddress: string, amount: string) → TxBuilder
Withdraw rewards from a stake address.
Parameters:
rewardAddress(string): Stake reward addressamount(string): Amount in lovelace
Example:
txBuilder.withdrawal('stake_test1...', '5000000')
Returns: TxBuilder
TxBuilder.txInCollateral(txHash: string, outputIndex: number, amount: Asset[], address: string) → TxBuilder
Add a collateral input.
Parameters:
txHash(string): Transaction hashoutputIndex(number): Output indexamount(Asset): Asset amountsaddress(string): Address
Example:
txBuilder.txInCollateral(
collateralTxHash,
0,
[{ unit: 'lovelace', quantity: '5000000' }],
'addr_test1...'
)
Returns: TxBuilder
TxBuilder.totalCollateral(amount: string) → TxBuilder
Set the total collateral amount.
Parameters:
amount(string): Amount in lovelace
Example:
txBuilder.totalCollateral('5000000')
set_total_collateral. In earlier versions it was stored but never applied to the built transaction.Returns: TxBuilder
TxBuilder.metadataValue(label: string, metadata: any) → TxBuilder
Add metadata to the transaction.
Parameters:
label(string): Metadata labelmetadata(any): Metadata content
Example:
// NFT metadata (CIP-25)
txBuilder.metadataValue('721', {
[policyId]: {
[assetName]: {
name: 'My NFT',
image: 'ipfs://...',
description: 'A unique NFT'
}
}
})
// Text metadata
txBuilder.metadataValue('674', {
msg: ['Hello', 'World']
})
Returns: TxBuilder
TxBuilder.invalidBefore(slot: number) → TxBuilder
Set the transaction validity start time.
Parameters:
slot(number): Slot number
Example:
txBuilder.invalidBefore(1000000)
Returns: TxBuilder
TxBuilder.invalidAfter(slot: number) → TxBuilder
Set the transaction validity end time.
Parameters:
slot(number): Slot number
Example:
txBuilder.invalidAfter(2000000)
Returns: TxBuilder
TxBuilder.complete() → Promise<Transaction>
Build and complete the transaction.
Example:
const tx = await txBuilder
.setInputs(utxos)
.txOut('addr_test1...', [{ unit: 'lovelace', quantity: '2000000' }])
.changeAddress(changeAddress)
.complete()
console.log('Transaction CBOR:', tx.to_hex())
complete() returns a live WASM Transaction object. When you only need the serialized bytes, prefer , which frees the object for you. Otherwise call tx.free() once you are done with it — WASM objects are not reclaimed promptly by the JS garbage collector, so failing to free them leaks memory under high volume. See Performance.If an evaluator was supplied to the constructor and the transaction contains Plutus redeemers, complete() runs a second build pass to write real exUnits into the redeemers before returning (see ).
Returns: Promise<Transaction>
Completed transaction (caller-owned; call .free() or use completeCbor())
TxBuilder.completeCbor() → Promise<string>
Build the transaction and return its CBOR hex, freeing the intermediate Transaction immediately. This is the leak-free path for high-volume workloads where you only need the serialized bytes — prefer it over complete() + .to_hex().
Example:
const cbor = await new TxBuilder()
.setInputs(utxos)
.txOut('addr_test1...', [{ unit: 'lovelace', quantity: '2000000' }])
.changeAddress(changeAddress)
.completeCbor()
const signedTx = await wallet.signTx(cbor)
Returns: Promise<string>
Transaction CBOR hex
TxBuilder.dispose() → void
Release all WASM memory held by the builder. After dispose() the builder must not be used again. Also exposed as [Symbol.dispose], so a builder created with the using keyword is cleaned up automatically when it leaves scope.
Example:
// Manual disposal
const builder = new TxBuilder()
const cbor = await builder.setInputs(utxos)./* … */.completeCbor()
builder.dispose()
// Automatic disposal (TypeScript 5.2+ / `using`)
{
using builder = new TxBuilder()
const cbor = await builder.setInputs(utxos)./* … */.completeCbor()
} // builder.dispose() called here
reset() between transactions and dispose() it at the end, or create a fresh using builder per transaction. Both keep WASM memory flat. See Performance.Returns: void
TxBuilder.reset() → TxBuilder
Reset the builder to its initial state.
Example:
txBuilder.reset()
// Builder is ready for a new transaction
Returns: TxBuilder
TxBuilder.calculateFee() → BigNum
Calculate the minimum fee.
Note: In the current release this method is a stub — it always returns
CardanoWASM.BigNum.zero(). The fee is computed internally duringcomplete(); do not rely oncalculateFee()for a real fee estimate yet.
Example:
const minFee = txBuilder.calculateFee()
console.log('Minimum fee:', minFee.to_str()) // currently always '0'
Returns: BigNum
Minimum fee (currently always 0)
TxBuilder.setFee(fee: string | BigNum) → TxBuilder
Force an explicit fee instead of letting complete() compute the minimum. The main use is Hydra, where Layer 2 transactions carry no fee — set '0'. On Layer 1 you normally omit this and let build_tx() compute the fee.
Example:
// Inside a Hydra Head — no fee
txBuilder.setFee('0')
Returns: TxBuilder
TxBuilder.setMinFee(minFee: string | BigNum) → TxBuilder
Set a floor the computed fee will not go below during complete().
Returns: TxBuilder
Other builder methods
TxBuilder exposes further chainable methods that mirror the ones above (see the source for full signatures):
- Reference inputs / scripts (CIP-31/33):
txInReference(txHash, outputIndex),txOutReferenceScript(scriptCbor, version?) - Explicit script versions:
spendingPlutusScript(version),mintPlutusScript(version) - Datums & collateral:
txOutDatumHashValue(datum),collateralReturn(address, amount) - Signing & metadata:
requiredSignerHash(pubKeyHash),auxiliaryData(hash) - Protocol params:
updateProtocolParams(params) - Min-ADA (static):
TxBuilder.minAdaForAssets(assets)
TxBuilder.minAda(output: TransactionOutput, protocolParams: Protocol) → BigNum (Static)
Calculate minimum ADA for an output.
Parameters:
output(TransactionOutput): Transaction outputprotocolParams(Protocol): Protocol parameters
Example:
const output = CardanoWASM.TransactionOutput.new(
CardanoWASM.Address.from_bech32('addr_test1...'),
CardanoWASM.Value.new(CardanoWASM.BigNum.from_str('1000000'))
)
const minAda = TxBuilder.minAda(output, protocolParams)
console.log('Minimum ADA:', minAda.to_str())
Returns: BigNum
Minimum ADA amount
Utility Functions
Building datums
The @hydra-sdk/transaction package exports only the tx-builder and the redeemer-builder helpers — there is no buildDatum export. When you need to construct PlutusData for a datum, use DatumUtils from @hydra-sdk/core.
Example:
import { DatumUtils } from '@hydra-sdk/core'
// Constr(0, [Int(42), Bytes('a1b2')])
const datum = DatumUtils.mkConstr(0, [
DatumUtils.mkInt(42),
DatumUtils.mkBytes('a1b2')
])
Returns: PlutusData
buildRedeemer(jsValue: Record<string, string>, options?) → Redeemer
Build a redeemer for a Plutus script. jsValue is required — each value is encoded as a bytes field of a Constr(0, …) redeemer. Calling it with no argument throws.
Parameters:
jsValue(Record<string, string>): Values to encode as redeemer fieldsoptions?:{ tag?: 'SPEND' | 'MINT' | 'REWARD' | 'CERT' | 'VOTE' | 'VOTING_PROPOSAL'; index?: number | string; exUnits?: { mem: string; steps: string } }(tag default'SPEND', index default0)
Example:
import { buildRedeemer } from '@hydra-sdk/transaction'
const redeemer = buildRedeemer({ action: 'claim' }, { tag: 'SPEND', index: 0 })
For most cases prefer
emptyRedeemer(...)(below) orRedeemerUtils.mkRedeemer(...)from@hydra-sdk/core, which build a redeemer directly fromPlutusData.
Returns: Redeemer
emptyRedeemer() → Redeemer
Create an empty redeemer.
Example:
import { emptyRedeemer } from '@hydra-sdk/transaction'
const redeemer = emptyRedeemer()
Returns: Redeemer
MetadataUtils.metadataObjToMetadatum(obj: any) → TransactionMetadatum
Convert a metadata object to a TransactionMetadatum. This helper lives in @hydra-sdk/core under the MetadataUtils namespace — it is not exported from @hydra-sdk/transaction.
Parameters:
obj(any): Metadata object
Example:
import { MetadataUtils } from '@hydra-sdk/core'
const metadata = MetadataUtils.metadataObjToMetadatum({
'1': 'Hello',
'2': 12345
})
Returns: TransactionMetadatum
Types and Interfaces
TxBuilderOptions
interface TxBuilderOptions {
fetcher?: IFetcher
submitter?: ISubmitter
/**
* Optional script evaluator (v1.2.0+). When provided and the transaction has
* Plutus redeemers, complete() runs a second build pass with the evaluated
* budgets so the fee is correct. Omit for Hydra (no on-chain evaluation).
*/
evaluator?: IEvaluator
/** Safety multiplier applied to evaluated exUnits (e.g. 1.1). Default: 1. (v1.2.0+) */
txEvaluationMultiplier?: number
isHydra?: boolean
params?: Partial<Protocol>
verbose?: boolean
/**
* Strict/testing mode: throw instead of continuing when tx building hits an
* issue (e.g. coin selection fails). Default: false. Not for production use.
*/
errorLogger?: boolean
}
IEvaluator, EvalAction, Budget
The evaluator contract for computing real Plutus execution units. The shapes match MeshJS's IEvaluator for interoperability — pass any provider-backed evaluator (Blockfrost / Ogmios / Demeter) or an offline UPLC evaluator.
interface Budget {
mem: number
steps: number
}
type EvalRedeemerTag = 'SPEND' | 'MINT' | 'CERT' | 'REWARD' | 'VOTE' | 'PROPOSE'
interface EvalAction {
tag: EvalRedeemerTag
index: number
budget: Budget
}
interface IEvaluator {
evaluateTx(txHex: string, additionalUtxos?: UTxO[], additionalTxs?: string[]): Promise<EvalAction[]>
}
CoinSelectionStrategy
type CoinSelectionStrategy =
| 'LargestFirst'
| 'RandomImprove'
| 'LargestFirstMultiAsset'
| 'RandomImproveMultiAsset'
Note:
TxBuilderOptionsandCoinSelectionStrategyare internal types — they are not re-exported from@hydra-sdk/transaction. The shapes are shown here for reference; pass plain object/string literals to the constructor and tosetInputs.
Asset
interface Asset {
unit: string // 'lovelace' or 'policyId.assetName'
quantity: string // Amount as string
}
Script evaluation (exUnits)
CSL cannot evaluate Plutus scripts itself, so by default TxBuilder keeps the placeholder exUnits on script redeemers. Supply an evaluator to compute the real execution units and get an accurately-priced transaction.
When an evaluator is set and the transaction has redeemers, complete():
- Builds a draft transaction.
- Calls
evaluator.evaluateTx(draftCbor)to obtain real budgets per redeemer. - Writes them back —
SPENDmatched by inputtxHash#index,MINTby policy id — optionally scaled bytxEvaluationMultiplier. - Rebuilds so the fee reflects the true script cost.
import { TxBuilder, IEvaluator } from '@hydra-sdk/transaction'
// A provider-backed evaluator (Blockfrost / Ogmios / Demeter) or a UPLC evaluator
const evaluator: IEvaluator = myProvider.evaluator
const tx = await new TxBuilder({ evaluator, txEvaluationMultiplier: 1.1 })
.setInputs(utxos)
.txIn(scriptUtxoHash, scriptUtxoIndex)
.txInScript(scriptCbor)
.txInEmptyRedeemer()
.txInCollateral(collateralHash, 0, [{ unit: 'lovelace', quantity: '5000000' }], collateralAddress)
.txOut(recipientAddress, [{ unit: 'lovelace', quantity: '2000000' }])
.changeAddress(changeAddress)
.complete() // exUnits are evaluated and written back automatically
SPEND and MINT budgets are remapped (CERT / REWARD / VOTE / PROPOSE are returned by the evaluator but not yet applied), and there is no bundled offline evaluator — supply your own. The rebuild runs a single extra pass, so a txEvaluationMultiplier of ~1.1 is recommended when exact fees matter. Without an evaluator (e.g. inside a Hydra Head), behaviour is unchanged.Complete Examples
Simple ADA Transfer
import { TxBuilder } from '@hydra-sdk/transaction'
import { AppWallet } from '@hydra-sdk/core'
async function sendAda() {
const wallet = new AppWallet({
networkId: 0,
key: { type: 'mnemonic', words: AppWallet.brew() }
})
const account = wallet.getAccount(0, 0)
const utxos = await wallet.queryUtxos(account.baseAddressBech32)
const tx = await new TxBuilder()
.setInputs(utxos)
.txOut('addr_test1qqr585tvlc7ylnqvz8pyqwauzrdu0mxag3m7q56grgmgu7sxu2hyfhlkwuxupa9d5085eunq2qywy7hvmvej456flknswgndm3', [
{ unit: 'lovelace', quantity: '2000000' }
])
.changeAddress(account.baseAddressBech32)
.complete()
const signedTx = await wallet.signTx(tx.to_hex(), false, 0, 0)
console.log('Signed transaction:', signedTx)
}
Multi-Asset Transaction
async function sendMultiAsset() {
const tx = await new TxBuilder()
.setInputs(utxos)
.txOut('addr_test1...', [
{ unit: 'lovelace', quantity: '2000000' },
{ unit: 'policyId.TokenA', quantity: '100' },
{ unit: 'policyId.TokenB', quantity: '50' }
])
.changeAddress(changeAddress)
.complete()
return tx
}
NFT Minting with Metadata
async function mintNFT() {
const policyId = 'your_policy_id'
const assetName = 'MyNFT'
const mintingScript = 'minting_script_cbor'
const tx = await new TxBuilder()
.setInputs(utxos)
.mint('1', policyId, assetName)
.txOut(recipientAddress, [
{ unit: 'lovelace', quantity: '2000000' },
{ unit: `${policyId}.${assetName}`, quantity: '1' }
])
.metadataValue('721', {
[policyId]: {
[assetName]: {
name: 'My Unique NFT',
image: 'ipfs://QmHash...',
description: 'A one-of-a-kind digital collectible'
}
}
})
.changeAddress(changeAddress)
.complete()
return tx
}
Plutus Script Interaction
async function interactWithPlutusScript() {
const scriptCbor = 'plutus_script_cbor'
const datum = CardanoWASM.PlutusData.new_map(
CardanoWASM.PlutusMap.new()
)
const tx = await new TxBuilder()
.setInputs(utxos)
.txIn(scriptUtxoHash, scriptUtxoIndex)
.txInScript(scriptCbor)
.txInDatumHash(datum)
.txInEmptyRedeemer()
.txInCollateral(collateralHash, 0, [{ unit: 'lovelace', quantity: '5000000' }], collateralAddress)
.txOut(recipientAddress, [{ unit: 'lovelace', quantity: '10000000' }])
.changeAddress(changeAddress)
.complete()
return tx
}
Related Documentation
- Core API - Wallet and utilities
- Hydra Bridge API - Hydra Layer 2 integration
