Commit 1992c5de authored by Jordan Frankfurt's avatar Jordan Frankfurt Committed by GitHub

fix: don't render LP position when token name or symbol includes a url (#5961)

parent 0208ccd7
...@@ -99,9 +99,9 @@ export default function PositionList({ ...@@ -99,9 +99,9 @@ export default function PositionList({
</ToggleLabel> </ToggleLabel>
</ToggleWrap> </ToggleWrap>
</MobileHeader> </MobileHeader>
{positions.map((p) => { {positions.map((p) => (
return <PositionListItem key={p.tokenId.toString()} positionDetails={p} /> <PositionListItem key={p.tokenId.toString()} {...p} />
})} ))}
</> </>
) )
} }
import { BigNumber } from '@ethersproject/bignumber'
import { render, screen } from 'test-utils'
import PositionListItem from '.'
jest.mock('hooks/Tokens', () => {
const originalModule = jest.requireActual('hooks/Tokens')
const uniSDK = jest.requireActual('@uniswap/sdk-core')
return {
__esModule: true,
...originalModule,
useToken: jest.fn(
() =>
new uniSDK.Token(
1,
'0x39AA39c021dfbaE8faC545936693aC917d5E7563',
8,
'https://www.example.com',
'example.com coin'
)
),
}
})
test('PositionListItem should not render when the name contains a url', () => {
const positionDetails = {
token0: '0x39AA39c021dfbaE8faC545936693aC917d5E7563',
token1: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
tokenId: BigNumber.from(436148),
fee: 100,
liquidity: BigNumber.from('0x5c985aff8059be04'),
tickLower: -800,
tickUpper: 1600,
}
render(<PositionListItem {...positionDetails} />)
screen.debug()
expect(screen.queryByText('.com', { exact: false })).toBe(null)
})
import { BigNumber } from '@ethersproject/bignumber'
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Percent, Price, Token } from '@uniswap/sdk-core' import { Percent, Price, Token } from '@uniswap/sdk-core'
import { Position } from '@uniswap/v3-sdk' import { Position } from '@uniswap/v3-sdk'
...@@ -15,9 +16,9 @@ import { Link } from 'react-router-dom' ...@@ -15,9 +16,9 @@ import { Link } from 'react-router-dom'
import { Bound } from 'state/mint/v3/actions' import { Bound } from 'state/mint/v3/actions'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
import { HideSmall, MEDIA_WIDTHS, SmallOnly } from 'theme' import { HideSmall, MEDIA_WIDTHS, SmallOnly } from 'theme'
import { PositionDetails } from 'types/position'
import { formatTickPrice } from 'utils/formatTickPrice' import { formatTickPrice } from 'utils/formatTickPrice'
import { unwrappedToken } from 'utils/unwrappedToken' import { unwrappedToken } from 'utils/unwrappedToken'
import { hasURL } from 'utils/urlChecks'
import { DAI, USDC_MAINNET, USDT, WBTC, WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens' import { DAI, USDC_MAINNET, USDT, WBTC, WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
...@@ -109,7 +110,13 @@ const DataText = styled.div` ...@@ -109,7 +110,13 @@ const DataText = styled.div`
` `
interface PositionListItemProps { interface PositionListItemProps {
positionDetails: PositionDetails token0: string
token1: string
tokenId: BigNumber
fee: number
liquidity: BigNumber
tickLower: number
tickUpper: number
} }
export function getPriceOrderingFromPositionForUI(position?: Position): { export function getPriceOrderingFromPositionForUI(position?: Position): {
...@@ -166,16 +173,15 @@ export function getPriceOrderingFromPositionForUI(position?: Position): { ...@@ -166,16 +173,15 @@ export function getPriceOrderingFromPositionForUI(position?: Position): {
} }
} }
export default function PositionListItem({ positionDetails }: PositionListItemProps) { export default function PositionListItem({
const { token0: token0Address,
token0: token0Address, token1: token1Address,
token1: token1Address, tokenId,
fee: feeAmount, fee: feeAmount,
liquidity, liquidity,
tickLower, tickLower,
tickUpper, tickUpper,
} = positionDetails }: PositionListItemProps) {
const token0 = useToken(token0Address) const token0 = useToken(token0Address)
const token1 = useToken(token1Address) const token1 = useToken(token1Address)
...@@ -203,10 +209,23 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr ...@@ -203,10 +209,23 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
// check if price is within range // check if price is within range
const outOfRange: boolean = pool ? pool.tickCurrent < tickLower || pool.tickCurrent >= tickUpper : false const outOfRange: boolean = pool ? pool.tickCurrent < tickLower || pool.tickCurrent >= tickUpper : false
const positionSummaryLink = '/pool/' + positionDetails.tokenId const positionSummaryLink = '/pool/' + tokenId
const removed = liquidity?.eq(0) const removed = liquidity?.eq(0)
const containsURL = useMemo(
() =>
[token0?.name, token0?.symbol, token1?.name, token1?.symbol].reduce(
(acc, testString) => acc || Boolean(testString && hasURL(testString)),
false
),
[token0?.name, token0?.symbol, token1?.name, token1?.symbol]
)
if (containsURL) {
return null
}
return ( return (
<LinkRow to={positionSummaryLink}> <LinkRow to={positionSummaryLink}>
<RowBetween> <RowBetween>
......
...@@ -10,6 +10,7 @@ import { RowBetween, RowFixed } from 'components/Row' ...@@ -10,6 +10,7 @@ import { RowBetween, RowFixed } from 'components/Row'
import { SwitchLocaleLink } from 'components/SwitchLocaleLink' import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
import { isSupportedChain } from 'constants/chains' import { isSupportedChain } from 'constants/chains'
import { useV3Positions } from 'hooks/useV3Positions' import { useV3Positions } from 'hooks/useV3Positions'
import { useMemo } from 'react'
import { AlertTriangle, BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather' import { AlertTriangle, BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { useToggleWalletModal } from 'state/application/hooks' import { useToggleWalletModal } from 'state/application/hooks'
...@@ -202,10 +203,6 @@ export default function Pool() { ...@@ -202,10 +203,6 @@ export default function Pool() {
const { positions, loading: positionsLoading } = useV3Positions(account) const { positions, loading: positionsLoading } = useV3Positions(account)
if (!isSupportedChain(chainId)) {
return <WrongNetworkCard />
}
const [openPositions, closedPositions] = positions?.reduce<[PositionDetails[], PositionDetails[]]>( const [openPositions, closedPositions] = positions?.reduce<[PositionDetails[], PositionDetails[]]>(
(acc, p) => { (acc, p) => {
acc[p.liquidity?.isZero() ? 1 : 0].push(p) acc[p.liquidity?.isZero() ? 1 : 0].push(p)
...@@ -214,7 +211,15 @@ export default function Pool() { ...@@ -214,7 +211,15 @@ export default function Pool() {
[[], []] [[], []]
) ?? [[], []] ) ?? [[], []]
const filteredPositions = [...openPositions, ...(userHideClosedPositions ? [] : closedPositions)] const filteredPositions = useMemo(
() => [...openPositions, ...(userHideClosedPositions ? [] : closedPositions)],
[closedPositions, openPositions, userHideClosedPositions]
)
if (!isSupportedChain(chainId)) {
return <WrongNetworkCard />
}
const showConnectAWallet = Boolean(!account) const showConnectAWallet = Boolean(!account)
const showV2Features = Boolean(V2_FACTORY_ADDRESSES[chainId]) const showV2Features = Boolean(V2_FACTORY_ADDRESSES[chainId])
......
import { hasURL } from './urlChecks'
test('hasURL', () => {
expect(hasURL('this is my personal website: https://www.example.com')).toBe(true)
expect(hasURL('#corngang')).toBe(false)
})
export function hasURL(str: string): boolean {
const pattern = new RegExp(
'(http|https):\\/\\/' + // Match either "http" or "https" for the protocol
'(\\w+:{0,1}\\w*)?' + // Allow for an optional username and password in the URL
'(\\S+)' + // Match the domain name or IP address
'(:[0-9]+)?' + // Allow for an optional port number in the URL
'(\\/|\\/([\\w#!:.?+=&%!\\-\\/]))?' // Allow for an optional path and query string in the URL
)
return pattern.test(str)
}
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