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({
</ToggleLabel>
</ToggleWrap>
</MobileHeader>
{positions.map((p) => {
return <PositionListItem key={p.tokenId.toString()} positionDetails={p} />
})}
{positions.map((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 { Percent, Price, Token } from '@uniswap/sdk-core'
import { Position } from '@uniswap/v3-sdk'
......@@ -15,9 +16,9 @@ import { Link } from 'react-router-dom'
import { Bound } from 'state/mint/v3/actions'
import styled from 'styled-components/macro'
import { HideSmall, MEDIA_WIDTHS, SmallOnly } from 'theme'
import { PositionDetails } from 'types/position'
import { formatTickPrice } from 'utils/formatTickPrice'
import { unwrappedToken } from 'utils/unwrappedToken'
import { hasURL } from 'utils/urlChecks'
import { DAI, USDC_MAINNET, USDT, WBTC, WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
......@@ -109,7 +110,13 @@ const DataText = styled.div`
`
interface PositionListItemProps {
positionDetails: PositionDetails
token0: string
token1: string
tokenId: BigNumber
fee: number
liquidity: BigNumber
tickLower: number
tickUpper: number
}
export function getPriceOrderingFromPositionForUI(position?: Position): {
......@@ -166,16 +173,15 @@ export function getPriceOrderingFromPositionForUI(position?: Position): {
}
}
export default function PositionListItem({ positionDetails }: PositionListItemProps) {
const {
token0: token0Address,
token1: token1Address,
fee: feeAmount,
liquidity,
tickLower,
tickUpper,
} = positionDetails
export default function PositionListItem({
token0: token0Address,
token1: token1Address,
tokenId,
fee: feeAmount,
liquidity,
tickLower,
tickUpper,
}: PositionListItemProps) {
const token0 = useToken(token0Address)
const token1 = useToken(token1Address)
......@@ -203,10 +209,23 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
// check if price is within range
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 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 (
<LinkRow to={positionSummaryLink}>
<RowBetween>
......
......@@ -10,6 +10,7 @@ import { RowBetween, RowFixed } from 'components/Row'
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
import { isSupportedChain } from 'constants/chains'
import { useV3Positions } from 'hooks/useV3Positions'
import { useMemo } from 'react'
import { AlertTriangle, BookOpen, ChevronDown, ChevronsRight, Inbox, Layers, PlusCircle } from 'react-feather'
import { Link } from 'react-router-dom'
import { useToggleWalletModal } from 'state/application/hooks'
......@@ -202,10 +203,6 @@ export default function Pool() {
const { positions, loading: positionsLoading } = useV3Positions(account)
if (!isSupportedChain(chainId)) {
return <WrongNetworkCard />
}
const [openPositions, closedPositions] = positions?.reduce<[PositionDetails[], PositionDetails[]]>(
(acc, p) => {
acc[p.liquidity?.isZero() ? 1 : 0].push(p)
......@@ -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 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