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
Complete Multichain Setup
Configure a single Magic instance to support multiple blockchain networks:JavaScript
Copy
Ask AI
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:TypeScript
Copy
Ask AI
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:TypeScript
Copy
Ask AI
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:TypeScript
Copy
Ask AI
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>
);
};