import { Contract, ethers } from 'ethers' import { ChainId, chainInfoMap } from '../config/chain' import { newLogger } from '../utils/logger' export class MerklyClient { wallet: ethers.Wallet chainId: number provider: ethers.JsonRpcProvider router: ethers.Contract static logger = newLogger('MerklyClient') constructor(privateKey: string, chainId: number) { const from = chainInfoMap[chainId].merklyInfo if (!from) { throw new Error('Unsupported chain') } this.chainId = chainId this.provider = new ethers.JsonRpcProvider(chainInfoMap[chainId].rpcUrl) this.wallet = new ethers.Wallet(privateKey, this.provider) this.router = new Contract( chainInfoMap[chainId].merklyInfo.routerAddress, [ 'function quoteBridge(uint32 _destination, uint amount) external view returns (uint fee)', 'function bridgeETH(uint32 _destination, uint amount) public payable returns (bytes32 messageId)', 'function bridgeWETH(uint32 _destination, uint amount) public payable returns (bytes32 messageId)', ], this.wallet, ) } async bridge(toChainId: number = ChainId.ARBITRUM) { const toInfo = chainInfoMap[toChainId].merklyInfo if (!toInfo) { throw new Error('Unsupported chain') } const balance = await this.provider.getBalance(this.wallet.address) const quote = await this.router.quoteBridge(toInfo.merklyChainId, balance) if (balance > quote) { const feeData = await this.provider.getFeeData() const estimatedGas = await this.router.bridgeETH.estimateGas(toInfo.merklyChainId, balance - quote, { value: balance, }) const gasCost = (feeData.gasPrice * estimatedGas * 108n) / 100n if (balance < quote + gasCost) { MerklyClient.logger.error('Insufficient balance') // throw new Error('Insufficient balance') } const tx = await this.router.bridgeETH(toInfo.merklyChainId, balance - quote - gasCost, { value: balance - gasCost, gasLimit: (estimatedGas * 105n) / 100n, gasPrice: feeData.gasPrice, }) return tx.hash } else { MerklyClient.logger.error('Insufficient balance') } } }