Commit f73a166d authored by Callil Capuozzo's avatar Callil Capuozzo

Merge branch 'main' of https://github.com/Uniswap/v3-interface into main

parents e1e52c06 ca4d9159
......@@ -33,14 +33,28 @@ export const DarkBadge = styled.div`
padding: 4px 6px;
`
export default function RangeBadge({ inRange }: { inRange?: boolean }) {
export default function RangeBadge({
removed,
inRange,
}: {
removed: boolean | undefined
inRange: boolean | undefined
}) {
const { t } = useTranslation()
return (
<BadgeWrapper>
{inRange ? (
{removed ? (
<MouseoverTooltip text={`Your position has 0 liquidity, and is not earning fees.`}>
<Badge variant={BadgeVariant.WARNING_OUTLINE}>
<AlertCircle width={14} height={14} />
&nbsp;
<BadgeText>{t('Inactive')}</BadgeText>
</Badge>
</MouseoverTooltip>
) : inRange ? (
<MouseoverTooltip
text={`The price of this pair is within your selected range. Your position is currently earning fees.`}
text={`The price of this pool is within your selected range. Your position is currently earning fees.`}
>
<Badge variant={BadgeVariant.DEFAULT}>
<ActiveDot /> &nbsp;
......@@ -49,7 +63,7 @@ export default function RangeBadge({ inRange }: { inRange?: boolean }) {
</MouseoverTooltip>
) : (
<MouseoverTooltip
text={`The price of this pair is outside of your selected range. Your position is not currently earning fees. `}
text={`The price of this pool is outside of your selected range. Your position is not currently earning fees.`}
>
<Badge variant={BadgeVariant.WARNING}>
<AlertCircle width={14} height={14} />
......
......@@ -159,7 +159,7 @@ interface CurrencyInputPanelProps {
pair?: Pair | null
hideInput?: boolean
otherCurrency?: Currency | null
fiatValue?: CurrencyAmount
fiatValue?: CurrencyAmount | null
priceImpact?: Percent
id: string
showCommonBases?: boolean
......
......@@ -141,7 +141,7 @@ export default function Menu() {
<Info size={14} />
About
</MenuItem>
<MenuItem href="https://uniswap.org/docs/v2">
<MenuItem href="https://docs.uniswap.org/">
<BookOpen size={14} />
Docs
</MenuItem>
......
import React, { useMemo, useState } from 'react'
import { Position } from '@uniswap/v3-sdk'
import Badge, { BadgeVariant } from 'components/Badge'
import Badge from 'components/Badge'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { usePool } from 'hooks/usePools'
import { useToken } from 'hooks/Tokens'
import { AlertCircle } from 'react-feather'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import styled from 'styled-components'
import { HideSmall, MEDIA_WIDTHS, SmallOnly } from 'theme'
......@@ -15,16 +13,9 @@ import { formatPrice } from 'utils/formatTokenAmount'
import Loader from 'components/Loader'
import { unwrappedToken } from 'utils/wrappedCurrency'
import { DAI, USDC, USDT, WBTC } from '../../constants'
import { MouseoverTooltip } from '../Tooltip'
import RangeBadge from 'components/Badge/RangeBadge'
import { RowFixed } from 'components/Row'
const ActiveDot = styled.span`
background-color: ${({ theme }) => theme.success};
border-radius: 50%;
height: 8px;
width: 8px;
margin-right: 4px;
`
const Row = styled(Link)`
align-items: center;
border-radius: 20px;
......@@ -65,9 +56,7 @@ const BadgeText = styled.div`
font-size: 12px;
`};
`
const BadgeWrapper = styled.div`
font-size: 14px;
`
const DataLineItem = styled.div`
font-size: 14px;
`
......@@ -185,8 +174,6 @@ export function getPriceOrderingFromPositionForUI(
}
export default function PositionListItem({ positionDetails }: PositionListItemProps) {
const { t } = useTranslation()
const {
token0: token0Address,
token1: token1Address,
......@@ -228,6 +215,8 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
;[priceLower, priceUpper, base, quote] = [priceUpper?.invert(), priceLower?.invert(), quote, base]
}
const removed = liquidity?.eq(0)
return (
<Row to={positionSummaryLink}>
<RowFixed>
......@@ -241,28 +230,7 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
<BadgeText>{new Percent(feeAmount, 1_000_000).toSignificant()}%</BadgeText>
</Badge>
</PrimaryPositionIdData>
<BadgeWrapper>
{outOfRange ? (
<MouseoverTooltip
text={`The price of this pair is outside of your selected range. Your position is not currently earning fees.`}
>
<Badge variant={BadgeVariant.WARNING}>
<AlertCircle width={14} height={14} style={{ marginRight: '' }} />
&nbsp;
<BadgeText>{t('Out of range')}</BadgeText>
</Badge>
</MouseoverTooltip>
) : (
<MouseoverTooltip
text={`The price of this pair is within your selected range. Your position is currently earning fees.`}
>
<Badge variant={BadgeVariant.DEFAULT}>
<ActiveDot /> &nbsp;
<BadgeText>{t('In range')}</BadgeText>
</Badge>
</MouseoverTooltip>
)}
</BadgeWrapper>
<RangeBadge removed={removed} inRange={!outOfRange} />
</RowFixed>
{priceLower && priceUpper ? (
......
......@@ -13,6 +13,7 @@ import RateToggle from 'components/RateToggle'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import RangeBadge from 'components/Badge/RangeBadge'
import { ThemeContext } from 'styled-components'
import { JSBI } from '@uniswap/v2-sdk'
export const PositionPreview = ({
position,
......@@ -55,6 +56,8 @@ export const PositionPreview = ({
setBaseCurrency(quoteCurrency)
}, [quoteCurrency])
const removed = position?.liquidity && JSBI.equal(position?.liquidity, JSBI.BigInt(0))
return (
<AutoColumn gap="md" style={{ marginTop: '0.5rem' }}>
<RowBetween style={{ marginBottom: '0.5rem' }}>
......@@ -69,7 +72,7 @@ export const PositionPreview = ({
{currency0?.symbol} / {currency1?.symbol}
</TYPE.label>
</RowFixed>
<RangeBadge inRange={inRange} />
<RangeBadge removed={removed} inRange={inRange} />
</RowBetween>
<LightCard>
......
......@@ -43,12 +43,4 @@ export const RowFixed = styled(Row)<{ gap?: string; justify?: string }>`
margin: ${({ gap }) => gap && `-${gap}`};
`
export const RowResponsive = styled(Row)`
${({ theme }) => theme.mediaWidth.upToSmall`
flex-direction: column;
justify-content: flext-start;
align-items: flex-start;
`}
`
export default Row
......@@ -44,7 +44,11 @@ export function MouseoverTooltipContent({ content, children, ...rest }: Omit<Too
const close = useCallback(() => setShow(false), [setShow])
return (
<TooltipContent {...rest} show={show} content={content}>
<div onMouseEnter={open} onMouseLeave={close}>
<div
style={{ display: 'inline-block', lineHeight: 0, padding: '0.25rem' }}
onMouseEnter={open}
onMouseLeave={close}
>
{children}
</div>
</TooltipContent>
......
......@@ -4,7 +4,7 @@ import { useLocation } from 'react-router'
import { Link } from 'react-router-dom'
import useParsedQueryString from '../../hooks/useParsedQueryString'
import useToggledVersion, { DEFAULT_VERSION, Version } from '../../hooks/useToggledVersion'
import { DEFAULT_VERSION, Version } from '../../hooks/useToggledVersion'
import { HideSmall, TYPE, SmallOnly } from '../../theme'
import { ButtonPrimary } from '../Button'
import styled from 'styled-components'
......@@ -17,7 +17,7 @@ const ResponsiveButton = styled(ButtonPrimary)`
height: 24px;
margin-left: 0.75rem;
${({ theme }) => theme.mediaWidth.upToSmall`
padding: 4px;
padding: 4px;
border-radius: 8px;
`};
`
......@@ -62,29 +62,3 @@ export default function BetterTradeLink({
</ResponsiveButton>
)
}
export function DefaultVersionLink() {
const location = useLocation()
const search = useParsedQueryString()
const version = useToggledVersion()
const linkDestination = useMemo(() => {
return {
...location,
search: `?${stringify({
...search,
use: DEFAULT_VERSION,
})}`,
}
}, [location, search])
return (
<ButtonPrimary
as={Link}
to={linkDestination}
style={{ width: 'fit-content', marginTop: '4px', padding: '0.5rem 0.5rem' }}
>
Showing {version.toUpperCase()} price. <b>Switch to Uniswap {DEFAULT_VERSION.toUpperCase()}</b>
</ButtonPrimary>
)
}
......@@ -12,23 +12,16 @@ interface TradePriceProps {
}
const StyledPriceContainer = styled.button`
display: flex;
justify-content: center;
align-items: center;
display: flex;
width: fit-content;
padding: 0;
font-size: 0.875rem;
font-weight: 400;
background-color: transparent;
border: none;
margin-left: 1rem;
height: 24px;
cursor: pointer;
${({ theme }) => theme.mediaWidth.upToSmall`
margin-left: 0;
margin-top: 8px;
`}
`
export default function TradePrice({ price, showInverted, setShowInverted }: TradePriceProps) {
......@@ -45,11 +38,13 @@ export default function TradePrice({ price, showInverted, setShowInverted }: Tra
const labelInverted = showInverted ? `${price.baseCurrency?.symbol} ` : `${price.quoteCurrency?.symbol}`
const flipPrice = useCallback(() => setShowInverted(!showInverted), [setShowInverted, showInverted])
const text = `${'1 ' + labelInverted + ' = ' + formattedPrice ?? '-'} ${label}`
return (
<StyledPriceContainer onClick={flipPrice}>
<StyledPriceContainer onClick={flipPrice} title={text}>
<div style={{ alignItems: 'center', display: 'flex', width: 'fit-content' }}>
<Text fontWeight={500} fontSize={14} color={theme.text1}>
{'1 ' + labelInverted + ' = ' + formattedPrice ?? '-'} {label}
{text}
</Text>
</div>
</StyledPriceContainer>
......
......@@ -206,7 +206,7 @@ export const SUPPORTED_WALLETS: { [key: string]: WalletInfo } = {
export const NetworkContextName = 'NETWORK'
// default allowed slippage, in bips
export const INITIAL_ALLOWED_SLIPPAGE = new Percent(50, 10_000)
export const INITIAL_ALLOWED_SLIPPAGE = new Percent(10, 10_000)
// 20 minutes, denominated in seconds
export const DEFAULT_DEADLINE_FROM_NOW = 60 * 20
......
......@@ -13,10 +13,10 @@ import { useActiveWeb3React } from './index'
import { useTokenAllowance } from './useTokenAllowance'
export enum ApprovalState {
UNKNOWN,
NOT_APPROVED,
PENDING,
APPROVED,
UNKNOWN = 'UNKNOWN',
NOT_APPROVED = 'NOT_APPROVED',
PENDING = 'PENDING',
APPROVED = 'APPROVED',
}
// returns a variable indicating the state of the approval and a function which approves if necessary or early returns
......
......@@ -27,7 +27,7 @@ interface PermitInfo {
version?: string
}
// todo: read this information from extensions on token lists
// todo: read this information from extensions on token lists or elsewhere (permit registry?)
const PERMITTABLE_TOKENS: {
[chainId in ChainId]: {
[checksummedTokenAddress: string]: PermitInfo
......
......@@ -15,6 +15,7 @@ import TransactionConfirmationModal, { ConfirmationModalContent } from '../../co
import CurrencyInputPanel from '../../components/CurrencyInputPanel'
import { RowBetween } from '../../components/Row'
import { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
import { useUSDCValue } from '../../hooks/useUSDCPrice'
import Review from './Review'
import { useActiveWeb3React } from '../../hooks'
import { useCurrency } from '../../hooks/Tokens'
......@@ -106,6 +107,7 @@ export default function AddLiquidity({
const { independentField, typedValue, startPriceTypedValue } = useV3MintState()
const {
pool,
ticks,
dependentField,
price,
......@@ -155,6 +157,11 @@ export default function AddLiquidity({
[dependentField]: parsedAmounts[dependentField]?.toSignificant(6) ?? '',
}
const usdcValues = {
[Field.CURRENCY_A]: useUSDCValue(parsedAmounts[Field.CURRENCY_A]),
[Field.CURRENCY_B]: useUSDCValue(parsedAmounts[Field.CURRENCY_B]),
}
// get the max amounts user can add
const maxAmounts: { [field in Field]?: TokenAmount } = [Field.CURRENCY_A, Field.CURRENCY_B].reduce(
(accumulator, field) => {
......@@ -348,9 +355,14 @@ export default function AddLiquidity({
quoteCurrency ?? undefined,
feeAmount,
tickLower,
tickUpper
tickUpper,
pool
)
// we need an existence check on parsed amounts for single-asset deposits
const showApprovalA = approvalA !== ApprovalState.APPROVED && !!parsedAmounts[Field.CURRENCY_A]
const showApprovalB = approvalB !== ApprovalState.APPROVED && !!parsedAmounts[Field.CURRENCY_B]
return (
<ScrollablePage>
<TransactionConfirmationModal
......@@ -452,8 +464,11 @@ export default function AddLiquidity({
handleRateToggle={() => {
onLeftRangeInput('')
onRightRangeInput('')
console.log('test')
history.push(`/add/${currencyIdB as string}/${currencyIdA as string}`)
history.push(
`/add/${currencyIdB as string}/${currencyIdA as string}${
feeAmount ? '/' + feeAmount : ''
}`
)
}}
/>
) : null}
......@@ -515,8 +530,9 @@ export default function AddLiquidity({
handleRateToggle={() => {
onLeftRangeInput('')
onRightRangeInput('')
console.log('test')
history.push(`/add/${currencyIdB as string}/${currencyIdA as string}`)
history.push(
`/add/${currencyIdB as string}/${currencyIdA as string}${feeAmount ? '/' + feeAmount : ''}`
)
}}
/>
) : null}
......@@ -602,6 +618,7 @@ export default function AddLiquidity({
showMaxButton={!atMaxAmounts[Field.CURRENCY_A]}
currency={currencies[Field.CURRENCY_A]}
id="add-liquidity-input-tokena"
fiatValue={usdcValues[Field.CURRENCY_A]}
showCommonBases
locked={depositADisabled}
/>
......@@ -613,6 +630,7 @@ export default function AddLiquidity({
onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
}}
showMaxButton={!atMaxAmounts[Field.CURRENCY_B]}
fiatValue={usdcValues[Field.CURRENCY_B]}
currency={currencies[Field.CURRENCY_B]}
id="add-liquidity-input-tokenb"
showCommonBases
......@@ -637,13 +655,13 @@ export default function AddLiquidity({
approvalB === ApprovalState.PENDING) &&
isValid && (
<RowBetween>
{approvalA !== ApprovalState.APPROVED && (
{showApprovalA && (
<ButtonPrimary
borderRadius="12px"
padding={'12px'}
onClick={approveACallback}
disabled={approvalA === ApprovalState.PENDING}
width={approvalB !== ApprovalState.APPROVED ? '48%' : '100%'}
width={showApprovalB ? '48%' : '100%'}
>
{approvalA === ApprovalState.PENDING ? (
<Dots>Approving {currencies[Field.CURRENCY_A]?.symbol}</Dots>
......@@ -652,13 +670,13 @@ export default function AddLiquidity({
)}
</ButtonPrimary>
)}
{approvalB !== ApprovalState.APPROVED && (
{showApprovalB && (
<ButtonPrimary
borderRadius="12px"
padding={'12px'}
onClick={approveBCallback}
disabled={approvalB === ApprovalState.PENDING}
width={approvalA !== ApprovalState.APPROVED ? '48%' : '100%'}
width={showApprovalA ? '48%' : '100%'}
>
{approvalB === ApprovalState.PENDING ? (
<Dots>Approving {currencies[Field.CURRENCY_B]?.symbol}</Dots>
......
import styled from 'styled-components'
import { AutoColumn } from 'components/Column'
import CurrencyInputPanel from 'components/CurrencyInputPanel'
import Card, { DarkGreyCard } from 'components/Card'
import { DarkGreyCard } from 'components/Card'
import Input from 'components/NumericalInput'
export const Wrapper = styled.div`
......@@ -24,16 +24,6 @@ export const ScrollablePage = styled.div`
flex-direction: row;
`
export const RangeBadge = styled(Card)<{ inRange?: boolean }>`
width: fit-content;
font-size: 14px;
font-weight: 500;
border-radius: 8px;
padding: 4px 6px;
color: ${({ theme }) => theme.black};
background-color: ${({ inRange, theme }) => (inRange ? theme.green1 : theme.yellow2)};
`
export const FixedPreview = styled.div`
position: relative;
padding: 16px;
......@@ -49,8 +39,8 @@ export const FixedPreview = styled.div`
`
export const DynamicSection = styled(AutoColumn)<{ disabled?: boolean }>`
opacity: ${({ disabled }) => (disabled ? '0.3' : '1')}
pointer-events: ${({ disabled }) => (disabled ? 'none' : 'initial')}
opacity: ${({ disabled }) => (disabled ? '0.3' : '1')};
pointer-events: ${({ disabled }) => (disabled ? 'none' : 'initial')};
`
export const CurrencyDropdown = styled(CurrencyInputPanel)`
......
......@@ -194,6 +194,8 @@ export function PositionPage({
const { token0: token0Address, token1: token1Address, fee: feeAmount, liquidity, tickLower, tickUpper, tokenId } =
positionDetails || {}
const removed = liquidity?.eq(0)
const token0 = useToken(token0Address)
const token1 = useToken(token1Address)
......@@ -236,9 +238,6 @@ export function PositionPage({
: undefined
}, [inverted, pool, priceLower, priceUpper])
// really can't figure out why i have to do this, getting conditional hook call errors otherwise
const WORKAROUND = typeof ratio === 'number' ? (inverted ? 100 - ratio : ratio) : undefined
// fees
const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, positionDetails)
......@@ -408,7 +407,7 @@ export function PositionPage({
<Badge style={{ marginRight: '8px' }}>
<BadgeText>{new Percent(feeAmount, 1_000_000).toSignificant()}%</BadgeText>
</Badge>
<RangeBadge inRange={inRange} />
<RangeBadge removed={removed} inRange={inRange} />
</RowFixed>
{ownsNFT && (
<RowFixed>
......@@ -424,7 +423,7 @@ export function PositionPage({
{t('Add Liquidity')}
</ButtonGray>
) : null}
{tokenId && (
{tokenId && !removed ? (
<ResponsiveButtonPrimary
as={Link}
to={`/remove/${tokenId}`}
......@@ -434,7 +433,7 @@ export function PositionPage({
>
{t('Remove Liquidity')}
</ResponsiveButtonPrimary>
)}
) : null}
</RowFixed>
)}
</ResponsiveRow>
......@@ -498,13 +497,13 @@ export function PositionPage({
<TYPE.main>
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)}
</TYPE.main>
{typeof ratio === 'number' && (
{typeof ratio === 'number' && !removed ? (
<DarkGreyCard padding="4px 6px" style={{ width: 'fit-content', marginLeft: '8px' }}>
<TYPE.main color={theme.text2} fontSize={11}>
{inverted ? ratio : 100 - ratio}%
</TYPE.main>
</DarkGreyCard>
)}
) : null}
</RowFixed>
</RowBetween>
<RowBetween>
......@@ -516,13 +515,13 @@ export function PositionPage({
<TYPE.main>
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)}
</TYPE.main>
{typeof ratio === 'number' && (
{typeof ratio === 'number' && !removed ? (
<DarkGreyCard padding="4px 6px" style={{ width: 'fit-content', marginLeft: '8px' }}>
<TYPE.main color={theme.text2} fontSize={11}>
{WORKAROUND}%
{inverted ? 100 - ratio : ratio}%
</TYPE.main>
</DarkGreyCard>
)}
) : null}
</RowFixed>
</RowBetween>
</AutoColumn>
......@@ -621,7 +620,7 @@ export function PositionPage({
</Label>
<HideExtraSmall>
<>
<RangeBadge inRange={inRange} />
<RangeBadge removed={removed} inRange={inRange} />
<span style={{ width: '8px' }} />
</>
</HideExtraSmall>
......
......@@ -138,7 +138,7 @@ export default function Pool() {
{t('Learn')}
</MenuItem>
),
link: 'https://uniswap.org/docs/v2/',
link: 'https://docs.uniswap.org/',
external: true,
},
]
......
......@@ -28,12 +28,12 @@ import Loader from 'components/Loader'
import { useToken } from 'hooks/Tokens'
import { unwrappedToken } from 'utils/wrappedCurrency'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { RangeBadge } from 'pages/AddLiquidity/styled'
import { Break } from 'components/earn/styled'
import { NonfungiblePositionManager } from '@uniswap/v3-sdk'
import { calculateGasMargin } from 'utils'
import useTheme from 'hooks/useTheme'
import { AddRemoveTabs } from 'components/NavigationTabs'
import RangeBadge from 'components/Badge/RangeBadge'
export const UINT128MAX = BigNumber.from(2).pow(128).sub(1)
......@@ -83,6 +83,8 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
} = useDerivedV3BurnInfo(position)
const { onPercentSelect } = useBurnV3ActionHandlers()
const removed = position?.liquidity?.eq(0)
// boilerplate for the slider
const [percentForSlider, onPercentSelectForSlider] = useDebouncedChangeHandler(percent, onPercentSelect)
......@@ -281,7 +283,7 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
<DoubleCurrencyLogo currency0={currency1} currency1={currency0} size={20} margin={true} />
<TYPE.label ml="10px" fontSize="20px">{`${currency0?.symbol}/${currency1?.symbol}`}</TYPE.label>
</RowFixed>
<RangeBadge inRange={!outOfRange}>{outOfRange ? 'Out of range' : 'In Range'}</RangeBadge>
<RangeBadge removed={removed} inRange={!outOfRange} />
</RowBetween>
<LightCard>
<AutoColumn gap="md">
......@@ -363,10 +365,10 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
<AutoColumn gap="12px" style={{ flex: '1' }}>
<ButtonConfirmed
confirmed={false}
disabled={percent === 0 || !liquidityValue0}
disabled={removed || percent === 0 || !liquidityValue0}
onClick={() => setShowConfirm(true)}
>
{error ?? 'Remove'}
{removed ? 'Inactive' : error ?? 'Remove'}
</ButtonConfirmed>
</AutoColumn>
</div>
......
......@@ -10,7 +10,7 @@ import { ArrowDown, CheckCircle, HelpCircle, Info, ArrowLeft } from 'react-feath
import ReactGA from 'react-ga'
import { Link, RouteComponentProps } from 'react-router-dom'
import { Text } from 'rebass'
import { ThemeContext } from 'styled-components'
import styled, { ThemeContext } from 'styled-components'
import AddressInputPanel from '../../components/AddressInputPanel'
import { ButtonConfirmed, ButtonError, ButtonGray, ButtonLight, ButtonPrimary } from '../../components/Button'
import { GreyCard } from '../../components/Card'
......@@ -18,7 +18,7 @@ import { AutoColumn } from '../../components/Column'
import CurrencyInputPanel from '../../components/CurrencyInputPanel'
import CurrencyLogo from '../../components/CurrencyLogo'
import Loader from '../../components/Loader'
import { AutoRow, RowResponsive, RowFixed } from '../../components/Row'
import Row, { AutoRow, RowFixed } from '../../components/Row'
import BetterTradeLink from '../../components/swap/BetterTradeLink'
import confirmPriceImpactWithoutFee from '../../components/swap/confirmPriceImpactWithoutFee'
import ConfirmSwapModal from '../../components/swap/ConfirmSwapModal'
......@@ -47,14 +47,25 @@ import {
useSwapState,
} from '../../state/swap/hooks'
import { useExpertModeManager, useUserSingleHopOnly, useUserSlippageTolerance } from '../../state/user/hooks'
import { LinkStyledButton, TYPE } from '../../theme'
import { HideSmall, LinkStyledButton, TYPE } from '../../theme'
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
import { computePriceImpactWithMaximumSlippage } from '../../utils/computePriceImpactWithMaximumSlippage'
import { getTradeVersion } from '../../utils/getTradeVersion'
import { isTradeBetter } from '../../utils/isTradeBetter'
import { maxAmountSpend } from '../../utils/maxAmountSpend'
import { warningSeverity } from '../../utils/prices'
import AppBody from '../AppBody'
const StyledInfo = styled(Info)`
opacity: 0.4;
color: ${({ theme }) => theme.text1};
height: 16px;
width: 16px;
:hover {
opacity: 0.8;
}
`
export default function Swap({ history }: RouteComponentProps) {
const loadedUrlParams = useDefaultsFromURLSearch()
......@@ -274,8 +285,17 @@ export default function Swap({ history }: RouteComponentProps) {
// errors
const [showInverted, setShowInverted] = useState<boolean>(false)
// warnings on price impact
const priceImpactSeverity = warningSeverity(priceImpact)
// warnings on the greater of fiat value price impact and execution price impact
const priceImpactSeverity = useMemo(() => {
const executionPriceImpact = trade ? computePriceImpactWithMaximumSlippage(trade, allowedSlippage) : undefined
return warningSeverity(
executionPriceImpact && priceImpact
? executionPriceImpact.greaterThan(priceImpact)
? executionPriceImpact
: priceImpact
: executionPriceImpact ?? priceImpact
)
}, [allowedSlippage, priceImpact, trade])
// show approve flow when: no error on inputs, not approved or pending, or approved in current session
// never show if price impact is above threshold in non expert mode
......@@ -398,7 +418,7 @@ export default function Swap({ history }: RouteComponentProps) {
</>
) : null}
<RowResponsive style={{ justifyContent: !trade ? 'center' : 'space-between' }}>
<Row style={{ justifyContent: !trade ? 'center' : 'space-between' }}>
<RowFixed>
{[V3TradeState.VALID, V3TradeState.SYNCING, V3TradeState.NO_ROUTE_FOUND].includes(v3TradeState) &&
(toggledVersion === Version.v3 && isTradeBetter(v3Trade, v2Trade) ? (
......@@ -424,7 +444,7 @@ export default function Swap({ history }: RouteComponentProps) {
>
<ArrowLeft color={theme.text3} size={12} /> &nbsp;
<TYPE.main style={{ lineHeight: '120%' }} fontSize={12}>
Back to V3
<HideSmall>Back to </HideSmall>V3
</TYPE.main>
</ButtonGray>
)
......@@ -447,33 +467,19 @@ export default function Swap({ history }: RouteComponentProps) {
</ButtonGray>
)}
</RowFixed>
<RowFixed>
{trade ? (
{trade ? (
<RowFixed>
<TradePrice
price={trade.worstExecutionPrice(allowedSlippage)}
showInverted={showInverted}
setShowInverted={setShowInverted}
/>
) : (
<TYPE.main></TYPE.main>
)}
{trade && (
<MouseoverTooltipContent content={<AdvancedSwapDetails trade={trade} />}>
<Info
size={16}
style={{
display: 'flex',
justifyContent: 'space-between',
height: '24px',
opacity: 0.4,
margin: '0 .75rem 0 .5rem',
}}
color={theme.text1}
/>
<StyledInfo />
</MouseoverTooltipContent>
)}
</RowFixed>
</RowResponsive>
</RowFixed>
) : null}
</Row>
<BottomGrouping>
{swapIsUnsupported ? (
......
......@@ -420,7 +420,8 @@ export function useRangeHopCallbacks(
quoteCurrency: Currency | undefined,
feeAmount: FeeAmount | undefined,
tickLower: number | undefined,
tickUpper: number | undefined
tickUpper: number | undefined,
pool?: Pool | undefined | null
) {
const { chainId } = useActiveWeb3React()
const baseToken = useMemo(() => wrappedCurrency(baseCurrency, chainId), [baseCurrency, chainId])
......@@ -431,32 +432,52 @@ export function useRangeHopCallbacks(
const newPrice = tickToPrice(baseToken, quoteToken, tickLower - TICK_SPACINGS[feeAmount])
return newPrice.toSignificant(5, undefined, Rounding.ROUND_UP)
}
// use pool current tick as starting tick if we have pool but no tick input
if (!(typeof tickLower === 'number') && baseToken && quoteToken && feeAmount && pool) {
const newPrice = tickToPrice(baseToken, quoteToken, pool.tickCurrent - TICK_SPACINGS[feeAmount])
return newPrice.toSignificant(5, undefined, Rounding.ROUND_UP)
}
return ''
}, [baseToken, quoteToken, tickLower, feeAmount])
}, [baseToken, quoteToken, tickLower, feeAmount, pool])
const getIncrementLower = useCallback(() => {
if (baseToken && quoteToken && typeof tickLower === 'number' && feeAmount) {
const newPrice = tickToPrice(baseToken, quoteToken, tickLower + TICK_SPACINGS[feeAmount])
return newPrice.toSignificant(5, undefined, Rounding.ROUND_UP)
}
// use pool current tick as starting tick if we have pool but no tick input
if (!(typeof tickLower === 'number') && baseToken && quoteToken && feeAmount && pool) {
const newPrice = tickToPrice(baseToken, quoteToken, pool.tickCurrent + TICK_SPACINGS[feeAmount])
return newPrice.toSignificant(5, undefined, Rounding.ROUND_UP)
}
return ''
}, [baseToken, quoteToken, tickLower, feeAmount])
}, [baseToken, quoteToken, tickLower, feeAmount, pool])
const getDecrementUpper = useCallback(() => {
if (baseToken && quoteToken && typeof tickUpper === 'number' && feeAmount) {
const newPrice = tickToPrice(baseToken, quoteToken, tickUpper - TICK_SPACINGS[feeAmount])
return newPrice.toSignificant(5, undefined, Rounding.ROUND_UP)
}
// use pool current tick as starting tick if we have pool but no tick input
if (!(typeof tickUpper === 'number') && baseToken && quoteToken && feeAmount && pool) {
const newPrice = tickToPrice(baseToken, quoteToken, pool.tickCurrent - TICK_SPACINGS[feeAmount])
return newPrice.toSignificant(5, undefined, Rounding.ROUND_UP)
}
return ''
}, [baseToken, quoteToken, tickUpper, feeAmount])
}, [baseToken, quoteToken, tickUpper, feeAmount, pool])
const getIncrementUpper = useCallback(() => {
if (baseToken && quoteToken && typeof tickUpper === 'number' && feeAmount) {
const newPrice = tickToPrice(baseToken, quoteToken, tickUpper + TICK_SPACINGS[feeAmount])
return newPrice.toSignificant(5, undefined, Rounding.ROUND_UP)
}
// use pool current tick as starting tick if we have pool but no tick input
if (!(typeof tickUpper === 'number') && baseToken && quoteToken && feeAmount && pool) {
const newPrice = tickToPrice(baseToken, quoteToken, pool.tickCurrent + TICK_SPACINGS[feeAmount])
return newPrice.toSignificant(5, undefined, Rounding.ROUND_UP)
}
return ''
}, [baseToken, quoteToken, tickUpper, feeAmount])
}, [baseToken, quoteToken, tickUpper, feeAmount, pool])
return { getDecrementLower, getIncrementLower, getDecrementUpper, getIncrementUpper }
}
......@@ -62,7 +62,7 @@ export const initialState: UserState = {
matchesDarkMode: false,
userExpertMode: false,
userSingleHopOnly: false,
userSlippageTolerance: 50,
userSlippageTolerance: 10,
userDeadline: DEFAULT_DEADLINE_FROM_NOW,
tokens: {},
pairs: {},
......@@ -76,7 +76,7 @@ export default createReducer(initialState, (builder) =>
// slippage isnt being tracked in local storage, reset to default
// noinspection SuspiciousTypeOfGuard
if (typeof state.userSlippageTolerance !== 'number') {
state.userSlippageTolerance = 50
state.userSlippageTolerance = 10
}
// deadline isnt being tracked in local storage, reset to default
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment