
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
@metamask/connect-multichain
Advanced tools
MetaMask Connect multichain client — CAIP multichain API, session management, and transport negotiation
@metamask/connect-multichainCore 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.
yarn add @metamask/connect-multichain
or
npm install @metamask/connect-multichain
import {
createMultichainClient,
getInfuraRpcUrls,
} from '@metamask/connect-multichain';
const client = await createMultichainClient({
dapp: {
name: 'My DApp',
url: 'https://mydapp.com',
},
api: {
supportedNetworks: {
// use the `getInfuraRpcUrls` helper to generate a map of Infura RPC endpoints
...getInfuraRpcUrls({ infuraApiKey: INFURA_API_KEY }),
// or specify your own CAIP Chain ID to rpc endpoint mapping
'eip155:1': 'https://mainnet.example.io/rpc',
'eip155:137': 'https://polygon-mainnet.example.io/rpc',
},
},
});
// Connect to MetaMask with specific chain scopes
await client.connect(['eip155:1', 'eip155:137'], []);
// Invoke methods on specific chains
const blockNumber = await client.invokeMethod({
scope: 'eip155:1',
request: {
method: 'eth_blockNumber',
params: [],
},
});
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, // Prefer browser extension over mobile QR
showInstallModal: false, // Show modal to install extension
headless: false, // Set true for custom QR UI
},
});
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',
},
},
});
// Connect will display QR code in terminal
await client.connect(['eip155:1'], []);
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);
},
},
});
This package is written in TypeScript and includes full type definitions. No additional @types package is required.
createMultichainClient(options)Factory function to create a new Multichain SDK instance.
Singleton:
createMultichainClientreturns a single shared instance per global context. Calling it a second time with different options will merge the newapi.supportedNetworks,versions,ui.*,mobile.*,transport.extensionId, anddebugvalues into the existing instance rather than creating a new one. Thedappvalue is never overwritten on subsequent calls.
| Option | Type | Required | Description |
|---|---|---|---|
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.enabled | boolean | No | Enables dapp-side analytics. Defaults to true; set to false to disable analytics events and wallet correlation metadata. |
analytics.integrationType | string | No | Integration type for analytics |
transport.extensionId | string | No | Custom extension ID |
versions | Partial<ConnectVersions> | No | Internal: set automatically by createEVMClient / createSolanaClient. Consumers do not need to provide this. |
debug | boolean | No | Enable debug logging |
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',
},
},
});
MetaMaskConnectMultichainThe main SDK class extending MultichainCore.
connect(scopes, caipAccountIds, sessionProperties?, forceRequest?)Connects to MetaMask with specified chain scopes.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
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'], // Chain scopes to request
['eip155:1:0x...'], // Specific accounts to request
);
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
| Name | Type | Required | Description |
|---|---|---|---|
scopes | Scope[] | No | Array of CAIP-2 chain identifiers to revoke (defaults to all scopes) |
Returns
Promise<void>
// Fully disconnect
await client.disconnect();
// Disconnect only specific scopes
await client.disconnect(['eip155:1']);
invokeMethod(options)Invokes an RPC method on a specific chain.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
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'],
},
});
| Property | Type | Description |
|---|---|---|
status | ConnectionStatus | Connection status ( 'loaded', 'pending', 'connecting', 'connected', 'disconnected') |
provider | MultichainApiClient | Multichain API client |
transport | ExtendedTransport | Active transport layer |
// Session changes
client.on('wallet_sessionChanged', (session) => {
console.log('Session updated:', session);
});
// QR code display (for custom UI)
client.on('display_uri', (uri) => {
console.log('Display QR code:', uri);
});
// Connection state changes
client.on('stateChanged', (status) => {
console.log('Status:', status);
});
MultichainCoreAbstract base class providing core multichain functionality.
on(event, handler)Registers an event handler.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
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
| Name | Type | Required | Description |
|---|---|---|---|
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
| Name | Type | Required | Description |
|---|---|---|---|
event | string | Yes | The event name to emit |
args | any | No | Arguments to pass to the event handlers |
Returns
void
getInfuraRpcUrls(options)Generates Infura RPC URLs for common networks keyed by CAIP Chain ID.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
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';
// Get all supported Infura RPC URLs
const rpcUrls = getInfuraRpcUrls({ infuraApiKey: 'YOUR_INFURA_KEY' });
// {
// 'eip155:1': 'https://mainnet.infura.io/v3/YOUR_KEY',
// 'eip155:137': 'https://polygon-mainnet.infura.io/v3/YOUR_KEY',
// 'eip155:11155111': 'https://sepolia.infura.io/v3/YOUR_KEY',
// ...
// }
// Filter to specific chains
const filtered = getInfuraRpcUrls({
infuraApiKey: 'YOUR_INFURA_KEY',
caipChainIds: ['eip155:1', 'eip155:137'],
});
// {
// 'eip155:1': 'https://mainnet.infura.io/v3/YOUR_KEY',
// 'eip155:137': 'https://polygon-mainnet.infura.io/v3/YOUR_KEY',
// }
The package exports various error classes for handling specific error conditions:
ProtocolError - Base protocol errorStorageError - Storage operation errorsRpcError - RPC request errorsimport { 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);
}
}
For custom QR code implementations, use headless mode:
const client = await createMultichainClient({
dapp: { name: 'My DApp' },
api: { supportedNetworks: { 'eip155:1': 'https://...' } },
ui: { headless: true },
});
// Listen for QR code URIs
client.on('display_uri', (uri) => {
// Display your custom QR code with this URI
displayMyCustomQRCode(uri);
});
await client.connect(['eip155:1'], []);
This package is part of a monorepo. Instructions for contributing can be found in the monorepo README.
MIT
FAQs
MetaMask Connect multichain client — CAIP multichain API, session management, and transport negotiation
The npm package @metamask/connect-multichain receives a total of 61,082 weekly downloads. As such, @metamask/connect-multichain popularity was classified as popular.
We found that @metamask/connect-multichain demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 7 open source maintainers collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.