> ## Documentation Index
> Fetch the complete documentation index at: https://docs.magic.link/llms.txt
> Use this file to discover all available pages before exploring further.

# Multichain

> Build multichain dApps with Magic using EVM chain switching and blockchain extensions to support multiple networks and ecosystems in a single application.

## Overview

Modern blockchain applications need to support multiple networks and blockchain ecosystems. Magic's SDK provides a unified approach for multichain support by configuring a single Magic instance with multiple extensions:

* **EVM Extensions**: Support multiple EVM-compatible chains with seamless switching
* **Blockchain Extensions**: Support non-EVM chains like Solana, Bitcoin, Hedera, and more

This allows you to interact with Polygon, Optimism, Solana, Hedera, and other networks all from one Magic SDK instance.

## Complete Multichain Setup

Configure a single Magic instance to support multiple blockchain networks:

```javascript JavaScript icon="square-js" theme={null}
import { Magic } from 'magic-sdk';
import { EVMExtension } from '@magic-ext/evm';
import { SolanaExtension } from '@magic-ext/solana';
import { HederaExtension } from '@magic-ext/hedera';
import { ethers } from 'ethers';

const magic = new Magic('YOUR_API_KEY', {
  extensions: [
    // EVM chain switching for Polygon and Optimism
    new EVMExtension([
      {
        rpcUrl: 'https://polygon-rpc.com/',
        chainId: 137,
        default: true,
      },
      {
        rpcUrl: 'https://mainnet.optimism.io',
        chainId: 10,
      },
    ]),
    // Blockchain extensions for Solana and Hedera
    new SolanaExtension({
      rpcUrl: 'https://api.mainnet-beta.solana.com',
    }),
    new HederaExtension({
      network: 'mainnet',
    }),
  ],
});

// Switch to Optimism network
await magic.evm.switchChain(10);

// Get current EVM address (works for any EVM chain)
const provider = new ethers.BrowserProvider(magic.rpcProvider);
const accounts = await provider.listAccounts();
const evmAddress = accounts[0].address;

// Get Solana address
const solanaAddress = await magic.solana.getPublicAddress();

// Get Hedera address
const hederaAddress = await magic.hedera.getPublicAddress();
```

## Network Management in Your Application

Implement a comprehensive network management system for your unified multichain Magic instance:

```tsx TypeScript icon="square-js" theme={null}
import React, { createContext, useState, useContext, useEffect } from 'react';
import { Magic } from 'magic-sdk';
import { EVMExtension } from '@magic-ext/evm';
import { SolanaExtension } from '@magic-ext/solana';
import { HederaExtension } from '@magic-ext/hedera';
import { ethers } from 'ethers';

// Define supported networks
export enum NetworkType {
  EVM = 'evm',
  SOLANA = 'solana',
  HEDERA = 'hedera',
}

export interface Network {
  type: NetworkType;
  chainId?: number; // For EVM chains
  name: string;
  rpcUrl?: string;
}

const SUPPORTED_NETWORKS: Network[] = [
  { type: NetworkType.EVM, chainId: 137, name: 'Polygon' },
  { type: NetworkType.EVM, chainId: 10, name: 'Optimism' },
  { type: NetworkType.SOLANA, name: 'Solana' },
  { type: NetworkType.HEDERA, name: 'Hedera' },
];

interface NetworkContextType {
  currentNetwork: Network;
  magicInstance: Magic | null;
  switchNetwork: (network: Network) => Promise<void>;
  getPublicAddress: () => Promise<string>;
}

const NetworkContext = createContext<NetworkContextType | undefined>(undefined);

export const NetworkProvider = ({ children }: {children: React.ReactNode}) => {
  const [currentNetwork, setCurrentNetwork] = useState<Network>(SUPPORTED_NETWORKS[0]);
  const [magicInstance, setMagicInstance] = useState<Magic | null>(null);
  
  // Initialize Magic instance
  useEffect(() => {
    const magic = new Magic('YOUR_API_KEY', {
      extensions: [
        new EVMExtension([
          { rpcUrl: 'https://polygon-rpc.com/', chainId: 137, default: true },
          { rpcUrl: 'https://mainnet.optimism.io', chainId: 10 },
        ]),
        new SolanaExtension({
          rpcUrl: 'https://api.mainnet-beta.solana.com',
        }),
        new HederaExtension({
          rpcUrl: 'https://mainnet-public.mirrornode.hedera.com',
        }),
      ],
    });
    setMagicInstance(magic);
  }, []);
  
  const switchNetwork = async (network: Network) => {
    if (!magicInstance) return;
    
    if (network.type === NetworkType.EVM && network.chainId) {
      // Switch EVM chain
      await magicInstance.evm.switchChain(network.chainId);
    }
    
    setCurrentNetwork(network);
  };
  
  const getPublicAddress = async (): Promise<string> => {
    if (!magicInstance) throw new Error('Magic instance not initialized');
    
    if (currentNetwork.type === NetworkType.EVM) {
      // Use ethers for EVM chains
      const provider = new ethers.BrowserProvider(magicInstance.rpcProvider);
      const accounts = await provider.listAccounts();
      return accounts[0].address;
    } else if (currentNetwork.type === NetworkType.SOLANA) {
      // Use Solana extension
      return await magicInstance.solana.getPublicAddress();
    } else if (currentNetwork.type === NetworkType.HEDERA) {
      // Use Hedera extension
      return await magicInstance.hedera.getPublicAddress();
    }
    
    throw new Error('Unsupported network type');
  };
  
  return (
    <NetworkContext.Provider value={{ 
      currentNetwork, 
      magicInstance, 
      switchNetwork,
      getPublicAddress
    }}>
      {children}
    </NetworkContext.Provider>
  );
};

export const useNetwork = () => {
  const context = useContext(NetworkContext);
  if (context === undefined) {
    throw new Error('useNetwork must be used within a NetworkProvider');
  }
  return context;
};
```

## Network Selector Component

Create a comprehensive network selector that handles both EVM chains and blockchain extensions:

```tsx TypeScript icon="square-js" theme={null}
import React from 'react';
import { useNetwork } from './NetworkContext';
import { SUPPORTED_NETWORKS } from './NetworkContext';

export const NetworkSelector = () => {
  const { currentNetwork, switchNetwork } = useNetwork();
  
  return (
    <div className="network-selector">
      <label htmlFor="network-select">Current Network:</label>
      <select 
        id="network-select"
        value={`${currentNetwork.type}-${currentNetwork.chainId || 'default'}`}
        onChange={(e) => {
          const [type, chainId] = e.target.value.split('-');
          const network = SUPPORTED_NETWORKS.find(n => 
            n.type === type && 
            (chainId === 'default' ? !n.chainId : n.chainId === parseInt(chainId))
          );
          if (network) switchNetwork(network);
        }}
      >
        {SUPPORTED_NETWORKS.map((network) => (
          <option 
            key={`${network.type}-${network.chainId || 'default'}`} 
            value={`${network.type}-${network.chainId || 'default'}`}
          >
            {network.name}
          </option>
        ))}
      </select>
    </div>
  );
};
```

## Performing Network-Specific Operations

Handle operations across different network types:

```tsx TypeScript icon="square-js" theme={null}
import { useNetwork } from './NetworkContext';
import { ethers } from 'ethers';

export const WalletOperations = () => {
  const { currentNetwork, magicInstance, getPublicAddress } = useNetwork();
  
  const handleGetAddress = async () => {
    try {
      const address = await getPublicAddress();
      console.log(`${currentNetwork.name} Address:`, address);
    } catch (error) {
      console.error('Failed to get address:', error);
    }
  };
  
  const handleRevealPrivateKey = async () => {
    if (!magicInstance) return;
    
    try {
      if (currentNetwork.type === NetworkType.EVM) {
        // For EVM chains, use the user module
        await magicInstance.user.revealEVMPrivateKey();
      } else if (currentNetwork.type === NetworkType.SOLANA) {
        // For Solana, use the extension
        await magicInstance.solana.revealPrivateKey();
      } else if (currentNetwork.type === NetworkType.HEDERA) {
        // For Hedera, use the extension
        await magicInstance.hedera.revealPrivateKey();
      }
    } catch (error) {
      console.error('Failed to reveal private key:', error);
    }
  };
  
  const handleSendTransaction = async (recipient: string, amount: string) => {
    if (!magicInstance) return;
    
    try {
      if (currentNetwork.type === NetworkType.EVM) {
        // EVM transaction using ethers
        const provider = new ethers.BrowserProvider(magicInstance.rpcProvider);
        const signer = provider.getSigner();
        
        const tx = await signer.sendTransaction({
          to: recipient,
          value: ethers.parseEther(amount)
        });
        
        console.log(`EVM Transaction sent:`, tx.hash);
        return tx;
      } else {
        // Non-EVM chains would require chain-specific transaction logic
        console.log('Non-EVM transaction logic would go here');
      }
    } catch (error) {
      console.error('Transaction failed:', error);
      throw error;
    }
  };
  
  return (
    <div className="wallet-operations">
      <button onClick={handleGetAddress}>
        Get {currentNetwork.name} Address
      </button>
      <button onClick={handleRevealPrivateKey}>
        Reveal Private Key
      </button>
      {/* Additional UI components */}
    </div>
  );
};
```

## Resources

* [EVM Chain Switching](/embedded-wallets/wallets/features/evm-chain-switching)
* [JavaScript SDK Reference](/embedded-wallets/sdk/client-side/javascript#evm-module)
* [React Native SDK Reference](/embedded-wallets/sdk/client-side/react-native#evm-module)
* [Blockchain Overview](/embedded-wallets/blockchains/overview)
