Skip to content

Commit

Permalink
replace blocktimestamp, don't use chainlink for gasprice
Browse files Browse the repository at this point in the history
  • Loading branch information
KillariDev committed Feb 7, 2024
1 parent 1b917ab commit 4565e3a
Show file tree
Hide file tree
Showing 5 changed files with 11 additions and 144 deletions.
95 changes: 5 additions & 90 deletions src/hooks/useAutoSlippageTolerance.ts
Original file line number Diff line number Diff line change
@@ -1,69 +1,13 @@
import { MixedRoute, partitionMixedRouteByProtocol, Protocol, Trade } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { Pair } from '@uniswap/v2-sdk'
import { Pool } from '@uniswap/v3-sdk'
import { Percent } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
import { L2_CHAIN_IDS } from 'constants/chains'
import JSBI from 'jsbi'
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import { useMemo } from 'react'
import { ClassicTrade } from 'state/routing/types'

import useGasPrice from './useGasPrice'
import useStablecoinPrice, { useStablecoinAmountFromFiatValue, useStablecoinValue } from './useStablecoinPrice'
import { useStablecoinAmountFromFiatValue, useStablecoinValue } from './useStablecoinPrice'

const DEFAULT_AUTO_SLIPPAGE = new Percent(5, 1000) // 0.5%

// Base costs regardless of how many hops in the route
const V3_SWAP_BASE_GAS_ESTIMATE = 100_000
const V2_SWAP_BASE_GAS_ESTIMATE = 135_000

// Extra cost per hop in the route
const V3_SWAP_HOP_GAS_ESTIMATE = 70_000
const V2_SWAP_HOP_GAS_ESTIMATE = 50_000

/**
* Return a guess of the gas cost used in computing slippage tolerance for a given trade
* @param trade the trade for which to _guess_ the amount of gas it would cost to execute
*
* V3 logic is inspired by:
* https://github.com/Uniswap/smart-order-router/blob/main/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts
* V2 logic is inspired by:
* https://github.com/Uniswap/smart-order-router/blob/main/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts
*/
function guesstimateGas(trade: Trade<Currency, Currency, TradeType> | undefined): number | undefined {
if (trade) {
let gas = 0
for (const { route } of trade.swaps) {
if (route.protocol === Protocol.V2) {
gas += V2_SWAP_BASE_GAS_ESTIMATE + route.pools.length * V2_SWAP_HOP_GAS_ESTIMATE
} else if (route.protocol === Protocol.V3) {
// V3 gas costs scale on initialized ticks being crossed, but we don't have that data here.
// We bake in some tick crossings into the base 100k cost.
gas += V3_SWAP_BASE_GAS_ESTIMATE + route.pools.length * V3_SWAP_HOP_GAS_ESTIMATE
} else if (route.protocol === Protocol.MIXED) {
const sections = partitionMixedRouteByProtocol(route as MixedRoute<Currency, Currency>)
gas += sections.reduce((gas, section) => {
if (section.every((pool) => pool instanceof Pool)) {
return gas + V3_SWAP_BASE_GAS_ESTIMATE + section.length * V3_SWAP_HOP_GAS_ESTIMATE
} else if (section.every((pool) => pool instanceof Pair)) {
return gas + V2_SWAP_BASE_GAS_ESTIMATE + (section.length - 1) * V2_SWAP_HOP_GAS_ESTIMATE
} else {
console.warn('Invalid section')
return gas
}
}, 0)
} else {
// fallback general gas estimation
gas += V3_SWAP_BASE_GAS_ESTIMATE + route.pools.length * V3_SWAP_HOP_GAS_ESTIMATE
}
}
return gas
}
return undefined
}

const MIN_AUTO_SLIPPAGE_TOLERANCE = DEFAULT_AUTO_SLIPPAGE
// assuming normal gas speeds, most swaps complete within 3 blocks and
// there's rarely price movement >5% in that time period
Expand All @@ -77,35 +21,16 @@ export default function useClassicAutoSlippageTolerance(trade?: ClassicTrade): P
const { chainId } = useWeb3React()
const onL2 = chainId && L2_CHAIN_IDS.includes(chainId)
const outputDollarValue = useStablecoinValue(trade?.outputAmount)
const nativeGasPrice = useGasPrice()

const gasEstimate = guesstimateGas(trade)
const gasEstimateUSD = useStablecoinAmountFromFiatValue(trade?.gasUseEstimateUSD) ?? null
const nativeCurrency = useNativeCurrency(chainId)
const nativeCurrencyPrice = useStablecoinPrice((trade && nativeCurrency) ?? undefined)

return useMemo(() => {
if (!trade || onL2) return DEFAULT_AUTO_SLIPPAGE

const nativeGasCost =
nativeGasPrice && typeof gasEstimate === 'number'
? JSBI.multiply(nativeGasPrice, JSBI.BigInt(gasEstimate))
: undefined
const dollarGasCost =
nativeCurrency && nativeGasCost && nativeCurrencyPrice
? nativeCurrencyPrice.quote(CurrencyAmount.fromRawAmount(nativeCurrency, nativeGasCost))
: undefined

// if valid estimate from api and using api trade, use gas estimate from api
// NOTE - dont use gas estimate for L2s yet - need to verify accuracy
// if not, use local heuristic
const dollarCostToUse =
chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) && gasEstimateUSD ? gasEstimateUSD : dollarGasCost

if (outputDollarValue && dollarCostToUse) {
if (outputDollarValue && gasEstimateUSD) {
// optimize for highest possible slippage without getting MEV'd
// so set slippage % such that the difference between expected amount out and minimum amount out < gas fee to sandwich the trade
const fraction = dollarCostToUse.asFraction.divide(outputDollarValue.asFraction)
const fraction = gasEstimateUSD.asFraction.divide(outputDollarValue.asFraction)
const result = new Percent(fraction.numerator, fraction.denominator)
if (result.greaterThan(MAX_AUTO_SLIPPAGE_TOLERANCE)) {
return MAX_AUTO_SLIPPAGE_TOLERANCE
Expand All @@ -119,15 +44,5 @@ export default function useClassicAutoSlippageTolerance(trade?: ClassicTrade): P
}

return DEFAULT_AUTO_SLIPPAGE
}, [
trade,
onL2,
nativeGasPrice,
gasEstimate,
nativeCurrency,
nativeCurrencyPrice,
chainId,
gasEstimateUSD,
outputDollarValue,
])
}, [trade, onL2, gasEstimateUSD, outputDollarValue])
}
14 changes: 2 additions & 12 deletions src/hooks/useCurrentBlockTimestamp.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
import { BigNumber } from '@ethersproject/bignumber'
import { useSingleCallResult } from 'lib/hooks/multicall'
import { useMemo } from 'react'

import { useInterfaceMulticall } from './useContract'

// gets the current timestamp from the blockchain
export default function useCurrentBlockTimestamp(): BigNumber | undefined {
const multicall = useInterfaceMulticall()
const resultStr: string | undefined = useSingleCallResult(
multicall,
'getCurrentBlockTimestamp'
)?.result?.[0]?.toString()
return useMemo(() => (typeof resultStr === 'string' ? BigNumber.from(resultStr) : undefined), [resultStr])
export default function useCurrentBlockTimestamp(): BigNumber {
return BigNumber.from(BigInt(Math.floor(Date.now() / 1000)))
}
27 changes: 0 additions & 27 deletions src/hooks/useGasPrice.ts

This file was deleted.

9 changes: 2 additions & 7 deletions src/hooks/useUSDPrice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,12 @@ import { useMemo } from 'react'

import useStablecoinPrice from './useStablecoinPrice'

export function useUSDPrice(
currencyAmount?: CurrencyAmount<Currency>,
prefetchCurrency?: Currency
): {
export function useUSDPrice(currencyAmount?: CurrencyAmount<Currency>): {
data?: number
isLoading: boolean
} {
const currency = currencyAmount?.currency ?? prefetchCurrency

// Use USDC-based pricing for chains.
const stablecoinPrice = useStablecoinPrice(currency)
const stablecoinPrice = useStablecoinPrice(currencyAmount?.currency)

return useMemo(() => {
if (currencyAmount && stablecoinPrice) {
Expand Down
10 changes: 2 additions & 8 deletions src/pages/Swap/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -313,18 +313,12 @@ function Swap({

const showFiatValueInput = Boolean(parsedAmounts[Field.INPUT])
const showFiatValueOutput = Boolean(parsedAmounts[Field.OUTPUT])
const getSingleUnitAmount = (currency?: Currency) => {
if (!currency) return
return CurrencyAmount.fromRawAmount(currency, JSBI.BigInt(10 ** currency.decimals))
}

const fiatValueInput = useUSDPrice(
parsedAmounts[Field.INPUT] ?? getSingleUnitAmount(currencies[Field.INPUT]),
currencies[Field.INPUT]
parsedAmounts[Field.INPUT] && showFiatValueInput ? parsedAmounts[Field.INPUT] : undefined
)
const fiatValueOutput = useUSDPrice(
parsedAmounts[Field.OUTPUT] ?? getSingleUnitAmount(currencies[Field.OUTPUT]),
currencies[Field.OUTPUT]
parsedAmounts[Field.OUTPUT] && showFiatValueOutput ? parsedAmounts[Field.OUTPUT] : undefined
)

const [routeNotFound, routeIsLoading, routeIsSyncing] = useMemo(
Expand Down

0 comments on commit 4565e3a

Please sign in to comment.