@metamask/connect-multichain
Core multichain connectivity library for MetaMask Connect SDK. Supports multiple blockchain networks including EVM chains (Ethereum, Polygon, etc.) and non-EVM chains (Solana, etc.).
This package provides support for connecting to MetaMask and using the CAIP Multichain API which agnostically supports making requests to multiple blockchain ecosystems simultaneously.
Installation
yarn add @metamask/connect-multichain
or
npm install @metamask/connect-multichain
Quick Start
import {
createMultichainClient,
getInfuraRpcUrls,
} from '@metamask/connect-multichain';
const client = await createMultichainClient({
dapp: {
name: 'My DApp',
url: 'https://mydapp.com',
},
api: {
supportedNetworks: {
...getInfuraRpcUrls({ infuraApiKey: INFURA_API_KEY }),
'eip155:1': 'https://mainnet.example.io/rpc',
'eip155:137': 'https://polygon-mainnet.example.io/rpc',
},
},
});
await client.connect(['eip155:1', 'eip155:137'], []);
const blockNumber = await client.invokeMethod({
scope: 'eip155:1',
request: {
method: 'eth_blockNumber',
params: [],
},
});
Usage
Browser (Web)
import { createMultichainClient } from '@metamask/connect-multichain';
const client = await createMultichainClient({
dapp: {
name: 'My Web DApp',
url: 'https://mydapp.com',
iconUrl: 'https://mydapp.com/icon.png',
},
api: {
supportedNetworks: {
'eip155:1': 'https://mainnet.infura.io/v3/YOUR_KEY',
},
},
ui: {
preferExtension: true,
showInstallModal: false,
headless: false,
},
});
Node.js
import { createMultichainClient } from '@metamask/connect-multichain';
const client = await createMultichainClient({
dapp: {
name: 'My Node App',
url: 'https://mydapp.com',
},
api: {
supportedNetworks: {
'eip155:1': 'https://mainnet.infura.io/v3/YOUR_KEY',
},
},
});
await client.connect(['eip155:1'], []);
React Native
import { Linking } from 'react-native';
import { createMultichainClient } from '@metamask/connect-multichain';
const client = await createMultichainClient({
dapp: {
name: 'My RN App',
url: 'https://mydapp.com',
},
api: {
supportedNetworks: {
'eip155:1': 'https://mainnet.infura.io/v3/YOUR_KEY',
},
},
mobile: {
preferredOpenLink: (deeplink) => {
Linking.openURL(deeplink);
},
},
});
TypeScript
This package is written in TypeScript and includes full type definitions. No additional @types package is required.
API Reference
createMultichainClient(options)
Factory function to create a new Multichain SDK instance.
Singleton: createMultichainClient returns a single shared instance per global context. Calling it a second time with different options will merge the new api.supportedNetworks, versions, ui.*, mobile.*, transport.extensionId, and debug values into the existing instance rather than creating a new one. The dapp value is never overwritten on subsequent calls.
Parameters
dapp.name | string | Yes | Name of your dApp |
api.supportedNetworks | RpcUrlsMap | Yes | Map of CAIP-2 chain IDs to RPC URLs |
dapp.url | string | No | URL of your dApp |
dapp.iconUrl | string | No | Icon URL for your dApp |
dapp.base64Icon | string | No | Base64-encoded icon (alternative to iconUrl) |
storage | StoreClient | No | Custom storage adapter |
ui.factory | BaseModalFactory | No | Custom modal factory |
ui.headless | boolean | No | Run without UI (for custom QR implementations) |
ui.preferExtension | boolean | No | Prefer browser extension (default: true) |
ui.showInstallModal | boolean | No | Show installation modal |
mobile.preferredOpenLink | (deeplink: string, target?: string) => void | No | Custom deeplink handler |
mobile.useDeeplink | boolean | No | Use metamask:// instead of universal links |
analytics.integrationType | string | No | Integration type for analytics |
transport.extensionId | string | No | Custom extension ID |
transport.onNotification | (notification: unknown) => void | No | Notification handler |
versions | Partial<ConnectVersions> | No | Internal: set automatically by createEVMClient / createSolanaClient. Consumers do not need to provide this. |
debug | boolean | No | Enable debug logging |
Returns
Promise<MetaMaskConnectMultichain> - A fully initialized SDK instance.
const client = await createMultichainClient({
dapp: { name: 'My DApp', url: 'https://mydapp.com' },
api: {
supportedNetworks: {
'eip155:1': 'https://mainnet.infura.io/v3/KEY',
'eip155:137': 'https://polygon-mainnet.infura.io/v3/KEY',
},
},
});
MetaMaskConnectMultichain
The main SDK class extending MultichainCore.
Methods
connect(scopes, caipAccountIds, sessionProperties?, forceRequest?)
Connects to MetaMask with specified chain scopes.
Parameters
scopes | Scope[] | Yes | Array of CAIP-2 chain identifiers to request permission for |
caipAccountIds | CaipAccountId[] | Yes | Array of CAIP-10 account identifiers to request (pass [] if no specific accounts should be requested) |
sessionProperties | SessionProperties | No | Additional session properties |
forceRequest | boolean | No | Force a new connection request even if already connected |
Returns
Promise<void>
await client.connect(
['eip155:1', 'eip155:137'],
['eip155:1:0x...'],
);
disconnect(scopes?)
Disconnects from the wallet. If scopes are provided, only the specified scopes are revoked; if there are remaining scopes, the connection stays alive. If omitted or empty, all scopes are revoked and the connection is fully torn down.
Parameters
scopes | Scope[] | No | Array of CAIP-2 chain identifiers to revoke (defaults to all scopes) |
Returns
Promise<void>
await client.disconnect();
await client.disconnect(['eip155:1']);
invokeMethod(options)
Invokes an RPC method on a specific chain.
Parameters
options.scope | Scope | Yes | The CAIP-2 chain identifier to invoke the method on |
options.request.method | string | Yes | The RPC method name |
options.request.params | unknown[] | No | The method parameters |
Returns
Promise<Json> - The result of the RPC method call.
const result = await client.invokeMethod({
scope: 'eip155:1',
request: {
method: 'eth_getBalance',
params: ['0x...', 'latest'],
},
});
Properties
status | ConnectionStatus | Connection status ( 'loaded', 'pending', 'connecting', 'connected', 'disconnected') |
provider | MultichainApiClient | Multichain API client |
transport | ExtendedTransport | Active transport layer |
Events
client.on('wallet_sessionChanged', (session) => {
console.log('Session updated:', session);
});
client.on('display_uri', (uri) => {
console.log('Display QR code:', uri);
});
client.on('stateChanged', (status) => {
console.log('Status:', status);
});
MultichainCore
Abstract base class providing core multichain functionality.
Methods
on(event, handler)
Registers an event handler.
Parameters
event | string | Yes | The event name to listen for |
handler | Function | Yes | The callback function to invoke when the event is emitted |
Returns
void
off(event, handler)
Removes an event handler.
Parameters
event | string | Yes | The event name to stop listening for |
handler | Function | Yes | The callback function to remove |
Returns
void
emit(event, args)
Emits an event to all registered handlers.
Parameters
event | string | Yes | The event name to emit |
args | any | No | Arguments to pass to the event handlers |
Returns
void
Utilities
getInfuraRpcUrls(options)
Generates Infura RPC URLs for common networks keyed by CAIP Chain ID.
Parameters
infuraApiKey | string | Yes | Your Infura API key |
caipChainIds | CaipChainId[] | No | CAIP-2 chain IDs to filter the output |
Returns
A map of CAIP-2 chain IDs to Infura RPC URLs. See https://docs.metamask.io/services
import { getInfuraRpcUrls } from '@metamask/connect-multichain';
const rpcUrls = getInfuraRpcUrls({ infuraApiKey: 'YOUR_INFURA_KEY' });
const filtered = getInfuraRpcUrls({
infuraApiKey: 'YOUR_INFURA_KEY',
caipChainIds: ['eip155:1', 'eip155:137'],
});
Errors
The package exports various error classes for handling specific error conditions:
ProtocolError - Base protocol error
StorageError - Storage operation errors
RpcError - RPC request errors
import { ProtocolError } from '@metamask/connect-multichain';
try {
await client.connect(['eip155:1'], []);
} catch (error) {
if (error instanceof ProtocolError) {
console.log('Protocol error:', error.code, error.message);
}
}
Headless Mode
For custom QR code implementations, use headless mode:
const client = await createMultichainClient({
dapp: { name: 'My DApp' },
api: { supportedNetworks: { 'eip155:1': 'https://...' } },
ui: { headless: true },
});
client.on('display_uri', (uri) => {
displayMyCustomQRCode(uri);
});
await client.connect(['eip155:1'], []);
Standards
Contributing
This package is part of a monorepo. Instructions for contributing can be found in the monorepo README.
License
MIT