Fees and change
There is no fee field in a Transaction. Any coins in our Inputs that we don’t explicitly send to an
Output are paid to the miner as the fee. That is rarely what we want. Instead, we add a Change Output
which sends the remainder, less the fee, back to ourselves. The TransactionBuilder works out the fee and the
change amount for us when we build.
The examples use the setup from the Transaction builder, in which Alice spends a 100,000-satoshi Output.
Adding a Change Output
Section titled “Adding a Change Output”TransactionBuilder builder = new TransactionBuilder() .spendFromTransaction(new TransactionSigner(SIGHASH, alice), fundingTx, 0, TransactionInput.MAX_SEQ_NUMBER, new P2PKHUnlockBuilder(alice.getPublicKey())) .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(50_000)) .sendChangeTo(aliceAddress);Transaction tx = builder.build(true);
// The Outputs we added with spendTo() come first, in order. The Change Output is always last.TransactionOutput toBob = tx.getOutputs().get(0);TransactionOutput change = tx.getOutputs().get(1);sendChangeTo(address) makes a P2PKH Change Output. sendChangeTo(lockingScriptBuilder) takes any locking
script builder instead, for change to a P2PK or a custom script.
The Outputs we add with spendTo() come first, in the order we added them, and the Change Output is always
the last Output. Code that looks up a payment by its Output index can rely on that.
When the change is worked out
Section titled “When the change is worked out”The builder works out the change when we call build(), from all the Inputs, Outputs and fee settings it
holds at that moment. The order of our calls doesn’t matter, so sendChangeTo() may come before spendTo().
// The change is worked out when we build, so sendChangeTo() may come before spendTo().Transaction tx = spendAlicesCoins() .sendChangeTo(aliceAddress) .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(50_000)) .build(true);
assertEquals(BigInteger.valueOf(50_000), tx.getOutputs().get(0).getAmount());assertEquals(BigInteger.valueOf(100_000 - 50_000 - 256), tx.getOutputs().get(1).getAmount());How the fee is estimated
Section titled “How the fee is estimated”The builder estimates the size of the signed Transaction, and multiplies it by the fee rate, which is 512
satoshis per kilobyte unless we call withFeePerKb(). The result is rounded up to the next satoshi, and is
never less than 256 satoshis.
The estimate is made up of:
- 26 bytes of overhead,
- for each Input, the size of its Unlocking Script once signed: 149 bytes for P2PKH, and for P2PK and multisig, the size their Signatures will take,
- the actual size of each Output, the Change Output included.
To see the builder’s numbers before we build, we first call calculateChange(), which adds the Change
Output to the estimate. estimateSize() and getFee() then report what the build will use.
TransactionBuilder builder = spendAlicesCoins() .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(50_000)) .sendChangeTo(aliceAddress);
// calculateChange() works out the Change Output, so that the estimate includes it.builder.calculateChange();
// 243 bytes at 512 satoshis per kilobyte is 125 satoshis, so the 256-satoshi minimum applies.long estimatedBytes = builder.estimateSize();BigInteger fee = builder.getFee();Until the change is worked out, though, getFee() reports everything that we don’t send, as if there were
no Change Output.
TransactionBuilder builder = spendAlicesCoins() .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(50_000)) .sendChangeTo(aliceAddress);
// Until the change is worked out, getFee() reports everything we don't send.assertEquals(BigInteger.valueOf(50_000), builder.getFee());At a higher rate, the size starts to count.
TransactionBuilder builder = spendAlicesCoins() .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(50_000)) .sendChangeTo(aliceAddress) .withFeePerKb(50_000);builder.calculateChange();
// 243 bytes at 50,000 satoshis per kilobyte, rounded up to the next satoshi.assertEquals(BigInteger.valueOf(12_150), builder.getFee());Transaction tx = builder.build(true);assertEquals(BigInteger.valueOf(100_000 - 50_000 - 12_150), tx.getOutputs().get(1).getAmount());Do note that today’s BSV miners accept fees well below 512 satoshis per kilobyte, and the 256-satoshi minimum is far above what a small Transaction needs. To pay less, we set the fee ourselves with
setFee(), from our own size estimate and the fee policy of our miner or API.
Setting a fixed fee
Section titled “Setting a fixed fee”setFee() replaces the estimate, and the Change Output takes whatever is left over. Like the other builder
methods, it returns the builder, and it can be called at any point before build().
Transaction tx = spendAlicesCoins() .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(50_000)) .sendChangeTo(aliceAddress) .setFee(BigInteger.valueOf(100)) .build(true);Leaving out the Change Output
Section titled “Leaving out the Change Output”Without sendChangeTo(), the fee is everything we don’t send. build(true) guards against losing coins this
way. If the leftover is more than 150 times the estimated fee, it throws.
// Without sendChangeTo(), everything we don't send is paid as the fee.Transaction tx = spendAlicesCoins() .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(99_700)) .build(true);
// build(true) refuses a fee far above the estimate when there is no Change Output.assertThrows(TransactionException.class, () -> spendAlicesCoins() .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(50_000)) .build(true));Dust and overspending
Section titled “Dust and overspending”// Outputs below 256 satoshis are dust, and build(true) rejects them...assertThrows(TransactionException.class, () -> spendAlicesCoins() .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(100)) .sendChangeTo(aliceAddress) .build(true));
// ...as it does Outputs that add up to more than the Inputs.assertThrows(TransactionException.class, () -> spendAlicesCoins() .spendTo(new P2PKHLockBuilder(bobAddress), BigInteger.valueOf(200_000)) .build(true));The dust limit is 256 satoshis per Output, change included. If the change would fall below it, we either raise
the payment by that amount, or pay it as fee by leaving sendChangeTo() out.

