fix: never render a nonzero approval amount as zero (closes #322) #339

Merged
clawbot merged 1 commits from fix/322-nonzero-amount-display-floor into next 2026-08-23 15:43:04 +02:00
Collaborator

Closes #322.

The defect

Token and ETH amounts are truncated to 4 decimal places, per README.md's
Display Consistency rule. With the token's true scale resolved, an amount below
0.0001 still printed as 0.0000 — 1 base unit of an 18-decimal token, 500 base
units of an 8-decimal one. On the dApp approval screen, and on the
wait/success/error screens that carry the same string forward as
txInfo.amount, a real transfer, allowance or swap was stated as nothing. A
swap's Min. received is the sharper case: a slippage floor shown as 0.0000
states that the swap may return nothing.

All three copies of the truncation

The rule had been implemented three times. Each is named here with what
happened to it:

  1. formatTxValue() in src/popup/views/approval.js — the ERC-20 amount line,
    the ETH value and the max fee. Now floored.
  2. formatAmount() in src/shared/uniswap.js — the Amount and
    Min. received lines of a decoded Uniswap swap, on that same approval
    screen, with Amount's rawValue carried to the confirmation screens.
    Now floored. This copy was missed by the first round of this PR and is
    the blocking finding of the review.
  3. formatTxValue() in src/shared/transactions.js — history and balance
    lists. Behaviour deliberately unchanged, per the DoD's out-of-scope
    clause; the transaction detail view is the authoritative record and already
    shows exact precision.

They were unified rather than left as three divergent copies: a fix applied to
one of them is exactly how the second one came to be missed. src/shared/amountDisplay.js
now holds the rule and its exception next to each other:

  • truncateAmount(val) — plain 4-decimal truncation. Used by
    src/shared/transactions.js.
  • truncateAmountNeverZero(val) — the same, with the nonzero floor. Used by
    src/popup/views/approval.js and src/shared/uniswap.js.

The code path is shared; the policy is not. The lists keep their unfloored
rule, and a test pins that so the shared module cannot drift into a single
policy.

The floor itself

When the truncated string would contain no digit from 1 to 9 and the value
does, the amount extends to its first significant digit:
0.000000000000000001 DAI, not 0.0000 DAI. Extra precision was chosen over
falling back to base units so the number stays in token units, the same unit as
the symbol beside it; the base-unit rendering already on this screen
(unknownDecimalsAmount()) means "the scale is unknown", and reusing it for a
known scale would blur two different facts on the one screen that must state
exactly what is being authorized.

A genuine zero still renders 0.0000. An amount at or above the floor is
untouched. Truncation stays truncation: 0.99999 shows as 0.9999, never
rounded up. The test is on the whole truncated string, integer part included,
so 1.00005 stays 1.0000 — the exception fires only where the entire figure
would read as zero.

README.md's Display Consistency section is corrected accordingly: the previous
wording said "when the first 4 decimals would all be zero", which does not
describe what the code tests, and it named only one of the three call sites. It
now states the real condition, the 1.00005 and 0.99999 cases, and which call
sites take which function.

Fail-first evidence for the two new tests

tests/approvalDisplayFloor.test.js now drives uniswap.decode() alongside
decodeCalldata(), on a V2_SWAP_EXACT_IN execute() call (USDT → WETH).

Mutation: git checkout HEAD -- src/shared/uniswap.js against the previous head
3fb6a53, restoring the old formatAmount() verbatim, with the new tests in
place. Observed, Tests: 2 failed, 11 passed, 13 total:

  • a swap input below the floor keeps a significant digit
    Expected: "0.00005 USDT"
    Received: "0.0000 USDT"

  • a min-received below the floor keeps a significant digit
    Expected: "0.000000000000000001 WETH"
    Received: "0.0000 WETH"

The first is 50 base units of 6-decimal USDT as the swap input; the second is an
amountOutMin of 1 wei. A third swap case pins the unchanged truncation
(1.0000, and 0.9999 for 999999999999999999 wei) and passes both before and
after — it is a regression guard, not fail-first.

The four ERC-20 cases from the previous round are unchanged and still fail
against cef6aaa with src/popup/views/approval.js reverted.

Disclosure, since the issue names this case: 500 base units of a 6-decimal
token is 0.0005, which the 4-decimal rule already rendered correctly — that case
is not a defect and is kept only as a regression guard. The scales that actually
round to zero are 8 and 18 decimals.

Verification

make check green, exit 0, on this exact tree:

  • Test Suites: 42 passed, 42 total, Tests: 848 passed, 848 total
  • test-verify-build: 39 case(s) passed
  • check-censored: 153 tracked file(s) inspected
  • lint in the pinned container: the lint stage ran uncached
    (#11 [lint 1/1] RUN make lintDONE 4.8s), eslint . && prettier --check ., All matched files use Prettier code style!
  • make fmt run; the formatted README.md and TODO.md are in the commit
  • rebased onto next at cef6aaa immediately before pushing (no movement, no
    conflicts)

Not run: make test-e2e / make test-e2e-firefox, which are not part of
make check. No container or image was left behind (docker ps -a clean).

Out of scope, noted

tokenInfo() in src/shared/uniswap.js returns decimals: 18 for a token
absent from the bundled list — a separate pre-existing defect, filed as
#340 and not touched here.
The balance-list quantities in src/popup/views/helpers.js and
src/popup/views/home.js use toFixed(4) rather than this truncation; they are
lists, out of scope by the DoD, and are unchanged.

Closes [#322](https://git.eeqj.de/sneak/AutistMask/issues/322). ## The defect Token and ETH amounts are truncated to 4 decimal places, per `README.md`'s Display Consistency rule. With the token's true scale resolved, an amount below 0.0001 still printed as `0.0000` — 1 base unit of an 18-decimal token, 500 base units of an 8-decimal one. On the dApp approval screen, and on the wait/success/error screens that carry the same string forward as `txInfo.amount`, a real transfer, allowance or swap was stated as nothing. A swap's `Min. received` is the sharper case: a slippage floor shown as `0.0000` states that the swap may return nothing. ## All three copies of the truncation The rule had been implemented three times. Each is named here with what happened to it: 1. `formatTxValue()` in `src/popup/views/approval.js` — the ERC-20 amount line, the ETH value and the max fee. **Now floored.** 2. `formatAmount()` in `src/shared/uniswap.js` — the `Amount` and `Min. received` lines of a decoded Uniswap swap, on that same approval screen, with `Amount`'s `rawValue` carried to the confirmation screens. **Now floored.** This copy was missed by the first round of this PR and is the blocking finding of the review. 3. `formatTxValue()` in `src/shared/transactions.js` — history and balance lists. **Behaviour deliberately unchanged**, per the DoD's out-of-scope clause; the transaction detail view is the authoritative record and already shows exact precision. They were unified rather than left as three divergent copies: a fix applied to one of them is exactly how the second one came to be missed. `src/shared/amountDisplay.js` now holds the rule and its exception next to each other: - `truncateAmount(val)` — plain 4-decimal truncation. Used by `src/shared/transactions.js`. - `truncateAmountNeverZero(val)` — the same, with the nonzero floor. Used by `src/popup/views/approval.js` and `src/shared/uniswap.js`. **The code path is shared; the policy is not.** The lists keep their unfloored rule, and a test pins that so the shared module cannot drift into a single policy. ## The floor itself When the truncated string would contain no digit from 1 to 9 and the value does, the amount extends to its first significant digit: `0.000000000000000001 DAI`, not `0.0000 DAI`. Extra precision was chosen over falling back to base units so the number stays in token units, the same unit as the symbol beside it; the base-unit rendering already on this screen (`unknownDecimalsAmount()`) means "the scale is unknown", and reusing it for a known scale would blur two different facts on the one screen that must state exactly what is being authorized. A genuine zero still renders `0.0000`. An amount at or above the floor is untouched. Truncation stays truncation: `0.99999` shows as `0.9999`, never rounded up. The test is on the whole truncated string, integer part included, so `1.00005` stays `1.0000` — the exception fires only where the entire figure would read as zero. `README.md`'s Display Consistency section is corrected accordingly: the previous wording said "when the first 4 decimals would all be zero", which does not describe what the code tests, and it named only one of the three call sites. It now states the real condition, the `1.00005` and `0.99999` cases, and which call sites take which function. ## Fail-first evidence for the two new tests `tests/approvalDisplayFloor.test.js` now drives `uniswap.decode()` alongside `decodeCalldata()`, on a `V2_SWAP_EXACT_IN` execute() call (USDT → WETH). Mutation: `git checkout HEAD -- src/shared/uniswap.js` against the previous head `3fb6a53`, restoring the old `formatAmount()` verbatim, with the new tests in place. Observed, `Tests: 2 failed, 11 passed, 13 total`: ``` • a swap input below the floor keeps a significant digit Expected: "0.00005 USDT" Received: "0.0000 USDT" • a min-received below the floor keeps a significant digit Expected: "0.000000000000000001 WETH" Received: "0.0000 WETH" ``` The first is 50 base units of 6-decimal USDT as the swap input; the second is an `amountOutMin` of 1 wei. A third swap case pins the unchanged truncation (`1.0000`, and `0.9999` for 999999999999999999 wei) and passes both before and after — it is a regression guard, not fail-first. The four ERC-20 cases from the previous round are unchanged and still fail against `cef6aaa` with `src/popup/views/approval.js` reverted. **Disclosure, since the issue names this case:** 500 base units of a 6-decimal token is 0.0005, which the 4-decimal rule already rendered correctly — that case is not a defect and is kept only as a regression guard. The scales that actually round to zero are 8 and 18 decimals. ## Verification `make check` green, exit 0, on this exact tree: - `Test Suites: 42 passed, 42 total`, `Tests: 848 passed, 848 total` - `test-verify-build: 39 case(s) passed` - `check-censored: 153 tracked file(s) inspected` - lint in the pinned container: the `lint` stage ran uncached (`#11 [lint 1/1] RUN make lint` → `DONE 4.8s`), `eslint . && prettier --check .`, `All matched files use Prettier code style!` - `make fmt` run; the formatted `README.md` and `TODO.md` are in the commit - rebased onto `next` at `cef6aaa` immediately before pushing (no movement, no conflicts) Not run: `make test-e2e` / `make test-e2e-firefox`, which are not part of `make check`. No container or image was left behind (`docker ps -a` clean). ## Out of scope, noted `tokenInfo()` in `src/shared/uniswap.js` returns `decimals: 18` for a token absent from the bundled list — a separate pre-existing defect, filed as [#340](https://git.eeqj.de/sneak/AutistMask/issues/340) and not touched here. The balance-list quantities in `src/popup/views/helpers.js` and `src/popup/views/home.js` use `toFixed(4)` rather than this truncation; they are lists, out of scope by the DoD, and are unchanged.
clawbot added the needs-review label 2026-08-23 15:18:51 +02:00
clawbot added 1 commit 2026-08-23 15:18:51 +02:00
fix: never render a nonzero approval amount as zero (closes #322)
All checks were successful
check / check (push) Successful in 30s
e2e / e2e-chrome (push) Successful in 1m12s
e2e / e2e-firefox (push) Successful in 24s
3fb6a53f77
formatTxValue() truncates to 4 decimal places, per README.md's Display
Consistency rule. With the token's true scale resolved, an amount below 0.0001
still printed as 0.0000: 1 base unit of an 18-decimal token, 500 base units of
an 8-decimal one. On the dApp approval screen — and on the wait/success/error
screens, which carry that same string forward as txInfo.amount — a real
transfer or allowance was therefore stated as nothing.

The copy of formatTxValue() in src/popup/views/approval.js now extends to the
first significant digit when the first 4 decimals would all be zero and the
value is not: 0.000000000000000001 DAI, not 0.0000 DAI. Extra precision was
chosen over falling back to base units so the number stays in token units, the
same unit as the symbol printed beside it; the base-unit rendering already on
this screen means "the scale is unknown", and reusing it for a known scale
would blur the two. A genuine zero still renders 0.0000, and an amount at or
above the floor is untouched.

The 4-decimal rule stays. The separate copy of formatTxValue() in
src/shared/transactions.js, which serves the history list, is deliberately not
changed: the history detail view already shows exact precision, and balance
lists and history are out of scope here.

tests/approvalDisplayFloor.test.js drives decodeCalldata() and asserts both the
displayed line and the rawValue the confirmation screens carry, at 6, 8 and 18
decimals and across every scale from 0 to 30, plus four cases pinning the
unchanged truncation. Against this tree with the source change reverted, 4 of
its cases fail — 1 base unit at 18 decimals gives "0.0000 DAI" where
"0.000000000000000001 DAI" is expected, 500 base units at 8 decimals gives
"0.0000" where "0.000005" is expected.

make check green: 42 suites, 844 tests; verify-build 39 cases; check-censored
152 files; eslint and prettier clean in the pinned container.
clawbot self-assigned this 2026-08-23 15:18:53 +02:00
Author
Collaborator

FAIL — needs-rework.

1. The invariant does not hold on the approval screen: the Uniswap path still renders a nonzero amount as 0.0000. formatAmount() at src/shared/uniswap.js:37 is a third copy of the 4-decimal truncation, untouched by this PR. It feeds the Amount and Min. received lines of the dApp approval screen through uniswap.decode() (src/popup/views/approval.js:182), and its rawValue is carried to the wait/success/error screens by src/popup/views/approval.js:271 — the same route the fixed ERC-20 path takes. Reproduced against this head (3fb6a53) with a V2_SWAP_EXACT_IN of 50 base units of USDT and amountOutMin of 1 wei:

Amount.value    = "0.0000 USDT"
Amount.rawValue = "0.0000"
Min. received   = "0.0000 WETH"

The DoD in #322 excludes only balance lists and history; this is the approval screen itself, so it is in scope. 0.00009 WBTC is roughly $9, so sub-floor swap legs are not theoretical, and Min. received reading 0.0000 states the slippage floor as "you may receive nothing" — the same money-loss failure mode as #306 and #322. Acceptable: formatAmount() gets the same floor (or all three truncators share one helper), with tests covering a sub-floor swap input amount and a sub-floor minimum output.

2. The disclosure is incomplete. The PR body names two copies of the truncation and argues the README exception scopes the divergence; there are three, and the third is on the screen the fix claims to have fixed. Consequently the README's new exception overclaims: "on the dApp approval screen and the wait/success/error screens ... the amount is extended to its first significant digit" is true only of the ERC-20 and native-ETH lines as shipped.

3. README wording, minor. "when the first 4 decimals would all be zero and the value is not, the amount is extended to its first significant digit" does not match the code — src/popup/views/approval.js:55 tests /[1-9]/ against the whole truncated string, so 1.00005 still renders 1.0000 (which is correct). The next sentence covers the case, but the stated condition is wrong standing alone.

Verified and passing: fail-first reproduced exactly (reverting src/popup/views/approval.js to next gives 1 failed suite / 4 failing cases with the stated output); truncation is still truncation, not rounding (0.99999 renders 0.9999); a genuine zero still renders 0.0000; decimals: 0 resolves to 0 with no falsy trap; negative and sub-floor-plus-integer inputs hold the invariant; make check green in an independent clone (42 suites, 844 tests, lint stage ran uncached in the pinned container, prettier clean); CI green on 3fb6a53; base is next; merges cleanly; scope confined to the 4 files with no balance-list or history change; no prohibited attribution anywhere; commit title carries (closes #322).

Confirming the author's disclosure: 500 base units of a 6-decimal token is 0.0005 and already renders 0.0005 against head, so the issue's headline example is arithmetically wrong and that DoD test case cannot fail first. The 8- and 18-decimal substitutes plus the every-scale loop are adequate coverage for that bullet.

Disclosure: a scratch probe test was written into the review clone to produce the Uniswap output above and deleted immediately; nothing was committed or pushed.

FAIL — `needs-rework`. **1. The invariant does not hold on the approval screen: the Uniswap path still renders a nonzero amount as `0.0000`.** `formatAmount()` at `src/shared/uniswap.js:37` is a *third* copy of the 4-decimal truncation, untouched by this PR. It feeds the `Amount` and `Min. received` lines of the dApp approval screen through `uniswap.decode()` (`src/popup/views/approval.js:182`), and its `rawValue` is carried to the wait/success/error screens by `src/popup/views/approval.js:271` — the same route the fixed ERC-20 path takes. Reproduced against this head (`3fb6a53`) with a `V2_SWAP_EXACT_IN` of 50 base units of USDT and `amountOutMin` of 1 wei: ``` Amount.value = "0.0000 USDT" Amount.rawValue = "0.0000" Min. received = "0.0000 WETH" ``` The DoD in [#322](https://git.eeqj.de/sneak/AutistMask/issues/322) excludes only balance lists and history; this is the approval screen itself, so it is in scope. 0.00009 WBTC is roughly $9, so sub-floor swap legs are not theoretical, and `Min. received` reading `0.0000` states the slippage floor as "you may receive nothing" — the same money-loss failure mode as [#306](https://git.eeqj.de/sneak/AutistMask/issues/306) and [#322](https://git.eeqj.de/sneak/AutistMask/issues/322). Acceptable: `formatAmount()` gets the same floor (or all three truncators share one helper), with tests covering a sub-floor swap input amount and a sub-floor minimum output. **2. The disclosure is incomplete.** The PR body names two copies of the truncation and argues the README exception scopes the divergence; there are three, and the third is on the screen the fix claims to have fixed. Consequently the README's new exception overclaims: "on the dApp approval screen and the wait/success/error screens ... the amount is extended to its first significant digit" is true only of the ERC-20 and native-ETH lines as shipped. **3. README wording, minor.** "when the first 4 decimals would all be zero and the value is not, the amount is extended to its first significant digit" does not match the code — `src/popup/views/approval.js:55` tests `/[1-9]/` against the whole truncated string, so `1.00005` still renders `1.0000` (which is correct). The next sentence covers the case, but the stated condition is wrong standing alone. Verified and passing: fail-first reproduced exactly (reverting `src/popup/views/approval.js` to `next` gives 1 failed suite / 4 failing cases with the stated output); truncation is still truncation, not rounding (`0.99999` renders `0.9999`); a genuine zero still renders `0.0000`; `decimals: 0` resolves to 0 with no falsy trap; negative and sub-floor-plus-integer inputs hold the invariant; `make check` green in an independent clone (42 suites, 844 tests, lint stage ran uncached in the pinned container, prettier clean); CI green on `3fb6a53`; base is `next`; merges cleanly; scope confined to the 4 files with no balance-list or history change; no prohibited attribution anywhere; commit title carries ` (closes #322)`. Confirming the author's disclosure: 500 base units of a 6-decimal token is 0.0005 and already renders `0.0005` against head, so the issue's headline example is arithmetically wrong and that DoD test case cannot fail first. The 8- and 18-decimal substitutes plus the every-scale loop are adequate coverage for that bullet. Disclosure: a scratch probe test was written into the review clone to produce the Uniswap output above and deleted immediately; nothing was committed or pushed.
clawbot added needs-rework and removed needs-review labels 2026-08-23 15:25:22 +02:00
clawbot force-pushed fix/322-nonzero-amount-display-floor from 3fb6a53f77 to 5f155f6ba6 2026-08-23 15:30:13 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-08-23 15:31:05 +02:00
Author
Collaborator

PASS — independent re-review; no defects found.

Anomalies and disclosures, none blocking:

  • No fourth copy of the 4-decimal rule exists: after this change the only implementation in src/ is src/shared/amountDisplay.js, reached by src/popup/views/approval.js, src/shared/uniswap.js and src/shared/transactions.js. The remaining amount-to-string sites are a different (6-decimal, trailing-trimmed) rule in src/shared/balances.js:31,39 and src/popup/views/confirmTx.js:299, which render a sub-1e-6 quantity as 0.0 in the send screen's Current balance and the send-confirm screen's Balance and fee lines. Pre-existing, untouched here, and outside #322's scope (balances) — but it is the one place adjacent to a confirmation screen where a nonzero quantity still reads as zero, and the approval screen's max fee is now floored while the send screen's is not. Worth a separate issue, not a change to this PR.
  • The author's out-of-scope call on src/popup/views/helpers.js:203 and src/popup/views/home.js:71 is honest: both are balance-list rows, and the approval/wait/success/error screens render only txInfo.amount, decoded.details and the fee, none of which route through them. Noting that both use toFixed(4), which rounds rather than truncates, so they can both overstate and zero out — again pre-existing and out of scope.
  • Disclosure of method: in my own clone I temporarily added a scratch probe test and, separately, reverted src/shared/uniswap.js and src/popup/views/approval.js to next to reproduce the fail-first evidence. Both were reverted; nothing was committed or pushed, and the tree is back at 5f155f6.

Verified: fail-first reproduced exactly (reverting src/shared/uniswap.js — blob 09f8c6a2 at both 3fb6a53 and next, so the stated mutation is exact — gives 2 failed, 846 passed, with the two claimed expected/received strings; the third swap case passes both before and after, as labelled; reverting src/popup/views/approval.js gives the 4 ERC-20 failures). truncateAmount is byte-identical in behaviour to both removed copies across a 20-case corpus including malformed input, so the history path is unchanged. Own probes on truncateAmountNeverZero: decimals 0 renders 1.0000 with no falsy trap, decimals 1-5 exact, 1.00005 to 1.0000, 0.99999 to 0.9999, exact zero to 0.0000 at every scale 0-30, negatives, 5., .5, integer-only, 19-digit integer parts, plus a 2000-case fuzz asserting output never exceeds input and never loses the last significant digit — no nonzero rendering as zero and no zero rendering as nonzero. tokenInfo()'s decimals: 18 default untouched (#340). make check green in my own clone with the lint stage running uncached in the pinned container (#11 [lint 1/1] RUN make lint ... DONE 5.2s), 42 suites / 848 tests, prettier clean. CI green on 5f155f6 (all 3 statuses). Base next, one commit, title carries (closes #322), mergeable, README prose matches the code and names all three call sites, no prohibited attribution anywhere.

PASS — independent re-review; no defects found. Anomalies and disclosures, none blocking: - No fourth copy of the 4-decimal rule exists: after this change the only implementation in `src/` is `src/shared/amountDisplay.js`, reached by `src/popup/views/approval.js`, `src/shared/uniswap.js` and `src/shared/transactions.js`. The remaining amount-to-string sites are a different (6-decimal, trailing-trimmed) rule in `src/shared/balances.js:31,39` and `src/popup/views/confirmTx.js:299`, which render a sub-1e-6 quantity as `0.0` in the send screen's `Current balance` and the send-confirm screen's `Balance` and fee lines. Pre-existing, untouched here, and outside [#322](https://git.eeqj.de/sneak/AutistMask/issues/322)'s scope (balances) — but it is the one place adjacent to a confirmation screen where a nonzero quantity still reads as zero, and the approval screen's max fee is now floored while the send screen's is not. Worth a separate issue, not a change to this PR. - The author's out-of-scope call on `src/popup/views/helpers.js:203` and `src/popup/views/home.js:71` is honest: both are balance-list rows, and the approval/wait/success/error screens render only `txInfo.amount`, `decoded.details` and the fee, none of which route through them. Noting that both use `toFixed(4)`, which rounds rather than truncates, so they can both overstate and zero out — again pre-existing and out of scope. - Disclosure of method: in my own clone I temporarily added a scratch probe test and, separately, reverted `src/shared/uniswap.js` and `src/popup/views/approval.js` to `next` to reproduce the fail-first evidence. Both were reverted; nothing was committed or pushed, and the tree is back at `5f155f6`. Verified: fail-first reproduced exactly (reverting `src/shared/uniswap.js` — blob `09f8c6a2` at both `3fb6a53` and `next`, so the stated mutation is exact — gives `2 failed, 846 passed`, with the two claimed expected/received strings; the third swap case passes both before and after, as labelled; reverting `src/popup/views/approval.js` gives the 4 ERC-20 failures). `truncateAmount` is byte-identical in behaviour to both removed copies across a 20-case corpus including malformed input, so the history path is unchanged. Own probes on `truncateAmountNeverZero`: decimals 0 renders `1.0000` with no falsy trap, decimals 1-5 exact, `1.00005` to `1.0000`, `0.99999` to `0.9999`, exact zero to `0.0000` at every scale 0-30, negatives, `5.`, `.5`, integer-only, 19-digit integer parts, plus a 2000-case fuzz asserting output never exceeds input and never loses the last significant digit — no nonzero rendering as zero and no zero rendering as nonzero. `tokenInfo()`'s `decimals: 18` default untouched ([#340](https://git.eeqj.de/sneak/AutistMask/issues/340)). `make check` green in my own clone with the lint stage running uncached in the pinned container (`#11 [lint 1/1] RUN make lint` ... `DONE 5.2s`), 42 suites / 848 tests, prettier clean. CI green on `5f155f6` (all 3 statuses). Base `next`, one commit, title carries ` (closes #322)`, mergeable, README prose matches the code and names all three call sites, no prohibited attribution anywhere.
clawbot added needs-rebase and removed needs-review labels 2026-08-23 15:38:43 +02:00
clawbot force-pushed fix/322-nonzero-amount-display-floor from 5f155f6ba6 to 578a3bc862 2026-08-23 15:42:15 +02:00 Compare
clawbot merged commit 669c443bf9 into next 2026-08-23 15:43:04 +02:00
clawbot deleted branch fix/322-nonzero-amount-display-floor 2026-08-23 15:43:04 +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#339