/** * Chain Configuration Utilities * * Provides helper functions to customize chain configurations (e.g., RPC URLs) * without needing to recreate entire ChainWalletConfig objects. * * @module chain-config */ import { ChainWalletConfig } from "./types"; import { DefaultChains } from "./constant"; /** * Override configuration for a single chain */ export interface ChainOverride { chainId: number; overrides: Partial; } /** * Get a single chain configuration with optional overrides. * * @param chainId - The chain ID to retrieve * @param overrides - Partial configuration to override (e.g., rpcUrl, bundlerUrl) * @returns Complete chain configuration with overrides applied * @throws Error if chainId is not found in DefaultChains * * @example * ```typescript * // Override RPC URL with your own Alchemy key * const ethConfig = getChainConfig(1, { * rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY" * }); * * const wallet = new EVMChainWallet(ethConfig, privateKey, 0); * ``` * * @example * ```typescript * // Override multiple properties * const baseConfig = getChainConfig(8453, { * rpcUrl: "https://base-mainnet.g.alchemy.com/v2/YOUR_KEY", * aaSupport: { * enabled: true, * bundlerUrl: "https://your-bundler.com", * paymasterUrl: "https://your-paymaster.com", * // ... other AA config * } * }); * ``` */ export function getChainConfig( chainId: number, overrides?: Partial ): ChainWalletConfig { const baseConfig = DefaultChains.find(c => c.chainId === chainId); if (!baseConfig) { throw new Error( `Chain with ID ${chainId} not found in DefaultChains. ` + `Available chains: ${DefaultChains.map(c => `${c.name} (${c.chainId})`).join(', ')}` ); } if (!overrides) { return { ...baseConfig }; } return { ...baseConfig, ...overrides }; } /** * Get multiple chain configurations with overrides applied. * * @param overrides - Array of chain overrides * @returns Array of complete chain configurations * @throws Error if any chainId is not found * * @example * ```typescript * // Configure multiple chains with custom RPC URLs * const chains = getMultipleChainConfigs([ * { * chainId: 1, * overrides: { rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY" } * }, * { * chainId: 56, * overrides: { rpcUrl: "https://bsc-dataseed.binance.org/" } * }, * { * chainId: 8453, * overrides: { rpcUrl: "https://base-mainnet.g.alchemy.com/v2/YOUR_KEY" } * } * ]); * * // Use the configured chains * const [ethConfig, bscConfig, baseConfig] = chains; * ``` */ export function getMultipleChainConfigs( overrides: ChainOverride[] ): ChainWalletConfig[] { return overrides.map(({ chainId, overrides: configOverrides }) => getChainConfig(chainId, configOverrides) ); } /** * Get all default chains with optional global overrides. * Useful when you want to apply the same override to all chains. * * @param globalOverrides - Overrides to apply to all chains * @returns Array of all chain configurations with overrides * * @example * ```typescript * // Use custom RPC provider for all chains (not recommended, just for demo) * const allChains = getAllChainsWithOverrides(); * ``` * * @example * ```typescript * // Get all chains without modifications * const defaultChains = getAllChainsWithOverrides(); * ``` */ export function getAllChainsWithOverrides( globalOverrides?: Partial ): ChainWalletConfig[] { if (!globalOverrides) { return DefaultChains.map(c => ({ ...c })); } return DefaultChains.map(chain => ({ ...chain, ...globalOverrides })); } /** * Create a custom chains list with selective overrides. * This is the most flexible option - allows you to override some chains * while keeping others as default. * * @param overrides - Map of chainId to overrides * @returns Array of all chain configurations with selective overrides * * @example * ```typescript * // Override only specific chains, keep others as default * const chains = getCustomizedChains({ * 1: { rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY" }, * 8453: { rpcUrl: "https://base-mainnet.g.alchemy.com/v2/YOUR_KEY" }, * // Other chains (56, 10, 42161) will use defaults * }); * * // Use with multi-chain savings manager * const savingsManager = new MultiChainSavingsManager(vm, chains); * ``` */ export function getCustomizedChains( overrides: Record> ): ChainWalletConfig[] { return DefaultChains.map(chain => { const override = overrides[chain.chainId]; if (!override) { return { ...chain }; } return { ...chain, ...override }; }); } /** * Helper function to quickly override just the RPC URL for a chain. * Convenience wrapper around getChainConfig. * * @param chainId - The chain ID to configure * @param rpcUrl - The custom RPC URL * @returns Complete chain configuration with new RPC URL * * @example * ```typescript * const ethConfig = withCustomRpc(1, "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"); * const wallet = new EVMChainWallet(ethConfig, privateKey, 0); * ``` */ export function withCustomRpc(chainId: number, rpcUrl: string): ChainWalletConfig { return getChainConfig(chainId, { rpcUrl }); } /** * Helper function to quickly override multiple chains' RPC URLs. * * @param rpcOverrides - Map of chainId to RPC URL * @returns Array of chain configurations with custom RPC URLs * * @example * ```typescript * const chains = withCustomRpcs({ * 1: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY", * 56: "https://bsc-dataseed.binance.org/", * 8453: "https://base-mainnet.g.alchemy.com/v2/YOUR_KEY" * }); * ``` */ export function withCustomRpcs( rpcOverrides: Record ): ChainWalletConfig[] { return Object.entries(rpcOverrides).map(([chainId, rpcUrl]) => withCustomRpc(Number(chainId), rpcUrl) ); } /** * Get a chain by name (case-insensitive) with optional overrides. * * @param chainName - Name of the chain (e.g., "Ethereum", "BSC", "Base") * @param overrides - Optional overrides to apply * @returns Complete chain configuration * @throws Error if chain name is not found * * @example * ```typescript * const ethConfig = getChainByName("Ethereum", { * rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY" * }); * * const baseConfig = getChainByName("base", { * rpcUrl: "https://base-mainnet.g.alchemy.com/v2/YOUR_KEY" * }); * ``` */ export function getChainByName( chainName: string, overrides?: Partial ): ChainWalletConfig { const normalizedName = chainName.toLowerCase(); const baseConfig = DefaultChains.find( c => c.name.toLowerCase() === normalizedName ); if (!baseConfig) { throw new Error( `Chain "${chainName}" not found in DefaultChains. ` + `Available chains: ${DefaultChains.map(c => c.name).join(', ')}` ); } if (!overrides) { return { ...baseConfig }; } return { ...baseConfig, ...overrides }; } /** * Predefined chain ID constants for convenience. * Use these instead of hardcoding chain IDs. */ export const ChainId = { ETHEREUM: 1, BSC: 56, BASE: 8453, ARBITRUM: 42161, OPTIMISM: 10, SOLANA: 123456789, // Pseudo chain ID for Solana } as const; /** * Predefined chain name constants for convenience. */ export const ChainName = { ETHEREUM: "Ethereum", BSC: "BSC", BASE: "Base", ARBITRUM: "Arbitrum One", OPTIMISM: "OP Mainnet", SOLANA: "Solana", } as const;