Skip to content

Frontend: five amount-scaling implementations, three of them hardcoding 7 decimals #396

Description

@zachyo

Files: frontend/components/forms/MintForm.tsx line 78; TransferForm.tsx line 67; BurnForm.tsx line 66; frontend/app/dashboard/[contractId]/components/admin/adminActions.ts lines 111 to 113; frontend/app/dashboard/[contractId]/components/TransferPanel.tsx line 200; frontend/app/my-account/components/OutgoingAllowancesSection.tsx line 70; frontend/app/dashboard/[contractId]/components/admin/MintCard.tsx line 195

Issue: Wave 8 found two scaling paths that disagreed. There are now five, and the worst three ignore the token's decimals altogether:

// MintForm.tsx:78, TransferForm.tsx:67, BurnForm.tsx:66 — identical
BigInt(Math.floor(parseFloat(formData.amount) * 1e7)),

1e7 is hardcoded. These three forms never read decimals. On a 6-decimal token every mint, transfer and burn is inflated 10x; on an 18-decimal token it is short by a factor of 10^11. The token contract accepts any decimal <= 18, and the deploy wizard offers the choice, so this is reachable by design rather than by accident.

The new admin code introduced a second float helper instead of importing the shared one:

// adminActions.ts:111 — parallel to lib/utils.ts:14, same bug, different name
export function scaleAmount(amount: string, decimals: number): bigint {
  return BigInt(Math.round(parseFloat(amount) * 10 ** decimals));
}

Every one of the 14 registered admin actions routes through scaleAmount, so the AdminPanel split inherited #395's precision loss wholesale. TransferPanel.tsx:200 is a third inline copy (Math.round(parseFloat(data.amount) * 10 ** tokenDecimals)). OutgoingAllowancesSection.tsx:70 does the inverse in floating point for display (Number(amount) / 10 ** tokenInfo.decimals), and MintCard.tsx:195 sums a batch-mint total with acc + Number(curr.amount).

This is the same drift channel that produced #83 and, before it, #29 and #54. Five hand-written copies of one conversion is why it keeps recurring.

Fix: Land #395's exact helper first, export it as the only scaling primitive along with its inverse fromBaseUnits, then delete the other four implementations and thread real decimals into the three forms. Add a lint rule or a unit test that fails on a literal 1e7 or 10 ** in app/ and components/, since this is the fourth wave to find hand-rolled scaling.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions