Skip to content

Amounts

All amounts in a Transaction are whole satoshis, and one coin is 100,000,000 satoshis. Bitcoin4J has two ways of holding an amount. The Coin class comes from BitcoinJ, and has arithmetic and formatting built in. The TransactionBuilder and TransactionOutput take BigInteger satoshis instead. We will need both.

Coin fromSatoshis = Coin.valueOf(12_345_678); // satoshis
Coin fromString = Coin.parseCoin("0.12345678"); // coins, as a decimal string
Coin fromDecimal = Coin.ofBtc(new BigDecimal("0.12345678"));
Coin oneCoin = Coin.COIN; // 100,000,000 satoshis

All four give us the same amount. parseCoin() and ofBtc() take the amount in coins, and throw if it has more than eight decimal places.

Please note that the names still say BTC in places (ofBtc(), MonetaryFormat.BTC). They are BitcoinJ’s names, and on BSV they mean the same units.

A Coin is immutable, and its methods return a new Coin.

Coin balance = Coin.valueOf(100_000);
Coin payment = Coin.valueOf(30_000);
Coin remaining = balance.subtract(payment).subtract(Coin.valueOf(256));
boolean enough = remaining.isGreaterThan(Coin.ZERO);

Along with add() and subtract() there are multiply(), divide(), negate() and the comparisons isGreaterThan(), isLessThan(), isPositive() and isNegative(). The arithmetic throws an ArithmeticException on overflow, rather than wrapping around.

Coin amount = Coin.valueOf(12_345_678);
String friendly = amount.toFriendlyString(); // "0.12345678 BSV"
String plain = amount.toPlainString(); // "0.12345678"
String withCode = MonetaryFormat.BTC.postfixCode().format(Coin.valueOf(50_000)).toString(); // "0.0005 BSV"
String milli = MonetaryFormat.MBTC.format(amount).toString(); // "mBSV 123.4568"

toFriendlyString() adds the unit, and toPlainString() leaves it out. For anything else, MonetaryFormat lets us choose the unit, the number of decimals and where the code goes. Its formatted values use the unit code BSV.

The builder takes BigInteger satoshis, and the interpreter takes a Coin, so we convert at the boundary.

// The TransactionBuilder and TransactionOutput take amounts as BigInteger satoshis,
// while the Interpreter takes a Coin.
Coin amount = Coin.parseCoin("0.0005");
BigInteger forBuilder = BigInteger.valueOf(amount.getValue());
Coin forInterpreter = Coin.valueOf(forBuilder.longValue());

It turns out that a long holds far more satoshis than will ever exist, so the conversion through longValue() is safe for any real amount.