# EVM Wallet Integration Self-custody wallet management and multi-chain trading. ## Overview The EVM module provides complete wallet and trading capabilities: ``` ┌─────────────────────────────────────────────────────────────┐ │ EVM Wallet Suite │ ├─────────────────┬─────────────────┬─────────────────────────┤ │ Wallet │ Trading │ Multi-Chain │ ├─────────────────┼─────────────────┼─────────────────────────┤ │ • Generation │ • Odos swaps │ • 7 chains supported │ │ • Mnemonic │ • Token sends │ • Balance checking │ │ • Keystore │ • ETH transfers │ • Common tokens │ │ • Encryption │ • Contract calls│ • Gas estimation │ └─────────────────┴─────────────────┴─────────────────────────┘ ``` ## Quick Start ### 1. Generate Wallet ```bash # Via CLI /wallet create # Or programmatically import { generateWallet } from './evm/wallet'; const wallet = generateWallet(); console.log(wallet.address, wallet.privateKey); ``` ### 2. Configure ```bash # Set wallet key for trading export EVM_PRIVATE_KEY="0x..." # Optional: Custom RPC endpoints export ETH_RPC_URL="https://your-eth-rpc.com" export BASE_RPC_URL="https://your-base-rpc.com" ``` ### 3. Check Balances ```bash /wallet balance 0x1234... ``` ### 4. Swap & Send ```bash /swap base ETH USDC 0.1 # Swap via Odos /send base 0x123... 0.1 # Send ETH ``` ## Commands ### Wallet Management | Command | Description | |---------|-------------| | `/wallet create [name]` | Generate new wallet | | `/wallet list` | List saved wallets | | `/wallet balance
` | Check balances across all chains | | `/chains` | List supported chains | ### Trading | Command | Description | |---------|-------------| | `/swap ` | Get swap quote via Odos | | `/send [token]` | Send ETH or tokens | ## Supported Chains | Chain | ID | Native | Explorer | |-------|-----|--------|----------| | Ethereum | 1 | ETH | etherscan.io | | Base | 8453 | ETH | basescan.org | | Polygon | 137 | MATIC | polygonscan.com | | Arbitrum | 42161 | ETH | arbiscan.io | | BNB Chain | 56 | BNB | bscscan.com | | Optimism | 10 | ETH | optimistic.etherscan.io | | Avalanche | 43114 | AVAX | snowtrace.io | ## Programmatic Usage ### Wallet Generation ```typescript import { generateWallet, walletFromMnemonic, walletFromPrivateKey, encryptKeystore, decryptKeystore, saveWallet, loadWallet, listWallets, } from './evm/wallet'; // Generate random wallet const wallet = generateWallet(); // { address, privateKey, mnemonic, publicKey } // From mnemonic (with derivation index) const wallet2 = walletFromMnemonic('word word word...', 0); // From private key const info = walletFromPrivateKey('0x...'); // Encrypt and save const path = saveWallet(wallet.privateKey, 'mypassword', 'main-wallet'); // Load later const loaded = loadWallet('main-wallet', 'mypassword'); // List saved const wallets = listWallets(); // [{ name: 'main-wallet', address: '0x...' }] ``` ### Multi-Chain Balances ```typescript import { getMultiChainBalances, getNativeBalance, getTokenBalance, getChainBalances, CHAINS, CHAIN_TOKENS, } from './evm/multichain'; // All chains at once const balances = await getMultiChainBalances('0x...'); for (const chain of balances.balances) { console.log(chain.chainName, chain.native.balance, chain.native.symbol); for (const token of chain.tokens) { console.log(' ', token.symbol, token.balance); } } // Single chain const ethBal = await getNativeBalance('ethereum', '0x...'); // Specific token const usdc = await getTokenBalance( 'base', '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', '0x...' ); // Common tokens are pre-configured console.log(CHAIN_TOKENS.base.USDC); // USDC address on Base ``` ### Odos Swaps ```typescript import { getOdosQuote, executeOdosSwap, swapNativeToToken, swapTokenToNative, swapTokens, getSupportedChains, } from './evm/odos'; // Get quote const quote = await getOdosQuote({ chain: 'base', inputToken: 'ETH', // or address outputToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC amount: '0.1', slippageBps: 50, // 0.5% }); console.log('Output:', quote.outputAmount); console.log('Price impact:', quote.priceImpact); console.log('Route:', quote.route); // Execute swap const result = await executeOdosSwap({ chain: 'base', inputToken: 'ETH', outputToken: '0x833589...', amount: '0.1', privateKey: process.env.EVM_PRIVATE_KEY!, slippageBps: 50, }); if (result.success) { console.log('TX:', result.txHash); console.log('Received:', result.outputAmount); } // Convenience functions await swapNativeToToken('polygon', '0x2791...', '100', privateKey); await swapTokenToNative('arbitrum', '0xaf88...', '1000', privateKey); await swapTokens('base', '0x...', '0x...', '50', privateKey); ``` ### Token Transfers ```typescript import { sendNative, sendToken, sendNativeBatch, sendTokenBatch, estimateNativeTransferGas, estimateTokenTransferGas, } from './evm/transfers'; // Send ETH const result = await sendNative({ chain: 'base', to: '0x...', amount: '0.1', privateKey: '0x...', }); // Send ERC20 const tokenResult = await sendToken({ chain: 'polygon', to: '0x...', amount: '100', privateKey: '0x...', tokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC }); // Batch transfers const recipients = [ { to: '0x111...', amount: '0.01' }, { to: '0x222...', amount: '0.02' }, ]; const results = await sendNativeBatch('ethereum', recipients, privateKey); // Gas estimation const gas = await estimateNativeTransferGas('ethereum', '0x...', '0.1'); console.log('Estimated cost:', gas.estimatedCost, 'ETH'); ``` ### Contract Calls ```typescript import { callContract, writeContract, getEventLogs, isContract, getContractInfo, COMMON_ABIS, encodeFunctionData, decodeFunctionData, } from './evm/contracts'; // Read-only call const result = await callContract({ chain: 'base', contractAddress: '0x...', abi: COMMON_ABIS.erc20, method: 'balanceOf', args: ['0x...'], }); console.log('Balance:', result.result); // Write call const writeResult = await writeContract({ chain: 'polygon', contractAddress: '0x...', abi: COMMON_ABIS.erc20, method: 'approve', args: ['0xspender', '1000000000000'], privateKey: '0x...', }); console.log('TX:', writeResult.txHash); // Query events const logs = await getEventLogs({ chain: 'ethereum', contractAddress: '0x...', abi: COMMON_ABIS.erc20, eventName: 'Transfer', fromBlock: 19000000, toBlock: 'latest', }); // Check if contract const isCtx = await isContract('base', '0x...'); // Use pre-built ABIs // COMMON_ABIS.erc20, erc721, erc1155, multicall, uniswapV2Pair, uniswapV2Router ``` ## Keystore Encryption Wallets are encrypted using: - **KDF**: scrypt (N=262144, r=8, p=1) - **Cipher**: AES-256-CTR - **MAC**: Keccak256 Storage location: `~/.clodds/wallets/` ```typescript // Encrypt const keystore = encryptKeystore(privateKey, 'mypassword'); // Decrypt const privateKey = decryptKeystore(keystore, 'mypassword'); ``` ## Configuration ### Environment Variables | Variable | Description | |----------|-------------| | `EVM_PRIVATE_KEY` | Wallet private key for trading | | `ETH_RPC_URL` | Ethereum RPC (default: llamarpc) | | `BASE_RPC_URL` | Base RPC (default: mainnet.base.org) | | `POLYGON_RPC_URL` | Polygon RPC | | `ARBITRUM_RPC_URL` | Arbitrum RPC | | `BSC_RPC_URL` | BNB Chain RPC | | `OPTIMISM_RPC_URL` | Optimism RPC | | `AVALANCHE_RPC_URL` | Avalanche RPC | ### Config File In `~/.clodds/clodds.json`: ```json { "evm": { "defaultChain": "base", "slippageBps": 50 } } ``` ## Security Notes 1. **Self-Custody**: Private keys never leave your machine 2. **Encrypted Storage**: Keystores use scrypt + AES-256 3. **No Cloud**: Nothing sent to external services (except RPC calls) 4. **Validate First**: Always check quotes before executing swaps ## Resources - [Odos Docs](https://docs.odos.xyz/) - [ethers.js v6](https://docs.ethers.org/v6/) - [EIP-2335 Keystore](https://eips.ethereum.org/EIPS/eip-2335)