MCP Blockchain Server

import { useState, useEffect } from 'react'; import { ethers } from 'ethers'; interface WalletState { provider: ethers.providers.Web3Provider | null; signer: ethers.Signer | null; account: string | null; chainId: string | null; isConnected: boolean; } interface TransactionRequest { to: string; value?: ethers.BigNumber; data?: string; gasLimit?: ethers.BigNumber; chainId?: number; } export function useWallet() { const [walletState, setWalletState] = useState<WalletState>({ provider: null, signer: null, account: null, chainId: null, isConnected: false, }); // Initialize wallet useEffect(() => { const initializeWallet = async () => { // Check if window.ethereum is available if (typeof window.ethereum !== 'undefined') { try { // Get accounts const accounts = await window.ethereum.request({ method: 'eth_accounts' }); if (accounts.length > 0) { // User is already connected const provider = new ethers.providers.Web3Provider(window.ethereum); const signer = provider.getSigner(); const network = await provider.getNetwork(); setWalletState({ provider, signer, account: accounts[0], chainId: network.chainId.toString(), isConnected: true, }); } } catch (error) { console.error('Error initializing wallet:', error); } } }; initializeWallet(); // Setup event listeners if (typeof window.ethereum !== 'undefined') { const handleAccountsChanged = (accounts: string[]) => { if (accounts.length === 0) { // User disconnected setWalletState({ provider: null, signer: null, account: null, chainId: null, isConnected: false, }); } else { // Account changed setWalletState(prevState => ({ ...prevState, account: accounts[0], isConnected: true, })); } }; const handleChainChanged = (chainIdHex: string) => { const chainId = parseInt(chainIdHex, 16).toString(); // Chain changed setWalletState(prevState => ({ ...prevState, chainId, })); }; window.ethereum.on('accountsChanged', handleAccountsChanged); window.ethereum.on('chainChanged', handleChainChanged); // Clean up event listeners return () => { window.ethereum.removeListener('accountsChanged', handleAccountsChanged); window.ethereum.removeListener('chainChanged', handleChainChanged); }; } }, []); // Connect wallet const connect = async () => { if (typeof window.ethereum === 'undefined') { throw new Error('MetaMask is not installed'); } try { // Request accounts const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); if (accounts.length === 0) { throw new Error('No accounts found'); } // Initialize provider and signer const provider = new ethers.providers.Web3Provider(window.ethereum); const signer = provider.getSigner(); const network = await provider.getNetwork(); setWalletState({ provider, signer, account: accounts[0], chainId: network.chainId.toString(), isConnected: true, }); return accounts[0]; } catch (error) { console.error('Error connecting wallet:', error); throw error; } }; // Switch chain const switchChain = async (chainId: string) => { if (!walletState.provider) { throw new Error('Wallet not connected'); } try { // Convert chainId to hex const chainIdHex = '0x' + parseInt(chainId).toString(16); await window.ethereum.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: chainIdHex }], }); // Update state with new chainId setWalletState(prevState => ({ ...prevState, chainId, })); } catch (error: any) { // If the chain is not added to MetaMask if (error.code === 4902) { // Add the chain try { await addChain(chainId); } catch (addError) { console.error('Error adding chain:', addError); throw addError; } } else { console.error('Error switching chain:', error); throw error; } } }; // Add chain const addChain = async (chainId: string) => { if (!walletState.provider) { throw new Error('Wallet not connected'); } try { // Define chain parameters const chainParams = getChainParams(chainId); await window.ethereum.request({ method: 'wallet_addEthereumChain', params: [chainParams], }); // Update state with new chainId setWalletState(prevState => ({ ...prevState, chainId, })); } catch (error) { console.error('Error adding chain:', error); throw error; } }; // Sign transaction const signTransaction = async (txRequest: TransactionRequest) => { if (!walletState.signer) { throw new Error('Wallet not connected'); } try { // Create transaction const tx = await walletState.signer.signTransaction(txRequest); return tx; } catch (error) { console.error('Error signing transaction:', error); throw error; } }; // Send transaction const sendTransaction = async (txRequest: TransactionRequest) => { if (!walletState.signer) { throw new Error('Wallet not connected'); } try { // Send transaction const tx = await walletState.signer.sendTransaction(txRequest); return tx; } catch (error) { console.error('Error sending transaction:', error); throw error; } }; // Disconnect wallet const disconnect = () => { setWalletState({ provider: null, signer: null, account: null, chainId: null, isConnected: false, }); }; return { ...walletState, connect, disconnect, switchChain, signTransaction, sendTransaction, }; } // Helper function to get chain parameters function getChainParams(chainId: string) { switch (chainId) { case '1': return { chainId: '0x1', chainName: 'Ethereum Mainnet', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18, }, rpcUrls: ['https://mainnet.infura.io/v3/'], blockExplorerUrls: ['https://etherscan.io/'], }; case '11155111': return { chainId: '0xaa36a7', chainName: 'Sepolia Testnet', nativeCurrency: { name: 'Sepolia Ether', symbol: 'ETH', decimals: 18, }, rpcUrls: ['https://sepolia.infura.io/v3/'], blockExplorerUrls: ['https://sepolia.etherscan.io/'], }; case '137': return { chainId: '0x89', chainName: 'Polygon Mainnet', nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18, }, rpcUrls: ['https://polygon-rpc.com/'], blockExplorerUrls: ['https://polygonscan.com/'], }; case '80001': return { chainId: '0x13881', chainName: 'Polygon Mumbai Testnet', nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18, }, rpcUrls: ['https://rpc-mumbai.maticvigil.com/'], blockExplorerUrls: ['https://mumbai.polygonscan.com/'], }; default: throw new Error(`Chain ID ${chainId} not supported`); } } // Add Ethereum to Window object declare global { interface Window { ethereum: any; } }