Skip to content

Commit 6ff7cb7

Browse files
authored
Merge branch 'main' into predict/clob-v2-cleanup-core
2 parents 29e54de + 5c58a8c commit 6ff7cb7

67 files changed

Lines changed: 6311 additions & 1078 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.eslintrc.js

Lines changed: 207 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,136 @@
11
/* eslint-disable import-x/no-commonjs */
2+
3+
/**
4+
* Files still allowed to import deprecated `app/util/number/index.js` during
5+
* the BN.js → BigInt migration. Kept in one array so the default import-fence
6+
* override can exclude them while the follow-up override below re-applies only
7+
* the expo-haptics / perps restrictions (see comments on those overrides).
8+
*/
9+
const utilNumberImportBurndownFiles = [
10+
'app/component-library/components-temp/CustomSpendCap/CustomInput/CustomInput.tsx',
11+
'app/component-library/components-temp/CustomSpendCap/CustomSpendCap.tsx',
12+
'app/component-library/components-temp/Price/AggregatedPercentage/AggregatedPercentage.tsx',
13+
'app/component-library/components-temp/Price/AggregatedPercentage/utils.ts',
14+
'app/components/UI/AccountInfoCard/index.js',
15+
'app/components/UI/AssetOverview/Price/Price.advanced.tsx',
16+
'app/components/UI/AssetOverview/Price/Price.legacy.tsx',
17+
'app/components/UI/AssetOverview/utils/marketDetails.ts',
18+
'app/components/UI/Bridge/components/QuoteSelectorView/QuoteRow.tsx',
19+
'app/components/UI/Bridge/components/QuoteSelectorView/index.tsx',
20+
'app/components/UI/Bridge/hooks/useBridgeQuoteData/index.ts',
21+
'app/components/UI/Bridge/hooks/useFormattedBalanceWithThreshold/index.ts',
22+
'app/components/UI/Bridge/hooks/useHasSufficientGas/index.ts',
23+
'app/components/UI/Bridge/hooks/useInsufficientBalance/index.ts',
24+
'app/components/UI/Bridge/hooks/useTokenBalanceInUsd/index.ts',
25+
'app/components/UI/Bridge/hooks/useTokensWithBalance/index.ts',
26+
'app/components/UI/Bridge/utils/exchange-rates.ts',
27+
'app/components/UI/Bridge/utils/formatNetworkFee.test.ts',
28+
'app/components/UI/Bridge/utils/formatNetworkFee.ts',
29+
'app/components/UI/Bridge/utils/transaction-history.ts',
30+
'app/components/UI/Card/hooks/useAssetBalances.tsx',
31+
'app/components/UI/Card/hooks/useCardDelegation.test.ts',
32+
'app/components/UI/Card/hooks/useCardDelegation.ts',
33+
'app/components/UI/Card/hooks/useNeedsGasFaucet.ts',
34+
'app/components/UI/Card/sdk/CardSDK.ts',
35+
'app/components/UI/CollectibleOverview/index.js',
36+
'app/components/UI/Earn/Views/EarnInputView/EarnInputView.test.tsx',
37+
'app/components/UI/Earn/Views/EarnLendingDepositConfirmationView/components/Erc20TokenHero/index.tsx',
38+
'app/components/UI/Earn/Views/EarnLendingDepositConfirmationView/index.tsx',
39+
'app/components/UI/Earn/Views/EarnLendingWithdrawalConfirmationView/index.tsx',
40+
'app/components/UI/Earn/Views/EarnWithdrawInputView/EarnWithdrawInputView.tsx',
41+
'app/components/UI/Earn/components/EarnLendingBalance/index.tsx',
42+
'app/components/UI/Earn/components/Earnings/EarningsHistory/EarningsHistory.utils.ts',
43+
'app/components/UI/Earn/components/InputDisplay/InputDisplay.test.tsx',
44+
'app/components/UI/Earn/hooks/useEarnGasFee.ts',
45+
'app/components/UI/Earn/hooks/useEarnInput.ts',
46+
'app/components/UI/Earn/hooks/useEarnings.ts',
47+
'app/components/UI/Earn/hooks/useInput.ts',
48+
'app/components/UI/Earn/hooks/useMultichainInputHandlers.ts',
49+
'app/components/UI/Earn/hooks/useMusdBalance.ts',
50+
'app/components/UI/Earn/hooks/useMusdCtaVisibility.ts',
51+
'app/components/UI/Earn/utils/number.ts',
52+
'app/components/UI/Earn/utils/token/index.ts',
53+
'app/components/UI/Earn/utils/tron.ts',
54+
'app/components/UI/HardwareWallet/AccountDetails/index.tsx',
55+
'app/components/UI/Money/constants/activityStyles.ts',
56+
'app/components/UI/Money/hooks/useMoneyAccountBalance.ts',
57+
'app/components/UI/Money/utils/moneyActivityFiat.ts',
58+
'app/components/UI/MultichainBridgeTransactionListItem/MultichainBridgeTransactionListItem.tsx',
59+
'app/components/UI/Notification/TransactionNotification/index.js',
60+
'app/components/UI/Ramp/Aggregator/Views/BuildQuote/BuildQuote.test.tsx',
61+
'app/components/UI/Ramp/Aggregator/Views/BuildQuote/BuildQuote.tsx',
62+
'app/components/UI/Ramp/Aggregator/Views/OrdersList/OrdersList.tsx',
63+
'app/components/UI/Ramp/Aggregator/Views/SendTransaction/SendTransaction.tsx',
64+
'app/components/UI/Ramp/Aggregator/components/OrderDetails.tsx',
65+
'app/components/UI/Ramp/Aggregator/components/OrderListItem/OrderListItem.tsx',
66+
'app/components/UI/Ramp/Aggregator/components/Quote/Quote.tsx',
67+
'app/components/UI/Ramp/Aggregator/hooks/useBalance.test.ts',
68+
'app/components/UI/Ramp/Aggregator/hooks/useBalance.ts',
69+
'app/components/UI/Ramp/Aggregator/hooks/useERC20GasLimitEstimation.ts',
70+
'app/components/UI/Ramp/Aggregator/hooks/useHandleSuccessfulOrder.ts',
71+
'app/components/UI/Ramp/Aggregator/hooks/useIntentAmount.ts',
72+
'app/components/UI/Ramp/Aggregator/utils/index.ts',
73+
'app/components/UI/Ramp/Deposit/utils/index.ts',
74+
'app/components/UI/Ramp/utils/getOrderAmount.ts',
75+
'app/components/UI/Ramp/utils/v2OrderToast.ts',
76+
'app/components/UI/Stake/components/StakingBalance/StakingBanners/ClaimBanner/ClaimBanner.tsx',
77+
'app/components/UI/Stake/components/StakingConfirmation/TokenValueStack/TokenValueStack.test.tsx',
78+
'app/components/UI/Stake/components/StakingConfirmation/TokenValueStack/TokenValueStack.tsx',
79+
'app/components/UI/Stake/components/StakingConfirmation/YouReceiveCard/YouReceiveCard.test.tsx',
80+
'app/components/UI/Stake/components/StakingConfirmation/YouReceiveCard/YouReceiveCard.tsx',
81+
'app/components/UI/Stake/hooks/useBalance.ts',
82+
'app/components/UI/Tokens/util/deriveBalanceFromAssetMarketDetails.test.ts',
83+
'app/components/UI/Tokens/util/deriveBalanceFromAssetMarketDetails.ts',
84+
'app/components/UI/TransactionElement/utils-gas.js',
85+
'app/components/UI/TransactionElement/utils.js',
86+
'app/components/UI/UrlAutocomplete/Result.tsx',
87+
'app/components/Views/AssetDetails/index.tsx',
88+
'app/components/Views/DetectedTokens/components/Token.tsx',
89+
'app/components/Views/GasEducationCarousel/index.js',
90+
'app/components/Views/NetworksManagement/NetworkDetailsView/hooks/useNetworkValidation.ts',
91+
'app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuyBottomSheet/useQuickBuyBottomSheet.ts',
92+
'app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuyBottomSheet/useQuickBuyQuotes.ts',
93+
'app/components/Views/SocialLeaderboard/utils/formatters.ts',
94+
'app/components/Views/UnifiedTransactionsView/useUnifiedTxActions.test.ts',
95+
'app/components/Views/confirmations/components/gas/max-base-fee-input/max-base-fee-input.tsx',
96+
'app/components/Views/confirmations/components/gas/priority-fee-input/priority-fee-input.tsx',
97+
'app/components/Views/confirmations/components/info/typed-sign-v3v4/simulation/components/native-value-display/native-value-display.tsx',
98+
'app/components/Views/confirmations/components/info/typed-sign-v3v4/simulation/components/value-display/value-display.tsx',
99+
'app/components/Views/confirmations/components/transactions/custom-amount/custom-amount.tsx',
100+
'app/components/Views/confirmations/context/send-context/utils.ts',
101+
'app/components/Views/confirmations/external/staking/hooks/useStakingDetails.ts',
102+
'app/components/Views/confirmations/hooks/earn/useCustomAmount.tsx',
103+
'app/components/Views/confirmations/hooks/gas/useCancelSpeedupGas/useCancelSpeedupGas.ts',
104+
'app/components/Views/confirmations/hooks/send/useBalance.ts',
105+
'app/components/Views/confirmations/hooks/send/useCurrencyConversions.ts',
106+
'app/components/Views/confirmations/hooks/send/usePercentageAmount.ts',
107+
'app/components/Views/confirmations/hooks/useTokenAmount.ts',
108+
'app/components/Views/confirmations/legacy/components/CustomNonceModal/index.js',
109+
'app/components/Views/confirmations/legacy/components/WatchAssetRequest/index.js',
110+
'app/components/Views/confirmations/utils/send.ts',
111+
'app/components/hooks/useAddressBalance/useAddressBalance.ts',
112+
'app/components/hooks/useGetFormattedTokensPerChain.tsx',
113+
'app/components/hooks/useGetTotalFiatBalanceCrossChains.tsx',
114+
'app/core/Engine/Engine.ts',
115+
'app/core/Engine/controllers/gas-fee-controller/gas-fee-controller-init.test.ts',
116+
'app/core/GasPolling/GasPolling.ts',
117+
'app/core/NotificationManager.js',
118+
'app/selectors/assets/assets-list.ts',
119+
'app/selectors/earnController/earn/index.ts',
120+
'app/selectors/multichain/evm.ts',
121+
// `app/util/**` importers of `./number` or `../number` (resolves to `index.js`);
122+
// same burndown contract as feature files — remove when migrated to
123+
// `../number/bigint` (or `./number/bigint` from `app/util/`).
124+
'app/util/confirm-tx.js',
125+
'app/util/conversions.js',
126+
'app/util/confirmation/gas.ts',
127+
'app/util/confirmation/transactions.ts',
128+
'app/util/custom-gas/index.js',
129+
'app/util/networks/index.js',
130+
'app/util/transactions/index.js',
131+
'app/util/transactions/index.test.ts',
132+
];
133+
2134
module.exports = {
3135
root: true,
4136
parser: '@typescript-eslint/parser',
@@ -42,6 +174,11 @@ module.exports = {
42174
'interface',
43175
],
44176
'@typescript-eslint/no-explicit-any': 'error',
177+
// Surface JSDoc @deprecated annotations at every use-site (warn for now;
178+
// ratchet to 'error' once the BN.js → BigInt migration is complete).
179+
// Pairs with the `import-x/no-restricted-paths` fence on
180+
// `app/util/number/index.js` in the app import-fence override below.
181+
'@typescript-eslint/no-deprecated': 'warn',
45182
// Under discussion
46183
'@typescript-eslint/no-duplicate-enum-values': 'off',
47184
'@typescript-eslint/no-shadow': [
@@ -466,11 +603,78 @@ module.exports = {
466603
},
467604
},
468605
{
469-
files: ['app/**/*.{ts,tsx}'],
606+
// Default app import fences (expo-haptics, perps, deprecated util/number/index.js).
607+
// `excludedFiles` applies to the whole override — listing burn-down paths
608+
// here would incorrectly skip expo/perps for those files, so burn-down is
609+
// excluded from *this* block only and picked up by the next override.
610+
files: ['app/**/*.{ts,tsx,js,jsx}'],
470611
excludedFiles: [
471-
'app/controllers/perps/**/*.{ts,tsx}',
472-
'app/util/haptics/**/*.{ts,tsx}',
612+
// Perps controller is exempt from importing itself.
613+
'app/controllers/perps/**/*.{ts,tsx,js,jsx}',
614+
// Designated expo-haptics wrapper — only this tree may import expo-haptics.
615+
'app/util/haptics/**/*.{ts,tsx,js,jsx}',
616+
// Legacy number utils + parity tests.
617+
'app/util/number/**',
618+
// BN.js → BigInt burn-down: still allowed util/number imports; see next override.
619+
...utilNumberImportBurndownFiles,
473620
],
621+
rules: {
622+
'no-restricted-imports': [
623+
'error',
624+
{
625+
paths: [
626+
{
627+
name: 'expo-haptics',
628+
message:
629+
'Import from app/util/haptics instead of expo-haptics directly.',
630+
},
631+
],
632+
patterns: [
633+
{
634+
group: ['**/controllers/perps', '**/controllers/perps/**'],
635+
message:
636+
'Use @metamask/perps-controller instead of relative imports into app/controllers/perps/.',
637+
},
638+
{
639+
group: ['expo-haptics/*'],
640+
message:
641+
'Import from app/util/haptics instead of expo-haptics directly.',
642+
},
643+
],
644+
},
645+
],
646+
// Fences the deprecated `app/util/number/index.js` module. We use
647+
// `import-x/no-restricted-paths` (not `no-restricted-imports`) because
648+
// it resolves each import to its absolute file, which means a single
649+
// entry catches every spelling that lands on `index.js` — bare
650+
// (`from '../util/number'`), explicit (`'../util/number/index'`),
651+
// and explicit-with-extension. Sibling modules like `bigint`,
652+
// `bignumber`, and `subscriptNotation` resolve to different files
653+
// and are unaffected, so no negation list is needed. Inherits the
654+
// burn-down allowlist from this override's `excludedFiles`; the
655+
// burn-down override below intentionally does not re-declare this
656+
// rule, so allow-listed files remain exempt.
657+
'import-x/no-restricted-paths': [
658+
'error',
659+
{
660+
zones: [
661+
{
662+
target: 'app',
663+
from: 'app/util/number/index.js',
664+
message:
665+
'app/util/number/index.js is deprecated. Import the BigInt-based replacement from app/util/number/bigint instead. See app/util/number/bigint-migration-reference.test.ts for migration patterns.',
666+
},
667+
],
668+
},
669+
],
670+
},
671+
},
672+
{
673+
// Re-apply expo-haptics + perps only for burn-down files. A second
674+
// override is required because ESLint replaces `no-restricted-imports`
675+
// when the same rule is set again — we cannot use one override with only
676+
// `excludedFiles` for util/number without silently dropping other fences.
677+
files: utilNumberImportBurndownFiles,
474678
rules: {
475679
'no-restricted-imports': [
476680
'error',

.github/CODEOWNERS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ app/core/Engine/README.md @MetaMask/mobile-pla
4343
app/core/Engine/types.ts @MetaMask/mobile-platform
4444
app/core/Engine/controllers/remote-feature-flag-controller/ @MetaMask/mobile-platform
4545
app/core/DeeplinkManager @MetaMask/mobile-platform
46+
# Deprecated BN.js helpers. Gated to discourage adding new exports; consumers
47+
# should migrate to app/util/number/bigint. See .eslintrc.js for the import
48+
# fence and bigint-migration-reference.test.ts for migration patterns.
49+
app/util/number/index.js @MetaMask/mobile-platform
4650
scripts/build.sh @MetaMask/mobile-platform
4751
fingerprint.config.js @MetaMask/mobile-platform
4852
builds.yml @MetaMask/mobile-platform

.github/rules/filter-rules.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ low_level_test_files: &low_level_test_files
2424
- '**/*.stories.*'
2525
- '**/*.snap'
2626

27+
# LOCALE TRANSLATION FILES
28+
locale_translation_files: &locale_translation_files
29+
- 'locales/languages/**/*.json'
30+
2731
# CONFIG FILES
2832
config_files: &config_files
2933
- '.eslint*'
@@ -47,6 +51,7 @@ e2e_ignorable:
4751
- *documentation_files
4852
- *asset_files
4953
- *low_level_test_files
54+
- *locale_translation_files
5055
- *config_files
5156
- *ci_files
5257

@@ -74,6 +79,7 @@ android_or_ignorable:
7479
- *documentation_files
7580
- *asset_files
7681
- *low_level_test_files
82+
- *locale_translation_files
7783
- *config_files
7884
- *ci_files
7985

@@ -82,6 +88,7 @@ ios_or_ignorable:
8288
- *documentation_files
8389
- *asset_files
8490
- *low_level_test_files
91+
- *locale_translation_files
8592
- *config_files
8693
- *ci_files
8794

.github/workflows/build.yml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -419,20 +419,14 @@ jobs:
419419
run: node scripts/rename-artifacts.js ${{ matrix.platform }}
420420

421421
# Upload build artifacts (only if build succeeded)
422-
# ios_simulator_path is set by scripts/rename-artifacts.js (staged under ios-simulator-upload/
423-
# in CI so upload-artifact uploads a .zip file, not a .app directory).
424422
- name: Upload iOS simulator app
425-
if: success() && matrix.platform == 'ios' && env.IS_SIM_BUILD == 'true'
423+
if: matrix.platform == 'ios' && env.IS_SIM_BUILD == 'true'
426424
uses: actions/upload-artifact@v4
427425
with:
428426
name: ios-app-${{ inputs.build_name }}
429427
path: ${{ steps.rename.outputs.ios_simulator_path }}
430428
if-no-files-found: error
431429

432-
- name: Remove iOS simulator staging directory
433-
if: success() && matrix.platform == 'ios' && env.IS_SIM_BUILD == 'true'
434-
run: rm -rf ios-simulator-upload
435-
436430
- name: Upload iOS IPA
437431
if: matrix.platform == 'ios' && (env.IS_SIM_BUILD != 'true' || env.IS_DEVICE_BUILD == 'true')
438432
uses: actions/upload-artifact@v4

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ To learn how to contribute to the MetaMask codebase, visit our [Contributor Docs
1515
## Documentation
1616

1717
- [Architecture](./docs/readme/architecture.md)
18+
- [BigInt number migration](./docs/bigint-migration-guide.md) (deprecated `app/util/number/index.js` burndown and ESLint allowlist)
1819
- [Expo Development Environment Setup](./docs/readme/expo-environment.md)
1920
- [Native Development Environment Setup](./docs/readme/environment.md)
2021
- [Build Troubleshooting](./docs/readme/troubleshooting.md)

app/components/UI/Perps/Views/PerpsWithdrawView/PerpsWithdrawView.test.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,18 @@ describe('PerpsWithdrawView', () => {
277277
beforeEach(() => {
278278
jest.clearAllMocks();
279279
(useNavigation as jest.Mock).mockReturnValue(mockNavigation);
280+
const mockUsePerpsLiveAccount =
281+
jest.requireMock('../../hooks/stream').usePerpsLiveAccount;
282+
mockUsePerpsLiveAccount.mockReturnValue({
283+
account: {
284+
availableBalance: '1000.00',
285+
marginUsed: '0.00',
286+
unrealizedPnl: '0.00',
287+
returnOnEquity: '0.00',
288+
totalBalance: '1000.00',
289+
},
290+
isInitialLoading: false,
291+
});
280292
});
281293

282294
describe('Component Rendering', () => {
@@ -296,6 +308,32 @@ describe('PerpsWithdrawView', () => {
296308
).toBeOnTheScreen();
297309
});
298310

311+
it('uses availableToTradeBalance for the displayed Unified Account balance', () => {
312+
const mockUsePerpsLiveAccount =
313+
jest.requireMock('../../hooks/stream').usePerpsLiveAccount;
314+
mockUsePerpsLiveAccount.mockReturnValue({
315+
account: {
316+
availableBalance: '0.00',
317+
availableToTradeBalance: '2500.00',
318+
marginUsed: '0.00',
319+
unrealizedPnl: '0.00',
320+
returnOnEquity: '0.00',
321+
totalBalance: '2500.00',
322+
},
323+
isInitialLoading: false,
324+
});
325+
326+
renderWithProviders(<PerpsWithdrawView />);
327+
328+
expect(
329+
screen.getByText(
330+
strings('perps.withdrawal.available_balance', {
331+
amount: '$2,500',
332+
}),
333+
),
334+
).toBeOnTheScreen();
335+
});
336+
299337
it('renders percentage buttons when focused', () => {
300338
renderWithProviders(<PerpsWithdrawView />);
301339

app/components/UI/Perps/Views/PerpsWithdrawView/PerpsWithdrawView.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,16 @@ const PerpsWithdrawView: React.FC = () => {
106106
// Get withdrawal tokens from hook
107107
const { destToken } = useWithdrawTokens();
108108

109-
// Truncate to 2 decimals so the user can withdraw exactly what they see.
109+
// Release-branch bridge for Unified Account: availableToTradeBalance includes
110+
// collateral HL can use in target mode. The full balance contract will replace
111+
// this with an explicit withdrawableBalance field. Truncate so users can
112+
// withdraw exactly the amount they see.
110113
const availableBalance = useMemo(() => {
111-
if (!account?.availableBalance) return 0;
112-
return truncateToTwoDecimals(parseCurrencyString(account.availableBalance));
113-
}, [account?.availableBalance]);
114+
const balance =
115+
account?.availableToTradeBalance ?? account?.availableBalance;
116+
if (!balance) return 0;
117+
return truncateToTwoDecimals(parseCurrencyString(balance));
118+
}, [account?.availableBalance, account?.availableToTradeBalance]);
114119

115120
const formattedBalance = useMemo(
116121
() => formatPerpsFiat(availableBalance),
@@ -152,7 +157,7 @@ const PerpsWithdrawView: React.FC = () => {
152157
usePerpsMeasurement({
153158
traceName: TraceName.PerpsWithdrawView,
154159
conditions: [
155-
!!account?.availableBalance,
160+
!!(account?.availableToTradeBalance ?? account?.availableBalance),
156161
!!destToken,
157162
availableBalance !== undefined,
158163
],

0 commit comments

Comments
 (0)