123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- import { ethers } from 'ethers'
- import { Router__factory, RouterETH, RouterETH__factory, StargateFeeLibraryV07__factory } from '../contract'
- import { chainInfoMap } from '../config/chain'
- import polly from 'polly-js'
- import { newLogger } from '../utils/logger'
- export class StargateClient {
- static logger = newLogger('StargateClient')
- wallet: ethers.Wallet
- chainId: number
- provider: ethers.JsonRpcProvider
- constructor(privateKey: string, chainId: number) {
- this.chainId = chainId
- this.provider = new ethers.JsonRpcProvider(chainInfoMap[chainId].rpcUrl)
- this.wallet = new ethers.Wallet(privateKey, this.provider)
- }
- async getFeeInfo(fromChainId: number, toChainId: number, sendAmount: bigint) {
- const dummyAddress = '0x0000000000000000000000000000000000000001'
- const fee = StargateFeeLibraryV07__factory.connect(chainInfoMap[fromChainId].feeAddress, this.wallet)
- const { eqFee, eqReward, lpFee, protocolFee, lkbRemove } = await fee.getFees(
- 13n,
- 13n,
- toChainId,
- dummyAddress,
- sendAmount,
- )
- const finalFee = eqFee - eqReward + lpFee + protocolFee + lkbRemove
- console.log('fee', ethers.formatEther(finalFee))
- }
- async getL0GasCost(toChainId: number) {
- const dummyAddress = '0x0000000000000000000000000000000000000001'
- const router = Router__factory.connect(chainInfoMap[this.chainId].routerAddress, this.wallet)
- const [gasCost] = await router.quoteLayerZeroFee(toChainId, 1, dummyAddress, '0x', {
- dstGasForCall: 0n,
- dstNativeAmount: 0n,
- dstNativeAddr: dummyAddress,
- })
- return (gasCost * 120n) / 100n
- }
- async bridge(toChainId: number) {
- const routerEth = RouterETH__factory.connect(chainInfoMap[this.chainId].ethRouterAddress, this.wallet)
- const lzGasCost = await this.getL0GasCost(toChainId)
- const { gasCost, gasPrice, gasLimit } = await this.calculateGasCost(toChainId, routerEth, lzGasCost)
- let cost = gasCost
- let limit = gasLimit
- return await polly()
- .waitAndRetry([1000 * 60, 1000 * 60 * 2, 1000 * 60 * 3])
- .executeForPromise(async info => {
- try {
- const balance = await this.provider.getBalance(this.wallet.address)
- // the cost is not precisely calculated, should be sufficient for common L2s
- if (balance < gasCost + lzGasCost) throw new Error('Insufficient balance')
- if (info.count > 0) {
- StargateClient.logger.info(`${this.wallet.address}: Retry ${info.count} times`)
- }
- // add 30% gas cost for each retry
- cost = (cost * 120n) / 100n
- limit = (limit * 120n) / 100n
- const sendAmount = balance - lzGasCost - cost
- // const sendAmount = ethers.parseEther('0.01')
- const minReceiveAmount = (sendAmount * 995n) / 1000n
- const res = await routerEth.swapETH(
- toChainId,
- this.wallet.address,
- this.wallet.address,
- sendAmount,
- minReceiveAmount,
- { value: sendAmount + lzGasCost, gasLimit: limit, gasPrice },
- )
- const receipt = await res.wait()
- if (!receipt.status) {
- throw new Error('Transaction reverted')
- }
- return res.hash
- } catch (e) {
- StargateClient.logger.error(e.message, `Failed to bridge to ${toChainId}`)
- throw e
- }
- })
- }
- async calculateGasCost(toChainId: number, routerEth: RouterETH, lzGasCost: bigint) {
- const feeData = await this.provider.getFeeData()
- const gasPrice = feeData.gasPrice
- const amount = ethers.parseEther('0.001')
- const gasLimit = await routerEth.swapETH.estimateGas(
- toChainId,
- this.wallet.address,
- this.wallet.address,
- amount,
- 0n,
- {
- value: amount + lzGasCost,
- },
- )
- // const gasCost = ((this.chainId === 110 ? gasPrice : ethers.parseUnits('0.6', 'gwei')) * gasLimit * 110n) / 100n
- return { gasCost: ethers.parseEther('0.0004'), gasPrice, gasLimit }
- }
- }
|