Conversation
a1aa988 to
9feba57
Compare
9feba57 to
7b64a6a
Compare
| * The raw blockchain balance without decimals applied (e.g., "1500000000" for 1.5 SOL). | ||
| * This provides precision for calculations using BigInt/BigNumber. | ||
| */ | ||
| rawAmount: string(), |
There was a problem hiding this comment.
rawAmount lacks numeric validation unlike amount field
Medium Severity
The rawAmount field uses string() for validation while amount uses StringNumberStruct which validates the string is numeric. This inconsistency allows non-numeric values like "hello" or "" to pass validation for rawAmount. Since the PR states rawAmount is intended for "calculations using BigInt/BigNumber", invalid non-numeric strings would cause runtime errors when consumers attempt BigInt(rawAmount). Using the same StringNumberStruct (or a stricter integer-only pattern) would provide consistent validation and catch invalid values at the API boundary rather than during calculations.
Additional Locations (1)
|
This PR is marked as stale because it has been open for 60 days with no activity. Please remove the stale label or leave a comment, or it will be closed in 14 days. |
Description
This PR adds a new required
rawAmountfield to theBalanceStructandFungibleAssetAmountStructtypes in the keyring API. This field stores the raw blockchain balance without decimals applied, providing precision for calculations usingBigInt/BigNumber.Motivation
The Problem
When snaps return balance data via
keyring_getAccountBalances, theamountfield contains the human-readable value with decimals already applied (e.g.,"1.5"for 1.5 SOL). However, this causes two issues:Double division bug: If amount is already normalized ("1.5"), dividing by decimals again produces incorrect values
Precision loss: parseFloat() has limited precision (~15-17 significant digits), causing data loss for large numbers:
parseFloat("1000000000000000001"); // → 1000000000000000000 (last digit lost!)
parseFloat("1000000000000000001"); // → 1000000000000000000 (last digit lost!)
This PR
Add a rawAmount field that stores the exact blockchain value as a string:
{
amount: "1.5", // UI amount (backward compatible)
rawAmount: "1500000000", // Raw blockchain value (precise)
unit: "SOL"
}
{ amount: "1.5", // UI amount (backward compatible) rawAmount: "1500000000", // Raw blockchain value (precise) unit: "SOL"}
This enables:
Backward compatibility: Existing consumers continue using amount
Precision: New consumers use rawAmount with BigInt/BigNumber for exact calculations
Changes
@metamask/keyring-api
BalanceStruct - Used by keyring_getAccountBalances response:
export const BalanceStruct = object({ amount: StringNumberStruct, // Human-readable (e.g., "1.5") unit: string(), // Symbol (e.g., "SOL") rawAmount: string(), // NEW: Raw value (e.g., "1500000000")});
FungibleAssetAmountStruct - Used by AccountBalancesUpdated event and transaction assets:
Snap Updates (Solana, Tron, BTC)
Updated getAccountBalances to return both fields:
Breaking Change
This is a breaking change - all snaps implementing keyring_getAccountBalances must now return rawAmount. All snaps have been updated accordingly.
Testing
Updated unit tests for BalanceStruct validation
Updated type definition tests (*.test-d.ts)
Updated mock data in KeyringClient.test.ts and SnapKeyring.test.ts
Note
Breaking change: precise balances via
rawAmountrawAmountinBalanceandFungibleAssetAmount(balance.ts,asset.ts); keep human-readableamountfor compatibilityAssetStruct, transaction fee/participant examples, and docs to includerawAmount; refine comments for clarityrawAmountinAccountBalancesUpdatedpayloads; adjust validation and type tests (events.test-d.ts,balance.test(-d).ts,asset.test(-d).ts,transaction.test(-d).ts)rawAmount(SnapKeyring.test.ts,KeyringClient.test.ts)Written by Cursor Bugbot for commit 7b64a6a. This will update automatically on new commits. Configure here.