Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas estimation #1726

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"@reduxjs/toolkit": "^1.9.2",
"@swapr/core": "^0.3.19",
"@swapr/periphery": "^0.3.22",
"@swapr/sdk": "1.8.1",
"@swapr/sdk": "ImpeccableHQ/swapr-sdk#gas-estimation-build",
"@types/react-helmet": "^6.1.6",
"@uniswap/smart-order-router": "^2.9.3",
"@uniswap/token-lists": "^1.0.0-beta.27",
Expand Down
69 changes: 69 additions & 0 deletions src/constants/data.ts
Original file line number Diff line number Diff line change
@@ -1 +1,70 @@
export const REFETCH_DATA_INTERVAL = 15000

interface TransactionParams {
from: string
to: string
value: string
data: string
}

export const alchemyExectuionBundleOptions = (params: TransactionParams[]) => ({
method: 'POST',
headers: { accept: 'application/json', 'content-type': 'application/json' },
body: JSON.stringify({
id: 1,
jsonrpc: '2.0',
method: 'alchemy_simulateExecutionBundle',
params: [params],
}),
})
interface ApiResponse {
jsonrpc: string
id: number
result: {
calls: {
type: string
from: string
to: string
value: string
gas: string
gasUsed: string
input: string
output: string
decoded?: {
authority: string
methodName: string
inputs: {
name: string
value: string
type: string
}[]
outputs: {
name: string
value: string
type: string
}[]
}
}[]
logs: {
address: string
data: string
topics: string[]
}[]
}[]
}

export const calucalateGasFromAlchemyResponse = async (response: Promise<Response>): Promise<number> => {
const data = (await response).json() as Promise<ApiResponse>
const awaitedData = await data
const gasUsed = awaitedData.result.map(item => {
return item.calls.reduce((sum, call) => {
return sum + parseInt(call.gasUsed)
}, 0)
})

const totalGasUsed = gasUsed.reduce((sum, value) => {
return sum + value
}, 0)

return totalGasUsed
}
56 changes: 25 additions & 31 deletions src/hooks/useGasFeesUSD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,46 @@ import { BigNumber } from 'ethers'
import { useMemo } from 'react'

import { MainnetGasPrice } from '../state/application/actions'
import { useMainnetGasPrices } from '../state/application/hooks'
import { useUserPreferredGasPrice } from '../state/user/hooks'
import { useGasInfo } from './useGasInfo'
import { useNativeCurrencyUSDPrice } from './useNativeCurrencyUSDPrice'

import { useActiveWeb3React } from './index'

export function useGasFeesUSD(gasEstimations: (BigNumber | null)[]): {
export function useGasFeesUSD(gasEstimations: (BigNumber | undefined)[]): {
loading: boolean
gasFeesUSD: (CurrencyAmount | null)[]
} {
const { chainId } = useActiveWeb3React()
const mainnetGasPrices = useMainnetGasPrices()

const [preferredGasPrice] = useUserPreferredGasPrice()
const { loading: loadingNativeCurrencyUSDPrice, nativeCurrencyUSDPrice } = useNativeCurrencyUSDPrice()
const { gas, loading: loadingGasPrices } = useGasInfo()

return useMemo(() => {
if (loadingNativeCurrencyUSDPrice) return { loading: true, gasFeesUSD: [] }
if (
!gasEstimations ||
gasEstimations.length === 0 ||
!preferredGasPrice ||
!chainId ||
(preferredGasPrice in MainnetGasPrice && !mainnetGasPrices)
)
if (loadingNativeCurrencyUSDPrice || loadingGasPrices) return { loading: true, gasFeesUSD: [] }

if (!gasEstimations || gasEstimations.length === 0 || !chainId || !preferredGasPrice)
return { loading: false, gasFeesUSD: [] }
const normalizedPreferredGasPrice =
mainnetGasPrices && preferredGasPrice in MainnetGasPrice
? mainnetGasPrices[preferredGasPrice as MainnetGasPrice]
: preferredGasPrice
// protects cases in which mainnet gas prices is undefined but
// preferred gas price remained set to INSTANT, FAST or NORMAL
if (Number.isNaN(normalizedPreferredGasPrice)) return { loading: false, gasFeesUSD: [] }

const gasMapped: {
[key in MainnetGasPrice]: number
} = {
[MainnetGasPrice.INSTANT]: gas.fast,
[MainnetGasPrice.FAST]: gas.slow,
[MainnetGasPrice.NORMAL]: gas.normal,
}

return {
loading: false,
gasFeesUSD: gasEstimations.map(gasEstimation => {
if (!gasEstimation) return null
const nativeCurrencyAmount = CurrencyAmount.nativeCurrency(
gasEstimation.mul(normalizedPreferredGasPrice).toString(),
chainId
)
if (gasEstimation === undefined) return null
//hardcoded gas price to 20 gwei

const gasCalc = gasMapped[preferredGasPrice as MainnetGasPrice] + '000000000'

const nativeCurrencyAmount = CurrencyAmount.nativeCurrency(gasEstimation.mul(gasCalc).toString(), chainId)

return CurrencyAmount.usd(
parseUnits(
nativeCurrencyAmount.multiply(nativeCurrencyUSDPrice).toFixed(USD.decimals),
Expand All @@ -53,12 +53,6 @@ export function useGasFeesUSD(gasEstimations: (BigNumber | null)[]): {
)
}),
}
}, [
gasEstimations,
loadingNativeCurrencyUSDPrice,
mainnetGasPrices,
nativeCurrencyUSDPrice,
preferredGasPrice,
chainId,
])
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [gasEstimations, loadingNativeCurrencyUSDPrice, nativeCurrencyUSDPrice, chainId])
}
10 changes: 8 additions & 2 deletions src/hooks/useSwapCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ interface FailedCall {
error: Error
}

type EstimatedSwapCall = SuccessfulCall | FailedCall
export type EstimatedSwapCall = SuccessfulCall | FailedCall

/**
* Returns the swap calls that can be used to make the trade
Expand Down Expand Up @@ -227,7 +227,13 @@ export function useSwapCallback({

const estimatedCalls: EstimatedSwapCall[] = await Promise.all(
swapCalls.map(async call => {
const transactionRequest = await call.transactionParameters
let transactionRequest: any
try {
transactionRequest = await call.transactionParameters
} catch (e) {
console.log('Failed to get transaction parameters', e)
}

// Ignore gas estimation if the request has gasLimit property
if (transactionRequest.gasLimit) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If transactionRequest is undefined it could break when checking transactionRequest.gasLimit. Also I don't think we want to console.log the error, use .error in this case.

Copy link
Collaborator Author

@Mi-Lan Mi-Lan Mar 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this part I noticed during testing that it wasn't handling the error so I put this in place. It didn't throw it for me.

return {
Expand Down
Loading