UNPKG

web3agent-aof

Version:

AI Framework for Onchain Operations and DeFi Interactions

191 lines 7.76 kB
import { ethers } from 'ethers'; // Bridge contract ABIs const LAYERZERO_BRIDGE_ABI = [ 'function estimateFees(uint16 dstChainId, address from, bytes calldata payload) external view returns (uint256 nativeFee, uint256 zroFee)', 'function bridge(uint16 dstChainId, address token, uint256 amount, address recipient) external payable' ]; const HOP_BRIDGE_ABI = [ 'function sendToL2(uint256 chainId, address recipient, uint256 amount, uint256 deadline, uint256 relayerFee) external payable', 'function calculateFee(uint256 chainId, uint256 amount) external view returns (uint256)' ]; export class BridgeManager { provider; wallet; bridgeContracts; constructor(provider, wallet) { this.provider = provider; this.wallet = wallet; this.bridgeContracts = new Map([ ['LayerZero', { ethereum: '0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675', bnb: '0x3c2269811836af69497E5F486A85D7316753cf62', arbitrum: '0x4D747149A57923Beb89f22E6B7B97f7D8c087A00' }], ['Hop', { ethereum: '0x3666cA85925629d7C42E1504BC7F7E6707cF34E8', bnb: '0x2A6F1F51a14B1147079aF4e3Ab4Fd5A75566E958', arbitrum: '0x0e0E3d2C5c292161999474247956EF542caBF8dd' }] ]); } async getBridgeQuote(params) { switch (params.bridgeProtocol) { case 'LayerZero': return await this.getLayerZeroQuote(params); case 'Hop': return await this.getHopQuote(params); case 'Across': return await this.getAcrossQuote(params); default: throw new Error(`Unsupported bridge protocol: ${params.bridgeProtocol}`); } } async findBestBridgeRoute(params) { // Get quotes from all supported bridges const quotes = await Promise.all([ this.getBridgeQuote({ ...params, bridgeProtocol: 'LayerZero' }), this.getBridgeQuote({ ...params, bridgeProtocol: 'Hop' }), this.getBridgeQuote({ ...params, bridgeProtocol: 'Across' }) ]); // Find the best route based on fees and estimated time const bestQuote = quotes.reduce((best, current) => { const currentScore = this.calculateRouteScore(current); const bestScore = this.calculateRouteScore(best); return currentScore > bestScore ? current : best; }); return { protocol: bestQuote.protocol, steps: await this.getBridgeSteps(params, bestQuote.protocol), totalFee: bestQuote.bridgeFee, estimatedTime: bestQuote.estimatedTime }; } async bridge(params) { const bridgeContract = await this.getBridgeContract(params.bridgeProtocol, params.targetChain); const recipient = params.recipient || await this.wallet.getAddress(); try { let tx; switch (params.bridgeProtocol) { case 'LayerZero': tx = await this.bridgeWithLayerZero(bridgeContract, params, recipient); break; case 'Hop': tx = await this.bridgeWithHop(bridgeContract, params, recipient); break; case 'Across': tx = await this.bridgeWithAcross(params, recipient); break; } const receipt = await tx.wait(); if (!receipt) { throw new Error('Transaction receipt is null'); } return { hash: receipt.hash, status: 'pending', sourceChain: params.sourceChain, targetChain: params.targetChain, sourceHash: receipt.hash, amount: params.amount, timestamp: Math.floor(Date.now() / 1000) }; } catch (error) { throw new Error(`Bridge transaction failed: ${error.message}`); } } async getBridgeContract(protocol, chain) { const contracts = this.bridgeContracts.get(protocol); if (!contracts || !contracts[chain.toLowerCase()]) { throw new Error(`Contract address not found for protocol: ${protocol} on chain: ${chain}`); } const address = contracts[chain.toLowerCase()]; const abi = protocol === 'LayerZero' ? LAYERZERO_BRIDGE_ABI : HOP_BRIDGE_ABI; return new ethers.Contract(address, abi, this.wallet); } async getLayerZeroQuote(params) { const bridgeContract = await this.getBridgeContract('LayerZero', params.targetChain); const dstChainId = this.getLayerZeroChainId(params.targetChain); const [nativeFee] = await bridgeContract.estimateFees(dstChainId, this.wallet.address, '0x'); return { estimatedGas: BigInt(300000), // Approximate gas limit bridgeFee: nativeFee.toString(), estimatedTime: 1800, // 30 minutes minAmountOut: params.amount, // LayerZero guarantees exact amount protocol: 'LayerZero' }; } async getHopQuote(params) { // Implementation for Hop bridge quote return { estimatedGas: BigInt(500000), bridgeFee: '0', estimatedTime: 600, // 10 minutes minAmountOut: params.amount, protocol: 'Hop' }; } async getAcrossQuote(params) { // Implementation for Across bridge quote return { estimatedGas: BigInt(400000), bridgeFee: '0', estimatedTime: 900, // 15 minutes minAmountOut: params.amount, protocol: 'Across' }; } calculateRouteScore(quote) { const feeFactor = 1 / Number(quote.bridgeFee); const timeFactor = 1 / quote.estimatedTime; return feeFactor * 0.7 + timeFactor * 0.3; // Weight fees more than time } async getBridgeSteps(params, protocol) { // Implementation to get bridge steps return []; } async bridgeWithLayerZero(contract, params, recipient) { const dstChainId = this.getLayerZeroChainId(params.targetChain); return await contract.bridge(dstChainId, params.token, params.amount, recipient, { value: params.amount } // For native token bridges ); } async bridgeWithHop(contract, params, recipient) { const deadline = Math.floor(Date.now() / 1000) + 3600; // 1 hour deadline return await contract.sendToL2(this.getHopChainId(params.targetChain), recipient, params.amount, deadline, 0 // relayerFee ); } async bridgeWithAcross(params, recipient) { // Implementation for Across bridge throw new Error('Across bridge not implemented yet'); } getLayerZeroChainId(chain) { const chainIds = { 'ethereum': 101, 'bnb': 102, 'avalanche': 106, 'polygon': 109, 'arbitrum': 110, 'optimism': 111, 'fantom': 112 }; const chainId = chainIds[chain.toLowerCase()]; if (!chainId) throw new Error(`Unsupported chain: ${chain}`); return chainId; } getHopChainId(chain) { const chainIds = { 'ethereum': 1, 'bnb': 56, 'polygon': 137, 'arbitrum': 42161, 'optimism': 10, 'gnosis': 100 }; const chainId = chainIds[chain.toLowerCase()]; if (!chainId) throw new Error(`Unsupported chain: ${chain}`); return chainId; } } //# sourceMappingURL=bridge.js.map