From 5cabf4c406c9233cb96ab64d4486c65dcbcaebd9 Mon Sep 17 00:00:00 2001 From: Jorge Galat Date: Fri, 27 Oct 2023 12:13:11 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=A9=B9=20gas:=20use=20l1=20gas=20oracle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- abi/GasPriceOracle.json | 66 +++++++++++++++++++ .../OperationsModal/ModalTxCost/index.tsx | 24 +++---- hooks/useApprove.ts | 4 +- hooks/useEstimateGas.ts | 26 ++++++-- wagmi.config.ts | 2 + 5 files changed, 104 insertions(+), 18 deletions(-) create mode 100644 abi/GasPriceOracle.json diff --git a/abi/GasPriceOracle.json b/abi/GasPriceOracle.json new file mode 100644 index 000000000..1107ac1c8 --- /dev/null +++ b/abi/GasPriceOracle.json @@ -0,0 +1,66 @@ +[ + { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, + { + "inputs": [], + "name": "baseFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "gasPrice", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes", "name": "_data", "type": "bytes" }], + "name": "getL1Fee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes", "name": "_data", "type": "bytes" }], + "name": "getL1GasUsed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1BaseFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "overhead", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "scalar", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/components/OperationsModal/ModalTxCost/index.tsx b/components/OperationsModal/ModalTxCost/index.tsx index 6b0d0aa85..eb820f522 100644 --- a/components/OperationsModal/ModalTxCost/index.tsx +++ b/components/OperationsModal/ModalTxCost/index.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import React from 'react'; import { Typography, Skeleton, Box } from '@mui/material'; import { useTranslation } from 'react-i18next'; import { formatUnits } from 'viem'; @@ -6,6 +6,8 @@ import { WEI_PER_ETHER } from 'utils/const'; import ModalInfo from 'components/common/modal/ModalInfo'; import useAccountData from 'hooks/useAccountData'; +import useEstimateGas from 'hooks/useEstimateGas'; +import useAsyncLoad from 'hooks/useAsyncLoad'; type Props = { gasCost?: bigint; @@ -14,24 +16,22 @@ type Props = { function ModalTxCost({ gasCost }: Props) { const { t } = useTranslation(); const { marketAccount } = useAccountData('WETH'); + const estimate = useEstimateGas(); + const { data: fallback } = useAsyncLoad(estimate); - const renderGas = useMemo(() => { - if (!gasCost || !marketAccount) return ; + const gas = gasCost || fallback; - const eth = parseFloat(formatUnits(gasCost, 18)).toFixed(6); - const usd = parseFloat(formatUnits((gasCost * marketAccount.usdPrice) / WEI_PER_ETHER, 18)).toFixed(2); + if (!gas || !marketAccount) return ; - return ( + const eth = parseFloat(formatUnits(gas, 18)).toFixed(6); + const usd = parseFloat(formatUnits((gas * marketAccount.usdPrice) / WEI_PER_ETHER, 18)).toFixed(2); + + return ( + {`~$${usd}`} {`(${eth} ETH)`} - ); - }, [gasCost, marketAccount]); - - return ( - - {renderGas} ); } diff --git a/hooks/useApprove.ts b/hooks/useApprove.ts index 3d5525600..859ca383a 100644 --- a/hooks/useApprove.ts +++ b/hooks/useApprove.ts @@ -1,5 +1,5 @@ import { useCallback, useState } from 'react'; -import { parseUnits, type Address, type EstimateGasParameters, type Hex } from 'viem'; +import { parseUnits, type Address, type EstimateContractGasParameters, type Hex } from 'viem'; import { ERC20, Market } from 'types/contracts'; import { useWeb3 } from './useWeb3'; import { useOperationContext } from 'contexts/OperationContext'; @@ -37,7 +37,7 @@ function useApprove({ const estimateGas = useCallback(async () => { if (!contract || !spender || !walletAddress || !opts) return; - let params: EstimateGasParameters; + let params: EstimateContractGasParameters; switch (operation) { case 'deposit': case 'depositAtMaturity': diff --git a/hooks/useEstimateGas.ts b/hooks/useEstimateGas.ts index 7418dd2fc..ce8946c82 100644 --- a/hooks/useEstimateGas.ts +++ b/hooks/useEstimateGas.ts @@ -1,9 +1,11 @@ import { useCallback, useMemo } from 'react'; +import { encodeFunctionData, type EstimateContractGasParameters } from 'viem'; import { usePublicClient } from 'wagmi'; +import { optimism } from 'wagmi/chains'; import { useWeb3 } from './useWeb3'; import { isE2E } from 'utils/client'; import { getAlchemyProvider } from 'utils/providers'; -import { EstimateGasParameters } from 'viem'; +import { l1GasPriceOracleABI } from 'types/abi'; export default function useEstimateGas() { const { chain } = useWeb3(); @@ -11,12 +13,28 @@ export default function useEstimateGas() { const publicClient = useMemo(() => (isE2E ? e2ePublicClient : getAlchemyProvider(chain)), [chain, e2ePublicClient]); return useCallback( - async (request: EstimateGasParameters) => { + async (request?: EstimateContractGasParameters) => { if (!publicClient) return; + let l1Gas = 0n; + if (chain.id === optimism.id) { + if (request) { + const data = encodeFunctionData(request); + l1Gas = await publicClient.readContract({ + abi: l1GasPriceOracleABI, + address: '0x420000000000000000000000000000000000000F', + functionName: 'getL1Fee', + args: [data], + }); + } else { + l1Gas = 5_555_555_555_55n; + } + } const gasPrice = await publicClient.getGasPrice(); - return gasPrice * (await publicClient.estimateGas(request)); + const gasUsed = request ? await publicClient.estimateContractGas(request) : 500_000n; + + return gasPrice * gasUsed + l1Gas; }, - [publicClient], + [publicClient, chain], ); } diff --git a/wagmi.config.ts b/wagmi.config.ts index 133bb8414..c8daab945 100644 --- a/wagmi.config.ts +++ b/wagmi.config.ts @@ -22,6 +22,7 @@ import SablierV2LockupLinear from '@exactly/protocol/deployments/goerli/SablierV import SablierV2NFTDescriptor from '@exactly/protocol/deployments/goerli/SablierV2NFTDescriptor.json' assert { type: 'json' }; import ExtraFinanceLendingABI from './abi/extraFinanceLending.json' assert { type: 'json' }; import DelegateRegistryABI from './abi/DelegateRegistry.json' assert { type: 'json' }; +import GasPriceOracle from './abi/GasPriceOracle.json' assert { type: 'json' }; import EscrowedEXA from '@exactly/protocol/deployments/goerli/esEXA.json' assert { type: 'json' }; import { Abi } from 'viem'; @@ -51,6 +52,7 @@ export default defineConfig({ { name: 'ExtraFinanceLending', abi: ExtraFinanceLendingABI as Abi }, { name: 'DelegateRegistry', abi: DelegateRegistryABI as Abi }, { name: 'EscrowedEXA', abi: EscrowedEXA.abi as Abi }, + { name: 'L1GasPriceOracle', abi: GasPriceOracle as Abi }, ], plugins: [ react({