From 4d3ed5d6ba6560e0778aa543dc81e79fa5fe71e7 Mon Sep 17 00:00:00 2001 From: Justin Domingue Date: Wed, 21 Jul 2021 15:08:35 -0700 Subject: [PATCH] feat: routing api integration (#2080) * initial routing api integration * add routing api slice * display route in dialog * addressed pr feedback * switch to `get` * renamed useRouterTradeExactIn to useRouter * moving few files to later iteration * removed unnecessary `as` * switch to polling * add todo for blocknumber freshness * remove account-slippage-deadline --- package.json | 2 +- src/hooks/useRouter.ts | 30 +++++++++++++++++++++ src/state/index.ts | 9 ++++--- src/state/routing/slice.ts | 54 ++++++++++++++++++++++++++++++++++++++ yarn.lock | 8 +++--- 5 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 src/hooks/useRouter.ts create mode 100644 src/state/routing/slice.ts diff --git a/package.json b/package.json index c539eead0d..1b60cd88e5 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@reach/dialog": "^0.10.3", "@reach/portal": "^0.10.3", "@react-hook/window-scroll": "^1.3.0", - "@reduxjs/toolkit": "^1.6.0", + "@reduxjs/toolkit": "^1.6.1", "@typechain/ethers-v5": "^7.0.0", "@types/d3": "^6.7.1", "@types/jest": "^25.2.1", diff --git a/src/hooks/useRouter.ts b/src/hooks/useRouter.ts new file mode 100644 index 0000000000..08aa614700 --- /dev/null +++ b/src/hooks/useRouter.ts @@ -0,0 +1,30 @@ +import { skipToken } from '@reduxjs/toolkit/query/react' +import { Currency, CurrencyAmount } from '@uniswap/sdk-core' +import ms from 'ms.macro' +import { useBlockNumber } from 'state/application/hooks' +import { useGetQuoteQuery } from 'state/routing/slice' +import { useActiveWeb3React } from './web3' + +export function useRouterTradeExactIn(amountIn?: CurrencyAmount, currencyOut?: Currency) { + const { account } = useActiveWeb3React() + + const blockNumber = useBlockNumber() + + const { isLoading, isError, data } = useGetQuoteQuery( + amountIn && currencyOut && account && blockNumber + ? { + tokenInAddress: amountIn.currency.wrapped.address, + tokenInChainId: amountIn.currency.chainId, + tokenOutAddress: currencyOut.wrapped.address, + tokenOutChainId: currencyOut.chainId, + amount: amountIn.quotient.toString(), + type: 'exactIn', + } + : skipToken, + { pollingInterval: ms`10s` } + ) + + // todo(judo): validate block number for freshness + + return !isLoading && !isError ? data?.routeString : undefined +} diff --git a/src/state/index.ts b/src/state/index.ts index 4d6975ee0c..9ac0d99961 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -13,7 +13,8 @@ import burn from './burn/reducer' import burnV3 from './burn/v3/reducer' import logs from './logs/slice' import multicall from './multicall/reducer' -import { api } from './data/slice' +import { api as dataApi } from './data/slice' +import { routingApi } from './routing/slice' const PERSISTED_KEYS: string[] = ['user', 'transactions', 'lists'] @@ -30,11 +31,13 @@ const store = configureStore({ multicall, lists, logs, - [api.reducerPath]: api.reducer, + [dataApi.reducerPath]: dataApi.reducer, + [routingApi.reducerPath]: routingApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ thunk: true }) - .concat(api.middleware) + .concat(dataApi.middleware) + .concat(routingApi.middleware) .concat(save({ states: PERSISTED_KEYS, debounce: 1000 })), preloadedState: load({ states: PERSISTED_KEYS }), }) diff --git a/src/state/routing/slice.ts b/src/state/routing/slice.ts new file mode 100644 index 0000000000..7dbe483124 --- /dev/null +++ b/src/state/routing/slice.ts @@ -0,0 +1,54 @@ +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' +import { SupportedChainId } from 'constants/chains' +import qs from 'qs' + +export interface GetQuoteResult { + blockNumber: string + gasPriceWei: string + gasUseEstimate: string + gasUseEstimateQuote: string + gasUseEstimateQuoteDecimals: string + gasUseEstimateUSD: string + methodParameters: { calldata: string; value: string } + quote: string + quoteDecimals: string + quoteGasAdjusted: string + quoteGasAdjustedDecimals: string + quoteId: string + routeEdges: { + fee: string + id: string + inId: string + outId: string + percent: number + type: string + }[] + routeNodes: { chainId: number; id: string; symbol: string; type: string }[] + routeString: string +} + +export const routingApi = createApi({ + baseQuery: fetchBaseQuery({ + baseUrl: 'https://api.uniswap.org/v1/', + }), + endpoints: (build) => ({ + getQuote: build.query< + GetQuoteResult, + { + tokenInAddress: string + tokenInChainId: SupportedChainId + tokenOutAddress: string + tokenOutChainId: SupportedChainId + amount: string + type: 'exactIn' | 'exactOut' + recipient?: string + slippageTolerance?: string + deadline?: string + } + >({ + query: (args) => `quote?${qs.stringify(args)}`, + }), + }), +}) + +export const { useGetQuoteQuery } = routingApi diff --git a/yarn.lock b/yarn.lock index c60838a8ce..1e8d212429 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2847,10 +2847,10 @@ "@react-hook/event" "^1.2.1" "@react-hook/throttle" "^2.2.0" -"@reduxjs/toolkit@^1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.6.0.tgz#0a17c6941c57341f8b31e982352b495ab69d5add" - integrity sha512-eGL50G+Vj5AG5uD0lineb6rRtbs96M8+hxbcwkHpZ8LQcmt0Bm33WyBSnj5AweLkjQ7ZP+KFRDHiLMznljRQ3A== +"@reduxjs/toolkit@^1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.6.1.tgz#7bc83b47352a663bf28db01e79d17ba54b98ade9" + integrity sha512-pa3nqclCJaZPAyBhruQtiRwtTjottRrVJqziVZcWzI73i6L3miLTtUyWfauwv08HWtiXLx1xGyGt+yLFfW/d0A== dependencies: immer "^9.0.1" redux "^4.1.0"