Skip to content

Commit 060968e

Browse files
chore(runway): cherry-pick fix: cp-7.62.0 Fix unknown asset presentation when nonEVM selected on network manager (#25056)
- fix: cp-7.62.0 Fix unknown asset presentation when nonEVM selected on network manager (#25024) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **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? --> This PR aims to fix unknown asset presentation when nonEVM is selected on network manager. ## **Changelog** No changelog as it's regression from last release. <!-- 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: ## **Related issues** Fixes: ## **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** https://github.com/user-attachments/assets/b0207e02-0931-4325-bfc8-4e75fa1ab7c8 ## **Pre-merge author checklist** - [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. ## **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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Fixes token resolution in confirmations and adds targeted tests. > > - Updates `useTokenAsset` to fetch tokens per `from` address using `selectAccountTokensAcrossChainsForAddress` > - Adds `useMemo` optimization and explicit handling for missing `chainId` or transaction metadata, returning `strings('token.unknown')` > - Continues using `getNativeTokenAddress` for native-token transaction types > - Adds tests covering unknown token, successful asset lookup, EVM send with non-EVM selected, missing `chainId`, and missing metadata > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 605f574. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [13d2932](13d2932) Co-authored-by: OGPoyraz <omergoktugpoyraz@gmail.com>
1 parent 89e91c6 commit 060968e

2 files changed

Lines changed: 117 additions & 28 deletions

File tree

app/components/Views/confirmations/hooks/useTokenAsset.test.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import merge from 'lodash/merge';
2+
13
import { strings } from '../../../../../locales/i18n';
24
import { useTokenAsset } from './useTokenAsset';
35
import { renderHookWithProvider } from '../../../../util/test/renderWithProvider';
46
import { backgroundState } from '../../../../util/test/initial-root-state';
57
import { stakingDepositConfirmationState } from '../../../../util/test/confirm-data-helpers';
8+
import { useTransactionMetadataRequest } from './transactions/useTransactionMetadataRequest';
69

710
jest.mock('./transactions/useTransactionMetadataRequest', () => ({
811
useTransactionMetadataRequest: jest.fn().mockReturnValue({
@@ -14,12 +17,30 @@ jest.mock('./transactions/useTransactionMetadataRequest', () => ({
1417
}),
1518
}));
1619

20+
const mockUseTransactionMetadataRequest =
21+
useTransactionMetadataRequest as jest.Mock;
22+
1723
describe('useTokenAsset', () => {
1824
beforeEach(() => {
1925
jest.clearAllMocks();
26+
mockUseTransactionMetadataRequest.mockReturnValue({
27+
chainId: '0x1',
28+
txParams: {
29+
to: '0x0000000000000000000000000000000000000000',
30+
from: '0x0000000000000000000000000000000000000000',
31+
},
32+
});
2033
});
2134

2235
it('returns "unknown" token name and symbol when the asset symbol is not found', () => {
36+
mockUseTransactionMetadataRequest.mockReturnValue({
37+
chainId: '0x1',
38+
txParams: {
39+
to: '0x1234567890123456789012345678901234567890',
40+
from: '0x0000000000000000000000000000000000000000',
41+
},
42+
});
43+
2344
const { result } = renderHookWithProvider(useTokenAsset, {
2445
state: {
2546
engine: {
@@ -44,4 +65,63 @@ describe('useTokenAsset', () => {
4465
});
4566
expect(result.current.displayName).toEqual('ETH');
4667
});
68+
69+
it('returns correct token when non-EVM network is selected but sending EVM token', () => {
70+
const evmAddress = '0x0000000000000000000000000000000000000000';
71+
mockUseTransactionMetadataRequest.mockReturnValue({
72+
chainId: '0x1',
73+
txParams: {
74+
to: evmAddress,
75+
from: evmAddress,
76+
},
77+
});
78+
79+
const stateWithNonEvmSelected = merge({}, stakingDepositConfirmationState, {
80+
engine: {
81+
backgroundState: {
82+
AccountsController: {
83+
internalAccounts: {
84+
selectedAccount: '0x0000000000000000000000000000000000000000',
85+
},
86+
},
87+
},
88+
},
89+
});
90+
91+
const { result } = renderHookWithProvider(useTokenAsset, {
92+
state: stateWithNonEvmSelected,
93+
});
94+
95+
expect(result.current.asset).toMatchObject({
96+
name: 'Ethereum',
97+
symbol: 'Ethereum',
98+
});
99+
expect(result.current.displayName).toEqual('ETH');
100+
});
101+
102+
it('returns "unknown" when chainId is not provided', () => {
103+
mockUseTransactionMetadataRequest.mockReturnValue({
104+
chainId: undefined,
105+
txParams: {
106+
to: '0x0000000000000000000000000000000000000000',
107+
from: '0x0000000000000000000000000000000000000000',
108+
},
109+
});
110+
111+
const { result } = renderHookWithProvider(useTokenAsset, {
112+
state: stakingDepositConfirmationState,
113+
});
114+
115+
expect(result.current.displayName).toEqual(strings('token.unknown'));
116+
});
117+
118+
it('returns "unknown" when transaction metadata is not available', () => {
119+
mockUseTransactionMetadataRequest.mockReturnValue(undefined);
120+
121+
const { result } = renderHookWithProvider(useTokenAsset, {
122+
state: stakingDepositConfirmationState,
123+
});
124+
125+
expect(result.current.displayName).toEqual(strings('token.unknown'));
126+
});
47127
});
Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { Hex } from '@metamask/utils';
22
import { TransactionType } from '@metamask/transaction-controller';
33
import { useSelector } from 'react-redux';
4+
import { useMemo } from 'react';
5+
import { getNativeTokenAddress } from '@metamask/assets-controllers';
46

57
import { strings } from '../../../../../locales/i18n';
6-
import { selectAccountTokensAcrossChains } from '../../../../selectors/multichain';
8+
import { selectAccountTokensAcrossChainsForAddress } from '../../../../selectors/multichain';
79
import { safeToChecksumAddress } from '../../../../util/address';
810
import { TokenI } from '../../../UI/Tokens/types';
911
import { useTransactionMetadataRequest } from './transactions/useTransactionMetadataRequest';
10-
import { getNativeTokenAddress } from '@metamask/assets-controllers';
12+
import { RootState } from '../../../../reducers';
1113

1214
const TypesForNativeToken = [
1315
TransactionType.simpleSend,
@@ -24,30 +26,37 @@ export const useTokenAsset = () => {
2426
} = useTransactionMetadataRequest() ?? {};
2527

2628
const nativeTokenAddress = getNativeTokenAddress(chainId as Hex);
27-
const tokens = useSelector(selectAccountTokensAcrossChains);
28-
29-
if (!chainId) {
30-
return { displayName: strings('token.unknown') };
31-
}
32-
33-
const tokenAddress =
34-
transactionType && TypesForNativeToken.includes(transactionType)
35-
? nativeTokenAddress
36-
: safeToChecksumAddress(txParams?.to)?.toLowerCase();
37-
38-
const asset = tokens[chainId]?.find(
39-
({ address }) => address.toLowerCase() === tokenAddress,
40-
) as TokenI;
41-
42-
if (!asset) {
43-
return { asset: {}, displayName: strings('token.unknown') };
44-
}
45-
46-
const { name, symbol, ticker } = asset;
47-
const displayName = ticker ?? symbol ?? name ?? strings('token.unknown');
48-
49-
return {
50-
asset,
51-
displayName,
52-
};
29+
const fromAddress = txParams?.from;
30+
const tokens = useSelector((state: RootState) =>
31+
selectAccountTokensAcrossChainsForAddress(state, fromAddress),
32+
);
33+
34+
const result = useMemo(() => {
35+
if (!chainId) {
36+
return { displayName: strings('token.unknown') };
37+
}
38+
39+
const tokenAddress =
40+
transactionType && TypesForNativeToken.includes(transactionType)
41+
? nativeTokenAddress
42+
: safeToChecksumAddress(txParams?.to)?.toLowerCase();
43+
44+
const asset = tokens[chainId]?.find(
45+
({ address }) => address.toLowerCase() === tokenAddress,
46+
) as TokenI;
47+
48+
if (!asset) {
49+
return { asset: {}, displayName: strings('token.unknown') };
50+
}
51+
52+
const { name, symbol, ticker } = asset;
53+
const displayName = ticker ?? symbol ?? name ?? strings('token.unknown');
54+
55+
return {
56+
asset,
57+
displayName,
58+
};
59+
}, [chainId, transactionType, nativeTokenAddress, txParams?.to, tokens]);
60+
61+
return result;
5362
};

0 commit comments

Comments
 (0)