Skip to main content

Connect to EVM and Solana in MetaMask

This guide walks you through setting up MetaMask Connect in a multichain JavaScript dapp. By the end, your dapp can connect to EVM networks and Solana at the same time, and make requests to each one without switching between them.

Prerequisites

  • Node.js version 19 or later installed.
  • A package manager installed, such as npm, Yarn, pnpm, or bun.
  • MetaMask installed in your browser or on mobile.

Steps

1. Install MetaMask Connect

Install the multichain client in an existing JavaScript project:

npm install @metamask/connect-multichain

2. Initialize the client

Initialize the multichain client with configuration options:

import { createMultichainClient } from '@metamask/connect-multichain'

const client = createMultichainClient({
dapp: {
name: 'My Multichain Dapp',
url: window.location.href,
iconUrl: 'https://mydapp.com/icon.png',
},
api: {
supportedNetworks: {
'eip155:1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
'eip155:137': 'https://polygon-mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': 'https://api.mainnet-beta.solana.com',
'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ': 'https://api.devnet.solana.com',
},
},
})

This example configures MetaMask Connect with:

  • dapp — Ensures trust by showing your dapp's name, url, and iconUrl during connection.
  • api.supportedNetworks — A map of CAIP-2 chain IDs to RPC URLs for all networks supported by the dapp.

3. Connect with scopes

Connect to MetaMask and request access to multiple chains across ecosystems:

// Connect with scopes across ecosystems - one approval for all chains
await client.connect(
[
'eip155:1', // Ethereum Mainnet
'eip155:137', // Polygon
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // Solana Mainnet
],
[] // Account preferences (optional)
)

The user sees a single approval prompt for all requested chains. This is a key advantage of the multichain approach — no separate connection flows per ecosystem.

4. Get session and accounts

After connecting, retrieve the session to see which chains and accounts the user authorized:

const session = await client.getSession()

// Accounts are in CAIP-10 format (e.g. "eip155:1:0x..." or "solana:5eykt...:83ast...")
const ethAccounts = session.sessionScopes['eip155:1']?.accounts || []
const polAccounts = session.sessionScopes['eip155:137']?.accounts || []
const solAccounts = session.sessionScopes['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp']?.accounts || []

console.log('ETH accounts:', ethAccounts)
console.log('POL accounts:', polAccounts)
console.log('SOL accounts:', solAccounts)

5. Invoke methods on any scope

Use invokeMethod to call RPC methods on any chain in the session. Extract the address from the CAIP-10 account string to use in your requests:

// Get ETH balance on Ethereum Mainnet
if (ethAccounts.length > 0) {
const ethAddress = ethAccounts[0].split(':')[2]
const ethBalance = await client.invokeMethod({
scope: 'eip155:1',
request: {
method: 'eth_getBalance',
params: [ethAddress, 'latest'],
},
})
console.log('ETH balance:', ethBalance)
}

// Get POL balance on Polygon
if (polAccounts.length > 0) {
const polAddress = polAccounts[0].split(':')[2]
const polBalance = await client.invokeMethod({
scope: 'eip155:137',
request: {
method: 'eth_getBalance',
params: [polAddress, 'latest'],
},
})
console.log('POL balance:', polBalance)
}

6. Get SOL balance using Solana RPC

note

invokeMethod doesn't currently support getBalance. If this is something you'd like to see, raise a feature request on the MetaMask Builder Hub.

To read Solana account balances, use @solana/kit to query the RPC directly:

npm install @solana/kit
import { address, createSolanaRpc } from '@solana/kit'

if (solAccounts.length > 0) {
const solAddress = solAccounts[0].split(':')[2]
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com')
const balance = await rpc.getBalance(address(solAddress)).send()
console.log('SOL balance:', balance)
}

Understanding scopes

Scopes are CAIP-2 chain identifiers that specify which blockchain you're targeting.

EcosystemFormatExample
EVMeip155:<chainId>eip155:1 (Ethereum), eip155:42161 (Linea), eip155:137 (Polygon)
Solanasolana:<genesisHash>solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp (Mainnet), solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ (Devnet)

Full example

import { createMultichainClient } from '@metamask/connect-multichain'
import { address, createSolanaRpc } from '@solana/kit'

async function main() {
// 1. Initialize client
const client = createMultichainClient({
dapp: {
name: 'Multichain Demo',
url: window.location.href,
},
api: {
supportedNetworks: {
'eip155:1': 'https://mainnet.infura.io/v3/YOUR_API_KEY',
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': 'https://api.mainnet-beta.solana.com',
},
},
})

// 2. Connect to both Ethereum Mainnet and Solana Mainnet
await client.connect(['eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], [])

// 3. Get accounts from session
const session = await client.getSession()
const ethAccounts = session.sessionScopes['eip155:1']?.accounts || []
const solAccounts =
session.sessionScopes['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp']?.accounts || []

console.log('ETH accounts:', ethAccounts)
console.log('SOL accounts:', solAccounts)

// 4. Get ETH balance
if (ethAccounts.length > 0) {
const ethAddress = ethAccounts[0].split(':')[2]
const ethBalance = await client.invokeMethod({
scope: 'eip155:1',
request: {
method: 'eth_getBalance',
params: [ethAddress, 'latest'],
},
})
console.log('ETH balance:', ethBalance)
}

// 5. Get SOL balance using @solana/kit (getBalance is not supported via invokeMethod)
if (solAccounts.length > 0) {
const solAddress = solAccounts[0].split(':')[2]
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com')
const balance = await rpc.getBalance(address(solAddress)).send()
console.log('SOL balance:', balance)
}

// 6. Send an ETH transaction
if (ethAccounts.length > 0) {
const ethAddress = ethAccounts[0].split(':')[2]
const txHash = await client.invokeMethod({
scope: 'eip155:1',
request: {
method: 'eth_sendTransaction',
params: [
{
from: ethAddress,
to: '0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7',
value: '0x29a2241af62c0000', // 3 ETH in wei
},
],
},
})
console.log('ETH tx hash:', txHash)
}

// TODO: Send a SOL transaction
}

main()

Next steps