From 4f566ab0c2e3f94819363098ed9715b919582019 Mon Sep 17 00:00:00 2001 From: Ian Lapham Date: Tue, 17 Sep 2019 18:47:32 -0400 Subject: [PATCH] Add Custom url parameters (#423) * query params for input and output currencies * add slippage option * add slippage cusytom param * updated for sender address * add field and amount support * update params for pool page * finish basic url support * update app format * update error checking to top level * update for all pages * fix build * param updates * fix slippage to basis points, update theme text, refactor to minimize lookups * fix code styles * update theme logic, remove extra setting, update rounding * remove eslint comment errors * remove logs, ignore lock * remove lock --- .gitignore | 4 +- package.json | 1 + src/components/AddressInputPanel/index.js | 3 +- src/components/CurrencyInputPanel/index.js | 2 +- src/components/ExchangePage/index.jsx | 60 ++++++++-- src/components/TransactionDetails/index.js | 123 ++++++++++++++------- src/constants/index.js | 5 + src/contexts/AllBalances.js | 2 - src/contexts/LocalStorage.js | 11 +- src/pages/App.js | 23 ++-- src/pages/Pool/AddLiquidity.js | 29 +++-- src/pages/Pool/CreateExchange.js | 21 ++-- src/pages/Pool/RemoveLiquidity.js | 13 ++- src/pages/Pool/index.js | 15 ++- src/pages/Send/index.js | 4 +- src/pages/Swap/index.js | 4 +- src/theme/index.js | 26 +++-- src/utils/index.js | 60 +++++++++- 18 files changed, 302 insertions(+), 104 deletions(-) diff --git a/.gitignore b/.gitignore index b478487237..e96dbf1c84 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ yarn-error.log* notes.txt .idea/ -.vscode/ \ No newline at end of file +.vscode/ + +package-lock.json \ No newline at end of file diff --git a/package.json b/package.json index fdeb6ba658..f91a7a6591 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@uniswap/sdk": "^1.0.0-beta.4", "copy-to-clipboard": "^3.2.0", "escape-string-regexp": "^2.0.0", + "history": "^4.9.0", "ethers": "^4.0.36", "i18next": "^15.0.9", "i18next-browser-languagedetector": "^3.0.1", diff --git a/src/components/AddressInputPanel/index.js b/src/components/AddressInputPanel/index.js index c3dad6cd57..e55bfcbc40 100644 --- a/src/components/AddressInputPanel/index.js +++ b/src/components/AddressInputPanel/index.js @@ -75,7 +75,8 @@ export default function AddressInputPanel({ title, initialInput = '', onChange = const { library } = useWeb3Context() - const [input, setInput] = useState(initialInput) + const [input, setInput] = useState(initialInput.address ? initialInput.address : '') + const debouncedInput = useDebounce(input, 150) const [data, setData] = useState({ address: undefined, name: undefined }) diff --git a/src/components/CurrencyInputPanel/index.js b/src/components/CurrencyInputPanel/index.js index a5fb9b238d..6738aa99cb 100644 --- a/src/components/CurrencyInputPanel/index.js +++ b/src/components/CurrencyInputPanel/index.js @@ -336,9 +336,9 @@ export default function CurrencyInputPanel({ onValueChange(e.target.value)} onKeyPress={e => { const charCode = e.which ? e.which : e.keyCode diff --git a/src/components/ExchangePage/index.jsx b/src/components/ExchangePage/index.jsx index fa51b41d96..d680d978d0 100644 --- a/src/components/ExchangePage/index.jsx +++ b/src/components/ExchangePage/index.jsx @@ -1,5 +1,6 @@ import React, { useState, useReducer, useEffect } from 'react' import ReactGA from 'react-ga' +import { createBrowserHistory } from 'history' import { useTranslation } from 'react-i18next' import { useWeb3Context } from 'web3-react' @@ -119,13 +120,17 @@ function calculateEtherTokenInputFromOutput(outputAmount, inputReserve, outputRe return numerator.div(denominator).add(ethers.constants.One) } -function getInitialSwapState(outputCurrency) { +function getInitialSwapState(state) { return { - independentValue: '', // this is a user input + independentValue: state.exactFieldURL && state.exactAmountURL ? state.exactAmountURL : '', // this is a user input dependentValue: '', // this is a calculated number - independentField: INPUT, - inputCurrency: 'ETH', - outputCurrency: outputCurrency ? outputCurrency : '' + independentField: state.exactFieldURL === 'output' ? OUTPUT : INPUT, + inputCurrency: state.inputCurrencyURL ? state.inputCurrencyURL : 'ETH', + outputCurrency: state.outputCurrencyURL + ? state.outputCurrencyURL + : state.initialCurrency + ? state.initialCurrency + : '' } } @@ -235,14 +240,32 @@ function getMarketRate( } } -export default function ExchangePage({ initialCurrency, sending }) { +export default function ExchangePage({ initialCurrency, sending = false, params }) { const { t } = useTranslation() const { account } = useWeb3Context() const addTransaction = useTransactionAdder() - const [rawSlippage, setRawSlippage] = useState(ALLOWED_SLIPPAGE_DEFAULT) - const [rawTokenSlippage, setRawTokenSlippage] = useState(TOKEN_ALLOWED_SLIPPAGE_DEFAULT) + // check if URL specifies valid slippage, if so use as default + const initialSlippage = (token = false) => { + let slippage = Number.parseInt(params.slippage) + if (!isNaN(slippage) && (slippage === 0 || slippage >= 1)) { + return slippage // round to match custom input availability + } + // check for token <-> token slippage option + return token ? TOKEN_ALLOWED_SLIPPAGE_DEFAULT : ALLOWED_SLIPPAGE_DEFAULT + } + + // check URL params for recipient, only on send page + const initialRecipient = () => { + if (sending && params.recipient) { + return params.recipient + } + return '' + } + + const [rawSlippage, setRawSlippage] = useState(() => initialSlippage()) + const [rawTokenSlippage, setRawTokenSlippage] = useState(() => initialSlippage(true)) const allowedSlippageBig = ethers.utils.bigNumberify(rawSlippage) const tokenAllowedSlippageBig = ethers.utils.bigNumberify(rawTokenSlippage) @@ -253,11 +276,21 @@ export default function ExchangePage({ initialCurrency, sending }) { }, []) // core swap state - const [swapState, dispatchSwapState] = useReducer(swapStateReducer, initialCurrency, getInitialSwapState) + const [swapState, dispatchSwapState] = useReducer( + swapStateReducer, + { + initialCurrency: initialCurrency, + inputCurrencyURL: params.inputCurrency, + outputCurrencyURL: params.outputCurrency, + exactFieldURL: params.exactField, + exactAmountURL: params.exactAmount + }, + getInitialSwapState + ) const { independentValue, dependentValue, independentField, inputCurrency, outputCurrency } = swapState - const [recipient, setRecipient] = useState({ address: '', name: '' }) + const [recipient, setRecipient] = useState({ address: initialRecipient(), name: '' }) const [recipientError, setRecipientError] = useState() // get swap type from the currency types @@ -468,6 +501,11 @@ export default function ExchangePage({ initialCurrency, sending }) { t ]) + useEffect(() => { + const history = createBrowserHistory() + history.push(window.location.pathname + '') + }, []) + const [inverted, setInverted] = useState(false) const exchangeRate = getExchangeRate(inputValueParsed, inputDecimals, outputValueParsed, outputDecimals) const exchangeRateInverted = getExchangeRate(inputValueParsed, inputDecimals, outputValueParsed, outputDecimals, true) @@ -655,7 +693,7 @@ export default function ExchangePage({ initialCurrency, sending }) { - + ) : ( '' diff --git a/src/components/TransactionDetails/index.js b/src/components/TransactionDetails/index.js index a68c2f9fd1..396b3958b3 100644 --- a/src/components/TransactionDetails/index.js +++ b/src/components/TransactionDetails/index.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react' +import React, { useState, useEffect, useRef, useCallback } from 'react' import ReactGA from 'react-ga' import { useTranslation } from 'react-i18next' import styled, { css, keyframes } from 'styled-components' @@ -502,40 +502,94 @@ export default function TransactionDetails(props) { checkBounds(debouncedInput) } + // destructure props for to limit effect callbacks + const setRawSlippage = props.setRawSlippage + const setRawTokenSlippage = props.setRawTokenSlippage + const setcustomSlippageError = props.setcustomSlippageError + + const updateSlippage = useCallback( + newSlippage => { + // round to 2 decimals to prevent ethers error + let numParsed = parseInt(newSlippage * 100) + + // set both slippage values in parents + setRawSlippage(numParsed) + setRawTokenSlippage(numParsed) + }, + [setRawSlippage, setRawTokenSlippage] + ) + // used for slippage presets - const setFromFixed = (index, slippage) => { - // update slippage in parent, reset errors and input state - updateSlippage(slippage) - setWarningType(WARNING_TYPE.none) - setActiveIndex(index) - props.setcustomSlippageError('valid`') - } + const setFromFixed = useCallback( + (index, slippage) => { + // update slippage in parent, reset errors and input state + updateSlippage(slippage) + setWarningType(WARNING_TYPE.none) + setActiveIndex(index) + setcustomSlippageError('valid`') + }, + [setcustomSlippageError, updateSlippage] + ) - const checkBounds = slippageValue => { - setWarningType(WARNING_TYPE.none) - props.setcustomSlippageError('valid') + /** + * @todo + * Breaks without useState here, able to + * break input parsing if typing is faster than + * debounce time + */ - if (slippageValue === '' || slippageValue === '.') { - props.setcustomSlippageError('invalid') - return setWarningType(WARNING_TYPE.emptyInput) - } + const [initialSlippage] = useState(props.rawSlippage) - // check bounds and set errors - if (Number(slippageValue) < 0 || Number(slippageValue) > 50) { - props.setcustomSlippageError('invalid') - return setWarningType(WARNING_TYPE.invalidEntryBound) + useEffect(() => { + switch (Number.parseInt(initialSlippage)) { + case 10: + setFromFixed(1, 0.1) + break + case 50: + setFromFixed(2, 0.5) + break + case 100: + setFromFixed(3, 1) + break + default: + // restrict to 2 decimal places + let acceptableValues = [/^$/, /^\d{1,2}$/, /^\d{0,2}\.\d{0,2}$/] + // if its within accepted decimal limit, update the input state + if (acceptableValues.some(val => val.test(initialSlippage / 100))) { + setUserInput(initialSlippage / 100) + setActiveIndex(4) + } } - if (Number(slippageValue) >= 0 && Number(slippageValue) < 0.1) { - props.setcustomSlippageError('valid') - setWarningType(WARNING_TYPE.riskyEntryLow) - } - if (Number(slippageValue) > 5) { - props.setcustomSlippageError('warning') - setWarningType(WARNING_TYPE.riskyEntryHigh) - } - //update the actual slippage value in parent - updateSlippage(Number(slippageValue)) - } + }, [initialSlippage, setFromFixed]) + + const checkBounds = useCallback( + slippageValue => { + setWarningType(WARNING_TYPE.none) + setcustomSlippageError('valid') + + if (slippageValue === '' || slippageValue === '.') { + setcustomSlippageError('invalid') + return setWarningType(WARNING_TYPE.emptyInput) + } + + // check bounds and set errors + if (Number(slippageValue) < 0 || Number(slippageValue) > 50) { + setcustomSlippageError('invalid') + return setWarningType(WARNING_TYPE.invalidEntryBound) + } + if (Number(slippageValue) >= 0 && Number(slippageValue) < 0.1) { + setcustomSlippageError('valid') + setWarningType(WARNING_TYPE.riskyEntryLow) + } + if (Number(slippageValue) > 5) { + setcustomSlippageError('warning') + setWarningType(WARNING_TYPE.riskyEntryHigh) + } + //update the actual slippage value in parent + updateSlippage(Number(slippageValue)) + }, + [setcustomSlippageError, updateSlippage] + ) // check that the theyve entered number and correct decimal const parseInput = e => { @@ -549,15 +603,6 @@ export default function TransactionDetails(props) { } } - const updateSlippage = newSlippage => { - // round to 2 decimals to prevent ethers error - let numParsed = parseInt(newSlippage * 100) - - // set both slippage values in parents - props.setRawSlippage(numParsed) - props.setRawTokenSlippage(numParsed) - } - const b = text => {text} const renderTransactionDetails = () => { diff --git a/src/constants/index.js b/src/constants/index.js index 982f58ba63..822209251d 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -4,3 +4,8 @@ export const FACTORY_ADDRESSES = { 4: '0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36', 42: '0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30' } + +export const SUPPORTED_THEMES = { + DARK: 'DARK', + LIGHT: 'LIGHT' +} diff --git a/src/contexts/AllBalances.js b/src/contexts/AllBalances.js index 51394b479c..0887917da8 100644 --- a/src/contexts/AllBalances.js +++ b/src/contexts/AllBalances.js @@ -68,14 +68,12 @@ export function useFetchAllBalances() { Object.keys(allTokens).map(async k => { let balance = null let ethRate = null - if (isAddress(k) || k === 'ETH') { if (k === 'ETH') { balance = await getEtherBalance(account, library).catch(() => null) ethRate = ONE } else { balance = await getTokenBalance(k, account, library).catch(() => null) - // only get values for tokens with positive balances if (!!balance && balance.gt(ZERO)) { const tokenReserves = await getTokenReserves(k, library).catch(() => null) diff --git a/src/contexts/LocalStorage.js b/src/contexts/LocalStorage.js index 67d5c3f16d..d6975ad077 100644 --- a/src/contexts/LocalStorage.js +++ b/src/contexts/LocalStorage.js @@ -95,11 +95,14 @@ export function useBetaMessageManager() { export function useDarkModeManager() { const [state, { updateKey }] = useLocalStorageContext() - const isDarkMode = state[DARK_MODE] + let isDarkMode = state[DARK_MODE] - const toggleDarkMode = useCallback(() => { - updateKey(DARK_MODE, !isDarkMode) - }, [updateKey, isDarkMode]) + const toggleDarkMode = useCallback( + value => { + updateKey(DARK_MODE, value === false || value === true ? value : !isDarkMode) + }, + [updateKey, isDarkMode] + ) return [state[DARK_MODE], toggleDarkMode] } diff --git a/src/pages/App.js b/src/pages/App.js index babcbe8fb8..40fabd2375 100644 --- a/src/pages/App.js +++ b/src/pages/App.js @@ -7,7 +7,7 @@ import Header from '../components/Header' import Footer from '../components/Footer' import NavigationTabs from '../components/NavigationTabs' -import { isAddress } from '../utils' +import { isAddress, getAllQueryParams } from '../utils' const Swap = lazy(() => import('./Swap')) const Send = lazy(() => import('./Send')) @@ -48,6 +48,7 @@ const Body = styled.div` ` export default function App() { + const params = getAllQueryParams() return ( <> @@ -63,27 +64,33 @@ export default function App() { {/* this Suspense is for route code-splitting */} - + } /> { + render={({ match, location }) => { if (isAddress(match.params.tokenAddress)) { - return + return ( + + ) } else { return } }} /> - + } /> { + render={({ match, location }) => { if (isAddress(match.params.tokenAddress)) { - return + return } else { return } @@ -96,7 +103,7 @@ export default function App() { '/create-exchange', '/create-exchange/:tokenAddress?' ]} - component={Pool} + component={() => } /> diff --git a/src/pages/Pool/AddLiquidity.js b/src/pages/Pool/AddLiquidity.js index 11ee282218..a5092dcc98 100644 --- a/src/pages/Pool/AddLiquidity.js +++ b/src/pages/Pool/AddLiquidity.js @@ -1,6 +1,7 @@ import React, { useReducer, useState, useCallback, useEffect, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useWeb3Context } from 'web3-react' +import { createBrowserHistory } from 'history' import { ethers } from 'ethers' import ReactGA from 'react-ga' import styled from 'styled-components' @@ -118,11 +119,13 @@ function calculateSlippageBounds(value) { } } -const initialAddLiquidityState = { - inputValue: '', - outputValue: '', - lastEditedField: INPUT, - outputCurrency: '' +function initialAddLiquidityState(state) { + return { + inputValue: state.ethAmountURL ? state.ethAmountURL : '', + outputValue: state.tokenAmountURL && !state.ethAmountURL ? state.tokenAmountURL : '', + lastEditedField: state.tokenAmountURL && state.ethAmountURL === '' ? OUTPUT : INPUT, + outputCurrency: state.tokenURL ? state.tokenURL : '' + } } function addLiquidityStateReducer(state, action) { @@ -153,7 +156,7 @@ function addLiquidityStateReducer(state, action) { } } default: { - return initialAddLiquidityState + return initialAddLiquidityState() } } } @@ -189,11 +192,21 @@ function getMarketRate(reserveETH, reserveToken, decimals, invert = false) { return getExchangeRate(reserveETH, 18, reserveToken, decimals, invert) } -export default function AddLiquidity() { +export default function AddLiquidity({ params }) { const { t } = useTranslation() const { library, active, account } = useWeb3Context() - const [addLiquidityState, dispatchAddLiquidityState] = useReducer(addLiquidityStateReducer, initialAddLiquidityState) + // clear url of query + useEffect(() => { + const history = createBrowserHistory() + history.push(window.location.pathname + '') + }, []) + + const [addLiquidityState, dispatchAddLiquidityState] = useReducer( + addLiquidityStateReducer, + { ethAmountURL: params.ethAmount, tokenAmountURL: params.tokenAmount, tokenURL: params.token }, + initialAddLiquidityState + ) const { inputValue, outputValue, lastEditedField, outputCurrency } = addLiquidityState const inputCurrency = 'ETH' diff --git a/src/pages/Pool/CreateExchange.js b/src/pages/Pool/CreateExchange.js index c768576d53..d9b11c4f32 100644 --- a/src/pages/Pool/CreateExchange.js +++ b/src/pages/Pool/CreateExchange.js @@ -1,11 +1,11 @@ import React, { useState, useEffect } from 'react' import { withRouter } from 'react-router' import { useWeb3Context } from 'web3-react' +import { createBrowserHistory } from 'history' import { ethers } from 'ethers' import styled from 'styled-components' import { useTranslation } from 'react-i18next' import ReactGA from 'react-ga' - import { Button } from '../../theme' import AddressInputPanel from '../../components/AddressInputPanel' import OversizedPanel from '../../components/OversizedPanel' @@ -54,13 +54,13 @@ const Flex = styled.div` } ` -function CreateExchange({ history, location }) { +function CreateExchange({ location, params }) { const { t } = useTranslation() const { account } = useWeb3Context() const factory = useFactoryContract() const [tokenAddress, setTokenAddress] = useState({ - address: '', + address: params.tokenAddress ? params.tokenAddress : '', name: '' }) const [tokenAddressError, setTokenAddressError] = useState() @@ -68,12 +68,11 @@ function CreateExchange({ history, location }) { const { name, symbol, decimals, exchangeAddress } = useTokenDetails(tokenAddress.address) const addTransaction = useTransactionAdder() - // clear location state, if it exists + // clear url of query useEffect(() => { - if (location.state) { - history.replace(location.pathname) - } - }, []) // eslint-disable-line react-hooks/exhaustive-deps + const history = createBrowserHistory() + history.push(window.location.pathname + '') + }, []) // validate everything const [errorMessage, setErrorMessage] = useState(!account && t('noWallet')) @@ -118,7 +117,11 @@ function CreateExchange({ history, location }) { <> diff --git a/src/pages/Pool/RemoveLiquidity.js b/src/pages/Pool/RemoveLiquidity.js index 894fb264a6..c11e4546e6 100644 --- a/src/pages/Pool/RemoveLiquidity.js +++ b/src/pages/Pool/RemoveLiquidity.js @@ -1,6 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react' import { useTranslation } from 'react-i18next' import ReactGA from 'react-ga' +import { createBrowserHistory } from 'history' import { useWeb3Context } from 'web3-react' import { ethers } from 'ethers' import styled from 'styled-components' @@ -141,14 +142,20 @@ function calculateSlippageBounds(value) { } } -export default function RemoveLiquidity() { +export default function RemoveLiquidity({ params }) { const { library, account, active } = useWeb3Context() const { t } = useTranslation() const addTransaction = useTransactionAdder() - const [outputCurrency, setOutputCurrency] = useState('') - const [value, setValue] = useState('') + // clear url of query + useEffect(() => { + const history = createBrowserHistory() + history.push(window.location.pathname + '') + }, []) + + const [outputCurrency, setOutputCurrency] = useState(params.poolTokenAddress) + const [value, setValue] = useState(params.poolTokenAmount ? params.poolTokenAmount : '') const [inputError, setInputError] = useState() const [valueParsed, setValueParsed] = useState() // parse value diff --git a/src/pages/Pool/index.js b/src/pages/Pool/index.js index 0bac5abe93..6d0eb6a20f 100644 --- a/src/pages/Pool/index.js +++ b/src/pages/Pool/index.js @@ -1,27 +1,32 @@ import React, { Suspense, lazy, useEffect } from 'react' import ReactGA from 'react-ga' import { Switch, Route, Redirect } from 'react-router-dom' - import ModeSelector from './ModeSelector' const AddLiquidity = lazy(() => import('./AddLiquidity')) const RemoveLiquidity = lazy(() => import('./RemoveLiquidity')) const CreateExchange = lazy(() => import('./CreateExchange')) -export default function Pool() { +export default function Pool({ params }) { useEffect(() => { ReactGA.pageview(window.location.pathname + window.location.search) }, []) + const AddLiquidityParams = () => + + const RemoveLiquidityParams = () => + + const CreateExchangeParams = () => + return ( <> {/* this Suspense is for route code-splitting */} - - - + + + { diff --git a/src/pages/Send/index.js b/src/pages/Send/index.js index fdd55ac289..da996d64bf 100644 --- a/src/pages/Send/index.js +++ b/src/pages/Send/index.js @@ -1,6 +1,6 @@ import React from 'react' import ExchangePage from '../../components/ExchangePage' -export default function Send({ initialCurrency }) { - return +export default function Send({ initialCurrency, params }) { + return } diff --git a/src/pages/Swap/index.js b/src/pages/Swap/index.js index bef79d33dc..52fd99162a 100644 --- a/src/pages/Swap/index.js +++ b/src/pages/Swap/index.js @@ -1,6 +1,6 @@ import React from 'react' import ExchangePage from '../../components/ExchangePage' -export default function Swap({ initialCurrency }) { - return +export default function Swap({ initialCurrency, params }) { + return } diff --git a/src/theme/index.js b/src/theme/index.js index b3229f8c5b..9a8dc53456 100644 --- a/src/theme/index.js +++ b/src/theme/index.js @@ -1,5 +1,7 @@ -import React from 'react' +import React, { useEffect } from 'react' import { ThemeProvider as StyledComponentsThemeProvider, createGlobalStyle, css } from 'styled-components' +import { getQueryParam, checkSupportedTheme } from '../utils' +import { SUPPORTED_THEMES } from '../constants' import { useDarkModeManager } from '../contexts/LocalStorage' export * from './components' @@ -32,6 +34,22 @@ const flexRowNoWrap = css` const white = '#FFFFFF' const black = '#000000' +export default function ThemeProvider({ children }) { + const [darkMode, toggleDarkMode] = useDarkModeManager() + const themeURL = checkSupportedTheme(getQueryParam(window.location, 'theme')) + const themeToRender = themeURL + ? themeURL.toUpperCase() === SUPPORTED_THEMES.DARK + ? true + : themeURL.toUpperCase() === SUPPORTED_THEMES.LIGHT + ? false + : darkMode + : darkMode + useEffect(() => { + toggleDarkMode(themeToRender) + }, [toggleDarkMode, themeToRender]) + return {children} +} + const theme = darkMode => ({ white, black, @@ -84,12 +102,6 @@ const theme = darkMode => ({ flexRowNoWrap }) -export default function ThemeProvider({ children }) { - const [darkMode] = useDarkModeManager() - - return {children} -} - export const GlobalStyle = createGlobalStyle` @import url('https://rsms.me/inter/inter.css'); html { font-family: 'Inter', sans-serif; } diff --git a/src/utils/index.js b/src/utils/index.js index 970c693797..feab8696a6 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -4,7 +4,7 @@ import FACTORY_ABI from '../constants/abis/factory' import EXCHANGE_ABI from '../constants/abis/exchange' import ERC20_ABI from '../constants/abis/erc20' import ERC20_BYTES32_ABI from '../constants/abis/erc20_bytes32' -import { FACTORY_ADDRESSES } from '../constants' +import { FACTORY_ADDRESSES, SUPPORTED_THEMES } from '../constants' import { formatFixed } from '@uniswap/sdk' import UncheckedJsonRpcSigner from './signer' @@ -33,6 +33,7 @@ const ETHERSCAN_PREFIXES = { 5: 'goerli.', 42: 'kovan.' } + export function getEtherscanLink(networkId, data, type) { const prefix = `https://${ETHERSCAN_PREFIXES[networkId] || ETHERSCAN_PREFIXES[1]}etherscan.io` @@ -47,6 +48,63 @@ export function getEtherscanLink(networkId, data, type) { } } +export function getQueryParam(windowLocation, name) { + var q = windowLocation.search.match(new RegExp('[?&]' + name + '=([^&#?]*)')) + return q && q[1] +} + +export function getAllQueryParams() { + let params = {} + params.theme = checkSupportedTheme(getQueryParam(window.location, 'theme')) + + params.inputCurrency = isAddress(getQueryParam(window.location, 'inputCurrency')) + ? getQueryParam(window.location, 'inputCurrency') + : '' + params.outputCurrency = isAddress(getQueryParam(window.location, 'outputCurrency')) + ? getQueryParam(window.location, 'outputCurrency') + : '' + params.slippage = !isNaN(getQueryParam(window.location, 'slippage')) ? getQueryParam(window.location, 'slippage') : '' + params.exactField = getQueryParam(window.location, 'exactField') + params.exactAmount = !isNaN(getQueryParam(window.location, 'exactAmount')) + ? getQueryParam(window.location, 'exactAmount') + : '' + params.theme = checkSupportedTheme(getQueryParam(window.location, 'theme')) + params.recipient = isAddress(getQueryParam(window.location, 'recipient')) + ? getQueryParam(window.location, 'recipient') + : '' + + // Add Liquidity params + params.ethAmount = !isNaN(getQueryParam(window.location, 'ethAmount')) + ? getQueryParam(window.location, 'ethAmount') + : '' + params.tokenAmount = !isNaN(getQueryParam(window.location, 'tokenAmount')) + ? getQueryParam(window.location, 'tokenAmount') + : '' + params.token = isAddress(getQueryParam(window.location, 'token')) ? getQueryParam(window.location, 'token') : '' + + // Remove liquidity params + params.poolTokenAmount = !isNaN(getQueryParam(window.location, 'poolTokenAmount')) + ? getQueryParam(window.location, 'poolTokenAmount') + : '' + params.poolTokenAddress = isAddress(getQueryParam(window.location, 'poolTokenAddress')) + ? getQueryParam(window.location, 'poolTokenAddress') + : '' + + // Create Exchange params + params.tokenAddress = isAddress(getQueryParam(window.location, 'tokenAddress')) + ? getQueryParam(window.location, 'tokenAddress') + : '' + + return params +} + +export function checkSupportedTheme(themeName) { + if (themeName && themeName.toUpperCase() in SUPPORTED_THEMES) { + return themeName.toUpperCase() + } + return null +} + export function getNetworkName(networkId) { switch (networkId) { case 1: {