From 723db9d0eaf247250bb3fafa94e11ea6cde00544 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 26 Aug 2022 11:19:51 -0700 Subject: [PATCH] feat: integrate widget settings/value (#4499) * widgets: v2.2.0 * refactor: wrap Widget * feat: integrate widget settings * refactor: import from widgets * fix: better settings integration * fix: include types * chore: formatting * build: bump widgets version * feat: integrate widget value * feat: integrate widget token selection * feat: clean up widget integration * build: bump widgets version * refactor: mv widget wrapper to components * refactor: split widget integrations * refactor: value -> inputs * fix: consolidate slippage hooks * fix: memoize currency search modal * refactor: clarify widget code * fix: allow loading token in widget * fix: add TradeType helpers --- package.json | 2 +- .../SearchModal/CurrencySearchModal.tsx | 6 +- src/components/TransactionSettings/index.tsx | 5 +- src/components/Widget/index.tsx | 49 +++++++++++ src/components/Widget/inputs.tsx | 88 +++++++++++++++++++ src/components/Widget/settings.ts | 57 ++++++++++++ src/components/Widget/transactions.ts | 18 ++++ src/components/swap/SwapModalFooter.tsx | 2 +- src/pages/TokenDetails/index.tsx | 47 ++-------- src/state/user/hooks.tsx | 31 +++---- ...oken-details-widget-theme.ts => widget.ts} | 1 + src/utils/token-details-widget-config.ts | 8 -- yarn.lock | 56 ++++++++++-- 13 files changed, 292 insertions(+), 78 deletions(-) create mode 100644 src/components/Widget/index.tsx create mode 100644 src/components/Widget/inputs.tsx create mode 100644 src/components/Widget/settings.ts create mode 100644 src/components/Widget/transactions.ts rename src/theme/{token-details-widget-theme.ts => widget.ts} (99%) delete mode 100644 src/utils/token-details-widget-config.ts diff --git a/package.json b/package.json index ff4f10ef78..55499d4299 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "@uniswap/v3-core": "1.0.0", "@uniswap/v3-periphery": "^1.1.1", "@uniswap/v3-sdk": "^3.9.0", - "@uniswap/widgets": "^2.1.1", + "@uniswap/widgets": "^2.3.1", "@vanilla-extract/css": "^1.7.2", "@vanilla-extract/css-utils": "^0.1.2", "@vanilla-extract/dynamic": "^2.0.2", diff --git a/src/components/SearchModal/CurrencySearchModal.tsx b/src/components/SearchModal/CurrencySearchModal.tsx index b499950bb3..147edd8b08 100644 --- a/src/components/SearchModal/CurrencySearchModal.tsx +++ b/src/components/SearchModal/CurrencySearchModal.tsx @@ -3,7 +3,7 @@ import { TokenList } from '@uniswap/token-lists' import TokenSafety from 'components/TokenSafety' import { TokenSafetyVariant, useTokenSafetyFlag } from 'featureFlags/flags/tokenSafety' import usePrevious from 'hooks/usePrevious' -import { useCallback, useEffect, useState } from 'react' +import { memo, useCallback, useEffect, useState } from 'react' import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' import { useUserAddedTokens } from 'state/user/hooks' @@ -33,7 +33,7 @@ export enum CurrencyModalView { tokenSafety, } -export default function CurrencySearchModal({ +export default memo(function CurrencySearchModal({ isOpen, onDismiss, onCurrencySelect, @@ -170,4 +170,4 @@ export default function CurrencySearchModal({ {content} ) -} +}) diff --git a/src/components/TransactionSettings/index.tsx b/src/components/TransactionSettings/index.tsx index 073c15e225..192b7a7336 100644 --- a/src/components/TransactionSettings/index.tsx +++ b/src/components/TransactionSettings/index.tsx @@ -7,7 +7,7 @@ import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign' import ms from 'ms.macro' import { darken } from 'polished' import { useState } from 'react' -import { useSetUserSlippageTolerance, useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks' +import { useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks' import styled, { useTheme } from 'styled-components/macro' import { ThemedText } from '../../theme' @@ -112,8 +112,7 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction const redesignFlag = useRedesignFlag() const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled - const userSlippageTolerance = useUserSlippageTolerance() - const setUserSlippageTolerance = useSetUserSlippageTolerance() + const [userSlippageTolerance, setUserSlippageTolerance] = useUserSlippageTolerance() const [deadline, setDeadline] = useUserTransactionTTL() diff --git a/src/components/Widget/index.tsx b/src/components/Widget/index.tsx new file mode 100644 index 0000000000..55cd783b58 --- /dev/null +++ b/src/components/Widget/index.tsx @@ -0,0 +1,49 @@ +import { Currency, SwapWidget } from '@uniswap/widgets' +import { useWeb3React } from '@web3-react/core' +import { RPC_URLS } from 'constants/networks' +import { useActiveLocale } from 'hooks/useActiveLocale' +import { useMemo } from 'react' +import { useIsDarkMode } from 'state/user/hooks' +import { DARK_THEME, LIGHT_THEME } from 'theme/widget' + +import { useSyncWidgetInputs } from './inputs' +import { useSyncWidgetSettings } from './settings' +import { useSyncWidgetTransactions } from './transactions' + +export const WIDGET_WIDTH = 320 + +const WIDGET_ROUTER_URL = 'https://api.uniswap.org/v1/' + +export interface WidgetProps { + defaultToken?: Currency +} + +export default function Widget({ defaultToken }: WidgetProps) { + const locale = useActiveLocale() + const darkMode = useIsDarkMode() + const theme = useMemo(() => (darkMode ? DARK_THEME : LIGHT_THEME), [darkMode]) + const { provider } = useWeb3React() + + const { inputs, tokenSelector } = useSyncWidgetInputs(defaultToken) + const { settings } = useSyncWidgetSettings() + const { transactions } = useSyncWidgetTransactions() + + return ( + <> + + {tokenSelector} + + ) +} diff --git a/src/components/Widget/inputs.tsx b/src/components/Widget/inputs.tsx new file mode 100644 index 0000000000..405f070c93 --- /dev/null +++ b/src/components/Widget/inputs.tsx @@ -0,0 +1,88 @@ +import { Currency, Field, SwapController, SwapEventHandlers, TradeType } from '@uniswap/widgets' +import CurrencySearchModal from 'components/SearchModal/CurrencySearchModal' +import { useCallback, useMemo, useState } from 'react' + +/** + * Integrates the Widget's inputs. + * Treats the Widget as a controlled component, using the app's own token selector for selection. + */ +export function useSyncWidgetInputs(defaultToken?: Currency) { + const [type, setType] = useState(TradeType.EXACT_INPUT) + const [amount, setAmount] = useState() + const onAmountChange = useCallback((field: Field, amount: string) => { + setType(toTradeType(field)) + setAmount(amount) + }, []) + + const [tokens, setTokens] = useState<{ [Field.INPUT]?: Currency; [Field.OUTPUT]?: Currency }>({ + [Field.OUTPUT]: defaultToken, + }) + const onSwitchTokens = useCallback(() => { + setType((type) => invertTradeType(type)) + setTokens((tokens) => ({ + [Field.INPUT]: tokens[Field.OUTPUT], + [Field.OUTPUT]: tokens[Field.INPUT], + })) + }, []) + + const [selectingField, setSelectingField] = useState() + const otherField = useMemo(() => (selectingField === Field.INPUT ? Field.OUTPUT : Field.INPUT), [selectingField]) + const [selectingToken, otherToken] = useMemo(() => { + if (selectingField === undefined) return [undefined, undefined] + return [tokens[selectingField], tokens[otherField]] + }, [otherField, selectingField, tokens]) + const onTokenSelectorClick = useCallback((field: Field) => { + setSelectingField(field) + return false + }, []) + const onTokenSelect = useCallback( + (token: Currency) => { + if (selectingField === undefined) return + setType(TradeType.EXACT_INPUT) + setTokens(() => { + return { + [otherField]: token === otherToken ? selectingToken : otherToken, + [selectingField]: token, + } + }) + }, + [otherField, otherToken, selectingField, selectingToken] + ) + const tokenSelector = ( + setSelectingField(undefined)} + selectedCurrency={selectingToken} + otherSelectedCurrency={otherToken} + onCurrencySelect={onTokenSelect} + /> + ) + + const value: SwapController = useMemo(() => ({ type, amount, ...tokens }), [amount, tokens, type]) + const valueHandlers: SwapEventHandlers = useMemo( + () => ({ onAmountChange, onSwitchTokens, onTokenSelectorClick }), + [onAmountChange, onSwitchTokens, onTokenSelectorClick] + ) + + return { inputs: { value, ...valueHandlers }, tokenSelector } +} + +// TODO(zzmp): Move to @uniswap/widgets. +function toTradeType(modifiedField: Field) { + switch (modifiedField) { + case Field.INPUT: + return TradeType.EXACT_INPUT + case Field.OUTPUT: + return TradeType.EXACT_OUTPUT + } +} + +// TODO(zzmp): Include in @uniswap/sdk-core (on TradeType, if possible). +function invertTradeType(tradeType: TradeType) { + switch (tradeType) { + case TradeType.EXACT_INPUT: + return TradeType.EXACT_OUTPUT + case TradeType.EXACT_OUTPUT: + return TradeType.EXACT_INPUT + } +} diff --git a/src/components/Widget/settings.ts b/src/components/Widget/settings.ts new file mode 100644 index 0000000000..1a8d723a99 --- /dev/null +++ b/src/components/Widget/settings.ts @@ -0,0 +1,57 @@ +import { Percent } from '@uniswap/sdk-core' +import { Slippage, SwapEventHandlers, SwapSettingsController } from '@uniswap/widgets' +import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/misc' +import { useCallback, useMemo, useState } from 'react' +import { useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks' + +/** + * Integrates the Widget's settings, keeping the widget and app settings in sync. + * NB: This acts as an integration layer, so certain values are duplicated in order to translate + * between app and widget representations. + */ +export function useSyncWidgetSettings() { + const [appTtl, setAppTtl] = useUserTransactionTTL() + const [widgetTtl, setWidgetTtl] = useState(appTtl / 60) + const onTransactionDeadlineChange = useCallback( + (widgetTtl: number | undefined) => { + setWidgetTtl(widgetTtl) + const appTtl = widgetTtl === undefined ? widgetTtl : widgetTtl * 60 + setAppTtl(appTtl ?? DEFAULT_DEADLINE_FROM_NOW) + }, + [setAppTtl] + ) + + const [appSlippage, setAppSlippage] = useUserSlippageTolerance() + const [widgetSlippage, setWidgetSlippage] = useState( + appSlippage === 'auto' ? undefined : appSlippage.toFixed(2) + ) + const onSlippageChange = useCallback( + (widgetSlippage: Slippage) => { + setWidgetSlippage(widgetSlippage.max) + if (widgetSlippage.auto || !widgetSlippage.max) { + setAppSlippage('auto') + } else { + setAppSlippage(new Percent(Math.floor(Number(widgetSlippage.max) * 100), 10_000)) + } + }, + [setAppSlippage] + ) + + const onSettingsReset = useCallback(() => { + setWidgetTtl(undefined) + setAppTtl(DEFAULT_DEADLINE_FROM_NOW) + setWidgetSlippage(undefined) + setAppSlippage('auto') + }, [setAppSlippage, setAppTtl]) + + const settings: SwapSettingsController = useMemo(() => { + const auto = appSlippage === 'auto' + return { slippage: { auto, max: widgetSlippage }, transactionTtl: widgetTtl } + }, [widgetSlippage, widgetTtl, appSlippage]) + const settingsHandlers: SwapEventHandlers = useMemo( + () => ({ onSettingsReset, onSlippageChange, onTransactionDeadlineChange }), + [onSettingsReset, onSlippageChange, onTransactionDeadlineChange] + ) + + return { settings: { settings, ...settingsHandlers } } +} diff --git a/src/components/Widget/transactions.ts b/src/components/Widget/transactions.ts new file mode 100644 index 0000000000..fedbe35048 --- /dev/null +++ b/src/components/Widget/transactions.ts @@ -0,0 +1,18 @@ +import { TransactionReceipt } from '@ethersproject/abstract-provider' +import { TransactionEventHandlers } from '@uniswap/widgets' +import { useMemo } from 'react' + +/** Integrates the Widget's transactions, showing the widget's transactions in the app. */ +export function useSyncWidgetTransactions() { + // TODO(jfrankfurt): Integrate widget transactions with app transaction tracking. + const txHandlers: TransactionEventHandlers = useMemo( + () => ({ + onTxSubmit: (hash: string, tx: unknown) => console.log('onTxSubmit'), + onTxSuccess: (hash: string, receipt: TransactionReceipt) => console.log('onTxSuccess'), + onTxFail: (hash: string, receipt: TransactionReceipt) => console.log('onTxFail'), + }), + [] + ) + + return { transactions: { ...txHandlers } } +} diff --git a/src/components/swap/SwapModalFooter.tsx b/src/components/swap/SwapModalFooter.tsx index 851b66edfe..e5142bfb98 100644 --- a/src/components/swap/SwapModalFooter.tsx +++ b/src/components/swap/SwapModalFooter.tsx @@ -119,7 +119,7 @@ export default function SwapModalFooter({ swapQuoteReceivedDate: Date | undefined }) { const transactionDeadlineSecondsSinceEpoch = useTransactionDeadline()?.toNumber() // in seconds since epoch - const isAutoSlippage = useUserSlippageTolerance() === 'auto' + const isAutoSlippage = useUserSlippageTolerance()[0] === 'auto' const [clientSideRouter] = useClientSideRouter() const tokenInAmountUsd = useStablecoinValue(trade.inputAmount)?.toFixed(2) const tokenOutAmountUsd = useStablecoinValue(trade.outputAmount)?.toFixed(2) diff --git a/src/pages/TokenDetails/index.tsx b/src/pages/TokenDetails/index.tsx index 992718c37e..cd3da16424 100644 --- a/src/pages/TokenDetails/index.tsx +++ b/src/pages/TokenDetails/index.tsx @@ -1,4 +1,3 @@ -import { SwapWidget } from '@uniswap/widgets' import { useWeb3React } from '@web3-react/core' import { LARGE_MEDIA_BREAKPOINT, @@ -12,20 +11,16 @@ import LoadingTokenDetail from 'components/Tokens/TokenDetails/LoadingTokenDetai import NetworkBalance from 'components/Tokens/TokenDetails/NetworkBalance' import TokenDetail from 'components/Tokens/TokenDetails/TokenDetail' import TokenSafetyMessage from 'components/TokenSafety/TokenSafetyMessage' +import Widget, { WIDGET_WIDTH } from 'components/Widget' import { getChainInfo } from 'constants/chainInfo' import { L1_CHAIN_IDS, L2_CHAIN_IDS, SupportedChainId, TESTNET_CHAIN_IDS } from 'constants/chains' import { checkWarning } from 'constants/tokenSafety' import { useToken } from 'hooks/Tokens' -import { useActiveLocale } from 'hooks/useActiveLocale' import { useNetworkTokenBalances } from 'hooks/useNetworkTokenBalances' -import { useCallback, useMemo } from 'react' +import { useMemo } from 'react' import { useParams } from 'react-router-dom' -import { useIsDarkMode } from 'state/user/hooks' import styled from 'styled-components/macro' -import { DARK_THEME, LIGHT_THEME } from 'theme/token-details-widget-theme' -import { ROUTER_URL, RPC_URL_MAP } from 'utils/token-details-widget-config' -const WIDGET_WIDTH = 320 const Footer = styled.div` display: none; @media only screen and (max-width: ${LARGE_MEDIA_BREAKPOINT}) { @@ -78,26 +73,13 @@ function NetworkBalances(tokenAddress: string) { export default function TokenDetails() { const { tokenAddress } = useParams<{ tokenAddress?: string }>() - const tokenSymbol = useToken(tokenAddress)?.symbol - - const darkMode = useIsDarkMode() - const widgetTheme = useMemo(() => (darkMode ? DARK_THEME : LIGHT_THEME), [darkMode]) - const locale = useActiveLocale() - const onTxSubmit = useCallback(() => { - console.log('onTxSubmit') - }, []) - const onTxSuccess = useCallback(() => { - console.log('onTxSuccess') - }, []) - const onTxFail = useCallback(() => { - console.log('onTxFail') - }, []) + const token = useToken(tokenAddress) const tokenWarning = tokenAddress ? checkWarning(tokenAddress) : null /* network balance handling */ const { data: networkData } = tokenAddress ? NetworkBalances(tokenAddress) : { data: null } - const { chainId: connectedChainId, provider } = useWeb3React() + const { chainId: connectedChainId } = useWeb3React() const totalBalance = 4.3 // dummy data const chainsToList = useMemo(() => { @@ -113,7 +95,7 @@ export default function TokenDetails() { ? chainsToList.map((chainId) => { const amount = networkData[chainId] const fiatValue = amount // for testing purposes - if (!fiatValue || !tokenSymbol) return null + if (!fiatValue || !token?.symbol) return null const chainInfo = getChainInfo(chainId) const networkColor = chainInfo.color if (!chainInfo) return null @@ -122,7 +104,7 @@ export default function TokenDetails() { key={chainId} logoUrl={chainInfo.logoUrl} balance={'1'} - tokenSymbol={tokenSymbol} + tokenSymbol={token?.symbol} fiatValue={fiatValue.toSignificant(2)} label={chainInfo.label} networkColor={networkColor} @@ -137,22 +119,7 @@ export default function TokenDetails() { <> - + {tokenWarning && } diff --git a/src/state/user/hooks.tsx b/src/state/user/hooks.tsx index 843d748966..b7649003ff 100644 --- a/src/state/user/hooks.tsx +++ b/src/state/user/hooks.tsx @@ -144,10 +144,20 @@ export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) return [clientSideRouter, setClientSideRouter] } -export function useSetUserSlippageTolerance(): (slippageTolerance: Percent | 'auto') => void { - const dispatch = useAppDispatch() +/** + * Return the user's slippage tolerance, from the redux store, and a function to update the slippage tolerance + */ +export function useUserSlippageTolerance(): [Percent | 'auto', (slippageTolerance: Percent | 'auto') => void] { + const userSlippageToleranceRaw = useAppSelector((state) => { + return state.user.userSlippageTolerance + }) + const userSlippageTolerance = useMemo( + () => (userSlippageToleranceRaw === 'auto' ? 'auto' : new Percent(userSlippageToleranceRaw, 10_000)), + [userSlippageToleranceRaw] + ) - return useCallback( + const dispatch = useAppDispatch() + const setUserSlippageTolerance = useCallback( (userSlippageTolerance: Percent | 'auto') => { let value: 'auto' | number try { @@ -164,19 +174,10 @@ export function useSetUserSlippageTolerance(): (slippageTolerance: Percent | 'au }, [dispatch] ) -} - -/** - * Return the user's slippage tolerance, from the redux store, and a function to update the slippage tolerance - */ -export function useUserSlippageTolerance(): Percent | 'auto' { - const userSlippageTolerance = useAppSelector((state) => { - return state.user.userSlippageTolerance - }) return useMemo( - () => (userSlippageTolerance === 'auto' ? 'auto' : new Percent(userSlippageTolerance, 10_000)), - [userSlippageTolerance] + () => [userSlippageTolerance, setUserSlippageTolerance], + [setUserSlippageTolerance, userSlippageTolerance] ) } @@ -200,7 +201,7 @@ export function useUserHideClosedPositions(): [boolean, (newHideClosedPositions: * @param defaultSlippageTolerance the default value to replace auto with */ export function useUserSlippageToleranceWithDefault(defaultSlippageTolerance: Percent): Percent { - const allowedSlippage = useUserSlippageTolerance() + const allowedSlippage = useUserSlippageTolerance()[0] return useMemo( () => (allowedSlippage === 'auto' ? defaultSlippageTolerance : allowedSlippage), [allowedSlippage, defaultSlippageTolerance] diff --git a/src/theme/token-details-widget-theme.ts b/src/theme/widget.ts similarity index 99% rename from src/theme/token-details-widget-theme.ts rename to src/theme/widget.ts index 33b85a082b..a8fb394c4b 100644 --- a/src/theme/token-details-widget-theme.ts +++ b/src/theme/widget.ts @@ -17,6 +17,7 @@ export const LIGHT_THEME = { warning: colorsLight.accentWarning, error: colorsLight.accentCritical, } + export const DARK_THEME = { // surface container: colorsDark.backgroundSurface, diff --git a/src/utils/token-details-widget-config.ts b/src/utils/token-details-widget-config.ts deleted file mode 100644 index 5a50624afc..0000000000 --- a/src/utils/token-details-widget-config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SupportedChainId } from 'constants/chains' -import { RPC_URLS } from 'constants/networks' - -export const ROUTER_URL = 'https://api.uniswap.org/v1/' -export const RPC_URL_MAP = Object.keys(RPC_URLS).reduce( - (acc, cur) => ({ ...acc, [cur]: [RPC_URLS[cur as unknown as SupportedChainId]] }), - {} -) diff --git a/yarn.lock b/yarn.lock index 0a928028ec..6da1321c63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1074,7 +1074,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== @@ -3678,7 +3678,7 @@ dependencies: "@types/react" "*" -"@types/react-redux@^7.1.24": +"@types/react-redux@^7.1.20", "@types/react-redux@^7.1.24": version "7.1.24" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0" integrity sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ== @@ -4212,10 +4212,10 @@ "@uniswap/v3-core" "1.0.0" "@uniswap/v3-periphery" "^1.0.1" -"@uniswap/widgets@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@uniswap/widgets/-/widgets-2.1.1.tgz#13aea0255b7516d86de6838d4de2507a9f84e0df" - integrity sha512-ZtJhZni1t1tM0ZsAu5INFDMa588RmRkXby8DAOou/RXz3dzh7jTKm7+wEph6QE9NE5eTdVvVgqbwH6QPLR3nuQ== +"@uniswap/widgets@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@uniswap/widgets/-/widgets-2.3.1.tgz#e9973cb34d19534ccf7a7dbe79de63bc5fe7e1e9" + integrity sha512-b6eL/fIjAkj52dj0TVcVF5FeQ1r3dAtPNoO4Go4zABVHlj6c4m6dariY3VQBkNnd2vwt40XBELtiuYXZn3DGjA== dependencies: "@babel/runtime" "^7.17.0" "@fontsource/ibm-plex-mono" "^4.5.1" @@ -4251,12 +4251,17 @@ polished "^3.3.2" popper-max-size-modifier "^0.2.0" qrcode "^1.5.0" + react "^17.0.1" + react-dom "^17.0.1" react-feather "^2.0.8" react-popper "^2.2.3" + react-redux "^7.2.2" react-virtualized-auto-sizer "^1.0.2" react-window "^1.8.5" rebass "^4.0.7" + redux "^4.1.2" setimmediate "^1.0.5" + styled-components "^5.3.0" tiny-invariant "^1.2.0" wcag-contrast "^3.0.0" wicg-inert "^3.1.1" @@ -14663,6 +14668,15 @@ react-dev-utils@^11.0.3: strip-ansi "6.0.0" text-table "0.2.0" +react-dom@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" @@ -14758,6 +14772,18 @@ react-query@^3.39.1: broadcast-channel "^3.4.1" match-sorter "^6.0.2" +react-redux@^7.2.2: + version "7.2.8" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.8.tgz#a894068315e65de5b1b68899f9c6ee0923dd28de" + integrity sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/react-redux" "^7.1.20" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^17.0.2" + react-redux@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.2.tgz#bc2a304bb21e79c6808e3e47c50fe1caf62f7aad" @@ -14926,6 +14952,14 @@ react-window@^1.8.5: "@babel/runtime" "^7.0.0" memoize-one ">=3.1.1 <6" +react@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" @@ -15621,6 +15655,14 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler@^0.23.0: version "0.23.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" @@ -16426,7 +16468,7 @@ style-loader@1.3.0: loader-utils "^2.0.0" schema-utils "^2.7.0" -styled-components@^5.3.5: +styled-components@^5.3.0, styled-components@^5.3.5: version "5.3.5" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.5.tgz#a750a398d01f1ca73af16a241dec3da6deae5ec4" integrity sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==