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 { 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 { SupportedChainId } from 'constants/chains'
import { BigNumber } from 'ethers' import { BigNumber } from 'ethers'
import { useMemo } from 'react' import { useMemo } from 'react'
import { useSingleContractMultipleData } from '../state/multicall/hooks' import { useSingleContractWithCallData } from '../state/multicall/hooks'
import { useAllV3Routes } from './useAllV3Routes' import { useAllV3Routes } from './useAllV3Routes'
import { useV3Quoter } from './useContract' import { useV3Quoter } from './useContract'
import { useActiveWeb3React } from './web3' import { useActiveWeb3React } from './web3'
...@@ -32,20 +32,19 @@ export function useBestV3TradeExactIn( ...@@ -32,20 +32,19 @@ export function useBestV3TradeExactIn(
amountIn?: CurrencyAmount<Currency>, amountIn?: CurrencyAmount<Currency>,
currencyOut?: Currency currencyOut?: Currency
): { state: V3TradeState; trade: Trade<Currency, Currency, TradeType.EXACT_INPUT> | null } { ): { 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 { routes, loading: routesLoading } = useAllV3Routes(amountIn?.currency, currencyOut)
const quoteExactInInputs = useMemo(() => { const quoter = useV3Quoter()
return routes.map((route) => [ const { chainId } = useActiveWeb3React()
encodeRouteToPath(route, false), const quotesResults = useSingleContractWithCallData(
amountIn ? `0x${amountIn.quotient.toString(16)}` : undefined, quoter,
]) amountIn
}, [amountIn, routes]) ? routes.map((route) => SwapQuoter.quoteCallParameters(route, amountIn, TradeType.EXACT_INPUT).calldata)
: [],
const quotesResults = useSingleContractMultipleData(quoter, 'quoteExactInput', quoteExactInInputs, { {
gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined, gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined,
}) }
)
return useMemo(() => { return useMemo(() => {
if ( if (
...@@ -121,20 +120,19 @@ export function useBestV3TradeExactOut( ...@@ -121,20 +120,19 @@ export function useBestV3TradeExactOut(
currencyIn?: Currency, currencyIn?: Currency,
amountOut?: CurrencyAmount<Currency> amountOut?: CurrencyAmount<Currency>
): { state: V3TradeState; trade: Trade<Currency, Currency, TradeType.EXACT_OUTPUT> | null } { ): { 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 { routes, loading: routesLoading } = useAllV3Routes(currencyIn, amountOut?.currency)
const quoteExactOutInputs = useMemo(() => { const quoter = useV3Quoter()
return routes.map((route) => [ const { chainId } = useActiveWeb3React()
encodeRouteToPath(route, true), const quotesResults = useSingleContractWithCallData(
amountOut ? `0x${amountOut.quotient.toString(16)}` : undefined, quoter,
]) amountOut
}, [amountOut, routes]) ? routes.map((route) => SwapQuoter.quoteCallParameters(route, amountOut, TradeType.EXACT_OUTPUT).calldata)
: [],
const quotesResults = useSingleContractMultipleData(quoter, 'quoteExactOutput', quoteExactOutInputs, { {
gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined, gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined,
}) }
)
return useMemo(() => { return useMemo(() => {
if ( if (
......
...@@ -154,6 +154,7 @@ function toCallState( ...@@ -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( export function useSingleContractMultipleData(
contract: Contract | null | undefined, contract: Contract | null | undefined,
methodName: string, methodName: string,
...@@ -162,21 +163,35 @@ export function useSingleContractMultipleData( ...@@ -162,21 +163,35 @@ export function useSingleContractMultipleData(
): CallState[] { ): CallState[] {
const fragment = useMemo(() => contract?.interface?.getFunction(methodName), [contract, methodName]) 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 gasRequired = options?.gasRequired
const blocksPerFetch = options?.blocksPerFetch
// encode calls
const calls = useMemo( const calls = useMemo(
() => () =>
contract && fragment && callInputs?.length > 0 && callInputs.every((inputs) => isValidMethodArgs(inputs)) contract
? callInputs.map<Call>((inputs) => { ? callDatas.map<Call | undefined>((callData) =>
return { callData
address: contract.address, ? {
callData: contract.interface.encodeFunctionData(fragment, inputs), address: contract.address,
...(gasRequired ? { gasRequired } : {}), callData,
} gasRequired,
}) }
: undefined
)
: [], : [],
[contract, fragment, callInputs, gasRequired] [contract, callDatas, gasRequired]
) )
const results = useCallsData(calls, blocksPerFetch ? { blocksPerFetch } : undefined) const results = useCallsData(calls, blocksPerFetch ? { blocksPerFetch } : undefined)
...@@ -185,7 +200,7 @@ export function useSingleContractMultipleData( ...@@ -185,7 +200,7 @@ export function useSingleContractMultipleData(
return useMemo(() => { return useMemo(() => {
return results.map((result) => toCallState(result, contract?.interface, fragment, latestBlockNumber)) return results.map((result) => toCallState(result, contract?.interface, fragment, latestBlockNumber))
}, [fragment, contract, results, latestBlockNumber]) }, [results, contract, fragment, latestBlockNumber])
} }
export function useMultipleContractSingleData( export function useMultipleContractSingleData(
...@@ -193,35 +208,34 @@ export function useMultipleContractSingleData( ...@@ -193,35 +208,34 @@ export function useMultipleContractSingleData(
contractInterface: Interface, contractInterface: Interface,
methodName: string, methodName: string,
callInputs?: OptionalMethodInputs, callInputs?: OptionalMethodInputs,
options?: Partial<ListenerOptions> & { gasRequired?: number } options: Partial<ListenerOptions> & { gasRequired?: number } = {}
): CallState[] { ): CallState[] {
const fragment = useMemo(() => contractInterface.getFunction(methodName), [contractInterface, methodName]) const fragment = useMemo(() => contractInterface.getFunction(methodName), [contractInterface, methodName])
const blocksPerFetch = options?.blocksPerFetch // encode callData
const gasRequired = options?.gasRequired
const callData: string | undefined = useMemo( const callData: string | undefined = useMemo(
() => () => (isValidMethodArgs(callInputs) ? contractInterface.encodeFunctionData(fragment, callInputs) : undefined),
fragment && isValidMethodArgs(callInputs)
? contractInterface.encodeFunctionData(fragment, callInputs)
: undefined,
[callInputs, contractInterface, fragment] [callInputs, contractInterface, fragment]
) )
const gasRequired = options?.gasRequired
const blocksPerFetch = options?.blocksPerFetch
// encode calls
const calls = useMemo( const calls = useMemo(
() => () =>
fragment && addresses && addresses.length > 0 && callData callData
? addresses.map<Call | undefined>((address) => { ? addresses.map<Call | undefined>((address) => {
return address && callData return address
? { ? {
address, address,
callData, callData,
...(gasRequired ? { gasRequired } : {}), gasRequired,
} }
: undefined : undefined
}) })
: [], : [],
[addresses, callData, fragment, gasRequired] [addresses, callData, gasRequired]
) )
const results = useCallsData(calls, blocksPerFetch ? { blocksPerFetch } : undefined) const results = useCallsData(calls, blocksPerFetch ? { blocksPerFetch } : undefined)
...@@ -237,29 +251,47 @@ export function useSingleCallResult( ...@@ -237,29 +251,47 @@ export function useSingleCallResult(
contract: Contract | null | undefined, contract: Contract | null | undefined,
methodName: string, methodName: string,
inputs?: OptionalMethodInputs, inputs?: OptionalMethodInputs,
options?: Partial<ListenerOptions> & { gasRequired?: number } options: Partial<ListenerOptions> & { gasRequired?: number } = {}
): CallState { ): 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 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() const latestBlockNumber = useBlockNumber()
return useMemo(() => { return useMemo(() => {
return toCallState(result, contract?.interface, fragment, latestBlockNumber) return results.map((result, i) =>
}, [result, contract, fragment, latestBlockNumber]) toCallState(
result,
contract?.interface,
contract?.interface?.getFunction(callDatas[i].substring(0, 10)),
latestBlockNumber
)
)
}, [results, contract, callDatas, latestBlockNumber])
} }
...@@ -4428,17 +4428,6 @@ ...@@ -4428,17 +4428,6 @@
resolved "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.0.tgz" resolved "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.0.tgz"
integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== 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": "@uniswap/v3-periphery@^1.1.1":
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.1.1.tgz#be6dfca7b29318ea0d76a7baf15d3b33c3c5e90a" resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.1.1.tgz#be6dfca7b29318ea0d76a7baf15d3b33c3c5e90a"
...@@ -4451,15 +4440,15 @@ ...@@ -4451,15 +4440,15 @@
base64-sol "1.0.1" base64-sol "1.0.1"
hardhat-watcher "^2.1.1" hardhat-watcher "^2.1.1"
"@uniswap/v3-sdk@^3.3.0": "@uniswap/v3-sdk@^3.4.1":
version "3.3.2" version "3.4.1"
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.3.2.tgz#78ce18c846739f8d16ae1296f6a6b2ef7c8e26ad" resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.4.1.tgz#2cf9b5f4dd826d6600245254e7bc7d2d4a4282ee"
integrity sha512-oADWpKPkmtgnrBr8xUmLURZnH1wO2HFPoQw/K2gI2ZLjyR1xkAbZT6X+hjLaXCdOI+PN5WMZo3/OiPUJC2X1bA== integrity sha512-P0zcgOgpSqEbI/2DVESm8kf8OydagMEAzZR7qqLOe4JsUyhK1A4u1dy8tYDgWUBW0WeruEXSPNGiEL0pYPy3HQ==
dependencies: dependencies:
"@ethersproject/abi" "^5.0.12" "@ethersproject/abi" "^5.0.12"
"@ethersproject/solidity" "^5.0.9" "@ethersproject/solidity" "^5.0.9"
"@uniswap/sdk-core" "^3.0.1" "@uniswap/sdk-core" "^3.0.1"
"@uniswap/v3-periphery" "1.0.0" "@uniswap/v3-periphery" "^1.1.1"
tiny-invariant "^1.1.0" tiny-invariant "^1.1.0"
tiny-warning "^1.0.3" 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