fix(keychain): float→BigInt crash in token send + HMR provider exports#2623
fix(keychain): float→BigInt crash in token send + HMR provider exports#2623tarrencev wants to merge 2 commits into
Conversation
C1: SendTokenDrawer computed base units as amount * 10**decimals and passed the result to BigInt(), so a fractional amount produced a non-integer float (0.0045 * 10**18 = 4499999999999999.5) and threw 'cannot be converted to a BigInt because it is not an integer' (seen in prod on /inventory/token). Parse the raw decimal input string into base units exactly with bigint math (parseTokenAmount), thread the input string through amount.tsx, and treat invalid/over-precision input as no-amount. Adds a regression test (0.0045 @ 18). C2: provider modules exported createContext()/hooks/constants alongside the Provider, breaking Vite Fast Refresh and invalidating context identity on hot-reload (cause of dev-only 'useX must be used within XProvider' errors). Enable react-refresh/only-export-components (warn) and split the offenders (starterpack, onchain-purchase, credit-purchase, upgrade, wallets) into context/provider/hook modules. Targeted modules warning-clean; tsc, lint (0 errors), format, and keychain tests (579 passing) green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The C2 split moved CONTROLLER_VERSIONS/UpgradeContext/UpgradeInterface/ UpgradeProviderProps out of provider/upgrade.tsx into upgrade-context.ts. .storybook/ is outside the package tsconfig (so tsc -b didn't catch it), but the Vercel keychain-storybook build compiles it — fixing the stale import path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| UpgradeInterface, | ||
| UpgradeProviderProps, | ||
| } from "../src/components/provider/upgrade"; | ||
| } from "../src/components/provider/upgrade-context"; |
There was a problem hiding this comment.
Blocking: context is still referenced here, but this diff removes its definition/export.
| @@ -1,8 +1,8 @@ | |||
| import { useCallback, useEffect, useMemo, useRef, useState } from "react"; | |||
| import { STABLE_CONTROLLER } from "@/components/provider/upgrade"; | |||
| import { STABLE_CONTROLLER } from "@/components/provider/upgrade-context"; | |||
There was a problem hiding this comment.
Blocking: context is still referenced here, but this diff removes its definition/export.
| ) { | ||
| return ""; | ||
| } else { | ||
| const baseUnitAmount = parseTokenAmount( |
There was a problem hiding this comment.
Blocking: parseTokenAmount is still referenced here, but this diff removes its definition/export.
| export type ControllerVersionInfo = { | ||
| version: string; | ||
| hash: string; | ||
| outsideExecutionVersion: OutsideExecutionVersion; |
There was a problem hiding this comment.
Blocking: OutsideExecutionVersion is still referenced here, but this diff removes its definition/export.
| changes: string[]; | ||
| }; | ||
|
|
||
| export const CONTROLLER_VERSIONS: ControllerVersionInfo[] = [ |
There was a problem hiding this comment.
Blocking: ControllerVersionInfo is still referenced here, but this diff removes its definition/export.
| children: ReactNode; | ||
| } | ||
|
|
||
| /** A chain whose account is behind the target version. */ |
There was a problem hiding this comment.
Blocking: is is still referenced here, but this diff removes its definition/export.
| } | ||
|
|
||
| /** A chain whose account is behind the target version. */ | ||
| export type OutdatedChain = { rpcUrl: string; version: ControllerVersionInfo }; |
There was a problem hiding this comment.
Blocking: ControllerVersionInfo is still referenced here, but this diff removes its definition/export.
| determineUpgradePath, | ||
| useUpgrade, | ||
| } from "./upgrade"; | ||
| } from "./upgrade-context"; |
There was a problem hiding this comment.
Blocking: context is still referenced here, but this diff removes its definition/export.
| (v) => addAddressPadding(v.hash) === addAddressPadding(classHash), | ||
| ); | ||
| import { | ||
| BETA_CONTROLLER, |
There was a problem hiding this comment.
Blocking: BETA_CONTROLLER is still referenced here, but this diff removes its definition/export.
| ); | ||
| import { | ||
| BETA_CONTROLLER, | ||
| ControllerVersionInfo, |
There was a problem hiding this comment.
Blocking: ControllerVersionInfo is still referenced here, but this diff removes its definition/export.
| @@ -1,8 +1,8 @@ | |||
| import { useCallback, useEffect, useMemo, useRef, useState } from "react"; | |||
| import { STABLE_CONTROLLER } from "@/components/provider/upgrade"; | |||
| import { STABLE_CONTROLLER } from "@/components/provider/upgrade-context"; | |||
There was a problem hiding this comment.
Blocking: context is still referenced here, but this diff removes its definition/export.
| ) { | ||
| return ""; | ||
| } else { | ||
| const baseUnitAmount = parseTokenAmount( |
There was a problem hiding this comment.
Blocking: parseTokenAmount is still referenced here, but this diff removes its definition/export.
| export type ControllerVersionInfo = { | ||
| version: string; | ||
| hash: string; | ||
| outsideExecutionVersion: OutsideExecutionVersion; |
There was a problem hiding this comment.
Blocking: OutsideExecutionVersion is still referenced here, but this diff removes its definition/export.
| changes: string[]; | ||
| }; | ||
|
|
||
| export const CONTROLLER_VERSIONS: ControllerVersionInfo[] = [ |
There was a problem hiding this comment.
Blocking: ControllerVersionInfo is still referenced here, but this diff removes its definition/export.
| { | ||
| version: "1.0.4", | ||
| hash: "0x24a9edbfa7082accfceabf6a92d7160086f346d622f28741bf1c651c412c9ab", | ||
| outsideExecutionVersion: OutsideExecutionVersion.V2, |
There was a problem hiding this comment.
Blocking: OutsideExecutionVersion is still referenced here, but this diff removes its definition/export.
| } | ||
|
|
||
| /** A chain whose account is behind the target version. */ | ||
| export type OutdatedChain = { rpcUrl: string; version: ControllerVersionInfo }; |
There was a problem hiding this comment.
Blocking: ControllerVersionInfo is still referenced here, but this diff removes its definition/export.
| determineUpgradePath, | ||
| useUpgrade, | ||
| } from "./upgrade"; | ||
| } from "./upgrade-context"; |
There was a problem hiding this comment.
Blocking: context is still referenced here, but this diff removes its definition/export.
| (v) => addAddressPadding(v.hash) === addAddressPadding(classHash), | ||
| ); | ||
| import { | ||
| BETA_CONTROLLER, |
There was a problem hiding this comment.
Blocking: BETA_CONTROLLER is still referenced here, but this diff removes its definition/export.
| ); | ||
| import { | ||
| BETA_CONTROLLER, | ||
| ControllerVersionInfo, |
There was a problem hiding this comment.
Blocking: ControllerVersionInfo is still referenced here, but this diff removes its definition/export.
| import { | ||
| BETA_CONTROLLER, | ||
| ControllerVersionInfo, | ||
| determineUpgradePath, |
There was a problem hiding this comment.
Blocking: determineUpgradePath is still referenced here, but this diff removes its definition/export.
From a PostHog error triage of the Controller. Two fixes:
C1 — real prod bug: float passed to
BigInt()in token sendSendTokenDrawercomputed the base-unit amount asamount * 10 ** decimalsand passed it toBigInt(). A fractional amount yields a non-integer float — e.g.0.0045 * 10**18 = 4499999999999999.5— which throwscannot be converted to a BigInt because it is not an integer. Observed in production (x.cartridge.gg,/inventory/token/…). Fix: parse the raw decimal input string into base units exactly with bigint math (parseTokenAmount), thread the input string throughamount.tsx, and treat invalid/over-precision input as no-amount. Regression test added (0.0045@ 18 decimals).C2 — dev HMR error class:
react-refresh/only-export-componentsProvider modules exported
createContext()/hooks/constants alongside the Provider, breaking Vite Fast Refresh and invalidating context identity on hot-reload — cause of the ~100 dev-onlyuseX must be used within XProvidererrors. Enabledreact-refresh/only-export-components(warn) and split the offenders (starterpack, onchain-purchase, credit-purchase, upgrade, wallets) into context/provider/hook modules.Verification
tsc -b, lint (0 errors),format:check, keychain tests (579 passing) green. Triaged + implemented with Codex; the "credits" PostHog errors were an unmerged local WIP branch (not on main) — nothing to fix there.🤖 Generated with Claude Code