diff --git a/public/locales/en.json b/public/locales/en.json
index 7fe01f5d1f..ebfa9c2f3c 100644
--- a/public/locales/en.json
+++ b/public/locales/en.json
@@ -9,7 +9,7 @@
"swapAnyway": "Swap Anyway",
"send": "Send",
"sendAnyway": "Send Anyway",
- "pool": "Supply",
+ "pool": "Pool",
"betaWarning": "This project is in beta. Use at your own risk.",
"input": "Input",
"output": "Output",
@@ -85,5 +85,7 @@
"enterTokenCont": "Enter a token address to continue",
"priceChange": "Expected price slippage",
"forAtLeast": "for at least ",
- "brokenToken": "The selected token is not compatible with Uniswap V1. Adding liquidity will result in locked funds."
+ "brokenToken": "The selected token is not compatible with Uniswap V1. Adding liquidity will result in locked funds.",
+ "toleranceExplanation": "Lowering this limit decreases your risk of frontrunning. However, this makes more likely that your transaction will fail due to normal price movements.",
+ "tokenSearchPlaceholder": "Search name or paste token address"
}
diff --git a/src/components/AddressInputPanel/index.js b/src/components/AddressInputPanel/index.js
index 2246a687dc..12715d5062 100644
--- a/src/components/AddressInputPanel/index.js
+++ b/src/components/AddressInputPanel/index.js
@@ -2,8 +2,7 @@ import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import { transparentize } from 'polished'
-import QR from '../../assets/svg/QR.svg'
-
+// import QR from '../../assets/svg/QR.svg'
import { isAddress } from '../../utils'
import { useWeb3React, useDebounce } from '../../hooks'
@@ -15,6 +14,8 @@ const InputPanel = styled.div`
background-color: ${({ theme }) => theme.bg1};
z-index: 1;
width: 100%;
+ height: 60px;
+
`
const ContainerRow = styled.div`
@@ -22,6 +23,7 @@ const ContainerRow = styled.div`
justify-content: center;
align-items: center;
border-radius: 1.25rem;
+ height: 60px;
border: 1px solid ${({ error, theme }) => (error ? theme.red1 : theme.bg3)};
background-color: ${({ theme }) => theme.bg1};
`
@@ -43,25 +45,26 @@ const Input = styled.input`
flex: 1 1 auto;
width: 0;
background-color: ${({ theme }) => theme.bg1};
-
+ font-size: 20px;
color: ${({ error, theme }) => (error ? theme.red1 : theme.blue1)};
overflow: hidden;
text-overflow: ellipsis;
+ font-weight: 500;
::placeholder {
color: ${({ theme }) => theme.text4};
}
`
-const QRWrapper = styled.div`
- display: flex;
- align-items: center;
- justify-content: center;
- border: 1px solid ${({ theme }) => theme.bg3};
- background: #fbfbfb;
- padding: 4px;
- border-radius: 8px;
-`
+// const QRWrapper = styled.div`
+// display: flex;
+// align-items: center;
+// justify-content: center;
+// border: 1px solid ${({ theme }) => theme.bg3};
+// background: #fbfbfb;
+// padding: 4px;
+// border-radius: 8px;
+// `
export default function AddressInputPanel({ initialInput = '', onChange, onError }) {
const { library } = useWeb3React()
@@ -172,14 +175,14 @@ export default function AddressInputPanel({ initialInput = '', onChange, onError
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
- placeholder="0x1234..."
+ placeholder="Recipient Address"
error={input !== '' && error}
onChange={onInput}
value={input}
/>
-
+ {/*
-
+ */}
diff --git a/src/components/AdvancedSettings/index.js b/src/components/AdvancedSettings/index.js
index 5c493a6d23..07b098f453 100644
--- a/src/components/AdvancedSettings/index.js
+++ b/src/components/AdvancedSettings/index.js
@@ -7,6 +7,7 @@ import { Link } from '../../theme/components'
import { TYPE } from '../../theme'
import { AutoColumn } from '../../components/Column'
import { ButtonRadio } from '../Button'
+import { useTranslation } from 'react-i18next'
import Row, { RowBetween, RowFixed } from '../../components/Row'
const InputWrapper = styled(RowBetween)`
@@ -27,6 +28,9 @@ const SLIPPAGE_INDEX = {
}
export default function AdvancedSettings({ setIsOpen, setDeadline, allowedSlippage, setAllowedSlippage }) {
+ // text translation
+ const { t } = useTranslation()
+
const [deadlineInput, setDeadlineInput] = useState(15)
const [slippageInput, setSlippageInput] = useState()
const [activeIndex, setActiveIndex] = useState(SLIPPAGE_INDEX[3])
@@ -82,8 +86,8 @@ export default function AdvancedSettings({ setIsOpen, setDeadline, allowedSlippa
back
- Limit additional price impact
-
+ Limit front-running tolerance
+
theme.blue5};
+ color: ${({ theme }) => theme.blue1};
+ font-size: 20px;
+ font-weight: 500;
+ &:focus {
+ box-shadow: 0 0 0 1pt ${({ theme, disabled }) => !disabled && darken(0.05, theme.blue5)};
+ background-color: ${({ theme, disabled }) => !disabled && darken(0.05, theme.blue5)};
+ }
+ &:hover {
+ background-color: ${({ theme, disabled }) => !disabled && darken(0.05, theme.blue5)};
+ }
+ &:active {
+ box-shadow: 0 0 0 1pt ${({ theme, disabled }) => !disabled && darken(0.1, theme.blue5)};
+ background-color: ${({ theme, disabled }) => !disabled && darken(0.1, theme.blue5)};
+ }
+`
+
export const ButtonSecondary = styled(Base)`
background-color: #ebf4ff;
color: #2172e5;
@@ -73,8 +91,6 @@ export const ButtonPink = styled(Base)`
background-color: ${({ theme }) => theme.pink2};
color: white;
- padding: 10px;
-
&:focus {
box-shadow: 0 0 0 1pt ${({ theme }) => darken(0.05, theme.pink2)};
background-color: ${({ theme }) => darken(0.05, theme.pink2)};
diff --git a/src/components/Card/index.js b/src/components/Card/index.js
index 93165221a4..e6abbc9e27 100644
--- a/src/components/Card/index.js
+++ b/src/components/Card/index.js
@@ -18,12 +18,24 @@ export const LightCard = styled(Card)`
`
export const GreyCard = styled(Card)`
- background-color: rgba(255, 255, 255, 0.9);
+ background-color: rgba(255, 255, 255, 0.6);
+`
+
+export const YellowCard = styled(Card)`
+ background-color: rgba(243, 190, 30, 0.3);
+ color: ${({ theme }) => theme.yellow2};
+ fontweight: 500;
+`
+
+export const PinkCard = styled(Card)`
+ background-color: rgba(255, 0, 122, 0.03);
+ color: ${({ theme }) => theme.pink2};
+ fontweight: 500;
`
const BlueCardStyled = styled(Card)`
- background-color: #ebf4ff;
- color: #2172e5;
+ background-color: ${({ theme }) => theme.blue5};
+ color: ${({ theme }) => theme.blue1};
border-radius: 12px;
padding: 8px;
width: fit-content;
diff --git a/src/components/ConfirmationModal/index.js b/src/components/ConfirmationModal/index.js
index 5294ec5648..c75558348d 100644
--- a/src/components/ConfirmationModal/index.js
+++ b/src/components/ConfirmationModal/index.js
@@ -23,6 +23,8 @@ const Section = styled(AutoColumn)`
const BottomSection = styled(Section)`
background-color: ${({ theme }) => theme.bg2};
+ border-bottom-left-radius: 10px;
+ border-bottom-right-radius: 10px;
`
const ConfirmedIcon = styled(ColumnCenter)`
diff --git a/src/components/CurrencyInputPanel/index.js b/src/components/CurrencyInputPanel/index.js
index 3511437789..087377e743 100644
--- a/src/components/CurrencyInputPanel/index.js
+++ b/src/components/CurrencyInputPanel/index.js
@@ -1,9 +1,7 @@
import React, { useState } from 'react'
import styled from 'styled-components'
import '@reach/tooltip/styles.css'
-import { ethers } from 'ethers'
import { darken } from 'polished'
-import { WETH } from '@uniswap/sdk'
import TokenLogo from '../TokenLogo'
import DoubleLogo from '../DoubleLogo'
@@ -16,30 +14,7 @@ import { Input as NumericalInput } from '../NumericalInput'
import { useWeb3React } from '../../hooks'
import { useTranslation } from 'react-i18next'
-import { useTokenContract } from '../../hooks'
-import { calculateGasMargin } from '../../utils'
import { useAddressBalance } from '../../contexts/Balances'
-import { useTransactionAdder, usePendingApproval } from '../../contexts/Transactions'
-
-import { ROUTER_ADDRESSES } from '../../constants'
-
-const GAS_MARGIN = ethers.utils.bigNumberify(1000)
-
-const SubCurrencySelect = styled.button`
- ${({ theme }) => theme.flexRowNoWrap}
- padding: 4px 50px 4px 15px;
- margin-right: -40px;
- line-height: 0;
- align-items: center;
- border-radius: 2.5rem;
- height: 2rem;
- outline: none;
- cursor: pointer;
- user-select: none;
- background: ${({ theme }) => theme.blue5};
- border: 1px solid ${({ theme }) => theme.blue1};
- color: ${({ theme }) => theme.blue1};
-`
const InputRow = styled.div`
${({ theme }) => theme.flexRowNoWrap}
@@ -156,8 +131,6 @@ export default function CurrencyInputPanel({
urlAddedTokens = [], // used
onTokenSelection = null,
token = null,
- showUnlock = false, // used to show unlock if approval needed
- disableUnlock = false,
disableTokenSelect = false,
hideBalance = false,
isExchange = false,
@@ -167,59 +140,11 @@ export default function CurrencyInputPanel({
showSendWithSwap = false
}) {
const { t } = useTranslation()
- const { account, chainId } = useWeb3React()
- const routerAddress = ROUTER_ADDRESSES[chainId]
+ const { account } = useWeb3React()
- const addTransaction = useTransactionAdder()
const [modalOpen, setModalOpen] = useState(false)
const userTokenBalance = useAddressBalance(account, token)
- const tokenContract = useTokenContract(token?.address)
- const pendingApproval = usePendingApproval(token?.address)
-
- function renderUnlockButton() {
- if (
- disableUnlock ||
- !showUnlock ||
- token?.address === 'ETH' ||
- token?.address === WETH[chainId].address ||
- !token?.address
- ) {
- return null
- } else {
- if (!pendingApproval) {
- return (
- {
- let estimatedGas
- let useUserBalance = false
- estimatedGas = await tokenContract.estimate
- .approve(routerAddress, ethers.constants.MaxUint256)
- .catch(e => {
- console.log('Error setting max token approval.')
- })
- if (!estimatedGas) {
- // general fallback for tokens who restrict approval amounts
- estimatedGas = await tokenContract.estimate.approve(routerAddress, userTokenBalance)
- useUserBalance = true
- }
- tokenContract
- .approve(routerAddress, useUserBalance ? userTokenBalance : ethers.constants.MaxUint256, {
- gasLimit: calculateGasMargin(estimatedGas, GAS_MARGIN)
- })
- .then(response => {
- addTransaction(response, { approval: token?.address })
- })
- }}
- >
- {t('unlock')}
-
- )
- } else {
- return {t('pending')}
- }
- }
- }
return (
@@ -234,7 +159,7 @@ export default function CurrencyInputPanel({
}}
/>
{!!token?.address && !atMax && MAX}
- {renderUnlockButton()}
+ {/* {renderUnlockButton()} */}
>
)}
)}
diff --git a/src/components/ExchangePage/index.tsx b/src/components/ExchangePage/index.tsx
index f6ed1a02ed..ff6d937d2b 100644
--- a/src/components/ExchangePage/index.tsx
+++ b/src/components/ExchangePage/index.tsx
@@ -16,29 +16,31 @@ import { Link } from '../../theme/components'
import { Text } from 'rebass'
import { TYPE } from '../../theme'
import { ArrowDown, ArrowUp } from 'react-feather'
-import { GreyCard, BlueCard } from '../../components/Card'
+import { GreyCard, BlueCard, YellowCard } from '../../components/Card'
import { AutoColumn, ColumnCenter } from '../../components/Column'
-import { ButtonPrimary, ButtonError } from '../Button'
import { RowBetween, RowFixed, AutoRow } from '../../components/Row'
+import { ButtonPrimary, ButtonError, ButtonLight } from '../Button'
import { usePair } from '../../contexts/Pairs'
import { useToken } from '../../contexts/Tokens'
import { usePopups } from '../../contexts/Application'
import { useRoute } from '../../contexts/Routes'
-import { useTransactionAdder } from '../../contexts/Transactions'
+// import { useTranslation } from 'react-i18next'
+import { useTransactionAdder, usePendingApproval } from '../../contexts/Transactions'
import { useAddressAllowance } from '../../contexts/Allowances'
import { useWeb3React, useTokenContract } from '../../hooks'
import { useAddressBalance, useAllBalances } from '../../contexts/Balances'
+import { INITIAL_TOKENS_CONTEXT } from '../../contexts/Tokens'
import { ROUTER_ADDRESSES } from '../../constants'
-import { getRouterContract, calculateGasMargin, getProviderOrSigner } from '../../utils'
+import { getRouterContract, calculateGasMargin, getProviderOrSigner, getEtherscanLink } from '../../utils'
const Wrapper = styled.div`
position: relative;
`
const ArrowWrapper = styled.div`
- padding: 4px;
+ padding: 6px;
border: 1px solid ${({ theme }) => theme.blue4};
border-radius: 12px;
display: flex;
@@ -221,6 +223,9 @@ const ALLOWED_SLIPPAGE_MEDIUM = 100
const ALLOWED_SLIPPAGE_HIGH = 500
function ExchangePage({ sendingInput = false, history }) {
+ // text translation
+ // const { t } = useTranslation()
+
const { chainId, account, library } = useWeb3React()
const routerAddress: string = ROUTER_ADDRESSES[chainId]
@@ -245,8 +250,27 @@ function ExchangePage({ sendingInput = false, history }) {
[Field.OUTPUT]: useToken(fieldData[Field.OUTPUT].address)
}
+ // token contracts for approvals and direct sends
+ const tokenContractInput: ethers.Contract = useTokenContract(tokens[Field.INPUT]?.address)
+ const tokenContractOutput: ethers.Contract = useTokenContract(tokens[Field.OUTPUT]?.address)
+
+ // check on pending approvals for token amounts
+ const pendingApprovalInput = usePendingApproval(tokens[Field.INPUT]?.address)
+ const pendingApprovalOutput = usePendingApproval(tokens[Field.OUTPUT]?.address)
+
+ // check for imported tokens to show warning
+ const importedTokenInput = tokens[Field.INPUT] && !!!INITIAL_TOKENS_CONTEXT?.[chainId]?.[tokens[Field.INPUT]?.address]
+ const importedTokenOutput =
+ tokens[Field.OUTPUT] && !!!INITIAL_TOKENS_CONTEXT?.[chainId]?.[tokens[Field.OUTPUT]?.address]
+
const pair: Pair = usePair(tokens[Field.INPUT], tokens[Field.OUTPUT])
+
+ // console.log(pair?.token0?.symbol)
+ // console.log(pair?.token1?.symbol)
+ // console.log('--------------')
+
const route = useRoute(tokens[Field.INPUT], tokens[Field.OUTPUT])
+ // const route = useRoute(pair)
const noRoute: boolean = !route && !!tokens[Field.INPUT] && !!tokens[Field.OUTPUT]
const emptyReserves = pair && JSBI.equal(JSBI.BigInt(0), pair.reserve0.raw)
@@ -274,8 +298,6 @@ function ExchangePage({ sendingInput = false, history }) {
[Field.OUTPUT]: useAddressBalance(account, tokens[Field.OUTPUT])
}
- // console.log(userBalances[Field.OUTPUT]?.raw.toString())
-
const parsedAmounts: { [field: number]: TokenAmount } = {}
if (typedValue !== '' && typedValue !== '.' && tokens[independentField]) {
try {
@@ -344,6 +366,13 @@ function ExchangePage({ sendingInput = false, history }) {
})
}, [])
+ // reset field if sending with with swap is cancled
+ useEffect(() => {
+ if (sending && !sendingWithSwap) {
+ onTokenSelection(Field.OUTPUT, null)
+ }
+ }, [onTokenSelection, sending, sendingWithSwap])
+
const MIN_ETHER: TokenAmount = chainId && new TokenAmount(WETH[chainId], JSBI.BigInt(parseEther('.01')))
let maxAmountInput: TokenAmount
@@ -427,8 +456,6 @@ function ExchangePage({ sendingInput = false, history }) {
outputApproval &&
JSBI.greaterThan(parsedAmounts[Field.OUTPUT].raw, outputApproval.raw)
- const tokenContract: ethers.Contract = useTokenContract(tokens[Field.INPUT]?.address)
-
// function for a pure send
async function onSend() {
setAttemptingTxn(true)
@@ -454,8 +481,8 @@ function ExchangePage({ sendingInput = false, history }) {
setShowConfirm(false)
})
} else {
- estimate = tokenContract.estimate.transfer
- method = tokenContract.transfer
+ estimate = tokenContractInput.estimate.transfer
+ method = tokenContractInput.transfer
args = [recipient, parsedAmounts[Field.INPUT].raw.toString()]
value = ethers.constants.Zero
const estimatedGasLimit = await estimate(...args, { value }).catch(e => {
@@ -592,6 +619,28 @@ function ExchangePage({ sendingInput = false, history }) {
})
}
+ async function approveAmount(field) {
+ let estimatedGas
+ let useUserBalance = false
+ const tokenContract = field === Field.INPUT ? tokenContractInput : tokenContractOutput
+
+ estimatedGas = await tokenContract.estimate.approve(routerAddress, ethers.constants.MaxUint256).catch(e => {
+ console.log('Error setting max token approval.')
+ })
+ if (!estimatedGas) {
+ // general fallback for tokens who restrict approval amounts
+ estimatedGas = await tokenContract.estimate.approve(routerAddress, userBalances[field])
+ useUserBalance = true
+ }
+ tokenContract
+ .approve(routerAddress, useUserBalance ? userBalances[field] : ethers.constants.MaxUint256, {
+ gasLimit: calculateGasMargin(estimatedGas, GAS_MARGIN)
+ })
+ .then(response => {
+ addTransaction(response, { approval: tokens[field]?.address })
+ })
+ }
+
// errors
const [generalError, setGeneralError] = useState('')
const [inputError, setInputError] = useState('')
@@ -806,7 +855,7 @@ function ExchangePage({ sendingInput = false, history }) {
)}
- Slippage setShowAdvanced(true)}>(edit limits)
+ Slippage
{slippageFromTrade && slippageFromTrade.toFixed(4)}%
@@ -909,7 +958,6 @@ function ExchangePage({ sendingInput = false, history }) {
onTokenSelection={address => _onTokenSelect(address)}
error={inputError}
pair={pair}
- showUnlock={showInputUnlock}
hideBalance={true}
hideInput={true}
showSendWithSwap={true}
@@ -928,19 +976,30 @@ function ExchangePage({ sendingInput = false, history }) {
token={tokens[Field.INPUT]}
error={inputError}
pair={pair}
- showUnlock={showInputUnlock}
onUserInput={onUserInput}
onMax={() => {
maxAmountInput && onMaxInput(maxAmountInput.toExact())
}}
onTokenSelection={address => onTokenSelection(Field.INPUT, address)}
/>
-
-
-
-
-
-
+ {sendingWithSwap ? (
+
+
+
+
+
+ setSendingWithSwap(false)} style={{ marginRight: '20px' }}>
+ Remove Swap
+
+
+ ) : (
+
+
+
+
+
+
+ )}
onTokenSelection(Field.OUTPUT, address)}
error={outputError}
pair={pair}
- showUnlock={showOutputUnlock}
/>
{!noRoute && ( // hide price if new exchange
@@ -962,8 +1020,8 @@ function ExchangePage({ sendingInput = false, history }) {
{pair
- ? `1 ${tokens[Field.INPUT].symbol} = ${route?.midPrice.toSignificant(6)} ${
- tokens[Field.OUTPUT].symbol
+ ? `1 ${tokens[Field.INPUT]?.symbol} = ${route?.midPrice.toSignificant(6)} ${
+ tokens[Field.OUTPUT]?.symbol
}`
: '-'}
@@ -1009,6 +1067,26 @@ function ExchangePage({ sendingInput = false, history }) {
Create one now
+ ) : showOutputUnlock ? (
+ {
+ !pendingApprovalOutput && approveAmount(Field.OUTPUT)
+ }}
+ disabled={pendingApprovalOutput}
+ >
+ {pendingApprovalOutput ? 'Waiting for unlock' : 'Unlock ' + tokens[Field.OUTPUT]?.symbol}
+
+ ) : showInputUnlock ? (
+ {
+ approveAmount(Field.INPUT)
+ }}
+ disabled={pendingApprovalInput}
+ >
+ {!pendingApprovalInput && pendingApprovalInput
+ ? 'Waiting for unlock'
+ : 'Unlock ' + tokens[Field.INPUT]?.symbol}
+
) : (
{
@@ -1039,23 +1117,58 @@ function ExchangePage({ sendingInput = false, history }) {
)}
-
- {warningHigh && (
-
-
-
-
- Slippage Warning
-
-
-
- This trade will move the price by {slippageFromTrade.toFixed(2)}%. This pool probably doesn’t have
- enough liquidity. Are you sure you want to continue this trade?
-
-
-
-
- )}
+
+
+ {importedTokenInput && (
+
+
+ Token imported via address
+
+
+ ({tokens[Field.INPUT]?.symbol})
+
+ (View on Etherscan)
+
+
+
+ Please verify the legitimacy of this token before making any transactions.
+
+
+
+ )}
+ {importedTokenOutput && (
+
+
+ Token imported via address
+
+
+ ({tokens[Field.OUTPUT]?.symbol})
+
+ (View on Etherscan)
+
+
+
+ Please verify the legitimacy of this token before making any transactions.
+
+
+
+ )}
+ {warningHigh && (
+
+
+
+ Slippage Warning
+
+
+
+ This trade will move the price by {slippageFromTrade.toFixed(2)}%. This pool probably doesn’t have
+ enough liquidity. Are you sure you want to continue this trade?
+
+
+
+ )}
+
+
)
}
diff --git a/src/components/Header/index.js b/src/components/Header/index.js
index 3e32c74f0a..a0f382cc56 100644
--- a/src/components/Header/index.js
+++ b/src/components/Header/index.js
@@ -4,7 +4,7 @@ import styled from 'styled-components'
import Row from '../Row'
import Menu from '../Menu'
import Logo from '../../assets/svg/logo.svg'
-import Card from '../Card'
+import Card, { YellowCard } from '../Card'
import Web3Status from '../Web3Status'
import { X } from 'react-feather'
import { Link } from '../../theme'
@@ -59,6 +59,7 @@ const AccountElement = styled.div`
border: 1px solid ${({ theme }) => theme.bg3};
border-radius: 8px;
padding-left: ${({ active }) => (active ? '8px' : 0)};
+ white-space: nowrap;
:focus {
border: 1px solid blue;
@@ -119,6 +120,26 @@ export default function Header() {
)}
+ {chainId === 4 && (
+
+ Rinkeby Testnet
+
+ )}
+ {chainId === 3 && (
+
+ Ropsten Testnet
+
+ )}
+ {chainId === 5 && (
+
+ Goerli Testnet
+
+ )}
+ {chainId === 42 && (
+
+ Kovan Testnet
+
+ )}
diff --git a/src/components/Modal/index.js b/src/components/Modal/index.js
index f635c7f7b0..b83d62c83a 100644
--- a/src/components/Modal/index.js
+++ b/src/components/Modal/index.js
@@ -66,7 +66,7 @@ const StyledDialogContent = styled(FilteredDialogContent)`
min-height: ${minHeight}vh;
`}
display: flex;
- overflow: hidden;
+ /* overflow: hidden; */
border-radius: 10px;
${({ theme }) => theme.mediaWidth.upToMedium`
width: 65vw;
diff --git a/src/components/NavigationTabs/index.js b/src/components/NavigationTabs/index.js
index dee57200e0..4b23faf4a6 100644
--- a/src/components/NavigationTabs/index.js
+++ b/src/components/NavigationTabs/index.js
@@ -22,9 +22,9 @@ const tabOrder = [
regex: /\/send/
},
{
- path: '/supply',
+ path: '/pool',
textKey: 'pool',
- regex: /\/supply/
+ regex: /\/pool/
}
]
@@ -105,7 +105,7 @@ function NavigationTabs({ location: { pathname }, history }) {
{adding || removing ? (
-
+
{adding ? 'Add' : 'Remove'} Liquidity
@@ -115,7 +115,7 @@ function NavigationTabs({ location: { pathname }, history }) {
) : finding ? (
-
+
Find a Pool
diff --git a/src/components/PositionCard/index.js b/src/components/PositionCard/index.js
index 72f12d6888..cabbbe6de6 100644
--- a/src/components/PositionCard/index.js
+++ b/src/components/PositionCard/index.js
@@ -1,5 +1,6 @@
-import React from 'react'
+import React, { useState } from 'react'
import styled from 'styled-components'
+import { darken } from 'polished'
import { withRouter } from 'react-router-dom'
import { Percent, Pair } from '@uniswap/sdk'
@@ -13,6 +14,7 @@ import DoubleLogo from '../DoubleLogo'
import { Text } from 'rebass'
import { GreyCard } from '../../components/Card'
import { AutoColumn } from '../Column'
+import { ChevronDown, ChevronUp } from 'react-feather'
import { ButtonSecondary } from '../Button'
import { RowBetween, RowFixed } from '../Row'
@@ -20,12 +22,22 @@ const FixedHeightRow = styled(RowBetween)`
height: 24px;
`
+const HoverCard = styled(Card)`
+ border: 1px solid ${({ theme }) => theme.bg3};
+ :hover {
+ cursor: pointer;
+ border: 1px solid ${({ theme }) => darken(0.06, theme.bg3)};
+ }
+`
+
function PositionCard({ pairAddress, token0, token1, history, minimal = false, ...rest }) {
const { account } = useWeb3React()
const allBalances = useAllBalances()
- const tokenAmount0 = allBalances?.[pairAddress]?.[token0.address]
- const tokenAmount1 = allBalances?.[pairAddress]?.[token1.address]
+ const [showMore, setShowMore] = useState(false)
+
+ const tokenAmount0 = allBalances?.[pairAddress]?.[token0?.address]
+ const tokenAmount1 = allBalances?.[pairAddress]?.[token1?.address]
const pair = tokenAmount0 && tokenAmount1 && new Pair(tokenAmount0, tokenAmount1)
@@ -46,97 +58,154 @@ function PositionCard({ pairAddress, token0, token1, history, minimal = false, .
userPoolBalance &&
pair.getLiquidityValue(token1, totalPoolTokens, userPoolBalance, false)
- function DynamicCard({ children, ...rest }) {
- if (!minimal) {
- return (
-
- {children}
-
- )
- } else {
- return {children}
- }
- }
-
- return (
-
-
-
-
-
-
- {token0?.symbol}:{token1?.symbol}
-
-
-
- {userPoolBalance ? userPoolBalance.toFixed(6) : '-'}
-
-
-
+ if (minimal) {
+ return (
+
+
-
- {token0?.symbol} Deposited:
-
- {token0Deposited ? (
-
-
-
- {token0Deposited?.toFixed(8)}
-
-
- ) : (
- '-'
- )}
+
+
+ Current Position
+
+
-
-
- {token1?.symbol} Deposited:
-
- {token1Deposited ? (
-
-
-
- {token1Deposited?.toFixed(8)}
-
-
- ) : (
- '-'
- )}
+ setShowMore(!showMore)}>
+
+
+
+ {token0?.symbol}:{token1?.symbol}
+
+
+
+
+ {userPoolBalance ? userPoolBalance.toFixed(6) : '-'}
+
+
- {!minimal && (
+
- Your pool share:
-
-
- {poolTokenPercentage ? poolTokenPercentage.toFixed(2) + '%' : '-'}
+ {token0?.symbol}:
+ {token0Deposited ? (
+
+ {!minimal && }
+
+ {token0Deposited?.toFixed(8)}
+
+
+ ) : (
+ '-'
+ )}
+
+
+ {token1?.symbol}:
+
+ {token1Deposited ? (
+
+ {!minimal && }
+
+ {token1Deposited?.toFixed(8)}
+
+
+ ) : (
+ '-'
+ )}
+
+
+
+
+ )
+ } else
+ return (
+ setShowMore(!showMore)}>
+
+
+
+
+
+ {token0?.symbol}:{token1?.symbol}
+
+
+
+
+ {userPoolBalance ? userPoolBalance.toFixed(6) : '-'}
+
+ {showMore ? (
+
+ ) : (
+
+ )}
+
+
+ {showMore && (
+
+
+
+ {token0?.symbol}:
+
+ {token0Deposited ? (
+
+ {!minimal && }
+
+ {token0Deposited?.toFixed(8)}
+
+
+ ) : (
+ '-'
+ )}
+
+
+
+ {token1?.symbol}:
+
+ {token1Deposited ? (
+
+ {!minimal && }
+
+ {token1Deposited?.toFixed(8)}
+
+
+ ) : (
+ '-'
+ )}
+
+ {!minimal && (
+
+
+ Your pool share:
+
+
+ {poolTokenPercentage ? poolTokenPercentage.toFixed(2) + '%' : '-'}
+
+
+ )}
+
+ )}
+ {showMore && (
+
+ {
+ history.push('/add/' + token0?.address + '-' + token1?.address)
+ }}
+ >
+ Add
+
+ {
+ history.push('/remove/' + token0?.address + '-' + token1?.address)
+ }}
+ >
+ Remove
+
+
)}
- {!minimal && (
-
- {
- history.push('/add/' + token0?.address + '-' + token1?.address)
- }}
- >
- Add
-
- {
- history.push('/remove/' + token0?.address + '-' + token1?.address)
- }}
- >
- Remove
-
-
- )}
-
-
- )
+
+ )
}
export default withRouter(PositionCard)
diff --git a/src/components/SearchModal/index.js b/src/components/SearchModal/index.js
index bad9cf18a5..66884dcabe 100644
--- a/src/components/SearchModal/index.js
+++ b/src/components/SearchModal/index.js
@@ -105,10 +105,11 @@ const PaddedItem = styled(RowBetween)`
`
const MenuItem = styled(PaddedItem)`
- cursor: pointer;
+ cursor: ${({ disabled }) => !disabled && 'pointer'};
:hover {
- background-color: ${({ theme }) => theme.bg2};
+ background-color: ${({ theme, disabled }) => !disabled && theme.bg2};
}
+ opacity: ${({ disabled }) => (disabled ? 0.5 : 1)};
`
// filters on results
const FILTERS = {
@@ -132,6 +133,7 @@ function SearchModal({
const allTokens = useAllTokens()
const allPairs = useAllPairs()
+
const allBalances = useAllBalances()
const [searchQuery, setSearchQuery] = useState('')
@@ -175,9 +177,6 @@ function SearchModal({
}
})
.map(k => {
- if (k === hiddenToken) {
- return false
- }
return {
name: allTokens[k].name,
symbol: allTokens[k].symbol,
@@ -185,7 +184,7 @@ function SearchModal({
balance: allBalances?.[account]?.[k]
}
})
- }, [allTokens, allBalances, account, sortDirection, hiddenToken])
+ }, [allTokens, allBalances, account, sortDirection])
const filteredTokenList = useMemo(() => {
return tokenList.filter(tokenEntry => {
@@ -350,7 +349,17 @@ function SearchModal({
const zeroBalance = balance && JSBI.equal(JSBI.BigInt(0), balance.raw)
return (
-
)}
+ {filterType === 'tokens' && Token Symbol}
diff --git a/src/components/TxnPopup/index.js b/src/components/TxnPopup/index.js
new file mode 100644
index 0000000000..b4ad9fec46
--- /dev/null
+++ b/src/components/TxnPopup/index.js
@@ -0,0 +1,29 @@
+import React from 'react'
+
+import { Link } from '../../theme/components'
+import { TYPE } from '../../theme'
+import { AutoColumn } from '../Column'
+
+import { useWeb3React } from '../../hooks'
+import { getEtherscanLink } from '../../utils'
+
+export default function TxnPopup({ hash, success }) {
+ const { chainId } = useWeb3React()
+ if (success) {
+ return (
+
+ Transaction Confirmed
+ Hash: {hash.slice(0, 8) + '...' + hash.slice(58, 65)}
+ View on Etherscan
+
+ )
+ } else {
+ return (
+
+ Transaction Failed
+ Hash: {hash.slice(0, 8) + '...' + hash.slice(58, 65)}
+ View on Etherscan
+
+ )
+ }
+}
diff --git a/src/components/Web3Status/index.js b/src/components/Web3Status/index.js
index a59479df86..33d3d27071 100644
--- a/src/components/Web3Status/index.js
+++ b/src/components/Web3Status/index.js
@@ -2,7 +2,7 @@ import React from 'react'
import styled, { css } from 'styled-components'
import { useTranslation } from 'react-i18next'
import { useWeb3React, UnsupportedChainIdError } from '@web3-react/core'
-import { darken, transparentize } from 'polished'
+import { darken } from 'polished'
import { Activity } from 'react-feather'
import { shortenAddress } from '../../utils'
@@ -10,8 +10,6 @@ import { useENSName } from '../../hooks'
import WalletModal from '../WalletModal'
import { useAllTransactions } from '../../contexts/Transactions'
import { useWalletModalToggle } from '../../contexts/Application'
-import { Spinner } from '../../theme'
-import Circle from '../../assets/images/circle.svg'
import { injected, walletconnect, walletlink, fortmatic, portis } from '../../connectors'
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
@@ -46,39 +44,40 @@ const Web3StatusError = styled(Web3StatusGeneric)`
`
const Web3StatusConnect = styled(Web3StatusGeneric)`
- background-color: transparent;
- border: 1px solid ${({ theme }) => theme.blue1};
+ background-color: ${({ theme }) => theme.blue4};
+ border: 1px solid ${({ theme }) => theme.blue4};
+ border: none;
color: ${({ theme }) => theme.blue1};
font-weight: 500;
:hover,
:focus {
- border: 1px solid ${({ theme }) => darken(0.1, theme.blue1)};
+ border: 1px solid ${({ theme }) => darken(0.1, theme.blue4)};
color: ${({ theme }) => darken(0.1, theme.blue1)};
}
${({ faded }) =>
faded &&
css`
- background-color: transparent;
- border: 1px solid ${({ theme }) => theme.blue1};
+ background-color: ${({ theme }) => theme.blue5};
+ border: 1px solid ${({ theme }) => theme.blue5};
color: ${({ theme }) => theme.blue1};
:hover,
:focus {
- border: 1px solid ${({ theme }) => darken(0.1, theme.blue1)};
+ border: 1px solid ${({ theme }) => darken(0.1, theme.blue4)};
color: ${({ theme }) => darken(0.1, theme.blue1)};
}
`}
`
const Web3StatusConnected = styled(Web3StatusGeneric)`
- background-color: ${({ pending, theme }) => (pending ? theme.blue5 : theme.bg1)};
+ background-color: ${({ pending, theme }) => (pending ? theme.blue1 : theme.bg1)};
border: 1px solid ${({ pending, theme }) => (pending ? theme.blue1 : theme.bg3)};
- color: ${({ pending, theme }) => (pending ? theme.blue1 : theme.text3)};
+ color: ${({ pending, theme }) => (pending ? theme.white : theme.text3)};
font-weight: 400;
:hover {
- background-color: ${({ pending, theme }) => (pending ? transparentize(0.9, theme.blue1) : darken(0.05, theme.bg1))};
+ background-color: ${({ pending, theme }) => (pending ? darken(0.05, theme.blue1) : darken(0.05, theme.bg1))};
:focus {
border: 1px solid ${({ pending, theme }) => (pending ? darken(0.1, theme.blue1) : darken(0.1, theme.bg3))};
@@ -93,6 +92,8 @@ const Text = styled.p`
white-space: nowrap;
margin: 0 0.5rem 0 0.25rem;
font-size: 0.83rem;
+ width: fit-content;
+ font-weight: 500;
`
const NetworkIcon = styled(Activity)`
@@ -102,10 +103,6 @@ const NetworkIcon = styled(Activity)`
height: 16px;
`
-const SpinnerWrapper = styled(Spinner)`
- margin: 0 0.25rem 0 0.25rem;
-`
-
const IconWrapper = styled.div`
${({ theme }) => theme.flexColumnNoWrap};
align-items: center;
@@ -166,9 +163,12 @@ export default function Web3Status() {
if (account) {
return (
- {hasPendingTransactions && }
- {ENSName || shortenAddress(account)}
- {getStatusIcon()}
+ {hasPendingTransactions ? (
+ {pending?.length} Pending
+ ) : (
+ {ENSName || shortenAddress(account)}
+ )}
+ {!hasPendingTransactions && getStatusIcon()}
)
} else if (error) {
diff --git a/src/contexts/Pairs.tsx b/src/contexts/Pairs.tsx
index d0812e1fc0..cf9e1553ee 100644
--- a/src/contexts/Pairs.tsx
+++ b/src/contexts/Pairs.tsx
@@ -5,6 +5,7 @@ import { INITIAL_TOKENS_CONTEXT } from './Tokens'
import { ChainId, WETH, Token, TokenAmount, Pair, JSBI } from '@uniswap/sdk'
const UPDATE = 'UPDATE'
+const UPDATE_PAIR_ENTITY = 'UPDATE_PAIR_ENTITY'
const ALL_PAIRS: [Token, Token][] = [
[
@@ -12,8 +13,8 @@ const ALL_PAIRS: [Token, Token][] = [
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735'] //dai
],
[
- INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735'],
- INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0x8ab15C890E5C03B5F240f2D146e3DF54bEf3Df44']
+ INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735'], // dai
+ INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0x8ab15C890E5C03B5F240f2D146e3DF54bEf3Df44'] // mkr
]
]
@@ -22,16 +23,20 @@ const PAIR_MAP: {
} = ALL_PAIRS.reduce((pairMap, [tokenA, tokenB]) => {
const tokens: [Token, Token] = tokenA?.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]
// ensure exchanges are unique
- if (pairMap?.[tokens[0].chainId]?.[tokens[0].address]?.[tokens[1].address] !== undefined)
+ if (pairMap?.[tokens[0].chainId]?.[tokens[0].address]?.[tokens[1].address]?.address !== undefined)
throw Error(`Duplicate exchange: ${tokenA} ${tokenB}`)
return {
...pairMap,
[tokens[0].chainId]: {
...pairMap?.[tokens[0].chainId],
- [tokens[0].address]: {
- ...pairMap?.[tokens[0].chainId]?.[tokens[0].address],
- [tokens[1].address]: Pair.getAddress(...tokens)
- }
+ addresses: {
+ ...pairMap?.[tokens[0].chainId]?.['addresses'],
+ [tokens[0].address]: {
+ ...pairMap?.[tokens[0].chainId]?.[tokens[0].address],
+ [tokens[1].address]: Pair.getAddress(...tokens)
+ }
+ },
+ entities: {}
}
}
}, {})
@@ -53,9 +58,25 @@ function reducer(state, { type, payload }) {
...state,
[tokensSorted[0].chainId]: {
...state?.[tokensSorted[0].chainId],
- [tokensSorted[0].address]: {
- ...state?.[tokensSorted[0].chainId]?.[tokensSorted[0].address],
- [tokensSorted[1].address]: Pair.getAddress(tokensSorted[0], tokensSorted[1])
+ addresses: {
+ ...state?.[tokensSorted[0].chainId]['addresses'],
+ [tokensSorted[0].address]: {
+ ...state?.[tokensSorted[0].chainId]?.[tokensSorted[0].address],
+ [tokensSorted[1].address]: Pair.getAddress(tokensSorted[0], tokensSorted[1])
+ }
+ }
+ }
+ }
+ }
+ case UPDATE_PAIR_ENTITY: {
+ const { pairAddress, pair, chainId } = payload
+ return {
+ ...state,
+ [chainId]: {
+ ...state?.[chainId],
+ entities: {
+ ...state?.[chainId]?.['entities'],
+ [pairAddress]: pair
}
}
}
@@ -73,8 +94,16 @@ export default function Provider({ children }) {
dispatch({ type: UPDATE, payload: { chainId, tokens } })
}, [])
+ const updatePairEntity = useCallback((pairAddress, pair, chainId) => {
+ dispatch({ type: UPDATE_PAIR_ENTITY, payload: { pairAddress, pair, chainId } })
+ }, [])
+
return (
- [state, { update }], [state, update])}>{children}
+ [state, { update, updatePairEntity }], [state, update, updatePairEntity])}
+ >
+ {children}
+
)
}
@@ -84,7 +113,7 @@ export function usePairAddress(tokenA?: Token, tokenB?: Token): string | undefin
const tokens: [Token, Token] = tokenA && tokenB && tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]
- const address = state?.[chainId]?.[tokens[0]?.address]?.[tokens[1]?.address]
+ const address = state?.[chainId]?.['addresses']?.[tokens[0]?.address]?.[tokens[1]?.address]
useEffect(() => {
if (address === undefined && tokenA && tokenB) {
@@ -97,36 +126,29 @@ export function usePairAddress(tokenA?: Token, tokenB?: Token): string | undefin
}
export function usePair(tokenA?: Token, tokenB?: Token): Pair | undefined {
+ const { chainId } = useWeb3React()
+ const [state, { updatePairEntity }] = usePairContext()
+
const address = usePairAddress(tokenA, tokenB)
+ const pair = state?.[chainId]?.['entities']?.[address]
+
const tokenAmountA = useAddressBalance(address, tokenA)
const tokenAmountB = useAddressBalance(address, tokenB)
- const [pair, setPair] = useState()
useEffect(() => {
if (!pair && tokenAmountA && tokenAmountB) {
- setPair(new Pair(tokenAmountA, tokenAmountB))
+ updatePairEntity(address, new Pair(tokenAmountA, tokenAmountB), chainId)
}
- }, [pair, tokenAmountA, tokenAmountB])
+ }, [pair, tokenAmountA, tokenAmountB, address, updatePairEntity, chainId])
- return useMemo(() => {
- return pair
- }, [pair])
-}
-
-export function useAllPairsRaw() {
- const { chainId } = useWeb3React()
- const [state] = usePairContext()
-
- const allExchangeDetails = state?.[chainId]
-
- return allExchangeDetails
+ return pair
}
export function useAllPairs() {
const { chainId } = useWeb3React()
const [state] = usePairContext()
- const allPairDetails = state?.[chainId]
+ const allPairDetails = state?.[chainId]?.['addresses']
const allPairs = useMemo(() => {
if (!allPairDetails) {
@@ -136,10 +158,14 @@ export function useAllPairs() {
Object.keys(allPairDetails).map(token0Address => {
return Object.keys(allPairDetails[token0Address]).map(token1Address => {
const pairAddress = allPairDetails[token0Address][token1Address]
- return (formattedExchanges[pairAddress] = {
- token0: token0Address,
- token1: token1Address
- })
+ if (pairAddress) {
+ return (formattedExchanges[pairAddress] = {
+ token0: token0Address,
+ token1: token1Address
+ })
+ } else {
+ return null
+ }
})
})
return formattedExchanges
diff --git a/src/contexts/Routes.tsx b/src/contexts/Routes.tsx
index 08b04794ef..07e1e4b65e 100644
--- a/src/contexts/Routes.tsx
+++ b/src/contexts/Routes.tsx
@@ -30,7 +30,7 @@ function reducer(state: RouteState, { type, payload }) {
[chainId]: {
...state[chainId],
[tokens[0]]: {
- ...state[tokens[0]],
+ ...state[chainId]?.[tokens[0]],
[tokens[1]]: {
route
}
@@ -77,14 +77,14 @@ export function useRoute(tokenA: Token, tokenB: Token) {
const defaultPair = usePair(tokenA, tokenB)
// get token<->WETH pairs
- const aToETH = usePair(tokenA && !tokenA.equals(WETH[chainId]) ? tokenA : null, WETH[chainId])
- const bToETH = usePair(tokenB && !tokenB.equals(WETH[chainId]) ? tokenB : null, WETH[chainId])
+ const aToETH = usePair(tokenA && chainId && !tokenA.equals(WETH[chainId]) ? tokenA : null, WETH[chainId])
+ const bToETH = usePair(tokenB && chainId && !tokenB.equals(WETH[chainId]) ? tokenB : null, WETH[chainId])
// needs to route through WETH
const requiresHop =
defaultPair &&
- JSBI.equal(defaultPair.reserve0.raw, JSBI.BigInt(0)) &&
- JSBI.equal(defaultPair.reserve1.raw, JSBI.BigInt(0))
+ JSBI.equal(defaultPair?.reserve0?.raw, JSBI.BigInt(0)) &&
+ JSBI.equal(defaultPair?.reserve1?.raw, JSBI.BigInt(0))
useEffect(() => {
if (!route && tokenA && tokenB) {
diff --git a/src/contexts/Tokens.tsx b/src/contexts/Tokens.tsx
index 65054b064e..7a2990c9c1 100644
--- a/src/contexts/Tokens.tsx
+++ b/src/contexts/Tokens.tsx
@@ -6,6 +6,9 @@ import { isAddress, getTokenName, getTokenSymbol, getTokenDecimals, safeAccess }
const UPDATE = 'UPDATE'
export const ALL_TOKENS = [
+ //Mainnet Tokens
+ WETH[ChainId.MAINNET],
+
// Rinkeby Tokens
WETH[ChainId.RINKEBY],
new Token(ChainId.RINKEBY, '0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735', 18, 'DAI', 'Dai Stablecoin'),
diff --git a/src/contexts/Transactions.js b/src/contexts/Transactions.js
index bb97d5435b..50094798c7 100644
--- a/src/contexts/Transactions.js
+++ b/src/contexts/Transactions.js
@@ -1,8 +1,10 @@
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
+import TxnPopup from '../components/TxnPopup'
+
import { useWeb3React } from '../hooks'
import { safeAccess } from '../utils'
-import { useBlockNumber } from './Application'
+import { useBlockNumber, usePopups } from './Application'
const RESPONSE = 'response'
const CUSTOM_DATA = 'CUSTOM_DATA'
@@ -110,6 +112,9 @@ export function Updater() {
const [state, { check, finalize }] = useTransactionsContext()
const allTransactions = safeAccess(state, [chainId]) || {}
+ // show popup on confirm
+ const [, addPopup] = usePopups()
+
useEffect(() => {
if ((chainId || chainId === 0) && library) {
let stale = false
@@ -126,6 +131,7 @@ export function Updater() {
check(chainId, hash, globalBlockNumber)
} else {
finalize(chainId, hash, receipt)
+ addPopup()
}
}
})
@@ -138,7 +144,7 @@ export function Updater() {
stale = true
}
}
- }, [chainId, library, allTransactions, globalBlockNumber, check, finalize])
+ }, [chainId, library, allTransactions, globalBlockNumber, check, finalize, addPopup])
return null
}
diff --git a/src/pages/App.js b/src/pages/App.js
index 5ed178e92e..ba2619a7e4 100644
--- a/src/pages/App.js
+++ b/src/pages/App.js
@@ -1,12 +1,16 @@
-import React, { Suspense, lazy } from 'react'
+import React, { Suspense, lazy, useState } from 'react'
import styled from 'styled-components'
-import { transparentize } from 'polished'
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom'
+import { Text } from 'rebass'
import Header from '../components/Header'
import NavigationTabs from '../components/NavigationTabs'
import Web3ReactManager from '../components/Web3ReactManager'
-import { useWeb3React } from '../hooks'
+import { TYPE } from '../theme'
+import { Hover } from '../theme/components'
+import { AutoColumn } from '../components/Column'
+import { PinkCard } from '../components/Card'
+import { ButtonPink } from '../components/Button'
import { isAddress, getAllQueryParams } from '../utils'
const Swap = lazy(() => import('./Swap'))
@@ -29,29 +33,6 @@ const HeaderWrapper = styled.div`
justify-content: space-between;
`
-const BetaMessage = styled.div`
- ${({ theme }) => theme.flexRowNoWrap}
- cursor: pointer;
- max-height: 40px;
- flex: 1 0 auto;
- align-items: center;
- position: relative;
- padding: 0.5rem 1rem;
- margin-bottom: 1rem;
- border: 1px solid ${({ theme }) => transparentize(0.6, theme.pink1)};
- background-color: ${({ theme }) => transparentize(0.9, theme.pink1)};
- border-radius: 1rem;
- font-size: 0.75rem;
- line-height: 1rem;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: ${({ theme }) => theme.pink1};
- min-width: 380px;
- text-align: center;
- justify-content: center;
-`
-
const BodyWrapper = styled.div`
display: flex;
flex-direction: column;
@@ -61,6 +42,12 @@ const BodyWrapper = styled.div`
flex: 1;
overflow: auto;
padding-top: 40px;
+
+ & > * {
+ max-width: calc(355px + 4rem);
+ width: 90%;
+ margin-bottom: 20px;
+ }
`
const Body = styled.div`
@@ -76,7 +63,7 @@ const Body = styled.div`
export default function App() {
const params = getAllQueryParams()
- const { chainId } = useWeb3React()
+ const [showMigrationMessage, toggleShowMigrationMessage] = useState(true)
return (
<>
@@ -86,17 +73,18 @@ export default function App() {
- {chainId === 1 && (
- Incorrect network. This site is intended to be used on Ethereum testnets only.
+ {showMigrationMessage && (
+
+
+ Uniswap has upgraded.
+ Are you a liquidity provider? Upgrade now using the migration helper.
+ Migrate your liquidity
+ toggleShowMigrationMessage(false)}>
+ Dismiss
+
+
+
)}
-
- {(chainId === 3 || chainId === 4 || chainId === 5 || chainId === 42) && (
-
- Connected to{' '}
- {chainId === 3 ? 'Ropsten ' : chainId === 4 ? 'Rinkeby' : chainId === 5 ? 'Goerli' : 'Kovan'} testnet.
-
- )}
-
@@ -138,7 +126,7 @@ export default function App() {
}
}}
/>
- } />
+ } />
} else {
- return
+ return
}
}}
/>
@@ -173,7 +161,7 @@ export default function App() {
if (t0 && t1) {
return
} else {
- return
+ return
}
}}
/>
diff --git a/src/pages/Supply/AddLiquidity.tsx b/src/pages/Supply/AddLiquidity.tsx
index 4131979c61..69f452ffb9 100644
--- a/src/pages/Supply/AddLiquidity.tsx
+++ b/src/pages/Supply/AddLiquidity.tsx
@@ -11,23 +11,23 @@ import PositionCard from '../../components/PositionCard'
import ConfirmationModal from '../../components/ConfirmationModal'
import CurrencyInputPanel from '../../components/CurrencyInputPanel'
import { Text } from 'rebass'
+import { TYPE } from '../../theme'
import { Plus } from 'react-feather'
-import { ButtonPrimary } from '../../components/Button'
import { AutoColumn, ColumnCenter } from '../../components/Column'
+import { ButtonPrimary, ButtonLight } from '../../components/Button'
import Row, { RowBetween, RowFlat, RowFixed } from '../../components/Row'
import { useToken } from '../../contexts/Tokens'
import { usePopups } from '../../contexts/Application'
-import { useWeb3React } from '../../hooks'
import { useAddressBalance } from '../../contexts/Balances'
import { useAddressAllowance } from '../../contexts/Allowances'
-import { useTransactionAdder } from '../../contexts/Transactions'
import { usePair, useTotalSupply } from '../../contexts/Pairs'
+import { useWeb3React, useTokenContract } from '../../hooks'
+import { useTransactionAdder, usePendingApproval } from '../../contexts/Transactions'
import { BigNumber } from 'ethers/utils'
import { ROUTER_ADDRESSES } from '../../constants'
import { getRouterContract, calculateGasMargin } from '../../utils'
-import { TYPE } from '../../theme'
// denominated in bips
const ALLOWED_SLIPPAGE = 200
@@ -43,7 +43,7 @@ const Wrapper = styled.div`
const FixedBottom = styled.div`
position: absolute;
- bottom: -200px;
+ bottom: -220px;
width: 100%;
`
@@ -158,6 +158,14 @@ export default function AddLiquidity({ token0, token1 }) {
[Field.OUTPUT]: useToken(fieldData[Field.OUTPUT].address)
}
+ // token contracts for approvals and direct sends
+ const tokenContractInput: ethers.Contract = useTokenContract(tokens[Field.INPUT]?.address)
+ const tokenContractOutput: ethers.Contract = useTokenContract(tokens[Field.OUTPUT]?.address)
+
+ // check on pending approvals for token amounts
+ const pendingApprovalInput = usePendingApproval(tokens[Field.INPUT]?.address)
+ const pendingApprovalOutput = usePendingApproval(tokens[Field.OUTPUT]?.address)
+
// exhchange data
const pair: Pair = usePair(tokens[Field.INPUT], tokens[Field.OUTPUT])
const route: Route = pair ? new Route([pair], tokens[independentField]) : undefined
@@ -456,6 +464,28 @@ export default function AddLiquidity({ token0, token1 }) {
})
}
+ async function approveAmount(field) {
+ let estimatedGas
+ let useUserBalance = false
+ const tokenContract = field === Field.INPUT ? tokenContractInput : tokenContractOutput
+
+ estimatedGas = await tokenContract.estimate.approve(routerAddress, ethers.constants.MaxUint256).catch(e => {
+ console.log('Error setting max token approval.')
+ })
+ if (!estimatedGas) {
+ // general fallback for tokens who restrict approval amounts
+ estimatedGas = await tokenContract.estimate.approve(routerAddress, userBalances[field])
+ useUserBalance = true
+ }
+ tokenContract
+ .approve(routerAddress, useUserBalance ? userBalances[field] : ethers.constants.MaxUint256, {
+ gasLimit: calculateGasMargin(estimatedGas, GAS_MARGIN)
+ })
+ .then(response => {
+ addTransaction(response, { approval: tokens[field]?.address })
+ })
+ }
+
const modalHeader = () => {
return (
@@ -569,7 +599,6 @@ export default function AddLiquidity({ token0, token1 }) {
onTokenSelection={onTokenSelection}
error={inputError}
pair={pair}
- showUnlock={showInputUnlock}
disableTokenSelect
/>
@@ -587,7 +616,6 @@ export default function AddLiquidity({ token0, token1 }) {
onTokenSelection={onTokenSelection}
error={outputError}
pair={pair}
- showUnlock={showOutputUnlock}
disableTokenSelect
/>
{!noLiquidity && (
@@ -599,16 +627,34 @@ export default function AddLiquidity({ token0, token1 }) {
)}
- {
- setShowConfirm(true)
- }}
- disabled={!isValid}
- >
-
- {generalError ? generalError : inputError ? inputError : outputError ? outputError : 'Supply'}
-
-
+ {showOutputUnlock ? (
+ {
+ approveAmount(Field.OUTPUT)
+ }}
+ >
+ {pendingApprovalOutput ? 'Waiting for unlock' : 'Unlock ' + tokens[Field.OUTPUT]?.symbol}
+
+ ) : showInputUnlock ? (
+ {
+ approveAmount(Field.INPUT)
+ }}
+ >
+ {pendingApprovalInput ? 'Waiting for unlock' : 'Unlock ' + tokens[Field.INPUT]?.symbol}
+
+ ) : (
+ {
+ setShowConfirm(true)
+ }}
+ disabled={!isValid}
+ >
+
+ {generalError ? generalError : inputError ? inputError : outputError ? outputError : 'Supply'}
+
+
+ )}
{!noLiquidity && (
{
return (
@@ -67,7 +62,7 @@ function Supply({ history }) {
setShowPoolSearch(true)
}}
>
- Join a pool
+ Join {filteredExchangeList?.length > 0 ? 'another' : 'a'} pool
@@ -80,34 +75,17 @@ function Supply({ history }) {
{filteredExchangeList}
- {filteredExchangeList?.length !== 0 ? `Don't see your ` : 'Already have '} liquidity?{' '}
+ {filteredExchangeList?.length !== 0 ? `Don't see a pool you joined? ` : 'Already joined a pool?'}{' '}
{
history.push('/find')
}}
>
- Find it now.
+ Find it.
-
-
-
-
- Earn fees with pooled market making.
-
-
- Provide liquidity to earn .3% spread fees for providing market depth.
-
-
-
- Learn More
-
-
-
-
-
setShowPoolSearch(false)} />
>
diff --git a/src/theme/components.js b/src/theme/components.js
index c1ca0e9ab8..a6ae06d64f 100644
--- a/src/theme/components.js
+++ b/src/theme/components.js
@@ -71,3 +71,9 @@ export const Spinner = styled.img`
width: 16px;
height: 16px;
`
+
+export const Hover = styled.div`
+ :hover {
+ cursor: pointer;
+ }
+`
diff --git a/src/theme/index.js b/src/theme/index.js
index 5ddc203266..0211cf5775 100644
--- a/src/theme/index.js
+++ b/src/theme/index.js
@@ -75,6 +75,7 @@ const theme = darkMode => ({
red1: '#FF6871',
green1: '#27AE60',
yellow1: '#FFE270',
+ yellow2: '#F3841E',
//shadows
shadow1: darkMode ? '#000' : '#2F80ED',
@@ -99,7 +100,17 @@ export const TYPE = {
),
largeHeader: ({ children, ...rest }) => (
-
+
+ {children}
+
+ ),
+ mediumHeader: ({ children, ...rest }) => (
+
+ {children}
+
+ ),
+ subHeader: ({ children, ...rest }) => (
+
{children}
),
@@ -113,6 +124,11 @@ export const TYPE = {
{children}
),
+ green: ({ children, ...rest }) => (
+
+ {children}
+
+ ),
gray: ({ children, ...rest }) => (
{children}