1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-22 09:23:21 +01:00

feat: add new linea mainnet network (#19326)

* feat: add new linea mainnet network

* fix: removed unused condition + lint code

* fix: update tests + fix network tab issue

* feat: add feature toggle for linea mainnet

* fix: add feature toggle for linea mainnet

* feat: add linea mainnet logo

* update @metamask/eth-json-rpc-infura package to support linea networks

* update linea mainnet block explorer url

* fix: refactor linea mainnet feature toggle

* fix: update linea mainnet chain id and rpc url

* fix: update settings-search unit test

* fix: update linea mainnet feature flag

* fix: remove useless async function keyword for linea mainnet feature flag
This commit is contained in:
Victorien Gauch 2023-06-16 18:35:33 +02:00 committed by GitHub
parent 70d86ee67c
commit e4923399a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 175 additions and 18 deletions

View File

@ -805,6 +805,9 @@
"connectingToLineaGoerli": {
"message": "Connecting to Linea Goerli test network"
},
"connectingToLineaMainnet": {
"message": "Connecting to Linea Mainnet"
},
"connectingToMainnet": {
"message": "Connecting to Ethereum Mainnet"
},
@ -2138,6 +2141,9 @@
"lineaGoerli": {
"message": "Linea Goerli test network"
},
"lineaMainnet": {
"message": "Linea Mainnet"
},
"link": {
"message": "Link"
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -6,6 +6,7 @@ import { setDashboardCookie } from '@metamask-institutional/portfolio-dashboard'
import { IPFS_DEFAULT_GATEWAY_URL } from '../../../shared/constants/network';
import { LedgerTransportTypes } from '../../../shared/constants/hardware-wallets';
import { ThemeType } from '../../../shared/constants/preferences';
import { shouldShowLineaMainnet } from '../../../shared/modules/network.utils';
export default class PreferencesController {
/**
@ -69,6 +70,7 @@ export default class PreferencesController {
: LedgerTransportTypes.u2f,
transactionSecurityCheckEnabled: false,
theme: ThemeType.os,
isLineaMainnetReleased: false,
...opts.initState,
};
@ -92,6 +94,8 @@ export default class PreferencesController {
global.setPreference = (key, value) => {
return this.setFeatureFlag(key, value);
};
this._showShouldLineaMainnetNetwork();
}
// PUBLIC METHODS
@ -574,4 +578,12 @@ export default class PreferencesController {
this.store.updateState({ infuraBlocked: isBlocked });
}
/**
* A method to check is the linea mainnet network should be displayed
*/
_showShouldLineaMainnetNetwork() {
const showLineaMainnet = shouldShowLineaMainnet();
this.store.updateState({ isLineaMainnetReleased: showLineaMainnet });
}
}

View File

@ -280,7 +280,8 @@ export default class TransactionController extends EventEmitter {
if (
type !== NETWORK_TYPES.RPC &&
type !== NETWORK_TYPES.SEPOLIA &&
type !== NETWORK_TYPES.LINEA_GOERLI
type !== NETWORK_TYPES.LINEA_GOERLI &&
type !== NETWORK_TYPES.LINEA_MAINNET
) {
return new Common({
chain: type,

View File

@ -305,7 +305,8 @@
"mainnet": "ok",
"goerli": "ok",
"sepolia": "ok",
"lineaGoerli": "ok"
"lineaGoerli": "ok",
"lineaMainnet": "ok"
}
},
"send": {

View File

@ -96,6 +96,7 @@ export const NETWORK_TYPES = {
RPC: 'rpc',
SEPOLIA: 'sepolia',
LINEA_GOERLI: 'linea-goerli',
LINEA_MAINNET: 'linea-mainnet',
} as const;
/**
@ -122,6 +123,7 @@ export const NETWORK_IDS = {
LOCALHOST: '1337',
SEPOLIA: '11155111',
LINEA_GOERLI: '59140',
LINEA_MAINNET: '59144',
} as const;
/**
@ -148,6 +150,7 @@ export const CHAIN_IDS = {
PALM: '0x2a15c308d',
SEPOLIA: '0xaa36a7',
LINEA_GOERLI: '0xe704',
LINEA_MAINNET: '0xe708',
AURORA: '0x4e454152',
MOONBEAM: '0x504',
MOONBEAM_TESTNET: '0x507',
@ -165,6 +168,7 @@ export const MAINNET_DISPLAY_NAME = 'Ethereum Mainnet';
export const GOERLI_DISPLAY_NAME = 'Goerli';
export const SEPOLIA_DISPLAY_NAME = 'Sepolia';
export const LINEA_GOERLI_DISPLAY_NAME = 'Linea Goerli';
export const LINEA_MAINNET_DISPLAY_NAME = 'Linea Mainnet';
export const LOCALHOST_DISPLAY_NAME = 'Localhost 8545';
export const BSC_DISPLAY_NAME = 'Binance Smart Chain';
export const POLYGON_DISPLAY_NAME = 'Polygon';
@ -197,6 +201,9 @@ export const SEPOLIA_RPC_URL = getRpcUrl({ network: NETWORK_TYPES.SEPOLIA });
export const LINEA_GOERLI_RPC_URL = getRpcUrl({
network: NETWORK_TYPES.LINEA_GOERLI,
});
export const LINEA_MAINNET_RPC_URL = getRpcUrl({
network: NETWORK_TYPES.LINEA_MAINNET,
});
export const LOCALHOST_RPC_URL = 'http://localhost:8545';
/**
@ -230,6 +237,7 @@ export const CURRENCY_SYMBOLS = {
export const ETH_TOKEN_IMAGE_URL = './images/eth_logo.png';
export const LINEA_GOERLI_TOKEN_IMAGE_URL = './images/linea-logo-testnet.png';
export const LINEA_MAINNET_TOKEN_IMAGE_URL = './images/linea-logo-mainnet.png';
export const TEST_ETH_TOKEN_IMAGE_URL = './images/black-eth-logo.svg';
export const BNB_TOKEN_IMAGE_URL = './images/bnb.png';
export const MATIC_TOKEN_IMAGE_URL = './images/matic-token.png';
@ -247,6 +255,7 @@ export const INFURA_PROVIDER_TYPES = [
NETWORK_TYPES.GOERLI,
NETWORK_TYPES.SEPOLIA,
NETWORK_TYPES.LINEA_GOERLI,
NETWORK_TYPES.LINEA_MAINNET,
] as const;
export const TEST_CHAINS = [
@ -260,7 +269,10 @@ const typedCapitalize = <K extends string>(k: K): Capitalize<K> =>
capitalize(k) as Capitalize<typeof k>;
export const TEST_NETWORK_TICKER_MAP: {
[K in Exclude<NetworkType, 'localhost' | 'mainnet' | 'rpc'>]: string;
[K in Exclude<
NetworkType,
'localhost' | 'mainnet' | 'rpc' | 'linea-mainnet'
>]: string;
} = {
[NETWORK_TYPES.GOERLI]: `${typedCapitalize(NETWORK_TYPES.GOERLI)}${
CURRENCY_SYMBOLS.ETH
@ -298,6 +310,11 @@ export const BUILT_IN_NETWORKS = {
chainId: CHAIN_IDS.MAINNET,
blockExplorerUrl: `https://etherscan.io`,
},
[NETWORK_TYPES.LINEA_MAINNET]: {
networkId: NETWORK_IDS.LINEA_MAINNET,
chainId: CHAIN_IDS.LINEA_MAINNET,
blockExplorerUrl: 'https://lineascan.build',
},
[NETWORK_TYPES.LOCALHOST]: {
networkId: NETWORK_IDS.LOCALHOST,
chainId: CHAIN_IDS.LOCALHOST,
@ -316,18 +333,21 @@ export const NETWORK_TO_NAME_MAP = {
[NETWORK_TYPES.GOERLI]: GOERLI_DISPLAY_NAME,
[NETWORK_TYPES.SEPOLIA]: SEPOLIA_DISPLAY_NAME,
[NETWORK_TYPES.LINEA_GOERLI]: LINEA_GOERLI_DISPLAY_NAME,
[NETWORK_TYPES.LINEA_MAINNET]: LINEA_MAINNET_DISPLAY_NAME,
[NETWORK_TYPES.LOCALHOST]: LOCALHOST_DISPLAY_NAME,
[NETWORK_IDS.GOERLI]: GOERLI_DISPLAY_NAME,
[NETWORK_IDS.SEPOLIA]: SEPOLIA_DISPLAY_NAME,
[NETWORK_IDS.LINEA_GOERLI]: LINEA_GOERLI_DISPLAY_NAME,
[NETWORK_IDS.MAINNET]: MAINNET_DISPLAY_NAME,
[NETWORK_IDS.LINEA_MAINNET]: LINEA_MAINNET_DISPLAY_NAME,
[NETWORK_IDS.LOCALHOST]: LOCALHOST_DISPLAY_NAME,
[CHAIN_IDS.GOERLI]: GOERLI_DISPLAY_NAME,
[CHAIN_IDS.SEPOLIA]: SEPOLIA_DISPLAY_NAME,
[CHAIN_IDS.LINEA_GOERLI]: LINEA_GOERLI_DISPLAY_NAME,
[CHAIN_IDS.MAINNET]: MAINNET_DISPLAY_NAME,
[CHAIN_IDS.LINEA_MAINNET]: LINEA_MAINNET_DISPLAY_NAME,
[CHAIN_IDS.LOCALHOST]: LOCALHOST_DISPLAY_NAME,
} as const;
@ -336,6 +356,7 @@ export const CHAIN_ID_TO_TYPE_MAP = {
[CHAIN_IDS.GOERLI]: NETWORK_TYPES.GOERLI,
[CHAIN_IDS.SEPOLIA]: NETWORK_TYPES.SEPOLIA,
[CHAIN_IDS.LINEA_GOERLI]: NETWORK_TYPES.LINEA_GOERLI,
[CHAIN_IDS.LINEA_MAINNET]: NETWORK_TYPES.LINEA_MAINNET,
[CHAIN_IDS.LOCALHOST]: NETWORK_TYPES.LOCALHOST,
} as const;
@ -344,12 +365,14 @@ export const CHAIN_ID_TO_RPC_URL_MAP = {
[CHAIN_IDS.SEPOLIA]: SEPOLIA_RPC_URL,
[CHAIN_IDS.LINEA_GOERLI]: LINEA_GOERLI_RPC_URL,
[CHAIN_IDS.MAINNET]: MAINNET_RPC_URL,
[CHAIN_IDS.LINEA_MAINNET]: LINEA_MAINNET_RPC_URL,
[CHAIN_IDS.LOCALHOST]: LOCALHOST_RPC_URL,
} as const;
export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP = {
[CHAIN_IDS.MAINNET]: ETH_TOKEN_IMAGE_URL,
[CHAIN_IDS.LINEA_GOERLI]: LINEA_GOERLI_TOKEN_IMAGE_URL,
[CHAIN_IDS.LINEA_MAINNET]: LINEA_MAINNET_TOKEN_IMAGE_URL,
[CHAIN_IDS.AVALANCHE]: AVAX_TOKEN_IMAGE_URL,
[CHAIN_IDS.BSC]: BNB_TOKEN_IMAGE_URL,
[CHAIN_IDS.POLYGON]: MATIC_TOKEN_IMAGE_URL,
@ -367,6 +390,7 @@ export const NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP = {
[NETWORK_IDS.SEPOLIA]: NETWORK_TYPES.SEPOLIA,
[NETWORK_IDS.LINEA_GOERLI]: NETWORK_TYPES.LINEA_GOERLI,
[NETWORK_IDS.MAINNET]: NETWORK_NAMES.HOMESTEAD,
[NETWORK_IDS.LINEA_MAINNET]: NETWORK_TYPES.LINEA_MAINNET,
} as const;
export const CHAIN_ID_TO_NETWORK_ID_MAP = {
@ -374,6 +398,7 @@ export const CHAIN_ID_TO_NETWORK_ID_MAP = {
[CHAIN_IDS.GOERLI]: NETWORK_IDS.GOERLI,
[CHAIN_IDS.SEPOLIA]: NETWORK_IDS.SEPOLIA,
[CHAIN_IDS.LINEA_GOERLI]: NETWORK_IDS.LINEA_GOERLI,
[CHAIN_IDS.LINEA_MAINNET]: NETWORK_IDS.LINEA_MAINNET,
[CHAIN_IDS.LOCALHOST]: NETWORK_IDS.LOCALHOST,
} as const;
@ -420,6 +445,11 @@ export const ETHERSCAN_SUPPORTED_NETWORKS = {
subdomain: 'goerli',
networkId: CHAIN_ID_TO_NETWORK_ID_MAP[CHAIN_IDS.LINEA_GOERLI],
},
[CHAIN_IDS.LINEA_MAINNET]: {
domain: 'lineascan.build',
subdomain: defaultEtherscanSubdomainPrefix,
networkId: CHAIN_ID_TO_NETWORK_ID_MAP[CHAIN_IDS.LINEA_MAINNET],
},
[CHAIN_IDS.BSC]: {
domain: 'bscscan.com',
subdomain: defaultEtherscanSubdomainPrefix,
@ -519,6 +549,7 @@ export const BUYABLE_CHAINS_MAP: {
| typeof CHAIN_IDS.FANTOM_TESTNET
| typeof CHAIN_IDS.MOONBEAM_TESTNET
| typeof CHAIN_IDS.LINEA_GOERLI
| typeof CHAIN_IDS.LINEA_MAINNET
| typeof CHAIN_IDS.GOERLI
>]: BuyableChainSettings;
} = {

View File

@ -56,3 +56,7 @@ export function isTokenDetectionEnabledForNetwork(chainId: string | undefined) {
function isSafeInteger(value: unknown): value is number {
return Number.isSafeInteger(value);
}
export function shouldShowLineaMainnet(): boolean {
return new Date().getTime() > Date.UTC(2023, 6, 11, 18);
}

View File

@ -161,6 +161,7 @@ function defaultFixture() {
trezorModel: null,
usedNetworks: {
[CHAIN_IDS.MAINNET]: true,
[CHAIN_IDS.LINEA_MAINNET]: true,
[CHAIN_IDS.GOERLI]: true,
[CHAIN_IDS.LOCALHOST]: true,
},
@ -187,6 +188,7 @@ function defaultFixture() {
incomingTransactions: {},
incomingTxLastFetchedBlockByChainId: {
[CHAIN_IDS.MAINNET]: null,
[CHAIN_IDS.LINEA_MAINNET]: null,
[CHAIN_IDS.GOERLI]: null,
[CHAIN_IDS.SEPOLIA]: null,
[CHAIN_IDS.LINEA_GOERLI]: null,
@ -329,6 +331,7 @@ function onboardingFixture() {
trezorModel: null,
usedNetworks: {
[CHAIN_IDS.MAINNET]: true,
[CHAIN_IDS.LINEA_MAINNET]: true,
[CHAIN_IDS.GOERLI]: true,
[CHAIN_IDS.LOCALHOST]: true,
},

View File

@ -66,6 +66,8 @@ export default class LoadingNetworkScreen extends PureComponent {
return t('connectingToSepolia');
case NETWORK_TYPES.LINEA_GOERLI:
return t('connectingToLineaGoerli');
case NETWORK_TYPES.LINEA_MAINNET:
return t('connectingToLineaMainnet');
default:
return t('connectingTo', [providerId]);
}

View File

@ -62,6 +62,9 @@ function renderBackgroundColor(color) {
case Color.lineaGoerliInverse:
bgColor = BackgroundColor.lineaGoerli;
break;
case Color.lineaMainnetInverse:
bgColor = BackgroundColor.lineaMainnet;
break;
default:
bgColor = null;
break;

View File

@ -37,9 +37,16 @@ import {
MetaMetricsEventCategory,
MetaMetricsEventName,
} from '../../../../shared/constants/metametrics';
import { getCompletedOnboarding } from '../../../ducks/metamask/metamask';
import {
getCompletedOnboarding,
isLineaMainnetNetworkReleased,
} from '../../../ducks/metamask/metamask';
const UNREMOVABLE_CHAIN_IDS = [CHAIN_IDS.MAINNET, ...TEST_CHAINS];
const UNREMOVABLE_CHAIN_IDS = [
CHAIN_IDS.MAINNET,
CHAIN_IDS.LINEA_MAINNET,
...TEST_CHAINS,
];
export const NetworkListMenu = ({ onClose }) => {
const t = useI18nContext();
@ -58,6 +65,8 @@ export const NetworkListMenu = ({ onClose }) => {
const completedOnboarding = useSelector(getCompletedOnboarding);
const lineaMainnetReleased = useSelector(isLineaMainnetNetworkReleased);
useEffect(() => {
if (showTestNetworks && !showTestNetworksRef.current) {
// Scroll to the bottom of the list
@ -76,6 +85,12 @@ export const NetworkListMenu = ({ onClose }) => {
<>
<Box className="multichain-network-list-menu" ref={networkListRef}>
{networks.map((network, index) => {
if (
!lineaMainnetReleased &&
network.providerType === 'linea-mainnet'
) {
return null;
}
const isCurrentNetwork = currentChainId === network.chainId;
const canDeleteNetwork =
!isCurrentNetwork &&

View File

@ -26,6 +26,7 @@ import Chip from '../chip/chip';
import { setFirstTimeUsedNetwork } from '../../../store/actions';
import { NETWORK_TYPES } from '../../../../shared/constants/network';
import { Icon, IconName, Text } from '../../component-library';
import { getNetworkLabelKey } from '../../../helpers/utils/i18n-helper';
const NewNetworkInfo = () => {
const t = useContext(I18nContext);
@ -95,7 +96,7 @@ const NewNetworkInfo = () => {
label={
providerConfig.type === NETWORK_TYPES.RPC
? providerConfig.nickname ?? t('privateNetwork')
: t(providerConfig.type)
: t(getNetworkLabelKey(providerConfig.type))
}
labelProps={{
color: Color.textDefault,

View File

@ -35,6 +35,8 @@ export const ValidColors = [
Color.sepoliaInverse,
Color.lineaGoerli,
Color.lineaGoerliInverse,
Color.lineaMainnet,
Color.lineaMainnetInverse,
];
export const ValidTags = [

View File

@ -43,6 +43,8 @@ $color-map: (
'sepolia-inverse': --color-network-sepolia-inverse,
'linea-goerli': --color-network-linea-goerli-default,
'linea-goerli-inverse': --color-network-linea-goerli-inverse,
'linea-mainnet': --color-network-linea-mainnet-default,
'linea-mainnet-inverse': --color-network-linea-mainnet-inverse,
'localhost': --color-network-localhost-default,
'transparent': --transparent,
'flask-purple': --color-flask-default,

View File

@ -4,8 +4,10 @@
--mainnet: #29b6af;
--inherit: inherit;
--transparent: transparent;
--color-network-linea-goerli-default: #000;
--color-network-linea-goerli-default: #61dfff;
--color-network-linea-goerli-inverse: #fcfcfc;
--color-network-linea-mainnet-default: #121212;
--color-network-linea-mainnet-inverse: #fcfcfc;
// DO NOT CHANGE
// Required for the QR reader to work properly
--qr-code-white-background: #fff;

View File

@ -426,3 +426,7 @@ export function doesUserHaveALedgerAccount(state) {
return kr.type === KeyringType.ledger;
});
}
export function isLineaMainnetNetworkReleased(state) {
return state.metamask.isLineaMainnetReleased;
}

View File

@ -48,6 +48,8 @@ export enum Color {
sepolia = 'sepolia',
lineaGoerli = 'linea-goerli',
lineaGoerliInverse = 'linea-goerli-inverse',
lineaMainnet = 'linea-mainnet',
lineaMainnetInverse = 'linea-mainnet-inverse',
transparent = 'transparent',
localhost = 'localhost',
inherit = 'inherit',
@ -78,6 +80,7 @@ export enum BackgroundColor {
goerli = 'goerli',
sepolia = 'sepolia',
lineaGoerli = 'linea-goerli',
lineaMainnet = 'linea-mainnet',
transparent = 'transparent',
localhost = 'localhost',
}
@ -104,6 +107,7 @@ export enum BorderColor {
goerli = 'goerli',
sepolia = 'sepolia',
lineaGoerli = 'linea-goerli',
lineaMainnet = 'linea-mainnet',
transparent = 'transparent',
localhost = 'localhost',
backgroundDefault = 'background-default', // exception for border color when element is meant to look "cut out"
@ -129,6 +133,8 @@ export enum TextColor {
sepolia = 'sepolia',
lineaGoerli = 'linea-goerli',
lineaGoerliInverse = 'linea-goerli-inverse',
lineaMainnet = 'linea-mainnet',
lineaMainnetInverse = 'linea-mainnet-inverse',
goerliInverse = 'goerli-inverse',
sepoliaInverse = 'sepolia-inverse',
transparent = 'transparent',
@ -154,6 +160,8 @@ export enum IconColor {
sepolia = 'sepolia',
lineaGoerli = 'linea-goerli',
lineaGoerliInverse = 'linea-goerli-inverse',
lineaMainnet = 'linea-mainnet',
lineaMainnetInverse = 'linea-mainnet-inverse',
goerliInverse = 'goerli-inverse',
sepoliaInverse = 'sepolia-inverse',
}

View File

@ -226,6 +226,13 @@ export const SETTINGS_CONSTANTS = [
route: `${NETWORKS_ROUTE}#networks-mainnet`,
icon: 'fa fa-plug',
},
{
tabMessage: (t) => t('networks'),
sectionMessage: (t) => t('lineaMainnet'),
descriptionMessage: (t) => t('lineaMainnet'),
route: `${NETWORKS_ROUTE}#networks-linea-mainnet`,
icon: 'fa fa-plug',
},
{
tabMessage: (t) => t('networks'),
sectionMessage: (t) => t('goerli'),

View File

@ -171,5 +171,8 @@ export function getNetworkLabelKey(network: string): string {
if (network === NETWORK_TYPES.LINEA_GOERLI) {
return 'lineaGoerli';
}
if (network === NETWORK_TYPES.LINEA_MAINNET) {
return 'lineaMainnet';
}
return network;
}

View File

@ -173,7 +173,7 @@ describe('Settings Search Utils', () => {
});
it('should get good network section number', () => {
expect(getNumberOfSettingsInSection(t, t('networks'))).toStrictEqual(5);
expect(getNumberOfSettingsInSection(t, t('networks'))).toStrictEqual(6);
});
it('should get good experimental section number', () => {

View File

@ -62,6 +62,7 @@ export function isDefaultMetaMaskChain(chainId) {
if (
!chainId ||
chainId === CHAIN_IDS.MAINNET ||
chainId === CHAIN_IDS.LINEA_MAINNET ||
chainId === CHAIN_IDS.GOERLI ||
chainId === CHAIN_IDS.SEPOLIA ||
chainId === CHAIN_IDS.LINEA_GOERLI ||

View File

@ -426,7 +426,9 @@ export default class ConfirmApproveContent extends Component {
this.props;
const useBlockExplorer =
rpcPrefs?.blockExplorerUrl ||
[...TEST_CHAINS, CHAIN_IDS.MAINNET].includes(chainId);
[...TEST_CHAINS, CHAIN_IDS.MAINNET, CHAIN_IDS.LINEA_MAINNET].includes(
chainId,
);
const titleTokenDescription = this.getTokenName();
const tokenIdWrapped = tokenId ? ` (#${tokenId})` : '';

View File

@ -64,7 +64,9 @@ export default function ConfirmTokenTransactionBase({
const getTitleTokenDescription = (renderType) => {
const useBlockExplorer =
rpcPrefs?.blockExplorerUrl ||
[...TEST_CHAINS, CHAIN_IDS.MAINNET].includes(chainId);
[...TEST_CHAINS, CHAIN_IDS.MAINNET, CHAIN_IDS.LINEA_MAINNET].includes(
chainId,
);
const nftCollection = nftCollections.find(
(collection) =>

View File

@ -601,6 +601,8 @@ export default class Routes extends Component {
return t('connectingToSepolia');
case NETWORK_TYPES.LINEA_GOERLI:
return t('connectingToLineaGoerli');
case NETWORK_TYPES.LINEA_MAINNET:
return t('connectingToLineaMainnet');
default:
return t('connectingTo', [providerId]);
}

View File

@ -97,13 +97,13 @@ const NetworksListItem = ({
<UrlIcon
className="networks-tab__content__icon-with-fallback"
fallbackClassName="networks-tab__content__icon-with-fallback"
name={label}
name={label || getNetworkLabelKey(labelKey)}
/>
)
)}
{network.isATestNetwork && network.chainId !== CHAIN_IDS.LINEA_GOERLI && (
<UrlIcon
name={label || labelKey}
name={label || getNetworkLabelKey(labelKey)}
fallbackClassName={classnames(
'networks-tab__content__icon-with-fallback',
{

View File

@ -45,7 +45,7 @@ const defaultNetworksData = [
},
{
labelKey: NETWORK_TYPES.LINEA_GOERLI,
iconColor: '#234FD5',
iconColor: '#61dfff',
providerType: NETWORK_TYPES.LINEA_GOERLI,
rpcUrl: getRpcUrl({
network: NETWORK_TYPES.LINEA_GOERLI,
@ -55,6 +55,18 @@ const defaultNetworksData = [
ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_GOERLI],
blockExplorerUrl: 'https://goerli.lineascan.build',
},
{
labelKey: NETWORK_TYPES.LINEA_MAINNET,
iconColor: '#121212',
providerType: NETWORK_TYPES.LINEA_MAINNET,
rpcUrl: getRpcUrl({
network: NETWORK_TYPES.LINEA_MAINNET,
excludeProjectId: true,
}),
chainId: CHAIN_IDS.LINEA_MAINNET,
ticker: CURRENCY_SYMBOLS.ETH,
blockExplorerUrl: 'https://lineascan.build',
},
];
export { defaultNetworksData };

View File

@ -18,10 +18,14 @@ import {
getNetworkConfigurations,
getNetworksTabSelectedNetworkConfigurationId,
} from '../../../selectors';
import { getProviderConfig } from '../../../ducks/metamask/metamask';
import {
getProviderConfig,
isLineaMainnetNetworkReleased,
} from '../../../ducks/metamask/metamask';
import {
NETWORK_TYPES,
TEST_CHAINS,
BUILT_IN_NETWORKS,
} from '../../../../shared/constants/network';
import { defaultNetworksData } from './networks-tab.constants';
import NetworksTabContent from './networks-tab-content';
@ -52,6 +56,7 @@ const NetworksTab = ({ addNewNetwork }) => {
const networksTabSelectedNetworkConfigurationId = useSelector(
getNetworksTabSelectedNetworkConfigurationId,
);
const isLineaMainnetReleased = useSelector(isLineaMainnetNetworkReleased);
const networkConfigurationsList = Object.entries(networkConfigurations).map(
([networkConfigurationId, networkConfiguration]) => {
@ -69,8 +74,14 @@ const NetworksTab = ({ addNewNetwork }) => {
},
);
const networksToRender = [...defaultNetworks, ...networkConfigurationsList];
let networksToRender = [...defaultNetworks, ...networkConfigurationsList];
if (!isLineaMainnetReleased) {
networksToRender = networksToRender.filter(
(network) =>
network.chainId !==
BUILT_IN_NETWORKS[NETWORK_TYPES.LINEA_MAINNET].chainId,
);
}
let selectedNetwork =
networksToRender.find(
(network) =>

View File

@ -34,6 +34,8 @@ import {
CURRENCY_SYMBOLS,
TEST_NETWORK_TICKER_MAP,
LINEA_GOERLI_TOKEN_IMAGE_URL,
LINEA_MAINNET_TOKEN_IMAGE_URL,
LINEA_MAINNET_DISPLAY_NAME,
} from '../../shared/constants/network';
import {
WebHIDConnectedStatuses,
@ -1198,6 +1200,16 @@ export function getAllNetworks(state) {
providerType: NETWORK_TYPES.MAINNET,
ticker: CURRENCY_SYMBOLS.ETH,
},
{
chainId: CHAIN_IDS.LINEA_MAINNET,
nickname: LINEA_MAINNET_DISPLAY_NAME,
rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.LINEA_MAINNET],
rpcPrefs: {
imageUrl: LINEA_MAINNET_TOKEN_IMAGE_URL,
},
providerType: NETWORK_TYPES.LINEA_MAINNET,
ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_MAINNET],
},
// Custom networks added by the user
...Object.values(networkConfigurations).filter(
({ chainId }) => ![CHAIN_IDS.LOCALHOST].includes(chainId),

View File

@ -7,6 +7,14 @@ import {
} from '../../shared/constants/network';
import * as selectors from './selectors';
jest.mock('../../shared/modules/network.utils', () => {
const actual = jest.requireActual('../../shared/modules/network.utils');
return {
...actual,
shouldShowLineaMainnet: jest.fn().mockResolvedValue(true),
};
});
describe('Selectors', () => {
describe('#getSelectedAddress', () => {
it('returns undefined if selectedAddress is undefined', () => {
@ -317,7 +325,7 @@ describe('Selectors', () => {
},
},
});
expect(networks).toHaveLength(1);
expect(networks).toHaveLength(2);
});
it('returns networks with showTestNetworks on', () => {
@ -328,7 +336,7 @@ describe('Selectors', () => {
},
},
});
expect(networks.length).toBeGreaterThan(1);
expect(networks.length).toBeGreaterThan(2);
});
});