Commit a52b7bf0 authored by Noah Zinsmeister's avatar Noah Zinsmeister Committed by GitHub

feat: use SDK to format calldata passed to quoter (#2305)

* replace useSingleCallResult implementation

use useSingleContractMultipleData instead

* use sdk methods to format quoter calldata

* create cleaner useSingleContractWithCallData fn

* clean up useMultipleContractSingleData

* address comments
parent 0ab1e5f1
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import { encodeRouteToPath, Route, Trade } from '@uniswap/v3-sdk'
import { Route, Trade, SwapQuoter } from '@uniswap/v3-sdk'
import { SupportedChainId } from 'constants/chains'
import { BigNumber } from 'ethers'
import { useMemo } from 'react'
import { useSingleContractMultipleData } from '../state/multicall/hooks'
import { useSingleContractWithCallData } from '../state/multicall/hooks'
import { useAllV3Routes } from './useAllV3Routes'
import { useV3Quoter } from './useContract'
import { useActiveWeb3React } from './web3'
......@@ -32,20 +32,19 @@ export function useBestV3TradeExactIn(
amountIn?: CurrencyAmount<Currency>,
currencyOut?: Currency
): { state: V3TradeState; trade: Trade<Currency, Currency, TradeType.EXACT_INPUT> | null } {
const { chainId } = useActiveWeb3React()
const quoter = useV3Quoter()
const { routes, loading: routesLoading } = useAllV3Routes(amountIn?.currency, currencyOut)
const quoteExactInInputs = useMemo(() => {
return routes.map((route) => [
encodeRouteToPath(route, false),
amountIn ? `0x${amountIn.quotient.toString(16)}` : undefined,
])
}, [amountIn, routes])
const quotesResults = useSingleContractMultipleData(quoter, 'quoteExactInput', quoteExactInInputs, {
gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined,
})
const quoter = useV3Quoter()
const { chainId } = useActiveWeb3React()
const quotesResults = useSingleContractWithCallData(
quoter,
amountIn
? routes.map((route) => SwapQuoter.quoteCallParameters(route, amountIn, TradeType.EXACT_INPUT).calldata)
: [],
{
gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined,
}
)
return useMemo(() => {
if (
......@@ -121,20 +120,19 @@ export function useBestV3TradeExactOut(
currencyIn?: Currency,
amountOut?: CurrencyAmount<Currency>
): { state: V3TradeState; trade: Trade<Currency, Currency, TradeType.EXACT_OUTPUT> | null } {
const { chainId } = useActiveWeb3React()
const quoter = useV3Quoter()
const { routes, loading: routesLoading } = useAllV3Routes(currencyIn, amountOut?.currency)
const quoteExactOutInputs = useMemo(() => {
return routes.map((route) => [
encodeRouteToPath(route, true),
amountOut ? `0x${amountOut.quotient.toString(16)}` : undefined,
])
}, [amountOut, routes])
const quotesResults = useSingleContractMultipleData(quoter, 'quoteExactOutput', quoteExactOutInputs, {
gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined,
})
const quoter = useV3Quoter()
const { chainId } = useActiveWeb3React()
const quotesResults = useSingleContractWithCallData(
quoter,
amountOut
? routes.map((route) => SwapQuoter.quoteCallParameters(route, amountOut, TradeType.EXACT_OUTPUT).calldata)
: [],
{
gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined,
}
)
return useMemo(() => {
if (
......
......@@ -154,6 +154,7 @@ function toCallState(
}
}
// formats many calls to a single function on a single contract, with the function name and inputs specified
export function useSingleContractMultipleData(
contract: Contract | null | undefined,
methodName: string,
......@@ -162,21 +163,35 @@ export function useSingleContractMultipleData(
): CallState[] {
const fragment = useMemo(() => contract?.interface?.getFunction(methodName), [contract, methodName])
const blocksPerFetch = options?.blocksPerFetch
// encode callDatas
const callDatas = useMemo(
() =>
contract && fragment
? callInputs.map<string | undefined>((callInput) =>
isValidMethodArgs(callInput) ? contract.interface.encodeFunctionData(fragment, callInput) : undefined
)
: [],
[callInputs, contract, fragment]
)
const gasRequired = options?.gasRequired
const blocksPerFetch = options?.blocksPerFetch
// encode calls
const calls = useMemo(
() =>
contract && fragment && callInputs?.length > 0 && callInputs.every((inputs) => isValidMethodArgs(inputs))
? callInputs.map<Call>((inputs) => {
return {
address: contract.address,
callData: contract.interface.encodeFunctionData(fragment, inputs),
...(gasRequired ? { gasRequired } : {}),
}
})
contract
? callDatas.map<Call | undefined>((callData) =>
callData
? {
address: contract.address,
callData,
gasRequired,
}
: undefined
)
: [],
[contract, fragment, callInputs, gasRequired]
[contract, callDatas, gasRequired]
)
const results = useCallsData(calls, blocksPerFetch ? { blocksPerFetch } : undefined)
......@@ -185,7 +200,7 @@ export function useSingleContractMultipleData(
return useMemo(() => {
return results.map((result) => toCallState(result, contract?.interface, fragment, latestBlockNumber))
}, [fragment, contract, results, latestBlockNumber])
}, [results, contract, fragment, latestBlockNumber])
}
export function useMultipleContractSingleData(
......@@ -193,35 +208,34 @@ export function useMultipleContractSingleData(
contractInterface: Interface,
methodName: string,
callInputs?: OptionalMethodInputs,
options?: Partial<ListenerOptions> & { gasRequired?: number }
options: Partial<ListenerOptions> & { gasRequired?: number } = {}
): CallState[] {
const fragment = useMemo(() => contractInterface.getFunction(methodName), [contractInterface, methodName])
const blocksPerFetch = options?.blocksPerFetch
const gasRequired = options?.gasRequired
// encode callData
const callData: string | undefined = useMemo(
() =>
fragment && isValidMethodArgs(callInputs)
? contractInterface.encodeFunctionData(fragment, callInputs)
: undefined,
() => (isValidMethodArgs(callInputs) ? contractInterface.encodeFunctionData(fragment, callInputs) : undefined),
[callInputs, contractInterface, fragment]
)
const gasRequired = options?.gasRequired
const blocksPerFetch = options?.blocksPerFetch
// encode calls
const calls = useMemo(
() =>
fragment && addresses && addresses.length > 0 && callData
callData
? addresses.map<Call | undefined>((address) => {
return address && callData
return address
? {
address,
callData,
...(gasRequired ? { gasRequired } : {}),
gasRequired,
}
: undefined
})
: [],
[addresses, callData, fragment, gasRequired]
[addresses, callData, gasRequired]
)
const results = useCallsData(calls, blocksPerFetch ? { blocksPerFetch } : undefined)
......@@ -237,29 +251,47 @@ export function useSingleCallResult(
contract: Contract | null | undefined,
methodName: string,
inputs?: OptionalMethodInputs,
options?: Partial<ListenerOptions> & { gasRequired?: number }
options: Partial<ListenerOptions> & { gasRequired?: number } = {}
): CallState {
const fragment = useMemo(() => contract?.interface?.getFunction(methodName), [contract, methodName])
return useSingleContractMultipleData(contract, methodName, [inputs], options)[0] ?? INVALID_CALL_STATE
}
const blocksPerFetch = options?.blocksPerFetch
// formats many calls to any number of functions on a single contract, with only the calldata specified
export function useSingleContractWithCallData(
contract: Contract | null | undefined,
callDatas: string[],
options: Partial<ListenerOptions> & { gasRequired?: number } = {}
): CallState[] {
const gasRequired = options?.gasRequired
const blocksPerFetch = options?.blocksPerFetch
// encode calls
const calls = useMemo(
() =>
contract
? callDatas.map<Call>((callData) => {
return {
address: contract.address,
callData,
gasRequired,
}
})
: [],
[contract, callDatas, gasRequired]
)
const results = useCallsData(calls, blocksPerFetch ? { blocksPerFetch } : undefined)
const calls = useMemo<Call[]>(() => {
return contract && fragment && isValidMethodArgs(inputs)
? [
{
address: contract.address,
callData: contract.interface.encodeFunctionData(fragment, inputs),
...(gasRequired ? { gasRequired } : {}),
},
]
: []
}, [contract, fragment, inputs, gasRequired])
const result = useCallsData(calls, blocksPerFetch ? { blocksPerFetch } : undefined)[0]
const latestBlockNumber = useBlockNumber()
return useMemo(() => {
return toCallState(result, contract?.interface, fragment, latestBlockNumber)
}, [result, contract, fragment, latestBlockNumber])
return results.map((result, i) =>
toCallState(
result,
contract?.interface,
contract?.interface?.getFunction(callDatas[i].substring(0, 10)),
latestBlockNumber
)
)
}, [results, contract, callDatas, latestBlockNumber])
}
......@@ -4428,17 +4428,6 @@
resolved "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.0.tgz"
integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA==
"@uniswap/v3-periphery@1.0.0":
version "1.0.0"
resolved "https://registry.npmjs.org/@uniswap/v3-periphery/-/v3-periphery-1.0.0.tgz"
integrity sha512-kRqUrjnyh+X1wJdSENPDFr9sjRVebv2KyLtfqDOPij0dXJ69GspFU2qrZXjouc6LYdkWG7x3fagiTlw0eGniYQ==
dependencies:
"@openzeppelin/contracts" "3.4.1-solc-0.7-2"
"@uniswap/lib" "^4.0.1-alpha"
"@uniswap/v2-core" "1.0.1"
"@uniswap/v3-core" "1.0.0"
base64-sol "1.0.1"
"@uniswap/v3-periphery@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.1.1.tgz#be6dfca7b29318ea0d76a7baf15d3b33c3c5e90a"
......@@ -4451,15 +4440,15 @@
base64-sol "1.0.1"
hardhat-watcher "^2.1.1"
"@uniswap/v3-sdk@^3.3.0":
version "3.3.2"
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.3.2.tgz#78ce18c846739f8d16ae1296f6a6b2ef7c8e26ad"
integrity sha512-oADWpKPkmtgnrBr8xUmLURZnH1wO2HFPoQw/K2gI2ZLjyR1xkAbZT6X+hjLaXCdOI+PN5WMZo3/OiPUJC2X1bA==
"@uniswap/v3-sdk@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.4.1.tgz#2cf9b5f4dd826d6600245254e7bc7d2d4a4282ee"
integrity sha512-P0zcgOgpSqEbI/2DVESm8kf8OydagMEAzZR7qqLOe4JsUyhK1A4u1dy8tYDgWUBW0WeruEXSPNGiEL0pYPy3HQ==
dependencies:
"@ethersproject/abi" "^5.0.12"
"@ethersproject/solidity" "^5.0.9"
"@uniswap/sdk-core" "^3.0.1"
"@uniswap/v3-periphery" "1.0.0"
"@uniswap/v3-periphery" "^1.1.1"
tiny-invariant "^1.1.0"
tiny-warning "^1.0.3"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment