Skip to content

fix(activity): read the transaction's recorded token quantity - #1425

Merged
bmc08gt merged 2 commits into
code/cashfrom
fix/activity-recorded-token-amount
Sep 8, 2026
Merged

fix(activity): read the transaction's recorded token quantity#1425
bmc08gt merged 2 commits into
code/cashfrom
fix/activity-recorded-token-amount

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

The details screen's Tokens row was an estimate, and #1417 said as much when it shipped: estimatedTokenAmountIn priced the entry's value against the mint's current circulating supply, so a historical entry stated what that value buys today rather than what actually moved. The feed has carried the real number all along.

The number that was already there

Every entry's amount comes from the proto's Common.CryptoPaymentAmount, and ActivityFeedMessageMapper puts its quarks straight into LocalFiat.underlyingTokenAmount — USD quarks for the reserve, that mint's own quarks for anything else. It survives persistence intact as MessageEntity.amountUsdc. tokenAmountOf now scales that by the mint's decimals and formats it. No curve in the path, so nothing to be stale about.

This is the same field iOS reads for the same row in code-payments/code-ios-app#733 (ExchangedFiat.onChainAmount), which is where the divergence was spotted.

Two scale bugs that went with it

The old reading was a round trip: Fiat.tokenBalance sold the token quarks to a USD value, then estimatedTokenAmountIn bought that value back into tokens. The two legs did not agree on scale — tokenBalance passes token.decimals, estimatedTokenAmountIn hardcodes mintDecimals = 6, and every launchpad mint has ten (DefaultMintQuarksPerUnit = 10_000_000_000). And the buy leg priced against launchpadMetadata?.currentCirculatingSupplyQuarks ?: 0, so a mint whose metadata had not resolved yet was valued against a supply of zero. Both go away with the round trip.

Formatting

Trailing zeros are trimmed rather than padded to the mint's decimals: 1,204.9050000000 states no more than 1,204.905. A USDF entry that read 20.000000 now reads 20. This matches iOS's formattedQuantity.

The screenshot fixtures declared a six-decimal Jeffy, which no launchpad mint is. It is ten now, and the hand-written USDF quantities were corrected to what the mapper actually produces.

Scope

FeedItemDetails, the expandable panel in the per-token history, computes its own Tokens row the same wrong way. It is a separate legacy surface with its own layout, so it is left for a follow-up rather than folded in here.

Tests

Four cases added to TransactionDetailsMapperTest: a ten-decimal mint, a mint with no launchpad metadata, the reserve, and an unresolved mint.

#1417 shipped the details screen's Tokens row as an estimate, and said so: it
priced the entry's value against the mint's current circulating supply, so a
historical entry stated what that value buys today rather than what moved at the
time. The feed has carried the real number all along.

Every entry's amount comes from the proto's `CryptoPaymentAmount`, and
`ActivityFeedMessageMapper` puts `quarks` straight into
`LocalFiat.underlyingTokenAmount` — USD quarks for the reserve, that mint's own
quarks for anything else. It survives persistence intact as
`MessageEntity.amountUsdc`. `tokenAmountOf` now scales that by the mint's
decimals and formats it, with no curve in the path.

Dropping the round trip also drops two scale bugs it carried. It sold token
quarks to a USD value at `token.decimals` and bought them back at a hardcoded
six, which is wrong for every launchpad mint at ten; and it priced against
`launchpadMetadata?.currentCirculatingSupplyQuarks ?: 0`, so a mint whose
metadata had not resolved was valued against a supply of zero.

Trailing zeros are now trimmed rather than padded to the mint's decimals, since
`1,204.9050000000` states no more than `1,204.905`. A USDF entry that read
`20.000000` reads `20`. iOS reads the same field for the same row in
code-payments/code-ios-app#733, so the two screens state one number.

The screenshot fixtures declared a six-decimal Jeffy, which no launchpad mint
is; it is ten now, and the hand-written USDF quantities match what the mapper
actually produces.
@bmc08gt bmc08gt self-assigned this Sep 8, 2026
@github-actions github-actions Bot added the type: fix Bug fix label Sep 8, 2026
The details mapper was holding the BigDecimal shift and the DecimalFormat
itself, which is scale arithmetic rather than mapping. `Token.formattedQuantity`
takes both, next to the `decimals` the shift reads.

FeedItemDetails needs the same reading, so having one place for it is the
point.
@github-actions github-actions Bot added the area: network gRPC, connectivity, API, exchange rates label Sep 8, 2026
@bmc08gt
bmc08gt merged commit 4cbd8c1 into code/cash Sep 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: network gRPC, connectivity, API, exchange rates type: fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant