feat: warn when adding liquidity to an unowned LP position (#6219)
* feat: warn when adding liquidity to an unowned LP position * update boolean name * use a better address equivalence check
This commit is contained in:
parent
1a79bac893
commit
18ec675c52
46
src/components/addLiquidity/OwnershipWarning.tsx
Normal file
46
src/components/addLiquidity/OwnershipWarning.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AlertTriangle } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
const ExplainerText = styled.div`
|
||||
color: ${({ theme }) => theme.textSecondary};
|
||||
`
|
||||
const TitleRow = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
color: ${({ theme }) => theme.accentWarning};
|
||||
margin-bottom: 8px;
|
||||
`
|
||||
const Wrapper = styled.div`
|
||||
background-color: ${({ theme }) => theme.accentWarningSoft};
|
||||
border-radius: 16px;
|
||||
margin-top: 12px;
|
||||
max-width: 480px;
|
||||
padding: 12px 20px;
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
interface OwnershipWarningProps {
|
||||
ownerAddress: string
|
||||
}
|
||||
|
||||
const OwnershipWarning = ({ ownerAddress }: OwnershipWarningProps) => (
|
||||
<Wrapper>
|
||||
<TitleRow>
|
||||
<AlertTriangle style={{ marginRight: '8px' }} />
|
||||
<ThemedText.SubHeader color="accentWarning">
|
||||
<Trans>Warning</Trans>
|
||||
</ThemedText.SubHeader>
|
||||
</TitleRow>
|
||||
<ExplainerText>
|
||||
<Trans>
|
||||
You are not the owner of this LP position. You will not be able to withdraw the liquidity from this position
|
||||
unless you own the following address: {ownerAddress}
|
||||
</Trans>
|
||||
</ExplainerText>
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
export default OwnershipWarning
|
@ -6,10 +6,12 @@ import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap
|
||||
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
|
||||
import { FeeAmount, NonfungiblePositionManager } from '@uniswap/v3-sdk'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import OwnershipWarning from 'components/addLiquidity/OwnershipWarning'
|
||||
import { sendEvent } from 'components/analytics'
|
||||
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
|
||||
import { useToggleWalletDrawer } from 'components/WalletDropdown'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
import { useSingleCallResult } from 'lib/hooks/multicall'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { AlertTriangle } from 'react-feather'
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
||||
@ -21,6 +23,7 @@ import {
|
||||
useV3MintState,
|
||||
} from 'state/mint/v3/hooks'
|
||||
import { useTheme } from 'styled-components/macro'
|
||||
import { addressesAreEquivalent } from 'utils/addressesAreEquivalent'
|
||||
|
||||
import { ButtonError, ButtonLight, ButtonPrimary, ButtonText } from '../../components/Button'
|
||||
import { BlueCard, OutlineCard, YellowCard } from '../../components/Card'
|
||||
@ -548,6 +551,12 @@ export default function AddLiquidity() {
|
||||
}),
|
||||
[usdcValueCurrencyB]
|
||||
)
|
||||
|
||||
const owner = useSingleCallResult(tokenId ? positionManager : null, 'ownerOf', [tokenId]).result?.[0]
|
||||
const ownsNFT =
|
||||
addressesAreEquivalent(owner, account) || addressesAreEquivalent(existingPositionDetails?.operator, account)
|
||||
const showOwnershipWarning = Boolean(account && !ownsNFT)
|
||||
|
||||
return (
|
||||
<>
|
||||
<ScrollablePage>
|
||||
@ -912,6 +921,7 @@ export default function AddLiquidity() {
|
||||
</ResponsiveTwoColumns>
|
||||
</Wrapper>
|
||||
</PageWrapper>
|
||||
{showOwnershipWarning && <OwnershipWarning ownerAddress={owner} />}
|
||||
{addIsUnsupported && (
|
||||
<UnsupportedCurrencyFooter
|
||||
show={addIsUnsupported}
|
||||
|
20
src/utils/addressesAreEquivalent.test.ts
Normal file
20
src/utils/addressesAreEquivalent.test.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { addressesAreEquivalent } from './addressesAreEquivalent'
|
||||
|
||||
describe('addressesAreEquivalent', () => {
|
||||
it('should return false for undefined addresses', () => {
|
||||
expect(addressesAreEquivalent(undefined, undefined)).toBe(false)
|
||||
})
|
||||
it('should return true for mismatched checksum equivalence', () => {
|
||||
expect(
|
||||
addressesAreEquivalent(
|
||||
'0x48c89D77ae34Ae475e4523b25aB01e363dce5A78',
|
||||
'0x48c89D77ae34Ae475e4523b25aB01e363dce5A78'.toLowerCase()
|
||||
)
|
||||
).toBe(true)
|
||||
})
|
||||
it('should return true for simple equivalence', () => {
|
||||
expect(
|
||||
addressesAreEquivalent('0x48c89D77ae34Ae475e4523b25aB01e363dce5A78', '0x48c89D77ae34Ae475e4523b25aB01e363dce5A78')
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
4
src/utils/addressesAreEquivalent.ts
Normal file
4
src/utils/addressesAreEquivalent.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export function addressesAreEquivalent(a?: string, b?: string) {
|
||||
if (!a || !b) return false
|
||||
return a === b || a.toLowerCase() === b.toLowerCase()
|
||||
}
|
Loading…
Reference in New Issue
Block a user