Skip to content

feat: Add Big Int module from Margelo#26960

Open
Cal-L wants to merge 6 commits intomainfrom
feat/MCWP-370-introduce-native-big-int
Open

feat: Add Big Int module from Margelo#26960
Cal-L wants to merge 6 commits intomainfrom
feat/MCWP-370-introduce-native-big-int

Conversation

@Cal-L
Copy link
Contributor

@Cal-L Cal-L commented Mar 4, 2026

Description

This PR only introduces the Big Int module from #20949 to reduce risk of breaking features. We will ask teams to incrementally update and test their areas once the module is used.

Changelog

CHANGELOG entry:

Related issues

Fixes:

Manual testing steps

Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]

Screenshots/Recordings

Before

After

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Adds a new BigInt-based numeric utility module and adjusts existing addHexPrefix/renderNumber behavior; mistakes here could impact value/fee formatting and conversions across the app. Changes are well-covered by extensive new unit tests but touch core number/hex handling.

Overview
Introduces a new app/util/number/bigint.ts module that mirrors the existing number helpers but uses native bigint (and @metamask/utils) for wei/token-unit conversions, fiat rendering, hex handling, and large-number localization, plus adds helpers like safeNumberToBigInt, safeBigIntToHex, toGwei, and bigIntAbs.

Updates the legacy app/util/number/index.js to refine addHexPrefix (handle non-strings, normalize 0X/-0X) and fixes renderNumber to return the full string when no decimal point is present. Adds comprehensive test coverage for the new BigInt module and extends existing tests to cover the adjusted behaviors.

Written by Cursor Bugbot for commit eef4f85. This will update automatically on new commits. Configure here.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbot metamaskbot added the team-mobile-platform Mobile Platform team label Mar 4, 2026
@Cal-L Cal-L added no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed no changelog required No changelog entry is required for this change No QA Needed Apply this label when your PR does not need any QA effort. labels Mar 4, 2026
@tommasini
Copy link
Contributor

Cursor note:

The only thing worth keeping an eye on as the migration continues is ensuring callers that use localizeLargeNumber with { includeK: true } or custom decimals remain pointed at index.js rather than bigint.ts until those options are added to the new module.

let fiatFixed = Math.round(Number(value) * base) / base;
fiatFixed = isNaN(fiatFixed) ? 0.0 : fiatFixed;
if (currencySymbols[currencyCode]) {
return `${currencySymbols[currencyCode]}${fiatFixed}`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renderFiat loses negative value currency formatting

Medium Severity

The renderFiat function in bigint.ts lost the negative value handling present in index.js. The old version extracts the sign, computes the absolute value, and formats as -$5. The new version directly interpolates fiatFixed (which may be negative) after the currency symbol, producing $-5 instead of -$5. This will cause incorrect currency formatting for any negative fiat value once callers migrate to this module.

Fix in Cursor Fix in Web

@github-actions
Copy link
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmations, SmokeTrade, SmokeWalletPlatform, SmokeNetworkAbstractions, SmokeNetworkExpansion, SmokeMultiChainAPI, SmokeRamps, SmokePerps, SmokePredictions
  • Selected Performance tags: @PerformanceAssetLoading, @PerformanceSwaps, @PerformancePredict, @PerformancePreps
  • Risk Level: high
  • AI Confidence: 86%
click to see 🤖 AI reasoning details

E2E Test Selection:
This PR introduces a new comprehensive bigint/number utility module (app/util/number/bigint.ts) and related tests. The file contains core numeric conversion and formatting logic used across the app, including:

  • Wei ↔ ETH/Gwei conversions (fromWei, toWei, toGwei)
  • Token minimal unit conversions (fromTokenMinimalUnit, toTokenMinimalUnit)
  • Fiat conversions and formatting
  • Render formatting helpers (renderFromWei, renderFromTokenMinimalUnit, renderFiatAddition)
  • Scientific notation handling (explicitly references swaps screen)

These utilities are cross-cutting and likely consumed by:

  • Transaction confirmations (gas, token amounts, fiat equivalents)
  • Swaps and bridge flows (quote display, execution amounts)
  • Perps deposits (USDC amounts)
  • Predictions (USDC balances and position sizes)
  • Ramps (buy/sell amount inputs and fiat conversions)
  • Wallet home balances and activity rendering
  • Multi-chain flows including Solana (token formatting)

Because numeric correctness directly affects user-visible balances, transaction values, gas fees, fiat displays, and swap inputs, this is a high-risk change despite being “just utilities.” Any regression could break confirmations, swaps, perps deposits, prediction positions, or balance rendering.

Selected tags:

  • SmokeConfirmations: Core dependency on amount + gas formatting.
  • SmokeTrade (+ SmokeConfirmations): Swaps/bridge rely heavily on conversion logic.
  • SmokePerps (+ SmokeWalletPlatform + SmokeConfirmations): USDC deposit math.
  • SmokePredictions (+ SmokeWalletPlatform + SmokeConfirmations): Position sizing and balances.
  • SmokeRamps: Fiat conversion + amount entry flows.
  • SmokeWalletPlatform: Wallet balances, activity list, multi-SRP display.
  • SmokeAccounts: Balance visibility across accounts and account switching.
  • SmokeNetworkAbstractions: Network-specific token filtering and display.
  • SmokeNetworkExpansion (+ SmokeConfirmations): Solana token transfers/signing.
  • SmokeMultiChainAPI (+ NetworkAbstractions + NetworkExpansion): Multi-chain session flows may surface numeric formatting in permissions + transaction paths.

Excluded:

  • FlaskBuildTests (no Snap-related changes).
  • SmokeCard (no card-specific logic touched).

Given the breadth of numeric impact across all financial flows, broad E2E coverage is justified.

Performance Test Selection:
These utilities are used in balance rendering, token list calculations, swap quote handling (explicit scientific notation handling for swaps), and trading flows (Perps and Predictions). While the changes are utility-level and not introducing new async/network logic, they are in hot paths for asset rendering and trading flows. Running AssetLoading, Swaps, Predict, and Preps performance tests mitigates regression risk in numeric-heavy UI flows.

View GitHub Actions results

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

type SignedHex = `0x${string}` | `-0x${string}`;

const MAX_DECIMALS_FOR_TOKENS = 36;
BigNumber.config({ DECIMAL_PLACES: MAX_DECIMALS_FOR_TOKENS });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global BigNumber config mutates shared library state

Medium Severity

BigNumber.config({ DECIMAL_PLACES: MAX_DECIMALS_FOR_TOKENS }) is a module-level side effect that globally changes the default decimal places from 20 to 36 for every BigNumber instance across the entire application. Any module that imports from bigint.ts (even indirectly) will silently alter the precision behavior of all existing bignumber.js consumers, including index.js and any other code relying on the default DECIMAL_PLACES of 20. This can cause subtle numerical differences in unrelated calculations throughout the app.

Fix in Cursor Fix in Web

typeof valueInput === 'string' ? valueInput : valueInput.toString();
const [from, to] = [value.indexOf(divider), 0];
return value.substring(from, to) || value;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fastSplit returns empty string for divider-at-start inputs

Medium Severity

fastSplit uses value.substring(from, to) where from is the divider index and to is always 0. When the divider is at position 0 (e.g. ".123" with default "." divider), substring(0, 0) returns "", and the || value fallback returns the entire string ".123" instead of the expected empty prefix. More critically, substring with from > to swaps the arguments, so when the divider is found at any position, it actually returns substring(0, index) — meaning the variable names from and to are misleading and the logic is coincidentally correct only due to JavaScript's substring argument-swapping behavior. This fragile, confusing implementation risks future maintenance bugs.

Fix in Cursor Fix in Web

@github-actions
Copy link
Contributor

E2E Fixture Validation — Schema is up to date
11 value mismatches detected (expected — fixture represents an existing user).
View details

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
78.2% Coverage on New Code (required ≥ 80%)
7.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog required No changelog entry is required for this change No QA Needed Apply this label when your PR does not need any QA effort. no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed size-XL team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants