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
This commit is contained in:
parent
61d6556a0d
commit
4f566ab0c2
4
.gitignore
vendored
4
.gitignore
vendored
@ -26,4 +26,6 @@ yarn-error.log*
|
||||
notes.txt
|
||||
.idea/
|
||||
|
||||
.vscode/
|
||||
.vscode/
|
||||
|
||||
package-lock.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",
|
||||
|
@ -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 })
|
||||
|
@ -336,9 +336,9 @@ export default function CurrencyInputPanel({
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.000000000000000001"
|
||||
error={!!errorMessage}
|
||||
placeholder="0.0"
|
||||
step="0.000000000000000001"
|
||||
onChange={e => onValueChange(e.target.value)}
|
||||
onKeyPress={e => {
|
||||
const charCode = e.which ? e.which : e.keyCode
|
||||
|
@ -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 }) {
|
||||
<DownArrow active={isValid} alt="arrow" />
|
||||
</DownArrowBackground>
|
||||
</OversizedPanel>
|
||||
<AddressInputPanel onChange={setRecipient} onError={setRecipientError} />
|
||||
<AddressInputPanel onChange={setRecipient} onError={setRecipientError} initialInput={recipient} />
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
|
@ -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 => <Bold>{text}</Bold>
|
||||
|
||||
const renderTransactionDetails = () => {
|
||||
|
@ -4,3 +4,8 @@ export const FACTORY_ADDRESSES = {
|
||||
4: '0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36',
|
||||
42: '0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30'
|
||||
}
|
||||
|
||||
export const SUPPORTED_THEMES = {
|
||||
DARK: 'DARK',
|
||||
LIGHT: 'LIGHT'
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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 (
|
||||
<>
|
||||
<Suspense fallback={null}>
|
||||
@ -63,27 +64,33 @@ export default function App() {
|
||||
{/* this Suspense is for route code-splitting */}
|
||||
<Suspense fallback={null}>
|
||||
<Switch>
|
||||
<Route exact strict path="/swap" component={Swap} />
|
||||
<Route exact strict path="/swap" component={() => <Swap params={params} />} />
|
||||
<Route
|
||||
exact
|
||||
strict
|
||||
path="/swap/:tokenAddress?"
|
||||
render={({ match }) => {
|
||||
render={({ match, location }) => {
|
||||
if (isAddress(match.params.tokenAddress)) {
|
||||
return <Swap initialCurrency={isAddress(match.params.tokenAddress)} />
|
||||
return (
|
||||
<Swap
|
||||
location={location}
|
||||
initialCurrency={isAddress(match.params.tokenAddress)}
|
||||
params={params}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return <Redirect to={{ pathname: '/swap' }} />
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Route exact strict path="/send" component={Send} />
|
||||
<Route exact strict path="/send" component={() => <Send params={params} />} />
|
||||
<Route
|
||||
exact
|
||||
strict
|
||||
path="/send/:tokenAddress?"
|
||||
render={({ match }) => {
|
||||
render={({ match, location }) => {
|
||||
if (isAddress(match.params.tokenAddress)) {
|
||||
return <Send initialCurrency={isAddress(match.params.tokenAddress)} />
|
||||
return <Send initialCurrency={isAddress(match.params.tokenAddress)} params={params} />
|
||||
} else {
|
||||
return <Redirect to={{ pathname: '/send' }} />
|
||||
}
|
||||
@ -96,7 +103,7 @@ export default function App() {
|
||||
'/create-exchange',
|
||||
'/create-exchange/:tokenAddress?'
|
||||
]}
|
||||
component={Pool}
|
||||
component={() => <Pool params={params} />}
|
||||
/>
|
||||
<Redirect to="/swap" />
|
||||
</Switch>
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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 }) {
|
||||
<>
|
||||
<AddressInputPanel
|
||||
title={t('tokenAddress')}
|
||||
initialInput={(location.state && location.state.tokenAddress) || ''}
|
||||
initialInput={
|
||||
params.tokenAddress
|
||||
? { address: params.tokenAddress }
|
||||
: { address: (location.state && location.state.tokenAddress) || '' }
|
||||
}
|
||||
onChange={setTokenAddress}
|
||||
onError={setTokenAddressError}
|
||||
/>
|
||||
|
@ -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
|
||||
|
@ -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 = () => <AddLiquidity params={params} />
|
||||
|
||||
const RemoveLiquidityParams = () => <RemoveLiquidity params={params} />
|
||||
|
||||
const CreateExchangeParams = () => <CreateExchange params={params} />
|
||||
|
||||
return (
|
||||
<>
|
||||
<ModeSelector />
|
||||
{/* this Suspense is for route code-splitting */}
|
||||
<Suspense fallback={null}>
|
||||
<Switch>
|
||||
<Route exact strict path="/add-liquidity" component={AddLiquidity} />
|
||||
<Route exact strict path="/remove-liquidity" component={RemoveLiquidity} />
|
||||
<Route exact strict path="/create-exchange" component={CreateExchange} />
|
||||
<Route exact strict path="/add-liquidity" component={AddLiquidityParams} />
|
||||
<Route exact strict path="/remove-liquidity" component={RemoveLiquidityParams} />
|
||||
<Route exact strict path="/create-exchange" component={CreateExchangeParams} />
|
||||
<Route
|
||||
path="/create-exchange/:tokenAddress"
|
||||
render={({ match }) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import ExchangePage from '../../components/ExchangePage'
|
||||
|
||||
export default function Send({ initialCurrency }) {
|
||||
return <ExchangePage initialCurrency={initialCurrency} sending={true} />
|
||||
export default function Send({ initialCurrency, params }) {
|
||||
return <ExchangePage initialCurrency={initialCurrency} params={params} sending={true} />
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import ExchangePage from '../../components/ExchangePage'
|
||||
|
||||
export default function Swap({ initialCurrency }) {
|
||||
return <ExchangePage initialCurrency={initialCurrency} />
|
||||
export default function Swap({ initialCurrency, params }) {
|
||||
return <ExchangePage initialCurrency={initialCurrency} params={params} />
|
||||
}
|
||||
|
@ -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 <StyledComponentsThemeProvider theme={theme(themeToRender)}>{children}</StyledComponentsThemeProvider>
|
||||
}
|
||||
|
||||
const theme = darkMode => ({
|
||||
white,
|
||||
black,
|
||||
@ -84,12 +102,6 @@ const theme = darkMode => ({
|
||||
flexRowNoWrap
|
||||
})
|
||||
|
||||
export default function ThemeProvider({ children }) {
|
||||
const [darkMode] = useDarkModeManager()
|
||||
|
||||
return <StyledComponentsThemeProvider theme={theme(darkMode)}>{children}</StyledComponentsThemeProvider>
|
||||
}
|
||||
|
||||
export const GlobalStyle = createGlobalStyle`
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
html { font-family: 'Inter', sans-serif; }
|
||||
|
@ -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: {
|
||||
|
Loading…
Reference in New Issue
Block a user