Skip to main content

wallet-integration

Use when integrating wallets into dApps. Covers WalletConnect, injected providers, EIP-1193, account abstraction (EIP-4337, EIP-7702), Safe SDK, multi-sig interaction, hardware wallets, and network switching.

Quellinformationen

Repository
ccashwell/evm-cortex
Letzte Quellaktivität
10. April 2026 um 16:31
Erkannte Sprache von SKILL.md
Englisch
Sterne
131
Forks
18

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
wallet-integration
description
Use when integrating wallets into dApps. Covers WalletConnect, injected providers, EIP-1193, account abstraction (EIP-4337, EIP-7702), Safe SDK, multi-sig interaction, hardware wallets, and network switching.
# Wallet Integration Patterns ## EIP-1193 Provider Standard All wallets expose a standard provider interface: ```typescript interface EIP1193Provider { request(args: { method: string; params?: unknown[] }): Promise<unknown>; on(event: string, listener: (...args: any[]) => void): void; removeListener(event: string, listener: (...args: any[]) => void): void; } // Common methods: await provider.request({ method: 'eth_requestAccounts' }); await provider.request({ method: 'eth_chainId' }); await provider.request({ method: 'personal_sign', params: [message, address] }); await provider.request({ method: 'eth_sendTransaction', params: [txParams] }); ``` ## Wallet Connection with RainbowKit ```tsx import { ConnectButton } from '@rainbow-me/rainbowkit'; function Header() { return ( <nav> <ConnectButton showBalance={true} chainStatus="icon" accountStatus="address" /> </nav> ); } ``` Custom connect button: ```tsx import { ConnectButton } from '@rainbow-me/rainbowkit'; function CustomConnect() { return ( <ConnectButton.Custom> {({ account, chain, openAccountModal, openChainModal, openConnectModal, mounted }) => { const connected = mounted && account && chain; if (!connected) { return <button onClick={openConnectModal}>Connect Wallet</button>; } if (chain.unsupported) { return <button onClick={openChainModal}>Wrong Network</button>; } return ( <div> <button onClick={openChainModal}>{chain.name}</button> <button onClick={openAccountModal}>{account.displayName}</button> </div> ); }} </ConnectButton.Custom> ); } ``` ## WalletConnect v2 ```typescript import { walletConnect } from 'wagmi/connectors'; const wcConnector = walletConnect({ projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID!, metadata: { name: 'My dApp', description: 'A great dApp', url: 'https://mydapp.xyz', icons: ['https://mydapp.xyz/icon.png'], }, showQrModal: true, }); ``` ## Injected Wallet Detection ```typescript import { injected } from 'wagmi/connectors'; import { useConnect } from 'wagmi'; function WalletList() { const { connectors, connect } = useConnect(); return ( <div> {connectors.map((connector) => ( <button key={connector.uid} onClick={() => connect({ connector })}> {connector.name} </button> ))} </div> ); } ``` ## Network Switching (EIP-3085) ```typescript import { useSwitchChain } from 'wagmi'; function NetworkSwitch() { const { chains, switchChain, isPending } = useSwitchChain(); return ( <div> {chains.map((chain) => ( <button key={chain.id} disabled={isPending} onClick={() => switchChain({ chainId: chain.id })} > {chain.name} </button> ))} </div> ); } // Add custom chain if not recognized async function addChain(provider: EIP1193Provider) { await provider.request({ method: 'wallet_addEthereumChain', params: [{ chainId: '0x2105', // Base (8453) chainName: 'Base', nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 }, rpcUrls: ['https://mainnet.base.org'], blockExplorerUrls: ['https://basescan.org'], }], }); } ``` ## Account Abstraction (EIP-4337) ```typescript import { createSmartAccountClient } from 'permissionless'; import { signerToSimpleSmartAccount } from 'permissionless/accounts'; import { createPimlicoClient } from 'permissionless/clients/pimlico'; import { createPublicClient, http } from 'viem'; import { base } from 'viem/chains'; const publicClient = createPublicClient({ chain: base, transport: http() }); const pimlicoClient = createPimlicoClient({ transport: http(`https://api.pimlico.io/v2/base/rpc?apikey=${PIMLICO_KEY}`), entryPoint: { address: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', version: '0.7' }, }); const smartAccount = await signerToSimpleSmartAccount(publicClient, { signer: walletClientSigner, entryPoint: { address: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', version: '0.7' }, }); const smartAccountClient = createSmartAccountClient({ account: smartAccount, chain: base, bundlerTransport: http(`https://api.pimlico.io/v2/base/rpc?apikey=${PIMLICO_KEY}`), paymaster: pimlicoClient, }); // Gasless transaction const hash = await smartAccountClient.sendTransaction({ to: '0xRecipient', value: 0n, data: '0x...', }); ``` ## Safe (Multi-Sig) Integration ```typescript import SafeApiKit from '@safe-global/api-kit'; import Safe from '@safe-global/protocol-kit'; const apiKit = new SafeApiKit({ chainId: 8453n }); // Propose a transaction const safeSdk = await Safe.init({ provider: rpcUrl, signer: signerPrivateKey, safeAddress: '0xSafeAddress', }); const safeTransaction = await safeSdk.createTransaction({ transactions: [{ to: '0xToken', data: encodeFunctionData({ abi: erc20Abi, functionName: 'transfer', args: [recipient, amount] }), value: '0', }], }); const safeTxHash = await safeSdk.getTransactionHash(safeTransaction); const signature = await safeSdk.signHash(safeTxHash); await apiKit.proposeTransaction({ safeAddress: '0xSafeAddress', safeTransactionData: safeTransaction.data, safeTxHash, senderAddress: signerAddress, senderSignature: signature.data, }); ``` ## Connection State Management ```tsx import { useAccount, useBalance, useDisconnect } from 'wagmi'; function WalletStatus() { const { address, isConnected, chain, connector } = useAccount(); const { data: balance } = useBalance({ address }); const { disconnect } = useDisconnect(); if (!isConnected) return <p>Not connected</p>; return ( <div> <p>Address: {address}</p> <p>Chain: {chain?.name}</p> <p>Wallet: {connector?.name}</p> <p>Balance: {balance?.formatted} {balance?.symbol}</p> <button onClick={() => disconnect()}>Disconnect</button> </div> ); } ``` ## Wallet Connection Flow 1. User clicks "Connect Wallet" 2. Modal shows available wallets (injected, WalletConnect, Coinbase) 3. User selects wallet → `eth_requestAccounts` 4. Check chain → `wallet_switchEthereumChain` if wrong 5. Store connection (wagmi handles persistence) 6. Listen for `accountsChanged` and `chainChanged` events 7. Handle disconnection gracefully ## Security Considerations - Validate `chainId` before every transaction - Don't trust `msg.sender` from wallet (user can spoof in dApp context) - Sign typed data (EIP-712) instead of raw messages when possible - Display human-readable transaction details before signing - Handle rejected transactions gracefully (user cancelled) - Clear sensitive state on disconnect - Validate addresses before sending (checksummed, not zero)
Auf GitHub ansehen