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.0variables: 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: 10000000The plan file
Section titled “The plan file”To parameterise the file, replace those values with ${...} by hand. Save the result as
payment.yaml:
version: 1.0variables: sender: addr_test1... receiver: addr_test1... amount: 10000000context: 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 ontoQuickTxBuilder: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 aresnake_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: paymenthere; minting, delegation, governance and script intents have their own types.
Load and execute
Section titled “Load and execute”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.
Where runtime values come from
Section titled “Where runtime values come from”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.
When TxPlan is the right tool
Section titled “When TxPlan is the right tool”| Situation | TxPlan? |
|---|---|
| One transaction shape, values differ per call | Yes — one plan file, different variables |
| Operators need to review transactions before they run | Yes — the plan is reviewable text |
| An agent or external system decides what to submit | Yes — generating config is safer than generating code |
| Transaction shape is fixed and known at compile time | No — plain QuickTx is simpler |
| Several transactions that depend on each other’s outputs | No — that is TxFlow |
| A continuous stream of transactions over time | No — 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