diff --git a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasEstimates.ts b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasEstimates.ts index 009acaf2ee..ccd6e9cfd8 100644 --- a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasEstimates.ts +++ b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasEstimates.ts @@ -2,13 +2,13 @@ import { BigNumber, constants, utils } from 'ethers' import useSWR from 'swr' import { useAccount } from 'wagmi' -import { DepositGasEstimates, GasEstimates } from '../arbTokenBridge.types' import { BridgeTransferStarterFactory } from '@/token-bridge-sdk/BridgeTransferStarterFactory' import { getProviderForChainId } from '@/token-bridge-sdk/utils' import { useBalanceOnSourceChain } from '../useBalanceOnSourceChain' import { useNetworks } from '../useNetworks' import { useSelectedToken } from '../useSelectedToken' import { useArbQueryParams } from '../useArbQueryParams' +import { TransferEstimateGasResult } from '@/token-bridge-sdk/BridgeTransferStarter' async function fetcher([ walletAddress, @@ -26,7 +26,7 @@ async function fetcher([ destinationChainErc20Address: string | undefined, destinationAddress: string | undefined, amount: BigNumber -]): Promise { +]): Promise { const _walletAddress = walletAddress ?? constants.AddressZero const sourceProvider = getProviderForChainId(sourceChainId) const signer = sourceProvider.getSigner(_walletAddress) @@ -54,7 +54,7 @@ export function useGasEstimates({ destinationChainErc20Address?: string amount: BigNumber }): { - gasEstimates: GasEstimates | DepositGasEstimates | undefined + gasEstimates: TransferEstimateGasResult error: any } { const [{ sourceChain, destinationChain }] = useNetworks() diff --git a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts index e687a083cd..7720d190e3 100644 --- a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts +++ b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useGasSummary.ts @@ -15,8 +15,6 @@ import { DepositGasEstimates } from '../arbTokenBridge.types' import { percentIncrease } from '@/token-bridge-sdk/utils' import { DEFAULT_GAS_PRICE_PERCENT_INCREASE } from '@/token-bridge-sdk/Erc20DepositStarter' import { useSelectedToken } from '../useSelectedToken' -import { useIsOftV2Transfer } from '../../components/TransferPanel/hooks/useIsOftV2Transfer' -import { useOftV2FeeEstimates } from './useOftV2FeeEstimates' import { isWithdrawalFromArbOneToEthereum, isWithdrawalFromArbSepoliaToSepolia @@ -43,8 +41,6 @@ export function getGasSummaryStatus({ amountBigNumber, balance, gasEstimatesError, - oftFeeEstimatesError, - oftFeeSummaryLoading, sourceChainId, destinationChainId }: { @@ -52,8 +48,6 @@ export function getGasSummaryStatus({ amountBigNumber: BigNumber balance: BigNumber | null gasEstimatesError: any - oftFeeEstimatesError: boolean - oftFeeSummaryLoading: boolean sourceChainId: number destinationChainId: number }): GasEstimationStatus { @@ -72,7 +66,7 @@ export function getGasSummaryStatus({ return 'unavailable' } - if (balance === null || oftFeeSummaryLoading) { + if (balance === null) { return 'loading' } @@ -80,7 +74,7 @@ export function getGasSummaryStatus({ return 'insufficientBalance' } - if (gasEstimatesError || oftFeeEstimatesError) { + if (gasEstimatesError) { return 'error' } @@ -126,28 +120,7 @@ export function useGasSummary(): UseGasSummaryResult { : selectedToken?.address }) - const isOft = useIsOftV2Transfer() - const { - feeEstimates: oftFeeEstimates, - error: oftFeeEstimatesError, - isLoading: oftFeeSummaryLoading - } = useOftV2FeeEstimates({ - sourceChainErc20Address: isDepositMode - ? selectedToken?.address - : selectedToken?.l2Address - }) - const estimatedParentChainGasFees = useMemo(() => { - if (isOft && oftFeeEstimates) { - return parseFloat( - utils.formatEther( - isDepositMode - ? oftFeeEstimates.sourceChainGasFee - : oftFeeEstimates.destinationChainGasFee - ) - ) - } - if (!estimateGasResult?.estimatedParentChainGas) { return } @@ -156,25 +129,9 @@ export function useGasSummary(): UseGasSummaryResult { estimateGasResult.estimatedParentChainGas.mul(parentChainGasPrice) ) ) - }, [ - estimateGasResult, - parentChainGasPrice, - isOft, - oftFeeEstimates, - isDepositMode - ]) + }, [estimateGasResult, parentChainGasPrice]) const estimatedChildChainGasFees = useMemo(() => { - if (isOft && oftFeeEstimates) { - return parseFloat( - utils.formatEther( - isDepositMode - ? oftFeeEstimates.destinationChainGasFee - : oftFeeEstimates.sourceChainGasFee - ) - ) - } - if (!estimateGasResult?.estimatedChildChainGas) { return } @@ -203,13 +160,7 @@ export function useGasSummary(): UseGasSummaryResult { estimateGasResult.estimatedChildChainGas.mul(childChainGasPrice) ) ) - }, [ - childChainGasPrice, - estimateGasResult, - isDepositMode, - oftFeeEstimates, - isOft - ]) + }, [childChainGasPrice, estimateGasResult, isDepositMode]) const gasSummaryStatus = useMemo( () => @@ -218,20 +169,10 @@ export function useGasSummary(): UseGasSummaryResult { amountBigNumber, balance, gasEstimatesError, - oftFeeEstimatesError, - oftFeeSummaryLoading, sourceChainId: networks.sourceChain.id, destinationChainId: networks.destinationChain.id }), - [ - selectedToken, - amountBigNumber, - balance, - gasEstimatesError, - oftFeeEstimatesError, - oftFeeSummaryLoading, - networks - ] + [selectedToken, amountBigNumber, balance, gasEstimatesError, networks] ) return { diff --git a/packages/arb-token-bridge-ui/src/hooks/__tests__/useGasSummary.test.tsx b/packages/arb-token-bridge-ui/src/hooks/__tests__/useGasSummary.test.tsx index 18f5d9a089..ae39214278 100644 --- a/packages/arb-token-bridge-ui/src/hooks/__tests__/useGasSummary.test.tsx +++ b/packages/arb-token-bridge-ui/src/hooks/__tests__/useGasSummary.test.tsx @@ -72,29 +72,17 @@ describe('getGasSummaryStatus', () => { } it('should return error if there is an OFT fee estimate error', async () => { - const result = getGasSummaryStatus({ - ...mockedGasSummaryParams, - oftFeeSummaryLoading: false, - oftFeeEstimatesError: true - }) + const result = getGasSummaryStatus(mockedGasSummaryParams) expect(result).toEqual('error') }) it('should return success if there is not an OFT fee estimate error', async () => { - const result = getGasSummaryStatus({ - ...mockedGasSummaryParams, - oftFeeSummaryLoading: false, - oftFeeEstimatesError: false - }) + const result = getGasSummaryStatus(mockedGasSummaryParams) expect(result).toEqual('success') }) it('should return loading if OFT fee summary is loading', async () => { - const result = getGasSummaryStatus({ - ...mockedGasSummaryParams, - oftFeeSummaryLoading: true, - oftFeeEstimatesError: false - }) + const result = getGasSummaryStatus(mockedGasSummaryParams) expect(result).toEqual('loading') }) }) @@ -105,8 +93,6 @@ describe('getGasSummaryStatus', () => { gasEstimatesError: new Error('cannot estimate gas'), amountBigNumber: BigNumber.from(100_000), balance: BigNumber.from(100_000), - oftFeeSummaryLoading: false, - oftFeeEstimatesError: false, sourceChainId: ChainId.ArbitrumOne, destinationChainId: ChainId.Ethereum }) @@ -119,8 +105,6 @@ describe('getGasSummaryStatus', () => { gasEstimatesError: 'walletNotConnected', amountBigNumber: BigNumber.from(100_000), balance: BigNumber.from(100_000), - oftFeeSummaryLoading: false, - oftFeeEstimatesError: false, sourceChainId: ChainId.ArbitrumOne, destinationChainId: ChainId.Ethereum }) @@ -133,8 +117,6 @@ describe('getGasSummaryStatus', () => { gasEstimatesError: 'walletNotConnected', amountBigNumber: BigNumber.from(100_000), balance: BigNumber.from(100_000), - oftFeeSummaryLoading: false, - oftFeeEstimatesError: false, sourceChainId: ChainId.ArbitrumSepolia, destinationChainId: ChainId.Sepolia }) diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/BridgeTransferStarter.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/BridgeTransferStarter.ts index 0edee982ca..28a00bc3b3 100644 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/BridgeTransferStarter.ts +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/BridgeTransferStarter.ts @@ -61,6 +61,11 @@ export type TransferProps = { overrides?: TransferOverrides } +export type TransferEstimateGasResult = + | GasEstimates + | DepositGasEstimates + | undefined + export type RequiresNativeCurrencyApprovalProps = { amount: BigNumber signer: Signer @@ -136,7 +141,7 @@ export abstract class BridgeTransferStarter { public abstract transferEstimateGas( props: TransferEstimateGasProps - ): Promise + ): Promise public abstract transfer(props: TransferProps): Promise } diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/OftV2TransferStarter.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/OftV2TransferStarter.ts index 1e027559a1..c178c1b44f 100644 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/OftV2TransferStarter.ts +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/OftV2TransferStarter.ts @@ -1,4 +1,4 @@ -import { constants, ethers, Signer } from 'ethers' +import { BigNumber, constants, Contract, ethers, Signer } from 'ethers' import { Provider } from '@ethersproject/providers' import { ERC20__factory } from '@arbitrum/sdk/dist/lib/abi/factories/ERC20__factory' import { @@ -11,14 +11,54 @@ import { BridgeTransferStarterProps } from './BridgeTransferStarter' import { fetchErc20Allowance } from '../util/TokenUtils' -import { getAddressFromSigner } from './utils' +import { getAddressFromSigner, getChainIdFromProvider } from './utils' import { getOftV2TransferConfig, buildSendParams, getOftV2Quote } from './oftUtils' -import oftV2Abi from './oftV2Abi.json' +import { oftV2Abi } from './oftV2Abi' import { isNetwork } from '../util/networks' +import { Address, prepareWriteContract, writeContract } from '@wagmi/core' +import { isDepositMode as isDepositModeUtil } from '../util/isDepositMode' + +async function prepareTransferConfig({ + signer, + oftContract, + destLzEndpointId, + amount, + destinationAddress +}: { + signer: Signer + oftContract: Contract + destLzEndpointId: number + amount: BigNumber + destinationAddress?: string +}) { + const address = await getAddressFromSigner(signer) + + const sendParams = buildSendParams({ + dstEid: destLzEndpointId, + address, + amount, + destinationAddress + }) + const quoteFee = await getOftV2Quote({ + sendParams, + address: oftContract.address as Address + }) + + return prepareWriteContract({ + address: oftContract.address as Address, + abi: oftV2Abi, + signer, + functionName: 'send', + args: [sendParams, quoteFee, address as Address], + overrides: { + value: quoteFee.nativeFee + } + }) +} export class OftV2TransferStarter extends BridgeTransferStarter { public transferType: TransferType = 'oftV2' @@ -131,7 +171,7 @@ export class OftV2TransferStarter extends BridgeTransferStarter { return allowance.lt(amount) } - public async approveTokenEstimateGas({ signer, amount }: ApproveTokenProps) { + public async approveTokenEstimateGas({ signer }: ApproveTokenProps) { await this.validateOftTransfer() const address = await getAddressFromSigner(signer) @@ -158,14 +198,41 @@ export class OftV2TransferStarter extends BridgeTransferStarter { return contract.functions.approve(spender, constants.MaxUint256) // Eth USDT will need MAX approval since that cannot be changed afterwards } - // for OFT, we don't have functions for gas estimates, `sendQuote` method tells us the fees directly - public async transferEstimateGas() { - return undefined + public async transferEstimateGas({ + amount, + signer, + destinationAddress + }: TransferEstimateGasProps) { + await this.validateOftTransfer() + + const oftContract = this.getOftAdapterContract(signer) + const config = await prepareTransferConfig({ + signer, + oftContract, + amount, + destLzEndpointId: this.destLzEndpointId!, + destinationAddress + }) + + const isDepositMode = isDepositModeUtil({ + sourceChainId: await getChainIdFromProvider(this.sourceChainProvider), + destinationChainId: await getChainIdFromProvider( + this.destinationChainProvider + ) + }) + + const gasEstimate = await signer.estimateGas(config.request) + + return { + estimatedParentChainGas: isDepositMode ? gasEstimate : constants.Zero, + estimatedChildChainGas: isDepositMode ? constants.Zero : gasEstimate + } } public async transferEstimateFee({ amount, - signer + signer, + destinationAddress }: TransferEstimateGasProps) { await this.validateOftTransfer() @@ -175,17 +242,39 @@ export class OftV2TransferStarter extends BridgeTransferStarter { const sendParams = buildSendParams({ dstEid: this.destLzEndpointId!, address, - amount + amount, + destinationAddress }) // the amount in native currency that needs to be paid at the source chain to cover for both source and destination message transfers const { nativeFee } = await getOftV2Quote({ - contract: oftContract, + address: oftContract.address as Address, sendParams }) + const gasEstimates = await this.transferEstimateGas({ + amount, + signer, + destinationAddress + }) + + /** + * getOftV2Quote return both gas fee and layerzero fee + * We substract gas estimate from the fee to get an estimate of the fee + */ + const isDepositMode = isDepositModeUtil({ + sourceChainId: await getChainIdFromProvider(this.sourceChainProvider), + destinationChainId: await getChainIdFromProvider( + this.destinationChainProvider + ) + }) + return { - estimatedSourceChainFee: nativeFee, + estimatedSourceChainFee: nativeFee.sub( + isDepositMode + ? gasEstimates.estimatedParentChainGas + : gasEstimates.estimatedChildChainGas + ), estimatedDestinationChainFee: constants.Zero } } @@ -193,30 +282,16 @@ export class OftV2TransferStarter extends BridgeTransferStarter { public async transfer({ amount, signer, destinationAddress }: TransferProps) { await this.validateOftTransfer() - const address = await getAddressFromSigner(signer) const oftContract = this.getOftAdapterContract(signer) - - const sendParams = buildSendParams({ - dstEid: this.destLzEndpointId!, - address, + const config = await prepareTransferConfig({ + signer, + oftContract, amount, + destLzEndpointId: this.destLzEndpointId!, destinationAddress }) - const { nativeFee, lzTokenFee } = await getOftV2Quote({ - contract: oftContract, - sendParams - }) - - const sendTx = await oftContract.send( - sendParams, - { - nativeFee: nativeFee, - lzTokenFee: lzTokenFee - }, - address, - { value: nativeFee } - ) + const sendTx = await writeContract(config) return { transferType: this.transferType, diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftUtils.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftUtils.ts index 0ad924eaba..75d53c7cc7 100644 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftUtils.ts +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftUtils.ts @@ -2,6 +2,9 @@ import { ethers } from 'ethers' import { ChainId } from '../types/ChainId' import { CommonAddress } from '../util/CommonAddressUtils' import { BigNumber } from 'ethers' +import { Address } from 'wagmi' +import { ReadContractResult, readContract } from '@wagmi/core' +import { oftV2Abi } from './oftV2Abi' // from https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts const oftProtocolConfig: { @@ -90,17 +93,12 @@ export function getOftV2TransferConfig({ } interface SendParam { dstEid: number - to: string - amountLD: string - minAmountLD: string - extraOptions: string - composeMsg: string - oftCmd: string -} - -interface QuoteResult { - nativeFee: string - lzTokenFee: string + to: Address + amountLD: BigNumber + minAmountLD: BigNumber + extraOptions: `0x${string}` + composeMsg: `0x${string}` + oftCmd: `0x${string}` } export function buildSendParams({ @@ -112,29 +110,35 @@ export function buildSendParams({ dstEid: number address: string amount: BigNumber - destinationAddress?: string + destinationAddress: string | undefined }): SendParam { return { dstEid, - to: ethers.utils.hexZeroPad(destinationAddress ?? address, 32), - amountLD: amount.toString(), - minAmountLD: amount.toString(), + to: ethers.utils.hexZeroPad(destinationAddress ?? address, 32) as Address, + amountLD: amount, + minAmountLD: amount, extraOptions: '0x', composeMsg: '0x', oftCmd: '0x' } } +type QuoteResult = ReadContractResult export async function getOftV2Quote({ - contract, + address, sendParams }: { - contract: ethers.Contract + address: Address sendParams: SendParam }): Promise { - const quote = await contract.quoteSend(sendParams, false) + const quote = await readContract({ + address, + abi: oftV2Abi, + functionName: 'quoteSend', + args: [sendParams, false] + }) return { - nativeFee: quote.nativeFee.toString(), - lzTokenFee: quote.lzTokenFee.toString() + nativeFee: quote.nativeFee, + lzTokenFee: quote.lzTokenFee } } diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftV2Abi.json b/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftV2Abi.json deleted file mode 100644 index 1347af51f1..0000000000 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftV2Abi.json +++ /dev/null @@ -1,381 +0,0 @@ -[ - { - "type": "error", - "name": "InvalidLocalDecimals", - "inputs": [] - }, - { - "type": "error", - "name": "SlippageExceeded", - "inputs": [ - { - "name": "amountLD", - "type": "uint256" - }, - { - "name": "minAmountLD", - "type": "uint256" - } - ] - }, - { - "type": "event", - "name": "OFTSent", - "inputs": [ - { - "name": "guid", - "type": "bytes32", - "indexed": true - }, - { - "name": "dstEid", - "type": "uint32", - "indexed": false - }, - { - "name": "fromAddress", - "type": "address", - "indexed": true - }, - { - "name": "amountSentLD", - "type": "uint256", - "indexed": false - }, - { - "name": "amountReceivedLD", - "type": "uint256", - "indexed": false - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "OFTReceived", - "inputs": [ - { - "name": "guid", - "type": "bytes32", - "indexed": true - }, - { - "name": "srcEid", - "type": "uint32", - "indexed": false - }, - { - "name": "toAddress", - "type": "address", - "indexed": true - }, - { - "name": "amountReceivedLD", - "type": "uint256", - "indexed": false - } - ], - "anonymous": false - }, - { - "type": "function", - "name": "oftVersion", - "inputs": [], - "outputs": [ - { - "name": "interfaceId", - "type": "bytes4" - }, - { - "name": "version", - "type": "uint64" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "token", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "approvalRequired", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "sharedDecimals", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "quoteOFT", - "inputs": [ - { - "name": "_sendParam", - "type": "tuple", - "components": [ - { - "name": "dstEid", - "type": "uint32" - }, - { - "name": "to", - "type": "bytes32" - }, - { - "name": "amountLD", - "type": "uint256" - }, - { - "name": "minAmountLD", - "type": "uint256" - }, - { - "name": "extraOptions", - "type": "bytes" - }, - { - "name": "composeMsg", - "type": "bytes" - }, - { - "name": "oftCmd", - "type": "bytes" - } - ] - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "components": [ - { - "name": "minAmountLD", - "type": "uint256" - }, - { - "name": "maxAmountLD", - "type": "uint256" - } - ] - }, - { - "name": "", - "type": "tuple[]", - "components": [ - { - "name": "feeAmountLD", - "type": "int256" - }, - { - "name": "description", - "type": "string" - } - ] - }, - { - "name": "", - "type": "tuple", - "components": [ - { - "name": "amountSentLD", - "type": "uint256" - }, - { - "name": "amountReceivedLD", - "type": "uint256" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "quoteSend", - "inputs": [ - { - "name": "_sendParam", - "type": "tuple", - "components": [ - { - "name": "dstEid", - "type": "uint32" - }, - { - "name": "to", - "type": "bytes32" - }, - { - "name": "amountLD", - "type": "uint256" - }, - { - "name": "minAmountLD", - "type": "uint256" - }, - { - "name": "extraOptions", - "type": "bytes" - }, - { - "name": "composeMsg", - "type": "bytes" - }, - { - "name": "oftCmd", - "type": "bytes" - } - ] - }, - { - "name": "_payInLzToken", - "type": "bool" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "components": [ - { - "name": "nativeFee", - "type": "uint256" - }, - { - "name": "lzTokenFee", - "type": "uint256" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "send", - "inputs": [ - { - "name": "_sendParam", - "type": "tuple", - "components": [ - { - "name": "dstEid", - "type": "uint32" - }, - { - "name": "to", - "type": "bytes32" - }, - { - "name": "amountLD", - "type": "uint256" - }, - { - "name": "minAmountLD", - "type": "uint256" - }, - { - "name": "extraOptions", - "type": "bytes" - }, - { - "name": "composeMsg", - "type": "bytes" - }, - { - "name": "oftCmd", - "type": "bytes" - } - ] - }, - { - "name": "_fee", - "type": "tuple", - "components": [ - { - "name": "nativeFee", - "type": "uint256" - }, - { - "name": "lzTokenFee", - "type": "uint256" - } - ] - }, - { - "name": "_refundAddress", - "type": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "components": [ - { - "name": "guid", - "type": "bytes32" - }, - { - "name": "nonce", - "type": "uint64" - }, - { - "name": "fee", - "type": "tuple", - "components": [ - { - "name": "nativeFee", - "type": "uint256" - }, - { - "name": "lzTokenFee", - "type": "uint256" - } - ] - } - ] - }, - { - "name": "", - "type": "tuple", - "components": [ - { - "name": "amountSentLD", - "type": "uint256" - }, - { - "name": "amountReceivedLD", - "type": "uint256" - } - ] - } - ], - "stateMutability": "payable" - } -] diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftV2Abi.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftV2Abi.ts new file mode 100644 index 0000000000..59e1c6c996 --- /dev/null +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/oftV2Abi.ts @@ -0,0 +1,381 @@ +export const oftV2Abi = [ + { + type: 'error', + name: 'InvalidLocalDecimals', + inputs: [] + }, + { + type: 'error', + name: 'SlippageExceeded', + inputs: [ + { + name: 'amountLD', + type: 'uint256' + }, + { + name: 'minAmountLD', + type: 'uint256' + } + ] + }, + { + type: 'event', + name: 'OFTSent', + inputs: [ + { + name: 'guid', + type: 'bytes32', + indexed: true + }, + { + name: 'dstEid', + type: 'uint32', + indexed: false + }, + { + name: 'fromAddress', + type: 'address', + indexed: true + }, + { + name: 'amountSentLD', + type: 'uint256', + indexed: false + }, + { + name: 'amountReceivedLD', + type: 'uint256', + indexed: false + } + ], + anonymous: false + }, + { + type: 'event', + name: 'OFTReceived', + inputs: [ + { + name: 'guid', + type: 'bytes32', + indexed: true + }, + { + name: 'srcEid', + type: 'uint32', + indexed: false + }, + { + name: 'toAddress', + type: 'address', + indexed: true + }, + { + name: 'amountReceivedLD', + type: 'uint256', + indexed: false + } + ], + anonymous: false + }, + { + type: 'function', + name: 'oftVersion', + inputs: [], + outputs: [ + { + name: 'interfaceId', + type: 'bytes4' + }, + { + name: 'version', + type: 'uint64' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'token', + inputs: [], + outputs: [ + { + name: '', + type: 'address' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'approvalRequired', + inputs: [], + outputs: [ + { + name: '', + type: 'bool' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'sharedDecimals', + inputs: [], + outputs: [ + { + name: '', + type: 'uint8' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'quoteOFT', + inputs: [ + { + name: '_sendParam', + type: 'tuple', + components: [ + { + name: 'dstEid', + type: 'uint32' + }, + { + name: 'to', + type: 'bytes32' + }, + { + name: 'amountLD', + type: 'uint256' + }, + { + name: 'minAmountLD', + type: 'uint256' + }, + { + name: 'extraOptions', + type: 'bytes' + }, + { + name: 'composeMsg', + type: 'bytes' + }, + { + name: 'oftCmd', + type: 'bytes' + } + ] + } + ], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + { + name: 'minAmountLD', + type: 'uint256' + }, + { + name: 'maxAmountLD', + type: 'uint256' + } + ] + }, + { + name: '', + type: 'tuple[]', + components: [ + { + name: 'feeAmountLD', + type: 'int256' + }, + { + name: 'description', + type: 'string' + } + ] + }, + { + name: '', + type: 'tuple', + components: [ + { + name: 'amountSentLD', + type: 'uint256' + }, + { + name: 'amountReceivedLD', + type: 'uint256' + } + ] + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'quoteSend', + inputs: [ + { + name: '_sendParam', + type: 'tuple', + components: [ + { + name: 'dstEid', + type: 'uint32' + }, + { + name: 'to', + type: 'bytes32' + }, + { + name: 'amountLD', + type: 'uint256' + }, + { + name: 'minAmountLD', + type: 'uint256' + }, + { + name: 'extraOptions', + type: 'bytes' + }, + { + name: 'composeMsg', + type: 'bytes' + }, + { + name: 'oftCmd', + type: 'bytes' + } + ] + }, + { + name: '_payInLzToken', + type: 'bool' + } + ], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + { + name: 'nativeFee', + type: 'uint256' + }, + { + name: 'lzTokenFee', + type: 'uint256' + } + ] + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'send', + inputs: [ + { + name: '_sendParam', + type: 'tuple', + components: [ + { + name: 'dstEid', + type: 'uint32' + }, + { + name: 'to', + type: 'bytes32' + }, + { + name: 'amountLD', + type: 'uint256' + }, + { + name: 'minAmountLD', + type: 'uint256' + }, + { + name: 'extraOptions', + type: 'bytes' + }, + { + name: 'composeMsg', + type: 'bytes' + }, + { + name: 'oftCmd', + type: 'bytes' + } + ] + }, + { + name: '_fee', + type: 'tuple', + components: [ + { + name: 'nativeFee', + type: 'uint256' + }, + { + name: 'lzTokenFee', + type: 'uint256' + } + ] + }, + { + name: '_refundAddress', + type: 'address' + } + ], + outputs: [ + { + name: '', + type: 'tuple', + components: [ + { + name: 'guid', + type: 'bytes32' + }, + { + name: 'nonce', + type: 'uint64' + }, + { + name: 'fee', + type: 'tuple', + components: [ + { + name: 'nativeFee', + type: 'uint256' + }, + { + name: 'lzTokenFee', + type: 'uint256' + } + ] + } + ] + }, + { + name: '', + type: 'tuple', + components: [ + { + name: 'amountSentLD', + type: 'uint256' + }, + { + name: 'amountReceivedLD', + type: 'uint256' + } + ] + } + ], + stateMutability: 'payable' + } +] as const