Skip to content

TxPlan: Getting Started

A Tx written in Java hardcodes the decisions. TxPlan moves them into a YAML document your application loads at run time — so a payout schedule, a treasury operation, or a customer-specific transfer becomes configuration you can review in a pull request rather than code you have to redeploy.

You need: Java 17+, cardano-client-lib, a backend, and a funded test account. If you have not built a transaction with this library yet, do Your first transaction first — this page assumes you know what Tx, from and a signer are.

The fastest way in: build it, then print it

Section titled “The fastest way in: build it, then print it”

Rather than learning the schema from a reference table, build the transaction you already know how to build and let TxPlan show you its YAML:

import com.bloxbean.cardano.client.quicktx.serialization.TxPlan;
Tx tx = new Tx()
.payToAddress(receiverAddress, Amount.ada(10))
.from(sender.baseAddress());
String yaml = TxPlan.from(tx)
.feePayer(sender.baseAddress())
.addVariable("sender", sender.baseAddress())
.addVariable("receiver", receiverAddress)
.toYaml();
System.out.println(yaml);

addVariable only adds entries to the variables: block that toYaml() writes. It doesn’t rewrite the transaction, so addresses and amounts in the output stay literal:

version: 1.0
variables:
receiver: addr_test1...
sender: addr_test1...
context:
fee_payer: addr_test1...
transaction:
- tx:
from: addr_test1...
change_address: addr_test1...
intents:
- type: payment
address: addr_test1...
amounts:
- unit: lovelace
quantity: 10000000

To parameterise the file, replace those values with ${...} by hand. Save the result as payment.yaml:

version: 1.0
variables:
sender: addr_test1...
receiver: addr_test1...
amount: 10000000
context:
fee_payer: ${sender}
transaction:
- tx:
from: ${sender}
intents:
- type: payment
address: ${receiver}
amounts:
- unit: lovelace
quantity: ${amount}

Four parts, and it is worth knowing which is which:

  • variables — the values every ${...} placeholder resolves against.
  • context — settings that apply to the whole plan and map onto QuickTxBuilder: fee_payer, fee_payer_ref, collateral_payer, collateral_payer_ref, signers, required_signers, valid_from_slot, valid_to_slot, additional_signers_count, deposit_payer, deposit_mode. Note these keys are snake_case.
  • transaction — a list of - tx: entries. A plan can carry several entries, each with a different sender. They are merged into one on-chain transaction with one hash.
  • intents — what each transaction actually does. type: payment here; minting, delegation, governance and script intents have their own types.
import java.nio.file.Files;
import java.nio.file.Path;
TxPlan plan = TxPlan.from(Files.readString(Path.of("payment.yaml")));
TxResult result = new QuickTxBuilder(backendService)
.compose(plan)
.withSigner(SignerProviders.signerFrom(sender))
.completeAndWait();
System.out.println(result.getTxStatus() + " " + result.getTxHash());

compose(TxPlan) maps the plan’s context block onto the builder for you — fee_payer becomes the fee payer, valid_to_slot becomes the validity bound. You do not repeat them in Java.

This is the one thing worth getting right early.

Variable expansion happens when the YAML is parsed, against the document’s own variables: block. TxPlan.from(yaml) returns a plan whose transactions are already fully materialised — so calling addVariable(...) on that returned plan does not change them. addVariable populates a plan you are serialising out; it does not inject into a plan you have read in.

To vary values per run, pass them to TxPlanCodec:

String template = Files.readString(Path.of("payment.yaml"));
TxPlan plan = TxPlanCodec.builder().build().fromYaml(template, Map.of(
"sender", sender.baseAddress(),
"receiver", receiverAddress,
"amount", adaToLovelace(10)));

Runtime values override the document’s variables:, and an exact ${name} keeps the value’s native type. TxPlanCodec is marked experimental.

For addresses and signing keys that are fixed per environment rather than per run, the signer registry is cleaner than variables: reference them as account://ops and resolve them at compose time with compose(plan, signerRegistry). See Advanced usage.

SituationTxPlan?
One transaction shape, values differ per callYes — one plan file, different variables
Operators need to review transactions before they runYes — the plan is reviewable text
An agent or external system decides what to submitYes — generating config is safer than generating code
Transaction shape is fixed and known at compile timeNo — plain QuickTx is simpler
Several transactions that depend on each other’s outputsNo — that is TxFlow
A continuous stream of transactions over timeNo — that is TxStream

TxPlan describes what to submit. It does not orchestrate ordering, dependencies or retries — that is TxFlow’s job, and TxFlow can execute plans as its steps.

  • TxPlan overview — YAML structure, intent types, context properties
  • Advanced usage — signer registry, script transactions, multi-entry plans
  • TxFlow — when the steps depend on each other