Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ exports[`CellSelectWithMenu should render with default settings correctly 1`] =
"alignItems": "center",
"backgroundColor": "#ffffff",
"flexDirection": "row",
"paddingRight": 20,
"width": "100%",
}
}
>
<TouchableOpacity
disabled={false}
style={
{
"flex": 1,
"opacity": 1,
"padding": 16,
"position": "relative",
"width": "90%",
"zIndex": 1,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ListItemMultiSelectButtonProps } from './ListItemMultiSelectButton.type
// Defaults
export const DEFAULT_LISTITEMMULTISELECT_GAP = 16;
export const BUTTON_TEST_ID = 'button-menu-select-test-id';
export const BUTTON_TEXT_TEST_ID = 'button-text-select-test-id';

// Sample consts
export const SAMPLE_LISTITEMMULTISELECT_PROPS: ListItemMultiSelectButtonProps =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ const styleSheet = (params: {
return StyleSheet.create({
base: Object.assign(
{
flex: 1,
position: 'relative',
opacity: isDisabled ? 0.5 : 1,
padding: 16,
width: '90%',
zIndex: 1,
} as ViewStyle,
style,
Expand Down Expand Up @@ -71,10 +71,8 @@ const styleSheet = (params: {
backgroundColor: isSelected
? colors.primary.muted
: colors.background.default,
paddingRight: 20,
flexDirection: 'row',
alignItems: 'center',
width: '100%',
},
itemColumn: {
display: 'flex',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ exports[`ListItemMultiSelectButton should render correctly with default props 1`
"alignItems": "center",
"backgroundColor": "#ffffff",
"flexDirection": "row",
"paddingRight": 20,
"width": "100%",
}
}
>
<TouchableOpacity
disabled={false}
style={
{
"flex": 1,
"opacity": 1,
"padding": 16,
"position": "relative",
"width": "90%",
"zIndex": 1,
}
}
Expand Down
1 change: 0 additions & 1 deletion app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,6 @@ const App = (props) => {
component={MultiRpcModal}
/>
) : null}

<Stack.Screen
name={Routes.SHEET.SHOW_TOKEN_ID}
component={ShowTokenIdSheet}
Expand Down
1 change: 0 additions & 1 deletion app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,6 @@ const Main = (props) => {
networkImageSource: networkImage,
});
}

previousNetworkConfigurations.current = networkConfigurations;
}, [networkConfigurations, networkName, networkImage, toastRef]);

Expand Down
23 changes: 9 additions & 14 deletions app/components/UI/AccountInfoCard/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
MOCK_ADDRESS_1,
} from '../../../util/test/accountsControllerTestUtils';
import { RootState } from '../../../reducers';
import { RpcEndpointType } from '@metamask/network-controller';
import { mockNetworkState } from '../../../util/test/network';

jest.mock('../../../core/Engine', () => ({
resetState: jest.fn(),
Expand Down Expand Up @@ -48,20 +50,13 @@ const mockInitialState: DeepPartial<RootState> = {
},
},
NetworkController: {
selectedNetworkClientId: 'sepolia',
networksMetadata: {},
networkConfigurations: {
sepolia: {
id: 'sepolia',
rpcUrl: 'http://localhost/v3/',
chainId: '0xaa36a7',
ticker: 'ETH',
nickname: 'sepolia',
rpcPrefs: {
blockExplorerUrl: 'https://etherscan.com',
},
},
},
...mockNetworkState({
chainId: '0xaa36a7',
id: 'mainnet',
nickname: 'Sepolia',
ticker: 'SepoliaETH',
type: RpcEndpointType.Infura,
}),
},
TokenBalancesController: {
contractBalances: {},
Expand Down
5 changes: 4 additions & 1 deletion app/components/UI/NetworkModal/NetworkAdded/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const createStyles = (colors: any) =>
flexDirection: 'row',
paddingVertical: 16,
},
base: {
padding: 16,
},
button: {
flex: 1,
},
Expand Down Expand Up @@ -41,7 +44,7 @@ const NetworkAdded = (props: NetworkAddedProps) => {
const styles = createStyles(colors);

return (
<View>
<View style={styles.base}>
<Text centered bold black big>
{strings('networks.new_network')}
</Text>
Expand Down
178 changes: 145 additions & 33 deletions app/components/UI/NetworkModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ import { useMetrics } from '../../../components/hooks/useMetrics';
import { toHex } from '@metamask/controller-utils';
import { rpcIdentifierUtility } from '../../../components/hooks/useSafeChains';
import Logger from '../../../util/Logger';
import { selectNetworkConfigurations } from '../../../selectors/networkController';
import {
NetworkConfiguration,
RpcEndpointType,
AddNetworkFields,
} from '@metamask/network-controller';

export interface SafeChain {
chainId: string;
Expand Down Expand Up @@ -162,6 +168,10 @@ const NetworkModals = (props: NetworkProps) => {
selectUseSafeChainsListValidation,
);

const networkConfigurationByChainId = useSelector(
selectNetworkConfigurations,
);

const customNetworkInformation = {
chainId,
blockExplorerUrl,
Expand Down Expand Up @@ -189,52 +199,154 @@ const NetworkModals = (props: NetworkProps) => {
checkNetwork();
}, [checkNetwork]);

const closeModal = () => {
const closeModal = async () => {
const { NetworkController } = Engine.context;
const url = new URLPARSE(rpcUrl);
!isPrivateConnection(url.hostname) && url.set('protocol', 'https:');
NetworkController.upsertNetworkConfiguration(
{
rpcUrl: url.href,

const existingNetwork = networkConfigurationByChainId[chainId];
let networkClientId;

if (existingNetwork) {
const updatedNetwork = await NetworkController.updateNetwork(
existingNetwork.chainId,
existingNetwork,
existingNetwork.chainId === chainId
? {
replacementSelectedRpcEndpointIndex:
existingNetwork.defaultRpcEndpointIndex,
}
: undefined,
);

networkClientId =
updatedNetwork?.rpcEndpoints?.[updatedNetwork.defaultRpcEndpointIndex]
?.networkClientId;
} else {
const addedNetwork = await NetworkController.addNetwork({
chainId,
ticker,
nickname,
rpcPrefs: { blockExplorerUrl },
},
{
// Metrics-related properties required, but the metric event is a no-op
// TODO: Use events for controller metric events
referrer: 'ignored',
source: 'ignored',
},
);
blockExplorerUrls: [blockExplorerUrl],
defaultRpcEndpointIndex: 0,
defaultBlockExplorerUrlIndex: 0,
name: nickname,
nativeCurrency: ticker,
rpcEndpoints: [
{
url: rpcUrl,
name: nickname,
type: RpcEndpointType.Custom,
},
],
});

networkClientId =
addedNetwork?.rpcEndpoints?.[addedNetwork.defaultRpcEndpointIndex]
?.networkClientId;
}

if (networkClientId) {
await NetworkController.setActiveNetwork(networkClientId);
}

onClose();
};

const switchNetwork = () => {
const handleExistingNetwork = async (
existingNetwork: NetworkConfiguration,
networkId: string,
) => {
const { NetworkController } = Engine.context;
const updatedNetwork = await NetworkController.updateNetwork(
existingNetwork.chainId,
existingNetwork,
existingNetwork.chainId === networkId
? {
replacementSelectedRpcEndpointIndex:
existingNetwork.defaultRpcEndpointIndex,
}
: undefined,
);

const { networkClientId } =
updatedNetwork?.rpcEndpoints?.[updatedNetwork.defaultRpcEndpointIndex] ??
{};

await NetworkController.setActiveNetwork(networkClientId);
};

const handleNewNetwork = async (
networkId: `0x${string}`,
networkRpcUrl: string,
name: string,
nativeCurrency: string,
networkBlockExplorerUrl: string,
) => {
const { NetworkController } = Engine.context;
const networkConfig = {
chainId: networkId,
blockExplorerUrls: networkBlockExplorerUrl
? [networkBlockExplorerUrl]
: [],
defaultRpcEndpointIndex: 0,
defaultBlockExplorerUrlIndex: blockExplorerUrl ? 0 : undefined,
name,
nativeCurrency,
rpcEndpoints: [
{
url: networkRpcUrl,
name,
type: RpcEndpointType.Custom,
},
],
} as AddNetworkFields;

return NetworkController.addNetwork(networkConfig);
};

const handleNavigation = (
onSwitchNetwork: () => void,
networkSwitchPopToWallet: boolean,
) => {
if (onSwitchNetwork) {
onSwitchNetwork();
} else {
networkSwitchPopToWallet
? navigation.navigate('WalletView')
: navigation.goBack();
}
};

const switchNetwork = async () => {
const { NetworkController, CurrencyRateController } = Engine.context;
const url = new URLPARSE(rpcUrl);
const existingNetwork = networkConfigurationByChainId[chainId];

CurrencyRateController.updateExchangeRate(ticker);
!isPrivateConnection(url.hostname) && url.set('protocol', 'https:');
NetworkController.upsertNetworkConfiguration(
{
rpcUrl: url.href,

if (!isPrivateConnection(url.hostname)) {
url.set('protocol', 'https:');
}

if (existingNetwork) {
await handleExistingNetwork(existingNetwork, chainId);
} else {
const addedNetwork = await handleNewNetwork(
chainId,
ticker,
rpcUrl,
nickname,
rpcPrefs: { blockExplorerUrl },
},
{
setActive: true,
// Metrics-related properties required, but the metric event is a no-op
// TODO: Use events for controller metric events
referrer: 'ignored',
source: 'ignored',
},
);
closeModal();
ticker,
blockExplorerUrl,
);
const { networkClientId } =
addedNetwork?.rpcEndpoints?.[addedNetwork.defaultRpcEndpointIndex] ??
{};

NetworkController.setActiveNetwork(networkClientId);
}
onClose();

if (onNetworkSwitch) {
onNetworkSwitch();
handleNavigation(onNetworkSwitch, shouldNetworkSwitchPopToWallet);
} else {
shouldNetworkSwitchPopToWallet
? navigation.navigate('WalletView')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function render(Component: React.ComponentType, chainId?: `0x${string}`) {
chainId: '0x89',
id: 'networkId1',
nickname: 'Polygon Mainnet',
ticker: 'MATIC',
ticker: 'POL',
},
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,22 @@ function NetworkSwitcher() {
const switchNetwork = useCallback(
(networkConfiguration) => {
const { CurrencyRateController, NetworkController } = Engine.context;
const entry = Object.entries(networkConfigurations).find(
([_a, { chainId }]) => chainId === networkConfiguration.chainId,
const config = Object.values(networkConfigurations).find(
({ chainId }) => chainId === networkConfiguration.chainId,
);

if (entry) {
const [networkConfigurationId] = entry;
const { ticker } = networkConfiguration;
if (config) {
const {
nativeCurrency: ticker,
rpcEndpoints,
defaultRpcEndpointIndex,
} = config;

const { networkClientId } =
rpcEndpoints?.[defaultRpcEndpointIndex] ?? {};

CurrencyRateController.updateExchangeRate(ticker);
NetworkController.setActiveNetwork(networkConfigurationId);
NetworkController.setActiveNetwork(networkClientId);
navigateToGetStarted();
}
},
Expand Down
Loading