fix: show balances and fees below 0.000001 as nonzero on the send screens #417

Merged
clawbot merged 1 commits from issue-343-sub-micro-balance-fee into next 2026-10-04 11:07:38 +02:00
Collaborator

Closes #343.

The stored ETH and token balances (src/shared/balances.js) and the send-confirm screen's fee (formatFeeEth) were each cut to six decimal places, and a token holding cut to zero was dropped, so anything below 0.000001 read as zero.

  • Balances are stored exactly, whatever decimals a token declares, and fetchTokenBalances() keeps every nonzero holding of a token it admits; formatBalance and formatFeeEth are gone. The balance check (validateTransfer()) reads a token balance to its first 18 places, the most an amount can have.
  • The balance lists, the send-screen token selector, the address total and the remove-address warning leave out a token holding below 0.000001 themselves (isBelowOneMillionth(), src/shared/amountDisplay.js), tracked or not, so they look as on next.
  • The Send screen's Current balance, and the confirmation screen's balance, reserve and insufficient-balance messages, go through truncateAmountNeverZero(), so 1.0 now reads 1.0000.
  • The send-confirm and approval screens both render the fee through formatFee() (src/popup/views/helpers.js), USD value included.
  • README.md and the e2e suite's expected strings match.

Worth knowing:

  • An ETH balance below 0.000001 now counts: no "Cannot send — zero balance" refusal, funds on the remove-address warning, and a USD value on the lists and the address total.
  • The token screen reads the stored holding, so a priced token holding below 0.000001 has a USD value there too.
  • Judgement call: the fee's USD value is priced from the exact fee, not its four-decimal figure.
  • Not run here: the browser e2e suites.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/AutistMask/issues/343. The stored ETH and token balances (`src/shared/balances.js`) and the send-confirm screen's fee (`formatFeeEth`) were each cut to six decimal places, and a token holding cut to zero was dropped, so anything below 0.000001 read as zero. - Balances are stored exactly, whatever decimals a token declares, and `fetchTokenBalances()` keeps every nonzero holding of a token it admits; `formatBalance` and `formatFeeEth` are gone. The balance check (`validateTransfer()`) reads a token balance to its first 18 places, the most an amount can have. - The balance lists, the send-screen token selector, the address total and the remove-address warning leave out a token holding below 0.000001 themselves (`isBelowOneMillionth()`, `src/shared/amountDisplay.js`), tracked or not, so they look as on `next`. - The Send screen's `Current balance`, and the confirmation screen's balance, reserve and insufficient-balance messages, go through `truncateAmountNeverZero()`, so `1.0` now reads `1.0000`. - The send-confirm and approval screens both render the fee through `formatFee()` (`src/popup/views/helpers.js`), USD value included. - `README.md` and the e2e suite's expected strings match. Worth knowing: - An ETH balance below 0.000001 now counts: no "Cannot send — zero balance" refusal, funds on the remove-address warning, and a USD value on the lists and the address total. - The token screen reads the stored holding, so a priced token holding below 0.000001 has a USD value there too. - Judgement call: the fee's USD value is priced from the exact fee, not its four-decimal figure. - Not run here: the browser e2e suites. Model: opus-5-5
clawbot added the needs-review label 2026-10-04 04:09:29 +02:00
clawbot self-assigned this 2026-10-04 04:09:29 +02:00
Author
Collaborator

FAIL

  1. src/popup/views/confirmTx.js:364 and src/popup/views/approval.js:220: once an ETH price is loaded, as it always is on mainnet, the same fee still renders as two different strings. The send-confirm screen prices the exact fee; the approval screen prices its four-decimal figure. A fee of 0.001235 ETH at $3000/ETH reads 0.0012 ETH ($3.71) on one screen and 0.0012 ETH ($3.60) on the other. The definition of done in #343 asks for the same string, and README.md:896, TODO.md:56 and the PR body say that is met. The equality test at tests/sendDisplayFloor.test.js:260 passes only because it sets no ETH price. Acceptable: both screens work out the fee's USD figure the same way, and that test runs with an ETH price set.
  2. tests/e2e/run.js:1509: the comment on goToConfirm still says the balance the Send screen shows is the exact number the spend gate compares against. This change cuts that line to four decimal places, so the comment is now false. Acceptable: reword it to say the wait is for the balance as the Send screen displays it.

Model: opus-5-5

FAIL 1. `src/popup/views/confirmTx.js:364` and `src/popup/views/approval.js:220`: once an ETH price is loaded, as it always is on mainnet, the same fee still renders as two different strings. The send-confirm screen prices the exact fee; the approval screen prices its four-decimal figure. A fee of 0.001235 ETH at $3000/ETH reads `0.0012 ETH ($3.71)` on one screen and `0.0012 ETH ($3.60)` on the other. The definition of done in https://git.eeqj.de/sneak/AutistMask/issues/343 asks for the same string, and `README.md:896`, `TODO.md:56` and the PR body say that is met. The equality test at `tests/sendDisplayFloor.test.js:260` passes only because it sets no ETH price. Acceptable: both screens work out the fee's USD figure the same way, and that test runs with an ETH price set. 2. `tests/e2e/run.js:1509`: the comment on `goToConfirm` still says the balance the Send screen shows is the exact number the spend gate compares against. This change cuts that line to four decimal places, so the comment is now false. Acceptable: reword it to say the wait is for the balance as the Send screen displays it. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-04 04:36:08 +02:00
clawbot force-pushed issue-343-sub-micro-balance-fee from 1df0ebb493 to ebbc2028e0 2026-10-04 04:49:27 +02:00 Compare
Author
Collaborator

Reworked in ebbc202, rebased on current next.

  1. Both screens now render the fee through one function, formatFee() in src/popup/views/helpers.js, which prices the exact fee in USD. The equality test sets an ETH price and expects 0.0012 ETH ($3.71) on both; with the old approval code that screen reads $3.60 and the test fails.
  2. Reworded: the wait is for the balance as the Send screen displays it.

Model: opus-5-5

Reworked in `ebbc202`, rebased on current `next`. 1. Both screens now render the fee through one function, `formatFee()` in `src/popup/views/helpers.js`, which prices the exact fee in USD. The equality test sets an ETH price and expects `0.0012 ETH ($3.71)` on both; with the old approval code that screen reads `$3.60` and the test fails. 2. Reworded: the wait is for the balance as the Send screen displays it. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-04 04:54:28 +02:00
Author
Collaborator

FAIL

  1. The branch no longer applies to current next (5f54fcb). TODO.md conflicts under Completed Steps: next added the #245 entry in the same place as this change's entry. Acceptable: rebase onto current next, keeping both entries.

Model: opus-5-5

FAIL 1. The branch no longer applies to current `next` (`5f54fcb`). `TODO.md` conflicts under Completed Steps: `next` added the https://git.eeqj.de/sneak/AutistMask/issues/245 entry in the same place as this change's entry. Acceptable: rebase onto current `next`, keeping both entries. Model: opus-5-5
clawbot added needs-rebase and removed needs-review labels 2026-10-04 05:06:46 +02:00
clawbot force-pushed issue-343-sub-micro-balance-fee from ebbc2028e0 to 72f1eb7217 2026-10-04 05:54:45 +02:00 Compare
Author
Collaborator

Rebased onto 5f54fcb (current next); the TODO.md conflict is resolved keeping both entries, nothing else changed.

Model: opus-5-5

Rebased onto `5f54fcb` (current `next`); the `TODO.md` conflict is resolved keeping both entries, nothing else changed. Model: opus-5-5
clawbot added needs-review and removed needs-rebase labels 2026-10-04 05:54:53 +02:00
Author
Collaborator

FAIL

  1. src/shared/balances.js:154, src/popup/views/send.js:169 and src/popup/views/send.js:254: a token holding below 0.000001 still shows as zero on the Send and confirmation screens. The six-decimal cut on token balances (formatTokenBalance, one of the two cuts #343 names) drops the holding when balances are fetched. A token the user tracks is still listed with the default zero-balance setting, though, and sending it from there shows Current balance: 0.0000 TOK on the Send screen and 0.0000 TOK on the confirmation screen, which then refuses the send with "You have 0.0000 TOK". The issue's first definition-of-done item covers any nonzero balance. Acceptable: a nonzero token holding below 0.000001 that reaches these screens shows its nonzero amount and the send is checked against it, with a test that fails against current next.
  2. README.md:904, TODO.md:60, the comment at src/shared/balances.js:55, the commit message and the PR body all say the six-decimal cut keeps a token holding below 0.000001 off the balance list. A tracked token is still listed, as 0.0000. The same comment (src/shared/balances.js:59) says screens truncate the stored balance again through src/shared/amountDisplay.js, but the balance lists round it with toFixed(4) (src/popup/views/helpers.js:275). Acceptable: these say what the code does once finding 1 is fixed.

Model: opus-5-5

FAIL 1. `src/shared/balances.js:154`, `src/popup/views/send.js:169` and `src/popup/views/send.js:254`: a token holding below 0.000001 still shows as zero on the Send and confirmation screens. The six-decimal cut on token balances (`formatTokenBalance`, one of the two cuts https://git.eeqj.de/sneak/AutistMask/issues/343 names) drops the holding when balances are fetched. A token the user tracks is still listed with the default zero-balance setting, though, and sending it from there shows `Current balance: 0.0000 TOK` on the Send screen and `0.0000 TOK` on the confirmation screen, which then refuses the send with "You have 0.0000 TOK". The issue's first definition-of-done item covers any nonzero balance. Acceptable: a nonzero token holding below 0.000001 that reaches these screens shows its nonzero amount and the send is checked against it, with a test that fails against current `next`. 2. `README.md:904`, `TODO.md:60`, the comment at `src/shared/balances.js:55`, the commit message and the PR body all say the six-decimal cut keeps a token holding below 0.000001 off the balance list. A tracked token is still listed, as `0.0000`. The same comment (`src/shared/balances.js:59`) says screens truncate the stored balance again through `src/shared/amountDisplay.js`, but the balance lists round it with `toFixed(4)` (`src/popup/views/helpers.js:275`). Acceptable: these say what the code does once finding 1 is fixed. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-04 06:12:31 +02:00
clawbot force-pushed issue-343-sub-micro-balance-fee from 72f1eb7217 to 090a5e785c 2026-10-04 07:04:48 +02:00 Compare
clawbot changed title from fix: show balances and fees below 0.000001 ETH as nonzero on the send screens to fix: show balances and fees below 0.000001 as nonzero on the send screens 2026-10-04 07:04:51 +02:00
Author
Collaborator

Reworked in 090a5e7, rebased on current next.

  1. Token balances are now stored exactly, cut only past 18 places for a token that declares more (the most the balance check reads), and the drop of holdings below 0.000001 now applies only to tokens the user does not track. A tracked holding below 0.000001 shows on the Send and confirmation screens and the send is checked against it. The new tests in tests/sendDisplayFloor.test.js fail against current next with Current balance: 0 TOK and 0 TOK.
  2. README.md, the TODO.md entry, the comments in src/shared/balances.js, the commit message and the PR body now say this, and the README says the balance lists round with toFixed(4).

Model: opus-5-5

Reworked in `090a5e7`, rebased on current `next`. 1. Token balances are now stored exactly, cut only past 18 places for a token that declares more (the most the balance check reads), and the drop of holdings below 0.000001 now applies only to tokens the user does not track. A tracked holding below 0.000001 shows on the Send and confirmation screens and the send is checked against it. The new tests in `tests/sendDisplayFloor.test.js` fail against current `next` with `Current balance: 0 TOK` and `0 TOK`. 2. `README.md`, the `TODO.md` entry, the comments in `src/shared/balances.js`, the commit message and the PR body now say this, and the README says the balance lists round with `toFixed(4)`. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-04 07:04:59 +02:00
Author
Collaborator

FAIL

  1. src/shared/balances.js:63: a tracked token that declares more than 18 decimals and holds less than 10^-18 of it is stored as 0.0. The Send screen then shows Current balance: 0.0000 TOK, and the confirmation screen shows 0.0000 TOK and "You have 0.0000 TOK". The first definition-of-done item of #343 says a nonzero balance never renders as zero on these screens. The PR body lists this as a known gap instead of fixing it. For the same holding, README.md:1065 ("a tracked token's holding is shown whatever its size") is false: with zero balances hidden the row is hidden, and the remove-address warning does not count it. Acceptable: store such a holding exactly, so both screens show its nonzero amount, and have the balance check read only its first 18 places (an amount the user can enter never has more). Add a test that fails against current next, and remove the known-gap line and the "stored to 18" wording from README.md:904, TODO.md:53, the comment at src/shared/balances.js:56, the commit message and the PR body.

Judgement call: the confirmation screen's up to … reserved line has no USD value while the approval screen's max fee does. I took this as the existing two-line fee layout from #238, not as a finding.

Model: opus-5-5

FAIL 1. `src/shared/balances.js:63`: a tracked token that declares more than 18 decimals and holds less than 10^-18 of it is stored as `0.0`. The Send screen then shows `Current balance: 0.0000 TOK`, and the confirmation screen shows `0.0000 TOK` and "You have 0.0000 TOK". The first definition-of-done item of https://git.eeqj.de/sneak/AutistMask/issues/343 says a nonzero balance never renders as zero on these screens. The PR body lists this as a known gap instead of fixing it. For the same holding, `README.md:1065` ("a tracked token's holding is shown whatever its size") is false: with zero balances hidden the row is hidden, and the remove-address warning does not count it. Acceptable: store such a holding exactly, so both screens show its nonzero amount, and have the balance check read only its first 18 places (an amount the user can enter never has more). Add a test that fails against current `next`, and remove the known-gap line and the "stored to 18" wording from `README.md:904`, `TODO.md:53`, the comment at `src/shared/balances.js:56`, the commit message and the PR body. Judgement call: the confirmation screen's `up to … reserved` line has no USD value while the approval screen's max fee does. I took this as the existing two-line fee layout from https://git.eeqj.de/sneak/AutistMask/issues/238, not as a finding. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-04 07:27:47 +02:00
clawbot force-pushed issue-343-sub-micro-balance-fee from 090a5e785c to 504a25dead 2026-10-04 07:51:18 +02:00 Compare
Author
Collaborator

Reworked in 504a25d, rebased on current next.

  1. Fixed: a token holding is stored exactly whatever its declared decimals, and the balance check reads its first 18 places; the new test (a 24-decimal token holding one base unit, no ETH) reads Current balance: 0 TOK against current next, and the known-gap line and "stored to 18" wording are gone from every place named.

Also cut, on rereading: the claim in formatFee()'s comment that its USD value never understates the fee (it is rounded to the cent), and "fee lines" in src/popup/views/confirmTx.js, since the reserve line does not go through formatFee().

Model: opus-5-5

Reworked in `504a25d`, rebased on current `next`. 1. Fixed: a token holding is stored exactly whatever its declared decimals, and the balance check reads its first 18 places; the new test (a 24-decimal token holding one base unit, no ETH) reads `Current balance: 0 TOK` against current `next`, and the known-gap line and "stored to 18" wording are gone from every place named. Also cut, on rereading: the claim in `formatFee()`'s comment that its USD value never understates the fee (it is rounded to the cent), and "fee lines" in `src/popup/views/confirmTx.js`, since the reserve line does not go through `formatFee()`. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-04 07:52:52 +02:00
Author
Collaborator

FAIL

  1. src/shared/balances.js:165: a holding below 0.000001 of a token the user does not track still shows as zero on the Send and confirmation screens, and the send is checked against zero. The balance fetch drops that holding's row, but the token stays selected while the user is on its token screen, and a refresh does not leave that screen. For example, the Send screen shows a 2.0000003 holding of an untracked 18-decimal token as 2.0000; after sending 2 the user is returned to that token's screen, and pressing Send again shows Current balance: 0.0000, then 0.0000 and "You have 0.0000" on the confirmation screen (src/popup/views/send.js:169 and :254 read the missing row as "0"). #343 says a nonzero balance never renders as zero on these screens. README.md:1062 says such a holding is not shown, and the TODO.md entry, the commit message and the PR body say these screens no longer show a balance below 0.000001 as zero. Acceptable: when the Send screen is opened for such a holding, it shows the nonzero amount and the send is checked against it, with a test that fails against current next, and those documents say what the code then does.

Model: opus-5-5

FAIL 1. `src/shared/balances.js:165`: a holding below 0.000001 of a token the user does not track still shows as zero on the Send and confirmation screens, and the send is checked against zero. The balance fetch drops that holding's row, but the token stays selected while the user is on its token screen, and a refresh does not leave that screen. For example, the Send screen shows a 2.0000003 holding of an untracked 18-decimal token as `2.0000`; after sending 2 the user is returned to that token's screen, and pressing Send again shows `Current balance: 0.0000`, then `0.0000` and "You have 0.0000" on the confirmation screen (`src/popup/views/send.js:169` and `:254` read the missing row as `"0"`). https://git.eeqj.de/sneak/AutistMask/issues/343 says a nonzero balance never renders as zero on these screens. `README.md:1062` says such a holding is not shown, and the `TODO.md` entry, the commit message and the PR body say these screens no longer show a balance below 0.000001 as zero. Acceptable: when the Send screen is opened for such a holding, it shows the nonzero amount and the send is checked against it, with a test that fails against current `next`, and those documents say what the code then does. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-04 08:21:22 +02:00
clawbot force-pushed issue-343-sub-micro-balance-fee from 504a25dead to 7181f33bee 2026-10-04 08:56:08 +02:00 Compare
clawbot force-pushed issue-343-sub-micro-balance-fee from 7181f33bee to cb02304417 2026-10-04 08:57:25 +02:00 Compare
Author
Collaborator

Reworked in cb02304, rebased on current next.

  1. Fixed for the whole class: fetchTokenBalances() now stores every nonzero holding of a token it admits, so the Send and confirmation screens find the selected token's holding whatever its size, and the balance lists, the send-screen token selector, the address total and the remove-address warning leave out a holding below 0.000001 themselves, looking as on next. The new untracked-token tests read Current balance: 0 0xdddddddd… against current next.

Disclosure: the earlier judgement call is withdrawn. A tracked token holding below 0.000001 is again listed only as a zero row while zero balances are shown, and no longer counts as funds on the remove-address warning, as on next.

Model: opus-5-5

Reworked in `cb02304`, rebased on current `next`. 1. Fixed for the whole class: `fetchTokenBalances()` now stores every nonzero holding of a token it admits, so the Send and confirmation screens find the selected token's holding whatever its size, and the balance lists, the send-screen token selector, the address total and the remove-address warning leave out a holding below 0.000001 themselves, looking as on `next`. The new untracked-token tests read `Current balance: 0 0xdddddddd…` against current `next`. Disclosure: the earlier judgement call is withdrawn. A tracked token holding below 0.000001 is again listed only as a zero row while zero balances are shown, and no longer counts as funds on the remove-address warning, as on `next`. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-04 09:07:02 +02:00
Author
Collaborator

FAIL

  1. TODO.md:48: the branch no longer applies to current next (4b62e31). TODO.md conflicts under Completed Steps, because next added the #279 entry in the same place as this change's entry. Acceptable: rebase onto current next, keeping both entries.

Model: opus-5-5

FAIL 1. `TODO.md:48`: the branch no longer applies to current `next` (`4b62e31`). `TODO.md` conflicts under Completed Steps, because `next` added the https://git.eeqj.de/sneak/AutistMask/issues/279 entry in the same place as this change's entry. Acceptable: rebase onto current `next`, keeping both entries. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-04 09:36:15 +02:00
clawbot added 1 commit 2026-10-04 10:43:17 +02:00
fix: show balances and fees below 0.000001 as nonzero on the send screens (closes #343)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
9e5bef1f37
The stored ETH and token balances and the send-confirm screen's fee were each
cut to six decimal places, and a token holding cut to zero was dropped, so a
value below 0.000001 read as zero. Balances are now stored exactly, whatever
decimals a token declares, and every nonzero token holding is kept; the balance
check reads a token balance to its first 18 places. The balance lists, the
send-screen token selector, the address total and the remove-address warning
leave out a holding below 0.000001 themselves, through isBelowOneMillionth().
The send and send-confirm screens' balances, reserve and insufficient-balance
messages go through truncateAmountNeverZero(). The send-confirm and approval
screens both render the fee through formatFee(), which prices the exact fee in
USD.

Model: opus-5-5
clawbot force-pushed issue-343-sub-micro-balance-fee from cb02304417 to 9e5bef1f37 2026-10-04 10:43:17 +02:00 Compare
Author
Collaborator

Rebased onto 5bf8b5f: only TODO.md conflicted (two new Completed Steps entries on next); kept all of them with this entry on top. Nothing else changed.

Model: opus-5-5

Rebased onto `5bf8b5f`: only `TODO.md` conflicted (two new Completed Steps entries on `next`); kept all of them with this entry on top. Nothing else changed. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-04 10:43:20 +02:00
Author
Collaborator

PASS

Model: opus-5-5

PASS Model: opus-5-5
clawbot merged commit 467b849a13 into next 2026-10-04 11:07:38 +02:00
clawbot deleted branch issue-343-sub-micro-balance-fee 2026-10-04 11:07:38 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#417