Skip to content

Commit 9573a84

Browse files
chore(runway): cherry-pick fix: skip useInsufficientNativeReserveError if non evm cp-7.77.0 (#30048)
- fix: skip useInsufficientNativeReserveError if non evm cp-7.77.0 (#29992) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Fixes an issue introduced by #29712, where the app would crash if a user tries to get a non-EVM swap quote. The fix was to skip `useInsufficientNativeReserveError` if it is a non-EVM network. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fixed app crashing when trying to get a Swaps quote for non-EVM networks ## **Related issues** Fixes: #29987 ## **Manual testing steps** ```gherkin 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** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/71ac2a8b-dcce-4015-a4c2-9ba02d719421 ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk guard change that prevents running EVM-only reserve logic on non-EVM chain IDs; main risk is accidentally suppressing the warning on chains that should still be checked. > > **Overview** > Prevents crashes when requesting swap/bridge quotes on non-EVM networks by short-circuiting `useInsufficientNativeReserveError` when `token.chainId` is non-EVM. > > Adds regression coverage ensuring the native-reserve warning is not shown for Solana swaps, and extends the hook tests to assert it returns `undefined` for multiple non-EVM native tokens (Solana/Bitcoin/Tron). Also updates the hook test store setup to use `legacy_createStore`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a00c033. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [662560f](662560f) Co-authored-by: infiniteflower <139582705+infiniteflower@users.noreply.github.com>
1 parent 748a66f commit 9573a84

3 files changed

Lines changed: 87 additions & 2 deletions

File tree

app/components/UI/Bridge/Views/BridgeView/BridgeView.test.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,53 @@ describe('BridgeView', () => {
817817
});
818818

819819
describe('Solana Swap', () => {
820+
it('renders non-EVM source token without native reserve warning', () => {
821+
const testState = createBridgeTestState({
822+
bridgeControllerOverrides: {
823+
quoteRequest: {
824+
insufficientBal: false,
825+
},
826+
quotesLoadingStatus: RequestStatus.FETCHED,
827+
quotes: [mockQuoteWithMetadata as unknown as QuoteResponse],
828+
},
829+
bridgeReducerOverrides: {
830+
sourceAmount: '1.0',
831+
sourceToken: {
832+
address: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501',
833+
chainId: SolScope.Mainnet,
834+
decimals: 9,
835+
image: '',
836+
name: 'Solana',
837+
symbol: 'SOL',
838+
},
839+
destToken: {
840+
address: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501',
841+
chainId: SolScope.Mainnet,
842+
decimals: 9,
843+
image: '',
844+
name: 'Solana',
845+
symbol: 'SOL',
846+
},
847+
},
848+
});
849+
850+
const { queryByText } = renderScreen(
851+
BridgeView,
852+
{
853+
name: Routes.BRIDGE.ROOT,
854+
},
855+
{ state: testState },
856+
);
857+
858+
expect(
859+
queryByText(
860+
strings('bridge.insufficient_native_reserve_title', {
861+
ticker: 'SOL',
862+
}),
863+
),
864+
).toBeNull();
865+
});
866+
820867
it('should set slippage to undefined when isSolanaSwap is true', async () => {
821868
const mockQuote = mockQuoteWithMetadata;
822869
const testState = createBridgeTestState({

app/components/UI/Bridge/hooks/useInsufficientNativeReserveError/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ export const useInsufficientNativeReserveError = ({
5555
!token?.address ||
5656
!token?.chainId ||
5757
!latestAtomicBalance ||
58-
!walletAddress
58+
!walletAddress ||
59+
isNonEvmChainId(token.chainId)
5960
) {
6061
return undefined;
6162
}

app/components/UI/Bridge/hooks/useInsufficientNativeReserveError/useInsufficientNativeReserveError.test.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { renderHook } from '@testing-library/react-hooks';
33
import { Provider } from 'react-redux';
4-
import { createStore, Store } from 'redux';
4+
import { legacy_createStore as createStore, Store } from 'redux';
55

66
import { BridgeToken } from '../../types';
77
import { BigNumber } from 'ethers';
@@ -58,6 +58,27 @@ const ethTokenOnMainnet: BridgeToken = {
5858
chainId: CHAIN_IDS.MAINNET as `0x${string}`,
5959
};
6060

61+
const nonEvmNativeTokens: BridgeToken[] = [
62+
{
63+
address: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501',
64+
symbol: 'SOL',
65+
decimals: 9,
66+
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
67+
},
68+
{
69+
address: 'bip122:000000000019d6689c085ae165831e93/slip44:0',
70+
symbol: 'BTC',
71+
decimals: 8,
72+
chainId: 'bip122:000000000019d6689c085ae165831e93',
73+
},
74+
{
75+
address: 'tron:728126428/slip44:195',
76+
symbol: 'TRX',
77+
decimals: 6,
78+
chainId: 'tron:728126428',
79+
},
80+
];
81+
6182
type RenderHookCallback<TProps, TResult> = (props: TProps) => TResult;
6283

6384
function renderHookWithWrapper<
@@ -172,6 +193,22 @@ describe('useInsufficientNativeReserveError', () => {
172193
expect(result.current).toStrictEqual(undefined);
173194
});
174195

196+
it.each(nonEvmNativeTokens)(
197+
'returns insufficientNativeReserveError=undefined for non-EVM native token $symbol',
198+
(token) => {
199+
const { result } = renderHookWithWrapper(() =>
200+
useInsufficientNativeReserveError({
201+
amount: '45',
202+
token,
203+
latestAtomicBalance: BigNumber.from('50000000000000000000'), // 50
204+
walletAddress: '0x13b7e6EBcd40777099E4c45d407745aB2de1D1F8',
205+
}),
206+
);
207+
208+
expect(result.current).toStrictEqual(undefined);
209+
},
210+
);
211+
175212
it('returns insufficientNativeReserveError=undefined when token is the native one but on a chain not concered with reserve', () => {
176213
const { result } = renderHookWithWrapper(() =>
177214
useInsufficientNativeReserveError({

0 commit comments

Comments
 (0)