TS migrations and commit hash in code link (#730)

* TypeScript in the utils directory, README fixes

* Remove unused methods

* Added unnecessary space

* Some env variable cleanup

* Bug in change

* Another file to ts

* App.tsx

* Header and Footer to tsx

* Few more TS migrations and add a commit hash title to the uni icon

* Few more TS migrations and put commit hash in code link

* Splitting up files

* Splitting up files (merged dark mode changes)
This commit is contained in:
Moody Salem 2020-05-07 18:52:26 -04:00 committed by GitHub
parent 404d7a60e5
commit 7fcecc22d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 439 additions and 396 deletions

@ -24,6 +24,7 @@
"@web3-react/walletconnect-connector": "^6.0.2", "@web3-react/walletconnect-connector": "^6.0.2",
"@web3-react/walletlink-connector": "^6.0.2", "@web3-react/walletlink-connector": "^6.0.2",
"copy-to-clipboard": "^3.2.0", "copy-to-clipboard": "^3.2.0",
"cross-env": "^7.0.2",
"escape-string-regexp": "^2.0.0", "escape-string-regexp": "^2.0.0",
"ethers": "^4.0.44", "ethers": "^4.0.44",
"history": "^4.9.0", "history": "^4.9.0",
@ -51,8 +52,8 @@
"use-media": "^1.4.0" "use-media": "^1.4.0"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "cross-env REACT_APP_GIT_COMMIT_HASH=$(git show -s --format=%H) react-scripts start",
"build": "react-scripts build", "build": "cross-env REACT_APP_GIT_COMMIT_HASH=$(git show -s --format=%H) react-scripts build",
"test": "react-scripts test --env=jsdom", "test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject", "eject": "react-scripts eject",
"lint:base": "yarn eslint './src/**/*.{js,jsx}'", "lint:base": "yarn eslint './src/**/*.{js,jsx}'",
@ -80,4 +81,4 @@
] ]
}, },
"license": "GPL-3.0-or-later" "license": "GPL-3.0-or-later"
} }

@ -1,15 +1,28 @@
import React, { useState, useReducer, useCallback, useEffect } from 'react' import React, { useState, useReducer, useCallback, useEffect } from 'react'
import styled from 'styled-components'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { withRouter } from 'react-router-dom' import { withRouter } from 'react-router-dom'
import { parseUnits, parseEther } from '@ethersproject/units' import { parseUnits, parseEther } from '@ethersproject/units'
import { WETH, TradeType, Pair, Trade, TokenAmount, JSBI, Percent } from '@uniswap/sdk' import { Field, initializeSwapState, reducer, SwapAction } from './swap-store'
import { WETH, TradeType, Pair, Trade, TokenAmount, JSBI, Percent, Fraction } from '@uniswap/sdk'
import {
AdvancedDropwdown,
ArrowWrapper,
BottomGrouping,
Dots,
ErrorText,
FixedBottom,
InputGroup,
MaxButton,
SectionBreak,
StyledBalanceMaxMini,
StyledNumerical,
TruncatedText,
Wrapper
} from './styleds'
import Copy from '../AccountDetails/Copy' import Copy from '../AccountDetails/Copy'
import TokenLogo from '../TokenLogo' import TokenLogo from '../TokenLogo'
import SlippageTabs from '../SlippageTabs' import SlippageTabs from '../SlippageTabs'
import QuestionHelper from '../Question' import QuestionHelper from '../Question'
import NumericalInput from '../NumericalInput'
import AddressInputPanel from '../AddressInputPanel' import AddressInputPanel from '../AddressInputPanel'
import ConfirmationModal from '../ConfirmationModal' import ConfirmationModal from '../ConfirmationModal'
import CurrencyInputPanel from '../CurrencyInputPanel' import CurrencyInputPanel from '../CurrencyInputPanel'
@ -37,263 +50,17 @@ import { getRouterContract, calculateGasMargin, getProviderOrSigner, getEthersca
import { useLocalStorageTokens } from '../../contexts/LocalStorage' import { useLocalStorageTokens } from '../../contexts/LocalStorage'
import { useDarkModeManager } from '../../contexts/LocalStorage' import { useDarkModeManager } from '../../contexts/LocalStorage'
const Wrapper = styled.div`
position: relative;
`
const ArrowWrapper = styled.div`
padding: 2px;
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
:hover {
cursor: pointer;
opacity: 0.8;
}
`
const FixedBottom = styled.div`
position: absolute;
margin-top: 1.5rem;
width: 100%;
margin-bottom: 40px;
`
const AdvancedDropwdown = styled.div`
position: absolute;
margin-top: -12px;
max-width: 455px;
width: 100%;
margin-bottom: 100px;
padding: 10px 0;
padding-top: 36px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
color: ${({ theme }) => theme.text2};
background-color: ${({ theme }) => theme.advancedBG};
color: ${({ theme }) => theme.text2};
z-index: -1;
`
const SectionBreak = styled.div`
height: 1px;
width: 100%;
background-color: ${({ theme }) => theme.bg3};
`
const BottomGrouping = styled.div`
margin-top: 12px;
position: relative;
`
const ErrorText = styled(Text)`
color: ${({ theme, warningLow, warningMedium, warningHigh }) =>
warningHigh ? theme.red1 : warningMedium ? theme.yellow2 : warningLow ? theme.green1 : theme.text1};
`
const InputGroup = styled(AutoColumn)`
position: relative;
padding: 40px 0 20px 0;
`
const StyledNumerical = styled(NumericalInput)`
text-align: center;
font-size: 48px;
font-weight: 500px;
width: 100%;
::placeholder {
color: ${({ theme }) => theme.text4};
}
`
const MaxButton = styled.button`
position: absolute;
right: 70px;
padding: 0.5rem 0.5rem;
background-color: ${({ theme }) => theme.blue5};
border: 1px solid ${({ theme }) => theme.blue5};
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
text-transform: uppercase;
cursor: pointer;
margin-right: 0.5rem;
color: ${({ theme }) => theme.blue1};
:hover {
border: 1px solid ${({ theme }) => theme.blue1};
}
:focus {
border: 1px solid ${({ theme }) => theme.blue1};
outline: none;
}
`
const StyledBalanceMaxMini = styled.button`
height: 24px;
background-color: ${({ theme }) => theme.bg2};
border: none;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 400;
margin-left: 6px;
cursor: pointer;
color: ${({ theme }) => theme.text2};
display: flex;
justify-content: center;
align-items: center;
width: fit-content;
float: right;
:hover {
background-color: ${({ theme }) => theme.bg3};
/* border: 1px solid ${({ theme, active }) => (active ? theme.bg2 : theme.blue4)}; */
}
:focus {
background-color: ${({ theme }) => theme.bg3};
/* border: 1px solid ${({ theme, active }) => (active ? theme.bg2 : theme.blue4)}; */
outline: none;
}
`
const TruncatedText = styled(Text)`
text-overflow: ellipsis;
width: 220px;
overflow: hidden;
`
// styles
const Dots = styled.span`
&::after {
display: inline-block;
animation: ellipsis 1.25s infinite;
content: '.';
width: 1em;
text-align: left;
}
@keyframes ellipsis {
0% {
content: '.';
}
33% {
content: '..';
}
66% {
content: '...';
}
}
`
enum Field {
INPUT,
OUTPUT
}
interface SwapState {
independentField: Field
typedValue: string
[Field.INPUT]: {
address: string | undefined
}
[Field.OUTPUT]: {
address: string | undefined
}
}
function initializeSwapState({ inputTokenAddress, outputTokenAddress, typedValue, independentField }): SwapState {
return {
independentField: independentField,
typedValue: typedValue,
[Field.INPUT]: {
address: inputTokenAddress
},
[Field.OUTPUT]: {
address: outputTokenAddress
}
}
}
enum SwapAction {
SELECT_TOKEN,
SWITCH_TOKENS,
TYPE
}
interface Payload {
[SwapAction.SELECT_TOKEN]: {
field: Field
address: string
}
[SwapAction.SWITCH_TOKENS]: undefined
[SwapAction.TYPE]: {
field: Field
typedValue: string
}
}
function reducer(
state: SwapState,
action: {
type: SwapAction
payload: Payload[SwapAction]
}
): SwapState {
switch (action.type) {
case SwapAction.SELECT_TOKEN: {
const { field, address } = action.payload as Payload[SwapAction.SELECT_TOKEN]
const otherField = field === Field.INPUT ? Field.OUTPUT : Field.INPUT
if (address === state[otherField].address) {
// the case where we have to swap the order
return {
...state,
independentField: state.independentField === Field.INPUT ? Field.OUTPUT : Field.INPUT,
[field]: { address },
[otherField]: { address: state[field].address }
}
} else {
// the normal case
return {
...state,
[field]: { address }
}
}
}
case SwapAction.SWITCH_TOKENS: {
return {
...state,
independentField: state.independentField === Field.INPUT ? Field.OUTPUT : Field.INPUT,
[Field.INPUT]: { address: state[Field.OUTPUT].address },
[Field.OUTPUT]: { address: state[Field.INPUT].address }
}
}
case SwapAction.TYPE: {
const { field, typedValue } = action.payload as Payload[SwapAction.TYPE]
return {
...state,
independentField: field,
typedValue
}
}
default: {
throw Error
}
}
}
function hex(value: JSBI) { function hex(value: JSBI) {
return ethers.utils.bigNumberify(value.toString()) return ethers.utils.bigNumberify(value.toString())
} }
const SWAP_TYPE = { enum SwapType {
EXACT_TOKENS_FOR_TOKENS: 'EXACT_TOKENS_FOR_TOKENS', EXACT_TOKENS_FOR_TOKENS,
EXACT_TOKENS_FOR_ETH: 'EXACT_TOKENS_FOR_ETH', EXACT_TOKENS_FOR_ETH,
EXACT_ETH_FOR_TOKENS: 'EXACT_ETH_FOR_TOKENS', EXACT_ETH_FOR_TOKENS,
TOKENS_FOR_EXACT_TOKENS: 'TOKENS_FOR_EXACT_TOKENS', TOKENS_FOR_EXACT_TOKENS,
TOKENS_FOR_EXACT_ETH: 'TOKENS_FOR_EXACT_ETH', TOKENS_FOR_EXACT_ETH,
ETH_FOR_EXACT_TOKENS: 'ETH_FOR_EXACT_TOKENS' ETH_FOR_EXACT_TOKENS
} }
const GAS_MARGIN = ethers.utils.bigNumberify(1000) const GAS_MARGIN = ethers.utils.bigNumberify(1000)
@ -333,21 +100,21 @@ function ExchangePage({ sendingInput = false, history, params }) {
typedValue: typedValue:
params.inputTokenAddress && !params.outputTokenAddress params.inputTokenAddress && !params.outputTokenAddress
? params.inputTokenAmount ? params.inputTokenAmount
? params.inputTokenAmount ? params.inputTokenAmount
: '' : ''
: !params.inputTokenAddress && params.outputTokenAddress : !params.inputTokenAddress && params.outputTokenAddress
? params.outputTokenAmount ? params.outputTokenAmount
? params.outputTokenAmount ? params.outputTokenAmount
: '' : ''
: params.inputTokenAddress && params.outputTokenAddress : params.inputTokenAddress && params.outputTokenAddress
? params.inputTokenAmount
? params.inputTokenAmount ? params.inputTokenAmount
? params.inputTokenAmount
: ''
: '' : ''
: '' ? ''
? '' : ''
: '' ? ''
? '' : ''
: ''
}, },
initializeSwapState initializeSwapState
) )
@ -441,7 +208,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
!!route && !!parsedAmounts[independentField] !!route && !!parsedAmounts[independentField]
? new Trade(route, parsedAmounts[independentField], tradeType) ? new Trade(route, parsedAmounts[independentField], tradeType)
: undefined : undefined
} catch (error) {} } catch (error) {
}
const slippageFromTrade: Percent = trade && trade.slippage const slippageFromTrade: Percent = trade && trade.slippage
@ -524,10 +292,11 @@ function ExchangePage({ sendingInput = false, history, params }) {
WETH[chainId] && WETH[chainId] &&
JSBI.greaterThan(userBalances[Field.INPUT].raw, isWETH(tokens[Field.INPUT]) ? MIN_ETHER.raw : JSBI.BigInt(0)) JSBI.greaterThan(userBalances[Field.INPUT].raw, isWETH(tokens[Field.INPUT]) ? MIN_ETHER.raw : JSBI.BigInt(0))
? isWETH(tokens[Field.INPUT]) ? isWETH(tokens[Field.INPUT])
? userBalances[Field.INPUT].subtract(MIN_ETHER) ? userBalances[Field.INPUT].subtract(MIN_ETHER)
: userBalances[Field.INPUT] : userBalances[Field.INPUT]
: undefined : undefined
} catch {} } catch {
}
const atMaxAmountInput: boolean = const atMaxAmountInput: boolean =
!!maxAmountInput && !!parsedAmounts[Field.INPUT] !!maxAmountInput && !!parsedAmounts[Field.INPUT]
@ -544,22 +313,22 @@ function ExchangePage({ sendingInput = false, history, params }) {
? JSBI.equal(maxAmountOutput.raw, parsedAmounts[Field.OUTPUT].raw) ? JSBI.equal(maxAmountOutput.raw, parsedAmounts[Field.OUTPUT].raw)
: undefined : undefined
function getSwapType(): string { function getSwapType(): SwapType {
if (tradeType === TradeType.EXACT_INPUT) { if (tradeType === TradeType.EXACT_INPUT) {
if (tokens[Field.INPUT] === WETH[chainId]) { if (tokens[Field.INPUT] === WETH[chainId]) {
return SWAP_TYPE.EXACT_ETH_FOR_TOKENS return SwapType.EXACT_ETH_FOR_TOKENS
} else if (tokens[Field.OUTPUT] === WETH[chainId]) { } else if (tokens[Field.OUTPUT] === WETH[chainId]) {
return SWAP_TYPE.EXACT_TOKENS_FOR_ETH return SwapType.EXACT_TOKENS_FOR_ETH
} else { } else {
return SWAP_TYPE.EXACT_TOKENS_FOR_TOKENS return SwapType.EXACT_TOKENS_FOR_TOKENS
} }
} else if (tradeType === TradeType.EXACT_OUTPUT) { } else if (tradeType === TradeType.EXACT_OUTPUT) {
if (tokens[Field.INPUT] === WETH[chainId]) { if (tokens[Field.INPUT] === WETH[chainId]) {
return SWAP_TYPE.ETH_FOR_EXACT_TOKENS return SwapType.ETH_FOR_EXACT_TOKENS
} else if (tokens[Field.OUTPUT] === WETH[chainId]) { } else if (tokens[Field.OUTPUT] === WETH[chainId]) {
return SWAP_TYPE.TOKENS_FOR_EXACT_ETH return SwapType.TOKENS_FOR_EXACT_ETH
} else { } else {
return SWAP_TYPE.TOKENS_FOR_EXACT_TOKENS return SwapType.TOKENS_FOR_EXACT_TOKENS
} }
} }
} }
@ -577,12 +346,12 @@ function ExchangePage({ sendingInput = false, history, params }) {
Field.INPUT === independentField Field.INPUT === independentField
? parsedAmounts[Field.INPUT] ? parsedAmounts[Field.INPUT]
: calculateSlippageAmount(parsedAmounts[Field.INPUT])?.[0] && : calculateSlippageAmount(parsedAmounts[Field.INPUT])?.[0] &&
new TokenAmount(tokens[Field.INPUT], calculateSlippageAmount(parsedAmounts[Field.INPUT])?.[1]), new TokenAmount(tokens[Field.INPUT], calculateSlippageAmount(parsedAmounts[Field.INPUT])?.[1]),
[Field.OUTPUT]: [Field.OUTPUT]:
Field.OUTPUT === independentField Field.OUTPUT === independentField
? parsedAmounts[Field.OUTPUT] ? parsedAmounts[Field.OUTPUT]
: calculateSlippageAmount(parsedAmounts[Field.OUTPUT])?.[0] && : calculateSlippageAmount(parsedAmounts[Field.OUTPUT])?.[0] &&
new TokenAmount(tokens[Field.INPUT], calculateSlippageAmount(parsedAmounts[Field.OUTPUT])?.[0]) new TokenAmount(tokens[Field.INPUT], calculateSlippageAmount(parsedAmounts[Field.OUTPUT])?.[0])
} }
const showInputApprove: boolean = const showInputApprove: boolean =
@ -603,11 +372,11 @@ function ExchangePage({ sendingInput = false, history, params }) {
addTransaction( addTransaction(
response, response,
'Send ' + 'Send ' +
parsedAmounts[Field.INPUT]?.toSignificant(3) + parsedAmounts[Field.INPUT]?.toSignificant(3) +
' ' + ' ' +
tokens[Field.INPUT]?.symbol + tokens[Field.INPUT]?.symbol +
' to ' + ' to ' +
recipient recipient
) )
setPendingConfirmation(false) setPendingConfirmation(false)
}) })
@ -632,11 +401,11 @@ function ExchangePage({ sendingInput = false, history, params }) {
addTransaction( addTransaction(
response, response,
'Send ' + 'Send ' +
parsedAmounts[Field.INPUT]?.toSignificant(3) + parsedAmounts[Field.INPUT]?.toSignificant(3) +
' ' + ' ' +
tokens[Field.INPUT]?.symbol + tokens[Field.INPUT]?.symbol +
' to ' + ' to ' +
recipient recipient
) )
setPendingConfirmation(false) setPendingConfirmation(false)
}) })
@ -659,9 +428,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
let estimate: Function, method: Function, args: any[], value: ethers.utils.BigNumber let estimate: Function, method: Function, args: any[], value: ethers.utils.BigNumber
const deadlineFromNow: number = Math.ceil(Date.now() / 1000) + deadline const deadlineFromNow: number = Math.ceil(Date.now() / 1000) + deadline
const swapType = getSwapType() switch (getSwapType()) {
switch (swapType) { case SwapType.EXACT_TOKENS_FOR_TOKENS:
case SWAP_TYPE.EXACT_TOKENS_FOR_TOKENS:
estimate = routerContract.estimate.swapExactTokensForTokens estimate = routerContract.estimate.swapExactTokensForTokens
method = routerContract.swapExactTokensForTokens method = routerContract.swapExactTokensForTokens
args = [ args = [
@ -673,7 +441,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
] ]
value = ethers.constants.Zero value = ethers.constants.Zero
break break
case SWAP_TYPE.TOKENS_FOR_EXACT_TOKENS: case SwapType.TOKENS_FOR_EXACT_TOKENS:
estimate = routerContract.estimate.swapTokensForExactTokens estimate = routerContract.estimate.swapTokensForExactTokens
method = routerContract.swapTokensForExactTokens method = routerContract.swapTokensForExactTokens
args = [ args = [
@ -685,7 +453,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
] ]
value = ethers.constants.Zero value = ethers.constants.Zero
break break
case SWAP_TYPE.EXACT_ETH_FOR_TOKENS: case SwapType.EXACT_ETH_FOR_TOKENS:
estimate = routerContract.estimate.swapExactETHForTokens estimate = routerContract.estimate.swapExactETHForTokens
method = routerContract.swapExactETHForTokens method = routerContract.swapExactETHForTokens
args = [ args = [
@ -696,7 +464,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
] ]
value = hex(slippageAdjustedAmounts[Field.INPUT].raw) value = hex(slippageAdjustedAmounts[Field.INPUT].raw)
break break
case SWAP_TYPE.TOKENS_FOR_EXACT_ETH: case SwapType.TOKENS_FOR_EXACT_ETH:
estimate = routerContract.estimate.swapTokensForExactETH estimate = routerContract.estimate.swapTokensForExactETH
method = routerContract.swapTokensForExactETH method = routerContract.swapTokensForExactETH
args = [ args = [
@ -708,7 +476,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
] ]
value = ethers.constants.Zero value = ethers.constants.Zero
break break
case SWAP_TYPE.EXACT_TOKENS_FOR_ETH: case SwapType.EXACT_TOKENS_FOR_ETH:
estimate = routerContract.estimate.swapExactTokensForETH estimate = routerContract.estimate.swapExactTokensForETH
method = routerContract.swapExactTokensForETH method = routerContract.swapExactTokensForETH
args = [ args = [
@ -720,7 +488,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
] ]
value = ethers.constants.Zero value = ethers.constants.Zero
break break
case SWAP_TYPE.ETH_FOR_EXACT_TOKENS: case SwapType.ETH_FOR_EXACT_TOKENS:
estimate = routerContract.estimate.swapETHForExactTokens estimate = routerContract.estimate.swapETHForExactTokens
method = routerContract.swapETHForExactTokens method = routerContract.swapETHForExactTokens
args = [ args = [
@ -746,13 +514,13 @@ function ExchangePage({ sendingInput = false, history, params }) {
addTransaction( addTransaction(
response, response,
'Swap ' + 'Swap ' +
slippageAdjustedAmounts?.[Field.INPUT]?.toSignificant(3) + slippageAdjustedAmounts?.[Field.INPUT]?.toSignificant(3) +
' ' + ' ' +
tokens[Field.INPUT]?.symbol + tokens[Field.INPUT]?.symbol +
' for ' + ' for ' +
slippageAdjustedAmounts?.[Field.OUTPUT]?.toSignificant(3) + slippageAdjustedAmounts?.[Field.OUTPUT]?.toSignificant(3) +
' ' + ' ' +
tokens[Field.OUTPUT]?.symbol tokens[Field.OUTPUT]?.symbol
) )
setPendingConfirmation(false) setPendingConfirmation(false)
}) })
@ -908,7 +676,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<Text fontSize={36} fontWeight={500}> <Text fontSize={36} fontWeight={500}>
{parsedAmounts[Field.INPUT]?.toSignificant(6)} {tokens[Field.INPUT]?.symbol} {parsedAmounts[Field.INPUT]?.toSignificant(6)} {tokens[Field.INPUT]?.symbol}
</Text> </Text>
<TokenLogo address={tokens[Field.INPUT]?.address} size={'30px'} /> <TokenLogo address={tokens[Field.INPUT]?.address} size={'30px'}/>
</RowBetween> </RowBetween>
<TYPE.darkGray fontSize={20}>To</TYPE.darkGray> <TYPE.darkGray fontSize={20}>To</TYPE.darkGray>
{ENS ? ( {ENS ? (
@ -920,7 +688,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
{recipient?.slice(0, 8)}...{recipient?.slice(34, 42)} {recipient?.slice(0, 8)}...{recipient?.slice(34, 42)}
</TYPE.blue> </TYPE.blue>
</Link> </Link>
<Copy toCopy={recipient} /> <Copy toCopy={recipient}/>
</AutoRow> </AutoRow>
</AutoColumn> </AutoColumn>
) : ( ) : (
@ -930,7 +698,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
{recipient?.slice(0, 6)}...{recipient?.slice(36, 42)} {recipient?.slice(0, 6)}...{recipient?.slice(36, 42)}
</TYPE.blue> </TYPE.blue>
</Link> </Link>
<Copy toCopy={recipient} /> <Copy toCopy={recipient}/>
</AutoRow> </AutoRow>
)} )}
</AutoColumn> </AutoColumn>
@ -942,7 +710,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<AutoColumn gap="lg" style={{ marginTop: '40px' }}> <AutoColumn gap="lg" style={{ marginTop: '40px' }}>
<AutoColumn gap="sm"> <AutoColumn gap="sm">
<AutoRow gap="10px"> <AutoRow gap="10px">
<TokenLogo address={tokens[Field.OUTPUT]?.address} size={'30px'} /> <TokenLogo address={tokens[Field.OUTPUT]?.address} size={'30px'}/>
<Text fontSize={36} fontWeight={500}> <Text fontSize={36} fontWeight={500}>
{slippageAdjustedAmounts[Field.OUTPUT]?.toSignificant(4)} {tokens[Field.OUTPUT]?.symbol} {slippageAdjustedAmounts[Field.OUTPUT]?.toSignificant(4)} {tokens[Field.OUTPUT]?.symbol}
</Text> </Text>
@ -970,14 +738,14 @@ function ExchangePage({ sendingInput = false, history, params }) {
{/* {!!slippageAdjustedAmounts[Field.INPUT] && slippageAdjustedAmounts[Field.INPUT].toSignificant(6)} */} {/* {!!slippageAdjustedAmounts[Field.INPUT] && slippageAdjustedAmounts[Field.INPUT].toSignificant(6)} */}
</TruncatedText> </TruncatedText>
<RowFixed gap="4px"> <RowFixed gap="4px">
<TokenLogo address={tokens[Field.INPUT]?.address} size={'24px'} /> <TokenLogo address={tokens[Field.INPUT]?.address} size={'24px'}/>
<Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}> <Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}>
{tokens[Field.INPUT]?.symbol || ''} {tokens[Field.INPUT]?.symbol || ''}
</Text> </Text>
</RowFixed> </RowFixed>
</RowBetween> </RowBetween>
<RowFixed> <RowFixed>
<ArrowDown size="16" color={theme(isDark).text2} /> <ArrowDown size="16" color={theme(isDark).text2}/>
</RowFixed> </RowFixed>
<RowBetween align="flex-end"> <RowBetween align="flex-end">
<TruncatedText fontSize={24} fontWeight={500} color={warningHigh ? theme(isDark).red1 : ''}> <TruncatedText fontSize={24} fontWeight={500} color={warningHigh ? theme(isDark).red1 : ''}>
@ -986,7 +754,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
{/* {!!slippageAdjustedAmounts[Field.OUTPUT] && slippageAdjustedAmounts[Field.OUTPUT].toSignificant(6)} */} {/* {!!slippageAdjustedAmounts[Field.OUTPUT] && slippageAdjustedAmounts[Field.OUTPUT].toSignificant(6)} */}
</TruncatedText> </TruncatedText>
<RowFixed gap="4px"> <RowFixed gap="4px">
<TokenLogo address={tokens[Field.OUTPUT]?.address} size={'24px'} /> <TokenLogo address={tokens[Field.OUTPUT]?.address} size={'24px'}/>
<Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}> <Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}>
{tokens[Field.OUTPUT]?.symbol || ''} {tokens[Field.OUTPUT]?.symbol || ''}
</Text> </Text>
@ -1046,17 +814,17 @@ function ExchangePage({ sendingInput = false, history, params }) {
> >
{pair && showInverted {pair && showInverted
? route.midPrice.invert().toSignificant(6) + ? route.midPrice.invert().toSignificant(6) +
' ' + ' ' +
tokens[Field.INPUT]?.symbol + tokens[Field.INPUT]?.symbol +
' / ' + ' / ' +
tokens[Field.OUTPUT]?.symbol tokens[Field.OUTPUT]?.symbol
: route.midPrice.toSignificant(6) + : route.midPrice.toSignificant(6) +
' ' + ' ' +
tokens[Field.OUTPUT]?.symbol + tokens[Field.OUTPUT]?.symbol +
' / ' + ' / ' +
tokens[Field.INPUT]?.symbol} tokens[Field.INPUT]?.symbol}
<StyledBalanceMaxMini onClick={() => setShowInverted(!showInverted)}> <StyledBalanceMaxMini onClick={() => setShowInverted(!showInverted)}>
<Repeat size={14} /> <Repeat size={14}/>
</StyledBalanceMaxMini> </StyledBalanceMaxMini>
</Text> </Text>
</RowBetween> </RowBetween>
@ -1066,7 +834,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
<TYPE.black fontSize={14} fontWeight={400}> <TYPE.black fontSize={14} fontWeight={400}>
{independentField === Field.INPUT ? (sending ? 'Min sent' : 'Minimum received') : 'Maximum sold'} {independentField === Field.INPUT ? (sending ? 'Min sent' : 'Minimum received') : 'Maximum sold'}
</TYPE.black> </TYPE.black>
<QuestionHelper text="A boundary is set so you are protected from large price movements after you submit your trade." /> <QuestionHelper
text="A boundary is set so you are protected from large price movements after you submit your trade."/>
</RowFixed> </RowFixed>
<RowFixed> <RowFixed>
<TYPE.black fontSize={14}> <TYPE.black fontSize={14}>
@ -1077,10 +846,10 @@ function ExchangePage({ sendingInput = false, history, params }) {
: slippageAdjustedAmounts[Field.OUTPUT]?.toFixed(5) : slippageAdjustedAmounts[Field.OUTPUT]?.toFixed(5)
: '-' : '-'
: slippageAdjustedAmounts[Field.INPUT] : slippageAdjustedAmounts[Field.INPUT]
? slippageAdjustedAmounts[Field.INPUT]?.toFixed(5) === '0.00000' ? slippageAdjustedAmounts[Field.INPUT]?.toFixed(5) === '0.00000'
? '<0.00001' ? '<0.00001'
: slippageAdjustedAmounts[Field.INPUT]?.toFixed(5) : slippageAdjustedAmounts[Field.INPUT]?.toFixed(5)
: '-'} : '-'}
</TYPE.black> </TYPE.black>
{parsedAmounts[Field.OUTPUT] && parsedAmounts[Field.INPUT] && ( {parsedAmounts[Field.OUTPUT] && parsedAmounts[Field.INPUT] && (
<TYPE.black fontSize={14} marginLeft={'4px'}> <TYPE.black fontSize={14} marginLeft={'4px'}>
@ -1096,7 +865,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<TYPE.black color={theme(isDark).text1} fontSize={14} fontWeight={400}> <TYPE.black color={theme(isDark).text1} fontSize={14} fontWeight={400}>
Price impact Price impact
</TYPE.black> </TYPE.black>
<QuestionHelper text="The difference between the market price and your price due to trade size." /> <QuestionHelper text="The difference between the market price and your price due to trade size."/>
</RowFixed> </RowFixed>
<ErrorText <ErrorText
fontWeight={500} fontWeight={500}
@ -1117,7 +886,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
<TYPE.black fontSize={14} fontWeight={400}> <TYPE.black fontSize={14} fontWeight={400}>
Liquidity Provider Fee Liquidity Provider Fee
</TYPE.black> </TYPE.black>
<QuestionHelper text="A portion of each trade (0.3%) goes to liquidity providers to incentivize liquidity on the protocol." /> <QuestionHelper
text="A portion of each trade (0.3%) goes to liquidity providers to incentivize liquidity on the protocol."/>
</RowFixed> </RowFixed>
<TYPE.black fontSize={14}> <TYPE.black fontSize={14}>
{feeTimesInputFormatted {feeTimesInputFormatted
@ -1139,7 +909,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
} }
} }
const PriceBar = function() { const PriceBar = function () {
return ( return (
<AutoRow justify="space-between"> <AutoRow justify="space-between">
<AutoColumn justify="center"> <AutoColumn justify="center">
@ -1186,7 +956,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
? `Sending ${parsedAmounts[Field.OUTPUT]?.toSignificant(6)} ${tokens[Field.OUTPUT]?.symbol} to ${recipient}` ? `Sending ${parsedAmounts[Field.OUTPUT]?.toSignificant(6)} ${tokens[Field.OUTPUT]?.symbol} to ${recipient}`
: `Sending ${parsedAmounts[Field.INPUT]?.toSignificant(6)} ${tokens[Field.INPUT]?.symbol} to ${recipient}` : `Sending ${parsedAmounts[Field.INPUT]?.toSignificant(6)} ${tokens[Field.INPUT]?.symbol} to ${recipient}`
: ` Swapping ${parsedAmounts[Field.INPUT]?.toSignificant(6)} ${tokens[Field.INPUT]?.symbol} for ${parsedAmounts[ : ` Swapping ${parsedAmounts[Field.INPUT]?.toSignificant(6)} ${tokens[Field.INPUT]?.symbol} for ${parsedAmounts[
Field.OUTPUT Field.OUTPUT
]?.toSignificant(6)} ${tokens[Field.OUTPUT]?.symbol}` ]?.toSignificant(6)} ${tokens[Field.OUTPUT]?.symbol}`
function _onTokenSelect(address: string) { function _onTokenSelect(address: string) {
@ -1241,7 +1011,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
Max Max
</MaxButton> </MaxButton>
)} )}
<StyledNumerical value={formattedAmounts[Field.INPUT]} onUserInput={val => onUserInput(Field.INPUT, val)} /> <StyledNumerical value={formattedAmounts[Field.INPUT]} onUserInput={val => onUserInput(Field.INPUT, val)}/>
<CurrencyInputPanel <CurrencyInputPanel
field={Field.INPUT} field={Field.INPUT}
value={formattedAmounts[Field.INPUT]} value={formattedAmounts[Field.INPUT]}
@ -1287,7 +1057,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<ColumnCenter> <ColumnCenter>
<RowBetween padding="0 12px"> <RowBetween padding="0 12px">
<ArrowWrapper onClick={onSwapTokens}> <ArrowWrapper onClick={onSwapTokens}>
<ArrowDown size="16" color={theme(isDark).text2} onClick={onSwapTokens} /> <ArrowDown size="16" color={theme(isDark).text2} onClick={onSwapTokens}/>
</ArrowWrapper> </ArrowWrapper>
<StyledBalanceMaxMini onClick={() => setSendingWithSwap(false)} style={{ marginRight: '0px' }}> <StyledBalanceMaxMini onClick={() => setSendingWithSwap(false)} style={{ marginRight: '0px' }}>
<TYPE.blue>Remove Swap</TYPE.blue> <TYPE.blue>Remove Swap</TYPE.blue>
@ -1325,7 +1095,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
/> />
{sendingWithSwap && ( {sendingWithSwap && (
<RowBetween padding="0 12px"> <RowBetween padding="0 12px">
<ArrowDown size="16" /> <ArrowDown size="16"/>
</RowBetween> </RowBetween>
)} )}
</> </>
@ -1357,7 +1127,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
{!noRoute && tokens[Field.OUTPUT] && tokens[Field.INPUT] && ( {!noRoute && tokens[Field.OUTPUT] && tokens[Field.INPUT] && (
<Card padding={advanced ? '.25rem 1.25rem 0 .75rem' : '.25rem .7rem .25rem 1.25rem'} borderRadius={'20px'}> <Card padding={advanced ? '.25rem 1.25rem 0 .75rem' : '.25rem .7rem .25rem 1.25rem'} borderRadius={'20px'}>
{advanced ? ( {advanced ? (
<PriceBar /> <PriceBar/>
) : ( ) : (
<AutoColumn gap="4px"> <AutoColumn gap="4px">
{' '} {' '}
@ -1373,17 +1143,17 @@ function ExchangePage({ sendingInput = false, history, params }) {
> >
{pair && showInverted {pair && showInverted
? route.midPrice.invert().toSignificant(6) + ? route.midPrice.invert().toSignificant(6) +
' ' + ' ' +
tokens[Field.INPUT]?.symbol + tokens[Field.INPUT]?.symbol +
' per ' + ' per ' +
tokens[Field.OUTPUT]?.symbol tokens[Field.OUTPUT]?.symbol
: route.midPrice.toSignificant(6) + : route.midPrice.toSignificant(6) +
' ' + ' ' +
tokens[Field.OUTPUT]?.symbol + tokens[Field.OUTPUT]?.symbol +
' per ' + ' per ' +
tokens[Field.INPUT]?.symbol} tokens[Field.INPUT]?.symbol}
<StyledBalanceMaxMini onClick={() => setShowInverted(!showInverted)}> <StyledBalanceMaxMini onClick={() => setShowInverted(!showInverted)}>
<Repeat size={14} /> <Repeat size={14}/>
</StyledBalanceMaxMini> </StyledBalanceMaxMini>
</Text> </Text>
</RowBetween> </RowBetween>
@ -1403,7 +1173,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
: priceSlippage.toFixed(4) + '%' : priceSlippage.toFixed(4) + '%'
: '-'}{' '} : '-'}{' '}
</ErrorText> </ErrorText>
<QuestionHelper text="The difference between the market price and your quoted price due to trade size." /> <QuestionHelper
text="The difference between the market price and your quoted price due to trade size."/>
</RowFixed> </RowFixed>
</RowBetween> </RowBetween>
)} )}
@ -1451,22 +1222,22 @@ function ExchangePage({ sendingInput = false, history, params }) {
{!account {!account
? 'Connect Wallet' ? 'Connect Wallet'
: generalError : generalError
? generalError ? generalError
: inputError : inputError
? inputError ? inputError
: outputError : outputError
? outputError ? outputError
: recipientError : recipientError
? recipientError ? recipientError
: tradeError : tradeError
? tradeError ? tradeError
: warningHigh : warningHigh
? sendingWithSwap ? sendingWithSwap
? 'Send Anyway' ? 'Send Anyway'
: 'Swap Anyway' : 'Swap Anyway'
: sending : sending
? 'Send' ? 'Send'
: 'Swap'} : 'Swap'}
</Text> </Text>
</ButtonError> </ButtonError>
)} )}
@ -1479,7 +1250,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<Text fontSize={16} fontWeight={500} style={{ userSelect: 'none' }}> <Text fontSize={16} fontWeight={500} style={{ userSelect: 'none' }}>
Show Advanced Show Advanced
</Text> </Text>
<ChevronDown color={theme(isDark).text2} /> <ChevronDown color={theme(isDark).text2}/>
</RowBetween> </RowBetween>
</Hover> </Hover>
)} )}
@ -1490,10 +1261,10 @@ function ExchangePage({ sendingInput = false, history, params }) {
<Text fontSize={16} color={theme(isDark).text2} fontWeight={500} style={{ userSelect: 'none' }}> <Text fontSize={16} color={theme(isDark).text2} fontWeight={500} style={{ userSelect: 'none' }}>
Hide Advanced Hide Advanced
</Text> </Text>
<ChevronUp color={theme(isDark).text2} /> <ChevronUp color={theme(isDark).text2}/>
</RowBetween> </RowBetween>
</Hover> </Hover>
<SectionBreak /> <SectionBreak/>
<AutoColumn style={{ padding: '0 20px' }}> <AutoColumn style={{ padding: '0 20px' }}>
<RowBetween> <RowBetween>
<RowFixed> <RowFixed>
@ -1508,8 +1279,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
text={ text={
independentField === Field.INPUT independentField === Field.INPUT
? sending ? sending
? 'Price can change between when a transaction is submitted and when it is executed. This is the minimum amount you will send. A worse rate will cause your transaction to revert.' ? 'Price can change between when a transaction is submitted and when it is executed. This is the minimum amount you will send. A worse rate will cause your transaction to revert.'
: 'Price can change between when a transaction is submitted and when it is executed. This is the minimum amount you will receive. A worse rate will cause your transaction to revert.' : 'Price can change between when a transaction is submitted and when it is executed. This is the minimum amount you will receive. A worse rate will cause your transaction to revert.'
: 'Price can change between when a transaction is submitted and when it is executed. This is the maximum amount you will pay. A worse rate will cause your transaction to revert.' : 'Price can change between when a transaction is submitted and when it is executed. This is the maximum amount you will pay. A worse rate will cause your transaction to revert.'
} }
/> />
@ -1518,15 +1289,15 @@ function ExchangePage({ sendingInput = false, history, params }) {
<TYPE.black color={theme(isDark).text1} fontSize={14}> <TYPE.black color={theme(isDark).text1} fontSize={14}>
{independentField === Field.INPUT {independentField === Field.INPUT
? slippageAdjustedAmounts[Field.OUTPUT] ? slippageAdjustedAmounts[Field.OUTPUT]
? slippageAdjustedAmounts[Field.OUTPUT]?.toFixed(5) === '0.00000' ? slippageAdjustedAmounts[Field.OUTPUT]?.lessThan(new Fraction(JSBI.BigInt(1), JSBI.BigInt(10000)))
? '<0.00001' ? '<0.00001'
: slippageAdjustedAmounts[Field.OUTPUT]?.toFixed(5) : slippageAdjustedAmounts[Field.OUTPUT]?.toFixed(5)
: '-' : '-'
: slippageAdjustedAmounts[Field.INPUT] : slippageAdjustedAmounts[Field.INPUT]
? slippageAdjustedAmounts[Field.INPUT]?.toFixed(5) === '0.00000' ? slippageAdjustedAmounts[Field.INPUT]?.lessThan(new Fraction(JSBI.BigInt(1), JSBI.BigInt(10000)))
? '<0.00001' ? '<0.00001'
: slippageAdjustedAmounts[Field.INPUT]?.toFixed(5) : slippageAdjustedAmounts[Field.INPUT]?.toFixed(5)
: '-'} : '-'}
</TYPE.black> </TYPE.black>
{parsedAmounts[Field.OUTPUT] && parsedAmounts[Field.INPUT] && ( {parsedAmounts[Field.OUTPUT] && parsedAmounts[Field.INPUT] && (
<TYPE.black fontSize={14} marginLeft={'4px'} color={theme(isDark).text1}> <TYPE.black fontSize={14} marginLeft={'4px'} color={theme(isDark).text1}>
@ -1542,7 +1313,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
<TYPE.black fontSize={14} fontWeight={400} color={theme(isDark).text1}> <TYPE.black fontSize={14} fontWeight={400} color={theme(isDark).text1}>
Price Impact Price Impact
</TYPE.black> </TYPE.black>
<QuestionHelper text="The difference between the market price and your quoted price due to trade size." /> <QuestionHelper
text="The difference between the market price and your quoted price due to trade size."/>
</RowFixed> </RowFixed>
<ErrorText <ErrorText
fontWeight={500} fontWeight={500}
@ -1563,7 +1335,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
<TYPE.black fontSize={14} fontWeight={400} color={theme(isDark).text1}> <TYPE.black fontSize={14} fontWeight={400} color={theme(isDark).text1}>
Liquidity Provider Fee Liquidity Provider Fee
</TYPE.black> </TYPE.black>
<QuestionHelper text="A portion of each trade (0.03%) goes to liquidity providers to incentivize liquidity on the protocol." /> <QuestionHelper
text="A portion of each trade (0.03%) goes to liquidity providers to incentivize liquidity on the protocol."/>
</RowFixed> </RowFixed>
<TYPE.black fontSize={14} color={theme(isDark).text1}> <TYPE.black fontSize={14} color={theme(isDark).text1}>
{feeTimesInputFormatted {feeTimesInputFormatted
@ -1572,12 +1345,13 @@ function ExchangePage({ sendingInput = false, history, params }) {
</TYPE.black> </TYPE.black>
</RowBetween> </RowBetween>
</AutoColumn> </AutoColumn>
<SectionBreak /> <SectionBreak/>
<RowFixed padding={'0 20px'}> <RowFixed padding={'0 20px'}>
<TYPE.black fontWeight={400} fontSize={14} color={theme(isDark).text1}> <TYPE.black fontWeight={400} fontSize={14} color={theme(isDark).text1}>
Set front running resistance Set front running resistance
</TYPE.black> </TYPE.black>
<QuestionHelper text="Your transaction will revert if the price changes more than this amount after you submit your trade." /> <QuestionHelper
text="Your transaction will revert if the price changes more than this amount after you submit your trade."/>
</RowFixed> </RowFixed>
<SlippageTabs <SlippageTabs
rawSlippage={allowedSlippage} rawSlippage={allowedSlippage}

@ -0,0 +1,154 @@
import styled from 'styled-components'
import { AutoColumn } from '../Column'
import NumericalInput from '../NumericalInput'
export const Wrapper = styled.div`
position: relative;
`
export const ArrowWrapper = styled.div`
padding: 2px;
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
:hover {
cursor: pointer;
opacity: 0.8;
}
`
export const FixedBottom = styled.div`
position: absolute;
margin-top: 1.5rem;
width: 100%;
margin-bottom: 40px;
`
export const AdvancedDropwdown = styled.div`
position: absolute;
margin-top: -12px;
max-width: 455px;
width: 100%;
margin-bottom: 100px;
padding: 10px 0;
padding-top: 36px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
color: ${({ theme }) => theme.text2};
background-color: ${({ theme }) => theme.advancedBG};
color: ${({ theme }) => theme.text2};
z-index: -1;
`
export const SectionBreak = styled.div`
height: 1px;
width: 100%;
background-color: ${({ theme }) => theme.bg3};
`
export const BottomGrouping = styled.div`
margin-top: 12px;
position: relative;
`
export const ErrorText = styled(Text)`
color: ${({ theme, warningLow, warningMedium, warningHigh }) =>
warningHigh ? theme.red1 : warningMedium ? theme.yellow2 : warningLow ? theme.green1 : theme.text1};
`
export const InputGroup = styled(AutoColumn)`
position: relative;
padding: 40px 0 20px 0;
`
export const StyledNumerical = styled(NumericalInput)`
text-align: center;
font-size: 48px;
font-weight: 500px;
width: 100%;
::placeholder {
color: ${({ theme }) => theme.text4};
}
`
export const MaxButton = styled.button`
position: absolute;
right: 70px;
padding: 0.5rem 0.5rem;
background-color: ${({ theme }) => theme.blue5};
border: 1px solid ${({ theme }) => theme.blue5};
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
text-transform: uppercase;
cursor: pointer;
margin-right: 0.5rem;
color: ${({ theme }) => theme.blue1};
:hover {
border: 1px solid ${({ theme }) => theme.blue1};
}
:focus {
border: 1px solid ${({ theme }) => theme.blue1};
outline: none;
}
`
export const StyledBalanceMaxMini = styled.button`
height: 24px;
background-color: ${({ theme }) => theme.bg2};
border: none;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 400;
margin-left: 6px;
cursor: pointer;
color: ${({ theme }) => theme.text2};
display: flex;
justify-content: center;
align-items: center;
width: fit-content;
float: right;
:hover {
background-color: ${({ theme }) => theme.bg3};
/* border: 1px solid ${({ theme, active }) => (active ? theme.bg2 : theme.blue4)}; */
}
:focus {
background-color: ${({ theme }) => theme.bg3};
/* border: 1px solid ${({ theme, active }) => (active ? theme.bg2 : theme.blue4)}; */
outline: none;
}
`
export const TruncatedText = styled(Text)`
text-overflow: ellipsis;
width: 220px;
overflow: hidden;
`
// styles
export const Dots = styled.span`
&::after {
display: inline-block;
animation: ellipsis 1.25s infinite;
content: '.';
width: 1em;
text-align: left;
}
@keyframes ellipsis {
0% {
content: '.';
}
33% {
content: '..';
}
66% {
content: '...';
}
}
`

@ -0,0 +1,95 @@
export enum Field {
INPUT,
OUTPUT
}
export interface SwapState {
independentField: Field
typedValue: string
[Field.INPUT]: {
address: string | undefined
}
[Field.OUTPUT]: {
address: string | undefined
}
}
export function initializeSwapState({ inputTokenAddress, outputTokenAddress, typedValue, independentField }): SwapState {
return {
independentField: independentField,
typedValue: typedValue,
[Field.INPUT]: {
address: inputTokenAddress
},
[Field.OUTPUT]: {
address: outputTokenAddress
}
}
}
export enum SwapAction {
SELECT_TOKEN,
SWITCH_TOKENS,
TYPE
}
export interface Payload {
[SwapAction.SELECT_TOKEN]: {
field: Field
address: string
}
[SwapAction.SWITCH_TOKENS]: undefined
[SwapAction.TYPE]: {
field: Field
typedValue: string
}
}
export function reducer(
state: SwapState,
action: {
type: SwapAction
payload: Payload[SwapAction]
}
): SwapState {
switch (action.type) {
case SwapAction.SELECT_TOKEN: {
const { field, address } = action.payload as Payload[SwapAction.SELECT_TOKEN]
const otherField = field === Field.INPUT ? Field.OUTPUT : Field.INPUT
if (address === state[otherField].address) {
// the case where we have to swap the order
return {
...state,
independentField: state.independentField === Field.INPUT ? Field.OUTPUT : Field.INPUT,
[field]: { address },
[otherField]: { address: state[field].address }
}
} else {
// the normal case
return {
...state,
[field]: { address }
}
}
}
case SwapAction.SWITCH_TOKENS: {
return {
...state,
independentField: state.independentField === Field.INPUT ? Field.OUTPUT : Field.INPUT,
[Field.INPUT]: { address: state[Field.OUTPUT].address },
[Field.OUTPUT]: { address: state[Field.INPUT].address }
}
}
case SwapAction.TYPE: {
const { field, typedValue } = action.payload as Payload[SwapAction.TYPE]
return {
...state,
independentField: field,
typedValue
}
}
default: {
throw Error
}
}
}

@ -13,7 +13,6 @@ import { isMobile } from 'react-device-detect'
import { YellowCard, GreyCard } from '../Card' import { YellowCard, GreyCard } from '../Card'
import { useWeb3React } from '../../hooks' import { useWeb3React } from '../../hooks'
import { useAddressBalance } from '../../contexts/Balances' import { useAddressBalance } from '../../contexts/Balances'
import { useWalletModalToggle } from '../../contexts/Application'
import { useDarkModeManager } from '../../contexts/LocalStorage' import { useDarkModeManager } from '../../contexts/LocalStorage'
import Logo from '../../assets/svg/logo.svg' import Logo from '../../assets/svg/logo.svg'
@ -138,7 +137,6 @@ function Header({ history }) {
const { account, chainId } = useWeb3React() const { account, chainId } = useWeb3React()
const userEthBalance = useAddressBalance(account, WETH[chainId]) const userEthBalance = useAddressBalance(account, WETH[chainId])
const toggleWalletModal = useWalletModalToggle()
const [isDark] = useDarkModeManager() const [isDark] = useDarkModeManager()
return ( return (
@ -189,7 +187,7 @@ function Header({ history }) {
) : ( ) : (
'' ''
)} )}
<Web3Status onClick={toggleWalletModal} /> <Web3Status />
</AccountElement> </AccountElement>
<Menu /> <Menu />

@ -79,13 +79,17 @@ const MenuItem = styled(Link)`
} }
` `
const CODE_LINK = !!process.env.REACT_APP_GIT_COMMIT_HASH ?
`https://github.com/Uniswap/uniswap-frontend/tree/${process.env.REACT_APP_GIT_COMMIT_HASH}`:
'https://github.com/Uniswap/uniswap-frontend'
export default function Menu() { export default function Menu() {
const node = useRef() const node = useRef<HTMLDivElement>()
const [open, toggle] = useToggle(false) const [open, toggle] = useToggle(false)
useEffect(() => { useEffect(() => {
const handleClickOutside = e => { const handleClickOutside = e => {
if (node.current.contains(e.target)) { if (node.current?.contains(e.target) ?? false) {
return return
} }
toggle() toggle()
@ -115,7 +119,7 @@ export default function Menu() {
<MenuItem id="link" href="https://uniswap.org/docs/v2"> <MenuItem id="link" href="https://uniswap.org/docs/v2">
Docs Docs
</MenuItem> </MenuItem>
<MenuItem id="link" href="https://github.com/Uniswap"> <MenuItem id="link" href={CODE_LINK}>
Code Code
</MenuItem> </MenuItem>
<MenuItem id="link" href="https://uniswap.info/"> <MenuItem id="link" href="https://uniswap.info/">

@ -13,9 +13,10 @@ export class FortmaticConnector extends FortmaticConnectorCore {
async activate() { async activate() {
if (!this.fortmatic) { if (!this.fortmatic) {
const { default: Fortmatic } = await import('fortmatic') const { default: Fortmatic } = await import('fortmatic')
const { apiKey, chainId } = this as any
this.fortmatic = new Fortmatic( this.fortmatic = new Fortmatic(
this.apiKey, apiKey,
this.chainId === 1 || this.chainId === 4 ? undefined : chainIdToNetwork[this.chainId] chainId === 1 || chainId === 4 ? undefined : chainIdToNetwork[chainId]
) )
} }
@ -33,6 +34,6 @@ export class FortmaticConnector extends FortmaticConnectorCore {
const [account] = await Promise.all([provider.enable().then(accounts => accounts[0]), pollForOverlayReady]) const [account] = await Promise.all([provider.enable().then(accounts => accounts[0]), pollForOverlayReady])
return { provider: this.fortmatic.getProvider(), chainId: this.chainId, account } return { provider: this.fortmatic.getProvider(), chainId: (this as any).chainId, account }
} }
} }

@ -2,14 +2,14 @@ import { NetworkConnector as NetworkConnectorCore } from '@web3-react/network-co
export class NetworkConnector extends NetworkConnectorCore { export class NetworkConnector extends NetworkConnectorCore {
pause() { pause() {
if (this.active) { if ((this as any).active) {
this.providers[this.currentChainId].stop() (this as any).providers[(this as any).currentChainId].stop()
} }
} }
resume() { resume() {
if (this.active) { if ((this as any).active) {
this.providers[this.currentChainId].start() (this as any).providers[(this as any).currentChainId].start()
} }
} }
} }

@ -3,7 +3,7 @@ import { useWeb3React as useWeb3ReactCore } from '@web3-react/core'
import { isMobile } from 'react-device-detect' import { isMobile } from 'react-device-detect'
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import ERC20_ABI from '../constants/abis/erc20' import ERC20_ABI from '../constants/abis/erc20.json'
import { injected } from '../connectors' import { injected } from '../connectors'
import { NetworkContextName } from '../constants' import { NetworkContextName } from '../constants'
import { getContract, getExchangeContract, isAddress } from '../utils' import { getContract, getExchangeContract, isAddress } from '../utils'
@ -25,7 +25,7 @@ export function useEagerConnect() {
setTried(true) setTried(true)
}) })
} else { } else {
if (isMobile && window.ethereum) { if (isMobile && (window as any).ethereum) {
activate(injected, undefined, true).catch(() => { activate(injected, undefined, true).catch(() => {
setTried(true) setTried(true)
}) })
@ -54,7 +54,7 @@ export function useInactiveListener(suppress = false) {
const { active, error, activate } = useWeb3ReactCore() // specifically using useWeb3React because of what this hook does const { active, error, activate } = useWeb3ReactCore() // specifically using useWeb3React because of what this hook does
useEffect(() => { useEffect(() => {
const { ethereum } = window const { ethereum } = window as any
if (ethereum && ethereum.on && !active && !error && !suppress) { if (ethereum && ethereum.on && !active && !error && !suppress) {
const handleChainChanged = () => { const handleChainChanged = () => {
@ -139,7 +139,7 @@ export function useBodyKeyDown(targetKey, onKeyDown, suppressOnKeyDown = false)
export function useENSName(address) { export function useENSName(address) {
const { library } = useWeb3React() const { library } = useWeb3React()
const [ENSName, setENSName] = useState() const [ENSName, setENSName] = useState<string | null>(null)
useEffect(() => { useEffect(() => {
if (isAddress(address)) { if (isAddress(address)) {
@ -163,7 +163,7 @@ export function useENSName(address) {
return () => { return () => {
stale = true stale = true
setENSName() setENSName(null)
} }
} }
}, [library, address]) }, [library, address])
@ -247,7 +247,7 @@ export function usePrevious(value) {
return ref.current return ref.current
} }
export function useToggle(initialState = false) { export function useToggle(initialState = false): [boolean, () => void] {
const [state, setState] = useState(initialState) const [state, setState] = useState(initialState)
const toggle = useCallback(() => setState(state => !state), []) const toggle = useCallback(() => setState(state => !state), [])
return [state, toggle] return [state, toggle]

@ -143,7 +143,7 @@ export default function App() {
const t1 = const t1 =
tokens?.[1] === 'ETH' ? 'ETH' : isAddress(tokens?.[1]) ? isAddress(tokens[1]) : undefined tokens?.[1] === 'ETH' ? 'ETH' : isAddress(tokens?.[1]) ? isAddress(tokens[1]) : undefined
if (t0 && t1) { if (t0 && t1) {
return <Remove token0={t0} token1={t1} params={params} /> return <Remove token0={t0} token1={t1} />
} else { } else {
return <Redirect to="/pool" /> return <Redirect to="/pool" />
} }
@ -154,7 +154,7 @@ export default function App() {
</Suspense> </Suspense>
</Web3ReactManager> </Web3ReactManager>
</Body> </Body>
<Footer></Footer> <Footer/>
</BodyWrapper> </BodyWrapper>
<StyledRed /> <StyledRed />
</AppWrapper> </AppWrapper>

@ -5276,6 +5276,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
sha.js "^2.4.8" sha.js "^2.4.8"
cross-env@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.2.tgz#bd5ed31339a93a3418ac4f3ca9ca3403082ae5f9"
integrity sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==
dependencies:
cross-spawn "^7.0.1"
cross-fetch@^2.1.0, cross-fetch@^2.1.1: cross-fetch@^2.1.0, cross-fetch@^2.1.1:
version "2.2.3" version "2.2.3"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.3.tgz#e8a0b3c54598136e037f8650f8e823ccdfac198e" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.3.tgz#e8a0b3c54598136e037f8650f8e823ccdfac198e"
@ -5304,6 +5311,15 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
shebang-command "^1.2.0" shebang-command "^1.2.0"
which "^1.2.9" which "^1.2.9"
cross-spawn@^7.0.1:
version "7.0.2"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.2.tgz#d0d7dcfa74e89115c7619f4f721a94e1fdb716d6"
integrity sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
crypto-browserify@3.12.0, crypto-browserify@^3.11.0: crypto-browserify@3.12.0, crypto-browserify@^3.11.0:
version "3.12.0" version "3.12.0"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"