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

feat: set the auto slippage tolerance by the dollar value of gas #2815

Merged
merged 6 commits into from
Nov 18, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/hooks/useGasPrice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import JSBI from 'jsbi'

import { useSingleCallResult } from '../state/multicall/hooks'
import { useContract } from './useContract'
import useENSAddress from './useENSAddress'

const CHAIN_DATA_ABI = [
{
inputs: [],
name: 'latestAnswer',
outputs: [{ internalType: 'int256', name: '', type: 'int256' }],
stateMutability: 'view',
type: 'function',
},
]

/**
* Returns the price of 1 gas in WEI for the currently selected network using the chainlink fast gas price oracle
*/
export default function useGasPrice(): JSBI | undefined {
const { address } = useENSAddress('fast-gas-gwei.data.eth')
const contract = useContract(address ?? undefined, CHAIN_DATA_ABI, false)

const resultStr = useSingleCallResult(contract, 'latestAnswer').result?.[0]?.toString()
return typeof resultStr === 'string' ? JSBI.BigInt(resultStr) : undefined
}
40 changes: 38 additions & 2 deletions src/hooks/useSwapSlippageTolerance.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,61 @@
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import { L2_CHAIN_IDS } from 'constants/chains'
import JSBI from 'jsbi'
import { useMemo } from 'react'

import { useUserSlippageToleranceWithDefault } from '../state/user/hooks'
import { useCurrency } from './Tokens'
import useGasPrice from './useGasPrice'
import useUSDCPrice, { useUSDCValue } from './useUSDCPrice'
import { useActiveWeb3React } from './web3'

const V2_SWAP_DEFAULT_SLIPPAGE = new Percent(50, 10_000) // .50%
const V3_SWAP_DEFAULT_SLIPPAGE = new Percent(50, 10_000) // .50%
const ONE_TENTHS_PERCENT = new Percent(10, 10_000) // .10%

/**
* 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
*/
function guestimateGas(
moodysalem marked this conversation as resolved.
Show resolved Hide resolved
trade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType> | undefined
): number | undefined {
if (!trade) return undefined
moodysalem marked this conversation as resolved.
Show resolved Hide resolved
if (trade instanceof V2Trade) return 90_000 + trade.route.pairs.length * 20_000
moodysalem marked this conversation as resolved.
Show resolved Hide resolved
// does not consider the number of ticks crossed
return 100_000 + trade.swaps.reduce((memo, swap) => swap.route.pools.length + memo, 0) * 30_000
}

export default function useSwapSlippageTolerance(
trade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType> | undefined
): Percent {
const { chainId } = useActiveWeb3React()
const onL2 = chainId && L2_CHAIN_IDS.includes(chainId)
const outputDollarValue = useUSDCValue(trade?.outputAmount)
const ethGasPrice = useGasPrice()

const gasEstimate = guestimateGas(trade)
const ether = useCurrency('ETH')
const etherPrice = useUSDCPrice(ether ?? undefined)

const defaultSlippageTolerance = useMemo(() => {
if (!trade || onL2) return ONE_TENTHS_PERCENT

const ethGasCost =
ethGasPrice && typeof gasEstimate === 'number' ? JSBI.multiply(ethGasPrice, JSBI.BigInt(gasEstimate)) : undefined
const dollarGasCost =
ether && ethGasCost && etherPrice ? etherPrice.quote(CurrencyAmount.fromRawAmount(ether, ethGasCost)) : undefined

if (outputDollarValue && dollarGasCost) {
const fraction = dollarGasCost.asFraction.divide(outputDollarValue.asFraction)
moodysalem marked this conversation as resolved.
Show resolved Hide resolved
return new Percent(fraction.numerator, fraction.denominator)
}

if (trade instanceof V2Trade) return V2_SWAP_DEFAULT_SLIPPAGE
return V3_SWAP_DEFAULT_SLIPPAGE
}, [onL2, trade])
}, [ethGasPrice, ether, etherPrice, gasEstimate, onL2, outputDollarValue, trade])

return useUserSlippageToleranceWithDefault(defaultSlippageTolerance)
}