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
16 changes: 16 additions & 0 deletions test/data/mock-send-state.json
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,22 @@
"0xeb9e64b93097bc15f01f13eae97015c57ab64823": {
"address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823",
"balance": "0x0"
},
"0xd5e099c71b797516c10ed0f0d895f429c2781111": {
"address": "0xd5e099c71b797516c10ed0f0d895f429c2781111",
"balance": "0x0"
},
"0x1234567890123456789012345678901234567890": {
"address": "0x1234567890123456789012345678901234567890",
"balance": "0x0"
},
"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq": {
"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"balance": "0x0"
},
"2byhg1jregmqQx2VfLGLn7hb5mStJw2iVVU8sfM5xTYj": {
"address": "2byhg1jregmqQx2VfLGLn7hb5mStJw2iVVU8sfM5xTYj",
"balance": "0x0"
}
},
"tokens": [
Expand Down
5 changes: 4 additions & 1 deletion test/integration/data/onboarding-completion-route.json
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,10 @@
"keyrings": [
{
"type": "HD Key Tree",
"accounts": ["0x03cf1158b58ccdfc04dd518f11f85c3ee7fa0189"]
"accounts": ["0x03cf1158b58ccdfc04dd518f11f85c3ee7fa0189"],
"metadata": {
"id": "test-keyring-id"
}
}
],
"knownMethodData": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,31 @@ describe('Connected Site Menu', () => {
},
},
},
domains: {},
domains: {
'https://uniswap.org/': 'mainnet-infura',
},
networkConfigurationsByChainId: defaultNetworkConfigurations,
selectedNetworkClientId: 'mainnet-infura',
keyrings: [
{
type: 'HD Key Tree',
accounts: [mockAccount1.address, mockAccount2.address],
metadata: {
id: 'test-keyring-id',
},
},
],
// Add multichain network state
selectedMultichainNetworkChainId: 'eip155:1',
isEvmSelected: true,
// Add permission history for the selector
permissionHistory: {
'https://uniswap.org/': {
eth_accounts: {
accounts: [`eip155:1:${mockAccount1.address}`],
},
},
},
...customState.metamask,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const render = () => {
// Add multichain network state
selectedMultichainNetworkChainId: 'eip155:5',
isEvmSelected: true,
selectedNetworkClientId: 'goerli-test-client',
multichainNetworkConfigurationsByChainId: {
...mockState.metamask.multichainNetworkConfigurationsByChainId,
'eip155:5': {
Expand All @@ -50,6 +51,41 @@ const render = () => {
isEvm: true,
},
},
// Add internal accounts for the new selector
internalAccounts: {
accounts: {
'eip155:5:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': {
id: 'eip155:5:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
type: 'eip155:eoa',
metadata: {
name: 'Test Account',
lastSelected: Date.now(),
},
scopes: ['eip155:5'],
methods: [],
options: {},
},
},
selectedAccount: 'eip155:5:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
},
// Add accounts for compatibility
accounts: {
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': {
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
balance: '0x0',
},
},
// Add keyrings for compatibility
keyrings: [
{
type: 'HD Key Tree',
accounts: ['0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'],
metadata: {
id: 'test-keyring-id',
},
},
],
// Add permissions for the test dapp
subjects: {
'https://metamask.github.io': {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, RefObject, useMemo } from 'react';
import React, { useContext, RefObject } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { parseCaipChainId } from '@metamask/utils';
import {
Expand All @@ -20,11 +20,11 @@ import {
TextVariant,
} from '../../../helpers/constants/design-system';
import { I18nContext } from '../../../contexts/i18n';
import { getOriginOfCurrentTab, getAllDomains } from '../../../selectors';
import { getNetworkConfigurationsByChainId } from '../../../../shared/modules/selectors/networks';
import { getOriginOfCurrentTab } from '../../../selectors';
import { getURLHost } from '../../../helpers/utils/util';
import { getImageForChainId } from '../../../selectors/multichain';
import { toggleNetworkMenu } from '../../../store/actions';
import { getDappActiveNetwork } from '../../../selectors/dapp';

type ConnectedSitePopoverProps = {
referenceElement: RefObject<HTMLElement>;
Expand All @@ -43,37 +43,10 @@ export const ConnectedSitePopover: React.FC<ConnectedSitePopoverProps> = ({
}) => {
const t = useContext(I18nContext);
const activeTabOrigin = useSelector(getOriginOfCurrentTab);
const dappActiveNetwork = useSelector(getDappActiveNetwork);
const siteName = getURLHost(activeTabOrigin);
const allDomains = useSelector(getAllDomains);
const networkConfigurationsByChainId = useSelector(
getNetworkConfigurationsByChainId,
);
const dispatch = useDispatch();

// Get the network that this dapp is actually connected to using domain mapping
const dappActiveNetwork = useMemo(() => {
if (!activeTabOrigin || !allDomains) {
return null;
}

// Get the networkClientId for this domain
const networkClientId = allDomains[activeTabOrigin];
if (!networkClientId) {
return null;
}

// Find the network configuration that has this networkClientId
const networkConfiguration = Object.values(
networkConfigurationsByChainId,
).find((network) => {
return network.rpcEndpoints.some(
(rpcEndpoint) => rpcEndpoint.networkClientId === networkClientId,
);
});

return networkConfiguration || null;
}, [activeTabOrigin, allDomains, networkConfigurationsByChainId]);

const getChainIdForImage = (chainId: `${string}:${string}`): string => {
const { namespace, reference } = parseCaipChainId(chainId);
return namespace === 'eip155'
Expand Down
28 changes: 28 additions & 0 deletions ui/pages/routes/routes.component.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@ describe('Routes Component', () => {
tokenBalances: {
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': '0x176270e2b862e4ed3',
},
permissionHistory: {
'https://metamask.github.io': {
eth_accounts: {
accounts: [
'eip155:1:0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
],
},
},
},
},
send: {
...mockSendState.send,
Expand Down Expand Up @@ -312,6 +321,25 @@ describe('toast display', () => {
},
selectedAccount: selectedAccountId ?? mockAccount.id,
},
accounts: {
...mockState.metamask.accounts,
[mockAccount.address]: {
balance: '0x0',
address: mockAccount.address,
},
[mockAccount2.address]: {
balance: '0x0',
address: mockAccount2.address,
},
[mockNonEvmAccount.address]: {
balance: '0x0',
address: mockNonEvmAccount.address,
},
[mockSolanaAccount.address]: {
balance: '0x0',
address: mockSolanaAccount.address,
},
},
accountsAssets: {
[selectedAccountId ?? mockAccount.id]: [],
},
Expand Down
107 changes: 93 additions & 14 deletions ui/selectors/dapp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ import {
} from '@metamask/network-controller';
import { getNetworkConfigurationsByChainId } from '../../shared/modules/selectors/networks';
import { getDappActiveNetwork } from './dapp';
import { getAllDomains, getOriginOfCurrentTab } from './selectors';
import {
getOrderedConnectedAccountsForActiveTab,
getOriginOfCurrentTab,
getAllDomains,
} from './selectors';
import { getMultichainNetworkConfigurationsByChainId } from './multichain';

// Mock the selectors that the new getDappActiveNetwork uses
jest.mock('./selectors', () => ({
getOrderedConnectedAccountsForActiveTab: jest.fn(),
getOriginOfCurrentTab: jest.fn(),
getAllDomains: jest.fn(),
}));
Expand All @@ -15,11 +22,21 @@ jest.mock('../../shared/modules/selectors/networks', () => ({
getNetworkConfigurationsByChainId: jest.fn(),
}));

jest.mock('./multichain', () => ({
getMultichainNetworkConfigurationsByChainId: jest.fn(),
}));

const mockGetOrderedConnectedAccountsForActiveTab = jest.mocked(
getOrderedConnectedAccountsForActiveTab,
);
const mockGetOriginOfCurrentTab = jest.mocked(getOriginOfCurrentTab);
const mockGetAllDomains = jest.mocked(getAllDomains);
const mockGetNetworkConfigurationsByChainId = jest.mocked(
getNetworkConfigurationsByChainId,
);
const mockGetMultichainNetworkConfigurationsByChainId = jest.mocked(
getMultichainNetworkConfigurationsByChainId,
);

describe('getDappActiveNetwork selector', () => {
beforeEach(() => {
Expand All @@ -43,57 +60,119 @@ describe('getDappActiveNetwork selector', () => {
nativeCurrency: '',
};

const mockEvmAccount = {
id: 'eip155:1:0x1234567890123456789012345678901234567890',
address: '0x1234567890123456789012345678901234567890',
type: 'eip155:eoa',
metadata: {
name: 'Test Account',
lastSelected: Date.now(),
},
scopes: ['eip155:1'],
methods: [],
options: {},
};

const mockSolanaAccount = {
id: 'solana:mainnet:0x1234567890123456789012345678901234567890',
address: '0x1234567890123456789012345678901234567890',
type: 'solana:data-account',
metadata: {
name: 'Test Solana Account',
lastSelected: Date.now(),
},
scopes: ['solana:mainnet'],
methods: [],
options: {},
};

const mockMultichainNetworkConfig: NetworkConfiguration = {
chainId: '0x1' as `0x${string}`,
name: 'Solana Mainnet',
nativeCurrency: 'SOL',
blockExplorerUrls: [],
defaultRpcEndpointIndex: 0,
rpcEndpoints: [
{
networkClientId: 'solana-mainnet',
type: RpcEndpointType.Custom,
url: '',
},
],
};

const arrangeMocks = () => {
mockGetOrderedConnectedAccountsForActiveTab.mockReturnValue([
mockEvmAccount,
]);
mockGetOriginOfCurrentTab.mockReturnValue(mockOrigin);

mockGetAllDomains.mockReturnValue({
[mockOrigin]: mockNetworkClientId,
});

mockGetNetworkConfigurationsByChainId.mockReturnValue({
'0x1': mockNetworkConfig,
});
mockGetMultichainNetworkConfigurationsByChainId.mockReturnValue({});

return {
mockOrigin,
mockNetworkClientId,
mockGetAllDomains,
mockGetOrderedConnectedAccountsForActiveTab,
mockGetOriginOfCurrentTab,
mockGetAllDomains,
mockGetNetworkConfigurationsByChainId,
mockGetMultichainNetworkConfigurationsByChainId,
mockState: {},
};
};

it('returns correct network configuration when all data is available', () => {
it('returns correct EVM network configuration when all data is available', () => {
const mocks = arrangeMocks();
const result = getDappActiveNetwork(mocks.mockState);
expect(result).toEqual({ ...mockNetworkConfig, isEvm: true });
});

it('returns correct non-EVM network configuration for Solana account', () => {
const mocks = arrangeMocks();
mocks.mockGetOrderedConnectedAccountsForActiveTab.mockReturnValue([
mockSolanaAccount,
]);
mocks.mockGetMultichainNetworkConfigurationsByChainId.mockReturnValue({
'solana:mainnet': mockMultichainNetworkConfig,
});

const result = getDappActiveNetwork(mocks.mockState);
expect(result).toEqual(mockNetworkConfig);
expect(result).toEqual({ ...mockMultichainNetworkConfig, isEvm: false });
});

it('returns null when activeTabOrigin is null', () => {
it('returns null when no connected accounts', () => {
const mocks = arrangeMocks();
mocks.mockGetOriginOfCurrentTab.mockReturnValue(null);
mocks.mockGetOrderedConnectedAccountsForActiveTab.mockReturnValue([]);
const result = getDappActiveNetwork(mocks.mockState);
expect(result).toBeNull();
});

it('returns null when allDomains is null', () => {
it('returns null when orderedConnectedAccounts is null', () => {
const mocks = arrangeMocks();
mocks.mockGetAllDomains.mockReturnValue(null);
mocks.mockGetOrderedConnectedAccountsForActiveTab.mockReturnValue(null);
const result = getDappActiveNetwork(mocks.mockState);
expect(result).toBeNull();
});

it('returns null when networkClientId not found for origin', () => {
it('returns null when no matching EVM network configuration exists', () => {
const mocks = arrangeMocks();
mocks.mockGetAllDomains.mockReturnValue({});
mocks.mockGetNetworkConfigurationsByChainId.mockReturnValue({});
const result = getDappActiveNetwork(mocks.mockState);
expect(result).toBeNull();
});

it('returns null when no matching network configuration exists', () => {
it('returns null when no matching non-EVM network configuration exists', () => {
const mocks = arrangeMocks();
mocks.mockGetNetworkConfigurationsByChainId.mockReturnValue({});
mocks.mockGetOrderedConnectedAccountsForActiveTab.mockReturnValue([
mockSolanaAccount,
]);
mocks.mockGetMultichainNetworkConfigurationsByChainId.mockReturnValue({});

const result = getDappActiveNetwork(mocks.mockState);
expect(result).toBeNull();
});
Expand Down
Loading
Loading