Skip to content

Commit 45c4dff

Browse files
authored
feat: add hyperevm network as additional network (#37684)
<!-- 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** - Network logos - Injective: update network logo/native token - HyperEVM `ChainId: 999` `Native Token Name: HYPE` `Chain Name : HyperEVM` - Added hyperevm in additional networks. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/37684?quickstart=1) ## **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: Added hyperevm network logo and native token CHANGELOG entry: Added hyperevm network in additional network list CHANGELOG entry: Update injective logo ## **Related issues** Fixes: ## **Manual testing steps** Go to the MetaMask Extension app 1/ Navigate to "chainList.org" search for `HyperEVM` and click add new network. 2/ Confirm that the network logo is displayed correctly 3/ Confirm that the native Token logo is displayed correctly ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** Injective logo is updated <img width="300" height="500" alt="Screenshot 2025-11-18 at 00 08 42" src="https://github.com/user-attachments/assets/68a0cb53-798b-489e-9a29-1135c1985f34" /> <img width="300" height="500" alt="Screenshot 2025-11-18 at 00 09 03" src="https://github.com/user-attachments/assets/ed802609-2ae7-432e-8f69-7bb017505391" /> Hyper Evm is in Custom network <img width="300" height="500" alt="Screenshot 2025-11-18 at 00 10 09" src="https://github.com/user-attachments/assets/b0e474cd-bcba-4d35-8625-6f6975648bd7" /> <img width="300" height="500" alt="Screenshot 2025-11-18 at 00 10 37" src="https://github.com/user-attachments/assets/92e72e5d-7b52-4875-8d36-dcf7b51db19d" /> <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/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] > Adds HyperEVM (chainId 0x3e7) across constants/UI with icon, RPC, explorer, and updates multiple network logos to square; adjusts Injective icon mapping and tests. > > - **Networks**: > - **HyperEVM (`0x3e7`)**: Added to `FEATURED_RPCS` with RPC `https://rpc.hyperliquid.xyz/evm`, explorer `https://hyperevmscan.io/`, currency `HYPE`, display name, and mappings in `CHAIN_IDS`, currency symbols, explorer URL maps, image maps, and token image maps. > - **Icons/Assets**: > - Replaced/normalized square SVGs for `bitcoin-logo.svg`, `injective.svg` (removed `injective-native.svg` and mapped native token to `injective.svg`), `monad.svg`, and `sei.svg`. > - Added `app/images/hyperevm.svg` and wired into image maps. > - **UI/Tests**: > - Network list snapshots now show `HyperEVM` under Additional networks with `./images/hyperevm.svg`. > - Updated `network.test.ts` expected chain IDs to include `HyperEVM`. > - Bridge selectors test filters to `ALLOWED_BRIDGE_CHAIN_IDS` and asserts shapes accordingly. > - Adjusted network manager state tests to use non-featured example chain IDs. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5c7c5d1. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 00d8be9 commit 45c4dff

File tree

9 files changed

+160
-30
lines changed

9 files changed

+160
-30
lines changed

app/images/hyperevm.svg

Lines changed: 45 additions & 0 deletions
Loading

app/images/injective-native.svg

Lines changed: 0 additions & 10 deletions
This file was deleted.

app/images/injective.svg

Lines changed: 3 additions & 9 deletions
Loading

shared/constants/common.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const SEI_DEFAULT_BLOCK_EXPLORER_URL = 'https://seitrace.com/';
3030
const SEI_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL = 'SEI Explorer';
3131
const MONAD_DEFAULT_BLOCK_EXPLORER_URL = 'https://monadscan.com/';
3232
const MONAD_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL = 'MonadScan';
33+
const HYPEREVM_DEFAULT_BLOCK_EXPLORER_URL = 'https://hyperevmscan.io/';
34+
const HYPEREVM_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL = 'HyperEVMScan';
3335

3436
type BlockExplorerUrlMap = {
3537
[key: string]: string;
@@ -48,6 +50,7 @@ export const CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP: BlockExplorerUrlMap = {
4850
[CHAIN_IDS.BASE]: BASE_DEFAULT_BLOCK_EXPLORER_URL,
4951
[CHAIN_IDS.SEI]: SEI_DEFAULT_BLOCK_EXPLORER_URL,
5052
[CHAIN_IDS.MONAD]: MONAD_DEFAULT_BLOCK_EXPLORER_URL,
53+
[CHAIN_IDS.HYPE]: HYPEREVM_DEFAULT_BLOCK_EXPLORER_URL,
5154
} as const;
5255

5356
export const CHAINID_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL_MAP: BlockExplorerUrlMap =
@@ -64,4 +67,5 @@ export const CHAINID_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL_MAP: BlockExplore
6467
[CHAIN_IDS.BASE]: BASE_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL,
6568
[CHAIN_IDS.SEI]: SEI_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL,
6669
[CHAIN_IDS.MONAD]: MONAD_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL,
70+
[CHAIN_IDS.HYPE]: HYPEREVM_DEFAULT_BLOCK_EXPLORER_HUMAN_READABLE_URL,
6771
} as const;

shared/constants/network.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ describe('NetworkConstants', () => {
3636
Linea: CHAIN_IDS.LINEA_MAINNET,
3737
Sei: CHAIN_IDS.SEI,
3838
Monad: CHAIN_IDS.MONAD,
39+
HyperEVM: CHAIN_IDS.HYPE,
3940
};
4041

4142
FEATURED_RPCS.forEach((rpc) => {

shared/constants/network.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ export const CHAIN_IDS = {
207207
LUKSO: '0x2a',
208208
INJECTIVE: '0x6f0',
209209
MONAD: '0x8f',
210+
HYPE: '0x3e7',
210211
} as const;
211212

212213
export const CHAINLIST_CHAIN_IDS_MAP = {
@@ -368,6 +369,7 @@ export const HEMI_DISPLAY_NAME = 'Hemi';
368369
export const PLASMA_DISPLAY_NAME = 'Plasma';
369370
export const LUKSO_DISPLAY_NAME = 'Lukso';
370371
export const INJECTIVE_DISPLAY_NAME = 'Injective';
372+
export const HYPEREVM_DISPLAY_NAME = 'HyperEVM';
371373

372374
// If `network.ts` is being run in the Node.js environment, `infura-project-id.ts` will not be imported,
373375
// so we need to look at process.env.INFURA_PROJECT_ID instead.
@@ -452,6 +454,7 @@ export const CURRENCY_SYMBOLS = {
452454
PLASMA: 'XPL',
453455
LUKSO: 'LYX',
454456
INJECTIVE: 'INJ',
457+
HYPE: 'HYPE',
455458
} as const;
456459

457460
// Non-EVM currency symbols
@@ -673,7 +676,7 @@ export const PLASMA_NATIVE_TOKEN_IMAGE_URL = './images/plasma-native.svg';
673676
export const LUKSO_IMAGE_URL = './images/lukso.svg';
674677
export const LUKSO_NATIVE_TOKEN_IMAGE_URL = './images/lukso-native.svg';
675678
export const INJECTIVE_IMAGE_URL = './images/injective.svg';
676-
export const INJECTIVE_NATIVE_TOKEN_IMAGE_URL = './images/injective-native.svg';
679+
export const HYPEREVM_IMAGE_URL = './images/hyperevm.svg';
677680

678681
export const INFURA_PROVIDER_TYPES = [
679682
NETWORK_TYPES.MAINNET,
@@ -835,6 +838,7 @@ export const NETWORK_TO_NAME_MAP = {
835838
[CHAIN_IDS.PLASMA]: PLASMA_DISPLAY_NAME,
836839
[CHAIN_IDS.LUKSO]: LUKSO_DISPLAY_NAME,
837840
[CHAIN_IDS.INJECTIVE]: INJECTIVE_DISPLAY_NAME,
841+
[CHAIN_IDS.HYPE]: HYPEREVM_DISPLAY_NAME,
838842
} as const;
839843

840844
export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP = {
@@ -992,6 +996,7 @@ export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP = {
992996
[CHAIN_IDS.PLASMA]: CURRENCY_SYMBOLS.PLASMA,
993997
[CHAIN_IDS.LUKSO]: CURRENCY_SYMBOLS.LUKSO,
994998
[CHAIN_IDS.INJECTIVE]: CURRENCY_SYMBOLS.INJECTIVE,
999+
[CHAIN_IDS.HYPE]: CURRENCY_SYMBOLS.HYPE,
9951000
} as const;
9961001

9971002
/**
@@ -1168,6 +1173,7 @@ export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP: Record<string, string> = {
11681173
[CHAIN_IDS.PLASMA]: PLASMA_IMAGE_URL,
11691174
[CHAIN_IDS.LUKSO]: LUKSO_IMAGE_URL,
11701175
[CHAIN_IDS.INJECTIVE]: INJECTIVE_IMAGE_URL,
1176+
[CHAIN_IDS.HYPE]: HYPEREVM_IMAGE_URL,
11711177
} as const;
11721178

11731179
export const CHAIN_ID_TO_ETHERS_NETWORK_NAME_MAP = {
@@ -1249,7 +1255,8 @@ export const CHAIN_ID_TOKEN_IMAGE_MAP = {
12491255
[CHAIN_IDS.HEMI]: ETH_TOKEN_IMAGE_URL,
12501256
[CHAIN_IDS.PLASMA]: PLASMA_NATIVE_TOKEN_IMAGE_URL,
12511257
[CHAIN_IDS.LUKSO]: LUKSO_NATIVE_TOKEN_IMAGE_URL,
1252-
[CHAIN_IDS.INJECTIVE]: INJECTIVE_NATIVE_TOKEN_IMAGE_URL,
1258+
[CHAIN_IDS.INJECTIVE]: INJECTIVE_IMAGE_URL,
1259+
[CHAIN_IDS.HYPE]: HYPEREVM_IMAGE_URL,
12531260
[MultichainNetworks.SOLANA]: SOLANA_IMAGE_URL,
12541261
[MultichainNetworks.SOLANA_TESTNET]: SOLANA_TESTNET_IMAGE_URL,
12551262
[MultichainNetworks.SOLANA_DEVNET]: SOLANA_DEVNET_IMAGE_URL,
@@ -1545,6 +1552,20 @@ export const FEATURED_RPCS: AddNetworkFields[] = [
15451552
blockExplorerUrls: ['https://monadscan.com/'],
15461553
defaultBlockExplorerUrlIndex: 0,
15471554
},
1555+
{
1556+
chainId: CHAIN_IDS.HYPE,
1557+
name: HYPEREVM_DISPLAY_NAME,
1558+
nativeCurrency: CURRENCY_SYMBOLS.HYPE,
1559+
rpcEndpoints: [
1560+
{
1561+
url: 'https://rpc.hyperliquid.xyz/evm',
1562+
type: RpcEndpointType.Custom,
1563+
},
1564+
],
1565+
defaultRpcEndpointIndex: 0,
1566+
blockExplorerUrls: ['https://hyperevmscan.io/'],
1567+
defaultBlockExplorerUrlIndex: 0,
1568+
},
15481569
{
15491570
chainId: CHAIN_IDS.BASE,
15501571
name: BASE_DISPLAY_NAME,

ui/components/multichain/network-list-menu/__snapshots__/network-list-menu.test.tsx.snap

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,44 @@ exports[`NetworkListMenu renders properly 1`] = `
551551
</button>
552552
</div>
553553
</div>
554+
<div
555+
class="mm-box new-network-list__list-of-networks mm-box--padding-top-4 mm-box--padding-bottom-4 mm-box--display-flex mm-box--justify-content-space-between mm-box--align-items-center"
556+
data-testid="popular-network-0x3e7"
557+
>
558+
<div
559+
class="mm-box mm-box--display-flex mm-box--align-items-center"
560+
>
561+
<div
562+
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-sm mm-avatar-network mm-text--body-sm mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-md mm-box--border-color-background-default mm-box--border-width-1 box--border-style-solid"
563+
>
564+
<img
565+
alt="HyperEVM logo"
566+
class="mm-avatar-network__network-image"
567+
src="./images/hyperevm.svg"
568+
/>
569+
</div>
570+
<div
571+
class="mm-box mm-box--margin-left-4"
572+
>
573+
<p
574+
class="mm-box mm-text mm-text--body-md mm-text--ellipsis mm-box--color-text-default mm-box--background-color-transparent"
575+
>
576+
HyperEVM
577+
</p>
578+
</div>
579+
</div>
580+
<div
581+
class="mm-box mm-box--margin-left-1 mm-box--display-flex mm-box--align-items-center"
582+
>
583+
<button
584+
class="mm-box mm-text mm-button-base add-network__add-button mm-button-link mm-button-link--size-auto mm-text--body-md-medium mm-box--padding-0 mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
585+
data-testid="test-add-button"
586+
type="link"
587+
>
588+
Add
589+
</button>
590+
</div>
591+
</div>
554592
<div
555593
class="mm-box new-network-list__list-of-networks mm-box--padding-top-4 mm-box--padding-bottom-4 mm-box--display-flex mm-box--justify-content-space-between mm-box--align-items-center"
556594
data-testid="popular-network-0xa"
@@ -1621,6 +1659,44 @@ exports[`NetworkListMenu should match snapshot when editing a network 1`] = `
16211659
</button>
16221660
</div>
16231661
</div>
1662+
<div
1663+
class="mm-box new-network-list__list-of-networks mm-box--padding-top-4 mm-box--padding-bottom-4 mm-box--display-flex mm-box--justify-content-space-between mm-box--align-items-center"
1664+
data-testid="popular-network-0x3e7"
1665+
>
1666+
<div
1667+
class="mm-box mm-box--display-flex mm-box--align-items-center"
1668+
>
1669+
<div
1670+
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-sm mm-avatar-network mm-text--body-sm mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-md mm-box--border-color-background-default mm-box--border-width-1 box--border-style-solid"
1671+
>
1672+
<img
1673+
alt="HyperEVM logo"
1674+
class="mm-avatar-network__network-image"
1675+
src="./images/hyperevm.svg"
1676+
/>
1677+
</div>
1678+
<div
1679+
class="mm-box mm-box--margin-left-4"
1680+
>
1681+
<p
1682+
class="mm-box mm-text mm-text--body-md mm-text--ellipsis mm-box--color-text-default mm-box--background-color-transparent"
1683+
>
1684+
HyperEVM
1685+
</p>
1686+
</div>
1687+
</div>
1688+
<div
1689+
class="mm-box mm-box--margin-left-1 mm-box--display-flex mm-box--align-items-center"
1690+
>
1691+
<button
1692+
class="mm-box mm-text mm-button-base add-network__add-button mm-button-link mm-button-link--size-auto mm-text--body-md-medium mm-box--padding-0 mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
1693+
data-testid="test-add-button"
1694+
type="link"
1695+
>
1696+
Add
1697+
</button>
1698+
</div>
1699+
</div>
16241700
<div
16251701
class="mm-box new-network-list__list-of-networks mm-box--padding-top-4 mm-box--padding-bottom-4 mm-box--display-flex mm-box--justify-content-space-between mm-box--align-items-center"
16261702
data-testid="popular-network-0xa"

ui/components/multichain/network-manager/hooks/useNetworkManagerState.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ describe('useNetworkManagerInitialTab() tests', () => {
3333
},
3434
{
3535
scenario: 'some enabled networks are not featured',
36-
enabledNetworks: ['eip155:1', 'eip155:137', 'eip155:999'],
36+
enabledNetworks: ['eip155:1', 'eip155:137', 'eip155:1776'],
3737
expectedTab: 'custom-networks',
3838
},
3939
{
4040
scenario: 'all enabled networks are non-featured',
41-
enabledNetworks: ['eip155:999', 'eip155:1000'],
41+
enabledNetworks: ['eip155:1776', 'eip155:1000'],
4242
expectedTab: 'custom-networks',
4343
},
4444
{

ui/ducks/bridge/selectors.test.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,13 @@ describe('Bridge selectors', () => {
180180
});
181181
const result = getAllBridgeableNetworks(state as never);
182182

183-
expect(result).toHaveLength(13);
184-
expect(result[0]).toStrictEqual(
185-
expect.objectContaining({ chainId: FEATURED_RPCS[0].chainId }),
186-
);
187-
expect(result[1]).toStrictEqual(
188-
expect.objectContaining({ chainId: FEATURED_RPCS[1].chainId }),
183+
// Only FEATURED_RPCS that are explicitly allowed for bridging
184+
const allowedFeaturedRpcs = FEATURED_RPCS.filter(({ chainId }) =>
185+
(ALLOWED_BRIDGE_CHAIN_IDS as readonly string[]).includes(chainId),
189186
);
190-
FEATURED_RPCS.forEach((rpcDefinition, idx) => {
187+
188+
// Ensure all allowed FEATURED_RPCS networks are present and correctly shaped
189+
allowedFeaturedRpcs.forEach((rpcDefinition, idx) => {
191190
expect(result[idx]).toStrictEqual(
192191
expect.objectContaining({
193192
...rpcDefinition,

0 commit comments

Comments
 (0)