fix: show balances and fees below 0.000001 ETH as nonzero on the send screens (closes #343)
check / check (push) Successful in 3m1s
e2e / e2e-chrome (push) Successful in 4m28s
e2e / e2e-firefox (push) Successful in 35s

The stored ETH balance and the send-confirm screen's fee were each cut to six
decimal places, so a value below 0.000001 read as 0.0. The ETH balance is now
stored exactly, and the send and send-confirm screens' balances, reserve and
insufficient-balance messages go through truncateAmountNeverZero(). Both the
send-confirm and approval screens render the fee through formatFee(), which
prices the exact fee in USD, so the same fee reads the same on both. Token
balances keep their six-decimal value: it also leaves dust off the balance
list, and keeps the string within the 18 decimals the balance check reads.

Model: opus-5-5
This commit is contained in:
2026-10-04 02:49:19 +00:00
committed by sneak
parent 00d6193ee7
commit ebbc2028e0
10 changed files with 392 additions and 70 deletions
+6 -8
View File
@@ -8,6 +8,7 @@ const {
renderAddressHtml,
attachCopyHandlers,
onViewLeave,
formatFee,
} = require("./helpers");
const { state, saveState } = require("../../shared/state");
const { networkByChainId } = require("../../shared/networks");
@@ -207,7 +208,7 @@ function showPhishingWarning(elementId, isPhishing) {
// and the nonce. The background compares every one of them against the signed
// artifact, so every one of them has to be on the screen — a number that is
// verified but never displayed is verified against nothing the user agreed to.
function showTxFee(approvedTx, ethPrice) {
function showTxFee(approvedTx) {
const network = networkByChainId(approvedTx.chainId);
$("approve-tx-network").textContent = network
? network.name
@@ -215,12 +216,9 @@ function showTxFee(approvedTx, ethPrice) {
const gasLimit = BigInt(approvedTx.gasLimit);
const feePerGas = BigInt(approvedTx.maxFeePerGas || approvedTx.gasPrice);
const maxFeeEth = formatTxValue(formatEther(gasLimit * feePerGas));
const usdStr = formatUsd(
ethPrice ? parseFloat(maxFeeEth) * ethPrice : null,
);
$("approve-tx-fee").textContent =
maxFeeEth + " ETH" + (usdStr ? " (" + usdStr + ")" : "");
// Through formatFee(), as the confirmation screen's fee is, so the same
// fee reads the same on both.
$("approve-tx-fee").textContent = formatFee(gasLimit * feePerGas);
let detail =
gasLimit.toString() +
@@ -332,7 +330,7 @@ function showTxApproval(details) {
$("approve-tx-value").textContent =
ethValueFormatted + " ETH" + (usdStr ? " (" + usdStr + ")" : "");
showTxFee(approvedTx, ethPrice);
showTxFee(approvedTx);
// Decode calldata (reuse decoded from above)
const decodedEl = $("approve-tx-decoded");