Running it: change and fees
Problem. Run the manifest you just wrote, and account for every satoshi it moves — including the ones you did not think about.
You have a manifest (Splitting a UTXO) but you have not run anything yet. Doing so is how you meet the rule that governs every transaction a manifest builds: every output a transaction carries has to come from the manifest. The fee is the single exception.
Run it — and watch it fail
First, a funded wallet. If you have not done this yet, create one and fill it from the faucet (Creating a wallet):
txw info --wallet wallet.json # copy the receive address
Paste that address into the Liquid testnet faucet, request the coins, then pick them up:
txw sync --wallet wallet.json
Now run the action. It is worth checking the file parses first — validate
touches no network and no wallet:
txw validate txmanifest.json
txw run txmanifest.json Split \
--network testnet --wallet wallet.json
You will be prompted for amount_each. Give it something well under a quarter
of your balance, and the build stops:
[error] PSET build failed:
0: L-BTC does not balance: inputs exceed outputs by 600 sat, but the fee is 486 sat, leaving 114 sat unaccounted for.
This action does not permit L-BTC change, so there is nowhere for it to go. Either set "allow_change": "lbtc_only" on the action, declare a change output, or size the input to outputs + fee exactly.
Nothing was broadcast and nothing was spent — this failed while building the transaction, before any signature existed.
Where does the surplus go?
The input you selected is worth more than the four outputs plus the fee. That leftover has to go somewhere, and the engine will not decide for you.
It could send it to your change address — but you did not ask for that. It could add it to the fee — but then 114 satoshis leave your wallet to a miner, in an amount nobody wrote down. Every output a transaction carries has to come from the manifest, so rather than invent one, it stops and tells you the three ways out.
Fix it: declare a change output
The usual answer. Add a fifth output:
{ "id": "change_out", "destination": "change", "asset": "lbtc", "optional": true }
It differs from the four above in three ways, and all three matter:
destination: "change"sends to your change address rather than your receive address.- No
amount_sat. A change output takes whatever is left after the other outputs and the fee. It is the only kind of output that computes its own amount. optional: truelets the action drop it, because that remainder can be zero — and a zero-satoshi output is not something you can broadcast.
With it declared, your input only has to be big enough. Too small and you get the other error, which is the same arithmetic from the other side:
Insufficient L-BTC: have 41000 sat, need 42126 sat (outputs 40000 + fee 2126)
Or: let the engine add one
The other answer from the error message. Add allow_change to the action,
beside description:
"allow_change": "lbtc_only"
This permits the engine to return an L-BTC surplus without a declared output.
"lbtc_only" is the setting worth reaching for: a surplus in any other asset
is still an error, so a protocol token you failed to account for cannot quietly
walk out. The default is "none", which is why you saw the error at all.
Which one
Declare a change output when you want the change to be part of the transaction
you described — as Split does. Set allow_change when the surplus is an
artefact of fee estimation rather than something the action is about.
And sometimes neither is right. An action with no change output must size its
outputs to the input exactly, fee included, which sounds impractical until you
meet a recursive covenant: the Last Will refresh path
recreates its own covenant and may have only two outputs, so it computes its
amount as will_in.amount_sat - fee and declares no change at all.
Take the first fix — add change_out — and carry on.
Where is the fee?
Elements transactions pay the fee as a real output — an explicit L-BTC output with an empty script. So this transaction will have six outputs, not five.
The fee is the one output the engine appends on its own, because its amount is only known once the transaction's size is, and that is after everything else is decided. It is always last.
That exception is worth remembering when you read a covenant. A program that
asserts num_outputs == 2 against a manifest declaring a single output is not
wrong — it is counting the fee.
If you want the fee visible in the manifest anyway, an output can declare
"destination": { "type": "fee" }. It produces nothing on its own; it is a note to the reader that the fee leg is expected here. None of the examples use it, but a covenant that counts outputs is the case where it earns its place.
Run it again
txw run txmanifest.json Split \
--network testnet --wallet wallet.json
This time it selects an input, builds four outputs plus change, signs, and broadcasts. Afterwards your wallet holds four fresh UTXOs:
txw sync --wallet wallet.json
txw get-balance --wallet wallet.json
The built-in shortcut. Because splitting is so common, the CLI ships it as a first-class command — no manifest needed:
txw split -n 4 --asset lbtc --amount-each 10000 --wallet wallet.jsonAnd
preparewill split automatically when an action needs more UTXOs than the wallet currently has. You have just written the long way round, which is the point — the next recipe does something no built-in command can.
The finished file
The complete file
{
"manifest_version": "0.2.0",
"protocol": "utxo-split",
"description": "Split one wallet UTXO into four equal wallet UTXOs.",
"chain": "liquid",
"actions": {
"Split": {
"description": "Split a wallet UTXO into four outputs of amount_each, returning any remainder (less fees) as change.",
"params": {
"amount_each": {
"type": "u64",
"description": "Satoshis to place in each of the four output UTXOs."
}
},
"inputs": [
{
"id": "funding_input",
"description": "A wallet UTXO large enough to cover four outputs plus fees.",
"utxo_source": "wallet",
"asset": "lbtc",
"amount_sat": { "min_amount": "params.amount_each * 4" }
}
],
"outputs": [
{ "id": "split_0", "destination": "wallet", "amount_sat": "params.amount_each", "asset": "lbtc" },
{ "id": "split_1", "destination": "wallet", "amount_sat": "params.amount_each", "asset": "lbtc" },
{ "id": "split_2", "destination": "wallet", "amount_sat": "params.amount_each", "asset": "lbtc" },
{ "id": "split_3", "destination": "wallet", "amount_sat": "params.amount_each", "asset": "lbtc" },
{ "id": "change_out", "destination": "change", "asset": "lbtc", "optional": true }
]
}
}
}
Try next
You have written a manifest and broadcast a transaction from it, and you know where every satoshi went. The next recipe adds the first real Simplicity covenant — a UTXO type, a script, and the witnesses to spend it: Hello World: Pay-to-Public-Key.