UNPKG

x0-react-sdk

Version:

React SDK for X0Pay Hyperlane token bridging with MetaMask and Safe wallet integration

194 lines (168 loc) 6.89 kB
// Internal configuration for X0Pay SDK import { ethers } from 'ethers'; import type { ChainConfig, TokenConfig, ChainTokenConfig } from './types'; export const CHAINS: ChainConfig[] = [ { chainId: '0x89', // 137 in hex name: 'Polygon', rpcUrls: ['https://polygon-rpc.com/'], nativeCurrency: { name: 'Matic', symbol: 'MATIC', decimals: 18 }, blockExplorerUrls: ['https://polygonscan.com/'], }, { chainId: '0xa86a', // 43114 in hex name: 'Avalanche', rpcUrls: ['https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc'], nativeCurrency: { name: 'Avalanche', symbol: 'AVAX', decimals: 18 }, blockExplorerUrls: ['https://snowtrace.io/'], }, ]; // Token configurations for each chain export const CHAIN_TOKEN_CONFIGS: ChainTokenConfig[] = [ { chainId: '0x89', // Polygon chainName: 'Polygon', tokens: [ { symbol: 'USDT', name: 'Tether USD', address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', // Polygon USDT decimals: 6, hypColAddress: '0x6316043b1EE191538A3903d95723506229B1e985', // Polygon USDT Hyperlane collateral }, { symbol: 'USDC', name: 'USDC', address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', // Polygon USDC decimals: 6, hypColAddress: '0xD1eB0Be5890bEBDE62E249162738C6cA53a4A240', // Polygon USDC Hyperlane collateral }, ], hookAddress: '0x9B31d0eb6D852939Fe5A2BB8a66F3b5E6679A3a5', // Replace with actual address destinationDomain: 170845, }, // Add Avalanche token configs { chainId: '0xa86a', // Avalanche chainName: 'Avalanche', tokens: [ { symbol: 'USDT', name: 'Tether USD', address: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7', // Avalanche USDT decimals: 6, hypColAddress: '0x9532B3ba9F7794A39495F3b37cC94309F8b97C25', // Avalanche USDT Hyperlane collateral }, ], hookAddress: '0xf5Ceb644825D3b98093090A88deeF0Ab1c8Ac04E', // Replace with actual address destinationDomain: 170845, }, ]; // Configuration manager class export class X0ConfigManager { private clientChains: ChainConfig[] = []; private clientChainTokenConfigs: ChainTokenConfig[] = []; constructor(clientChains?: ChainConfig[], clientChainTokenConfigs?: ChainTokenConfig[]) { this.clientChains = clientChains || []; this.clientChainTokenConfigs = clientChainTokenConfigs || []; } // Get merged chains (client configs override defaults) getChains(): ChainConfig[] { const mergedChains = [...CHAINS]; this.clientChains.forEach(clientChain => { const existingIndex = mergedChains.findIndex(chain => chain.chainId === clientChain.chainId); if (existingIndex >= 0) { mergedChains[existingIndex] = clientChain; } else { mergedChains.push(clientChain); } }); return mergedChains; } // Get merged chain token configs (client configs override defaults) getChainTokenConfigs(): ChainTokenConfig[] { const mergedConfigs = [...CHAIN_TOKEN_CONFIGS]; this.clientChainTokenConfigs.forEach(clientConfig => { const existingIndex = mergedConfigs.findIndex(config => config.chainId === clientConfig.chainId); if (existingIndex >= 0) { mergedConfigs[existingIndex] = clientConfig; } else { mergedConfigs.push(clientConfig); } }); return mergedConfigs; } // Get chain token config by chain ID getChainTokenConfig(chainId: string): ChainTokenConfig | undefined { const configs = this.getChainTokenConfigs(); return configs.find(config => config.chainId === chainId); } // Get token config by chain ID and symbol getTokenConfig(chainId: string, symbol: string): TokenConfig | undefined { const chainConfig = this.getChainTokenConfig(chainId); return chainConfig?.tokens.find(token => token.symbol === symbol); } // Get default config for a chain and token (without recipient) getDefaultConfig(chainId: string, tokenSymbol: string) { const chainConfig = this.getChainTokenConfig(chainId); const tokenConfig = this.getTokenConfig(chainId, tokenSymbol); if (!chainConfig || !tokenConfig) { throw new Error(`Configuration not found for chain ${chainId} and token ${tokenSymbol}`); } // Use token-specific destination domain if provided, otherwise fall back to chain's destination domain const destinationDomain = tokenConfig.destinationDomain ?? chainConfig.destinationDomain; return { erc20TokenAddress: tokenConfig.address, hypColAddress: tokenConfig.hypColAddress, hookAddress: chainConfig.hookAddress, destinationDomain: destinationDomain, }; } // Get recipient from hook contract async getRecipientFromHook(provider: any, hookAddress: string): Promise<string> { try { // ABI for the vaultAddress function const hookABI = [ "function vaultAddress() external view returns (address)" ]; const hookContract = new ethers.Contract(hookAddress, hookABI, provider); const recipient = await hookContract.vaultAddress(); // Convert address to bytes32 format for Hyperlane message return ethers.utils.hexZeroPad(recipient, 32); } catch (error) { throw new Error(`Failed to get recipient from hook contract: ${error}`); } } // Get complete config with recipient from hook contract async getCompleteConfig(provider: any, chainId: string, tokenSymbol: string) { const baseConfig = this.getDefaultConfig(chainId, tokenSymbol); const recipient = await this.getRecipientFromHook(provider, baseConfig.hookAddress); return { ...baseConfig, recipient, }; } // Update client configurations updateClientConfigs(clientChains?: ChainConfig[], clientChainTokenConfigs?: ChainTokenConfig[]) { if (clientChains) { this.clientChains = clientChains; } if (clientChainTokenConfigs) { this.clientChainTokenConfigs = clientChainTokenConfigs; } } } // Global config manager instance export const globalConfigManager = new X0ConfigManager(); // Helper function to get chain token config by chain ID (backward compatibility) export const getChainTokenConfig = (chainId: string): ChainTokenConfig | undefined => { return globalConfigManager.getChainTokenConfig(chainId); }; // Helper function to get token config by chain ID and symbol (backward compatibility) export const getTokenConfig = (chainId: string, symbol: string): TokenConfig | undefined => { return globalConfigManager.getTokenConfig(chainId, symbol); }; // Helper function to get default config for a chain and token (backward compatibility) export const getDefaultConfig = (chainId: string, tokenSymbol: string) => { return globalConfigManager.getDefaultConfig(chainId, tokenSymbol); };