Skip to main content
Switch your user’s embedded wallet to different EVM-compatible networks programmatically. MoonKey makes it easy to change networks for multi-chain applications.

Overview

Switching chains allows your application to interact with different blockchain networks without requiring users to manually change networks. This is particularly useful for:
  • Multi-chain dApps: Support operations across multiple networks
  • Network optimization: Move to cheaper or faster chains for specific operations
  • Feature availability: Access chain-specific protocols and features
  • User experience: Seamlessly switch networks based on app context

React SDK

Basic Usage

To switch the network of an embedded wallet, use the switchChain method from the useSwitchChain hook:
  • Using useSwitchChain
  • Using Wallet Method
import { useMoonKey } from '@moon-key/react-auth';
import { useSwitchChain } from '@moon-key/react-auth/ethereum';

function SwitchNetworkButton() {
  const { user } = useMoonKey();
  const { switchChain } = useSwitchChain();

  const handleSwitch = async () => {
    if (!user?.wallet) {
      alert('No wallet found');
      return;
    }

    try {
      // Switch to Base (chainId: 8453)
      await switchChain(8453);
      console.log('Switched to Base');
      alert('Network switched successfully!');
    } catch (error) {
      console.error('Failed to switch network:', error);
    }
  };

  return (
    <button onClick={handleSwitch}>
      Switch to Base
    </button>
  );
}

Chain ID Formats

The switchChain method accepts chain IDs in two formats:
// As a decimal number (recommended)
await switchChain(1); // Ethereum Mainnet

// As a hexadecimal string
await switchChain('0x1'); // Ethereum Mainnet
Using decimal numbers is recommended for better readability and consistency across your codebase.

Supported Chains

MoonKey supports switching to any EVM-compatible chain that has been configured in your app. Common networks include:
NetworkChain ID (Decimal)Chain ID (Hex)
Ethereum Mainnet10x1
Sepolia Testnet111551110xaa36a7
Base84530x2105
Optimism100xa
Arbitrum One421610xa4b1
Polygon1370x89
Avalanche C-Chain431140xa86a
BNB Smart Chain560x38
Learn how to configure additional networks in the Configuring EVM Networks guide.

Complete Examples

Multi-Chain Network Selector

'use client';
import { useMoonKey } from '@moon-key/react-auth';
import { useSwitchChain } from '@moon-key/react-auth/ethereum';
import { useState } from 'react';

interface Network {
  name: string;
  chainId: number;
  logo: string;
}

const NETWORKS: Network[] = [
  { name: 'Ethereum', chainId: 1, logo: '🔷' },
  { name: 'Base', chainId: 8453, logo: '🔵' },
  { name: 'Optimism', chainId: 10, logo: '🔴' },
  { name: 'Arbitrum', chainId: 42161, logo: '🔷' },
  { name: 'Polygon', chainId: 137, logo: '🟣' }
];

export default function NetworkSelector() {
  const { user, isAuthenticated } = useMoonKey();
  const { switchChain } = useSwitchChain();
  const [currentChainId, setCurrentChainId] = useState<number>(1);
  const [isSwitching, setIsSwitching] = useState(false);

  const handleSwitchNetwork = async (chainId: number) => {
    if (!user?.wallet) {
      alert('Please connect your wallet first');
      return;
    }

    setIsSwitching(true);

    try {
      await switchChain(chainId);
      setCurrentChainId(chainId);
      console.log(`Switched to chain ${chainId}`);
    } catch (error) {
      console.error('Failed to switch network:', error);
      alert('Failed to switch network. Please try again.');
    } finally {
      setIsSwitching(false);
    }
  };

  if (!isAuthenticated) {
    return <p>Please sign in to switch networks</p>;
  }

  return (
    <div className="network-selector">
      <h2>Select Network</h2>
      
      <div className="networks-grid">
        {NETWORKS.map((network) => (
          <button
            key={network.chainId}
            onClick={() => handleSwitchNetwork(network.chainId)}
            disabled={isSwitching || currentChainId === network.chainId}
            className={`network-button ${
              currentChainId === network.chainId ? 'active' : ''
            }`}
          >
            <span className="network-logo">{network.logo}</span>
            <span className="network-name">{network.name}</span>
            {currentChainId === network.chainId && <span></span>}
          </button>
        ))}
      </div>

      {isSwitching && <p className="switching-text">Switching network...</p>}
    </div>
  );
}

Network Switch with Confirmation

'use client';
import { useMoonKey } from '@moon-key/react-auth';
import { useSwitchChain } from '@moon-key/react-auth/ethereum';
import { useState } from 'react';

export default function NetworkSwitchWithConfirmation() {
  const { user } = useMoonKey();
  const { switchChain } = useSwitchChain();
  const [showConfirmation, setShowConfirmation] = useState(false);
  const [targetChain, setTargetChain] = useState<{ id: number; name: string } | null>(null);

  const requestNetworkSwitch = (chainId: number, chainName: string) => {
    setTargetChain({ id: chainId, name: chainName });
    setShowConfirmation(true);
  };

  const confirmSwitch = async () => {
    if (!user?.wallet || !targetChain) return;

    try {
      await switchChain(targetChain.id);
      alert(`Successfully switched to ${targetChain.name}`);
    } catch (error) {
      console.error('Failed to switch:', error);
      alert('Failed to switch network');
    } finally {
      setShowConfirmation(false);
      setTargetChain(null);
    }
  };

  const cancelSwitch = () => {
    setShowConfirmation(false);
    setTargetChain(null);
  };

  return (
    <div className="network-switch">
      <button onClick={() => requestNetworkSwitch(8453, 'Base')}>
        Switch to Base
      </button>

      {showConfirmation && targetChain && (
        <div className="confirmation-modal">
          <div className="modal-content">
            <h3>Switch Network?</h3>
            <p>
              You are about to switch to <strong>{targetChain.name}</strong> (Chain ID: {targetChain.id})
            </p>
            <p>This will change your wallet's active network.</p>
            <div className="modal-actions">
              <button onClick={confirmSwitch} className="confirm-btn">
                Confirm
              </button>
              <button onClick={cancelSwitch} className="cancel-btn">
                Cancel
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

Error Handling

Handle common errors when switching chains:
import { useMoonKey } from '@moon-key/react-auth';
import { useSwitchChain } from '@moon-key/react-auth/ethereum';

function SafeNetworkSwitch() {
  const { user } = useMoonKey();
  const { switchChain } = useSwitchChain();

  const handleSwitch = async (chainId: number) => {
    if (!user?.wallet) {
      alert('No wallet connected');
      return;
    }

    try {
      await switchChain(chainId);
      console.log('Network switched successfully');
    } catch (error: any) {
      // Handle specific error cases
      if (error.code === 'CHAIN_NOT_CONFIGURED') {
        alert(
          'This network is not configured. Please add it in your app settings.'
        );
      } else if (error.code === 'USER_REJECTED') {
        console.log('User cancelled network switch');
      } else if (error.message?.includes('unsupported')) {
        alert('This chain is not supported by MoonKey');
      } else {
        console.error('Unexpected error:', error);
        alert('Failed to switch network: ' + error.message);
      }
    }
  };

  return (
    <button onClick={() => handleSwitch(8453)}>
      Switch Network
    </button>
  );
}

Getting Current Chain

To get the current chain ID of the wallet:
import { useMoonKey } from '@moon-key/react-auth';
import { useWallets } from '@moon-key/react-auth/ethereum';

function CurrentChainDisplay() {
  const { user } = useMoonKey();
  const { wallets } = useWallets();

  if (!user?.wallet || wallets.length === 0) {
    return <p>No wallet connected</p>;
  }

  const wallet = wallets[0];
  const currentChainId = wallet.chainId;

  return (
    <div className="current-chain">
      <p>Current Chain ID: {currentChainId}</p>
      <p>Current Chain: {getChainName(currentChainId)}</p>
    </div>
  );
}

function getChainName(chainId: number): string {
  const chains: Record<number, string> = {
    1: 'Ethereum Mainnet',
    11155111: 'Sepolia Testnet',
    8453: 'Base',
    10: 'Optimism',
    42161: 'Arbitrum One',
    137: 'Polygon'
  };

  return chains[chainId] || `Chain ${chainId}`;
}

Best Practices

Ensure chains are properly configured in your MoonKeyProvider:
import { MoonKeyProvider } from '@moon-key/react-auth';
import { mainnet, base, optimism, arbitrum } from 'viem/chains';

<MoonKeyProvider
  publishableKey="your-moonkey-publishableKey"
  config={{
    chains: [mainnet, base, optimism, arbitrum]
  }}
>
  {children}
</MoonKeyProvider>
Always inform users when switching networks:
const handleSwitch = async (chainId: number, chainName: string) => {
  // Show loading state
  setIsLoading(true);
  setStatusMessage(`Switching to ${chainName}...`);

  try {
    await switchChain(chainId);
    setStatusMessage(`Successfully switched to ${chainName}`);
  } catch (error) {
    setStatusMessage('Failed to switch network');
  } finally {
    setIsLoading(false);
  }
};
Check chain compatibility before enabling features:
const isFeatureAvailable = (chainId: number): boolean => {
  const supportedChains = [1, 8453, 10]; // Mainnet, Base, Optimism
  return supportedChains.includes(chainId);
};

if (!isFeatureAvailable(currentChainId)) {
  return (
    <div>
      <p>This feature is not available on this network</p>
      <button onClick={() => switchChain(8453)}>
        Switch to Base
      </button>
    </div>
  );
}
Display human-readable names instead of chain IDs:
const CHAIN_NAMES: Record<number, string> = {
  1: 'Ethereum',
  8453: 'Base',
  10: 'Optimism',
  42161: 'Arbitrum'
};

<button onClick={() => switchChain(8453)}>
  Switch to {CHAIN_NAMES[8453]}
</button>
Ensure correct network before executing transactions:
const executeTransaction = async (targetChainId: number) => {
  const currentChainId = wallet.chainId;

  // Check if we're on the right chain
  if (currentChainId !== targetChainId) {
    const confirmed = confirm(
      `This operation requires switching to chain ${targetChainId}. Continue?`
    );

    if (!confirmed) return;

    // Switch to correct chain
    await switchChain(targetChainId);
  }

  // Now execute the transaction
  await sendTransaction({ ... });
};
Provide fallback options when switching fails:
const handleCriticalOperation = async (requiredChainId: number) => {
  try {
    await switchChain(requiredChainId);
    await performOperation();
  } catch (error) {
    // Offer alternative if switch fails
    const useAlternative = confirm(
      'Failed to switch network. Use alternative chain?'
    );

    if (useAlternative) {
      await switchChain(alternativeChainId);
      await performOperation();
    }
  }
};

Troubleshooting

If you get a “chain not configured” error, add the chain to your configuration:
// Add the chain to your MoonKeyProvider
import { MoonKeyProvider } from '@moon-key/react-auth';
import { base } from 'viem/chains';

<MoonKeyProvider
  publishableKey="your-moonkey-publishableKey"
  config={{
    chains: [base] // Add your required chains here
  }}
>
  {children}
</MoonKeyProvider>
See Configuring EVM Networks for more details.
If the network doesn’t seem to switch:
  1. Check wallet state: Ensure wallet is connected
  2. Wait for promise: Make sure to await the switchChain call
  3. Verify chain support: Check if the chain is configured
  4. Check for errors: Look for error messages in console
const handleSwitch = async (chainId: number) => {
  console.log('Current chain:', wallet.chainId);
  
  try {
    await switchChain(chainId);
    console.log('Switch successful');
    console.log('New chain:', wallet.chainId);
  } catch (error) {
    console.error('Switch failed:', error);
  }
};
Avoid switching chains multiple times in quick succession:
let isSwitching = false;

const handleSwitch = async (chainId: number) => {
  if (isSwitching) {
    console.log('Already switching chains, please wait');
    return;
  }

  isSwitching = true;

  try {
    await switchChain(chainId);
  } catch (error) {
    console.error('Switch failed:', error);
  } finally {
    isSwitching = false;
  }
};
If switching with hex strings isn’t working, use decimal numbers:
// ✅ Recommended - use decimal
await switchChain(8453);

// ⚠️ Use hex only if required by your setup
await switchChain('0x2105');

Next Steps