fix potential off by 1 sat rounding error on imported send to many dialog amounts
What changed, and why it matters
This commit fixes a small rounding bug when importing a 'send to many' payment list in Sparrow Wallet. When amounts were entered in whole bitcoins (BTC), the app converted them to satoshis by multiplying with a large constant using normal decimal math. Because computers can store decimal fractions imprecisely, the result could be off by one satoshi (the smallest Bitcoin unit). The fix uses a dedicated helper that handles the conversion more safely. A one-satoshi error is tiny in dollar terms, but could cause a transaction to be slightly wrong or, in edge cases, fail validation.
Review `BitcoinUnit.getSatsValue(double)` to confirm it uses a rounding mode appropriate for monetary conversion (e.g., HALF_UP or exact parsing). Consider adding unit tests covering BTC values with many decimal places and edge cases such as 0.00000001 BTC. Users relying on imported send-to-many lists should verify payment totals after updating.
Security signals we found
Financial-amount rounding error in transaction construction
Floating-point conversion from BTC to satoshis replaced with unit-aware helper
Potential off-by-one satoshi discrepancy in imported payment amounts
No input validation or bounds checks added in this patch
Evidence from the diff
The patch replaces two direct conversions from BTC to satoshis with bitcoinUnit.getSatsValue(doubleAmount). Previously, code multiplied a parsed double by Transaction.SATOSHIS_PER_BITCOIN and cast to long, which is vulnerable to floating-point representation error and truncation, producing amounts off by one satoshi. The change centralizes conversion through a presumably rounding-aware helper. It is a correctness fix, not a memory-safety or cryptographic bug, and the commit message explicitly frames it as a rounding-error fix.
Changed components
src/main/java/com/sparrowwallet/sparrow/control/SendToManyDialog.javaSend-to-many CSV import pathSend-to-many clipboard/text import pathInspect captured patch +2 / −6
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/SendToManyDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/SendToManyDialog.java
index 1f7e6f7..40a2c57 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/SendToManyDialog.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/SendToManyDialog.java
@@ -219,7 +219,7 @@ public class SendToManyDialog extends Dialog<List<Payment>> {
long amount;
if(bitcoinUnit == BitcoinUnit.BTC) {
double doubleAmount = Double.parseDouble(csvReader.get(1).replace(",", ""));
- amount = (long)(doubleAmount * Transaction.SATOSHIS_PER_BITCOIN);
+ amount = bitcoinUnit.getSatsValue(doubleAmount);
} else {
amount = Long.parseLong(csvReader.get(1).replace(",", ""));
}
@@ -487,11 +487,7 @@ public class SendToManyDialog extends Dialog<List<Payment>> {
}
if(sendToAddress != null && value != null) {
- if(bitcoinUnit == BitcoinUnit.BTC) {
- value = value * Transaction.SATOSHIS_PER_BITCOIN;
- }
-
- payments.add(sendToAddress.toPayment(label, value.longValue(), false));
+ payments.add(sendToAddress.toPayment(label, bitcoinUnit.getSatsValue(value), false));
}
}
Why this scored 42/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.