feat: [info] Add Liquidity and Swap buttons on PDP (#7382)
* feat: setup initial pool details page and route * add pool data query and call on enw page * make query dynamic to url chainId * Get and display Header info * add token symbols * split header into its own file * add helper function to not default to eth chain * add helper function tests * add header component tests * add mocked test for PDP * use valid values * allow unsupported BE chains supported by thegraph * typecheck * remove useless row * no longer needed child * use first and last child * move mock consts to their own file * skele linear task * return null * descriptiive pool not found bool * modify correct logo container * update snapshots * instantiate all chain apollo clients * added snapshot test * merge main and update snapshots * Update src/pages/PoolDetails/PoolDetailsHeader.tsx Co-authored-by: Nate Wienert <natewienert@gmail.com> * type feeTier * setup init stats component * correctly query pool data for t24, t48, and tWeek timestamps * add comments * sanitize pool data and update tests * correct test data * add todo * lint * show correct data * remove logs * use formatter * showing colored bars * styled graph * get muted color * refactor: move getColor to src * refactor useColor to use getColor function * remove consts * refactor files * 1st class var support courtesy of carter * remove logging and adds comments * mobile styling * move Stats to its own file * add test cases * add test file * update padding * remove old test file * respond to feedback * right column wrapper * add non-functional pdp buttons * update tests * add button functionality * working tokenId for position * split buttons in their own file * add tests * reduce screenshots --------- Co-authored-by: Nate Wienert <natewienert@gmail.com>
This commit is contained in:
parent
524ce49fcb
commit
81accd1864
@ -1,8 +1,5 @@
|
|||||||
import { BigNumber } from '@ethersproject/bignumber'
|
|
||||||
import { ChainId, WETH9 } from '@uniswap/sdk-core'
|
|
||||||
import { FeeAmount, Pool, Position } from '@uniswap/v3-sdk'
|
|
||||||
import { USDC_MAINNET } from 'constants/tokens'
|
|
||||||
import { mocked } from 'test-utils/mocked'
|
import { mocked } from 'test-utils/mocked'
|
||||||
|
import { owner, useMultiChainPositionsReturnValue } from 'test-utils/pools/fixtures'
|
||||||
import { render } from 'test-utils/render'
|
import { render } from 'test-utils/render'
|
||||||
|
|
||||||
import Pools from '.'
|
import Pools from '.'
|
||||||
@ -12,53 +9,6 @@ jest.mock('./useMultiChainPositions')
|
|||||||
|
|
||||||
jest.spyOn(console, 'warn').mockImplementation()
|
jest.spyOn(console, 'warn').mockImplementation()
|
||||||
|
|
||||||
const owner = '0xf5b6bb25f5beaea03dd014c6ef9fa9f3926bf36c'
|
|
||||||
|
|
||||||
const pool = new Pool(
|
|
||||||
USDC_MAINNET,
|
|
||||||
WETH9[ChainId.MAINNET],
|
|
||||||
FeeAmount.MEDIUM,
|
|
||||||
'1851127709498178402383049949138810',
|
|
||||||
'7076437181775065414',
|
|
||||||
201189
|
|
||||||
)
|
|
||||||
|
|
||||||
const position = new Position({
|
|
||||||
pool,
|
|
||||||
liquidity: 1341008833950736,
|
|
||||||
tickLower: 200040,
|
|
||||||
tickUpper: 202560,
|
|
||||||
})
|
|
||||||
const details = {
|
|
||||||
nonce: BigNumber.from('0'),
|
|
||||||
tokenId: BigNumber.from('0'),
|
|
||||||
operator: '0x0',
|
|
||||||
token0: USDC_MAINNET.address,
|
|
||||||
token1: WETH9[ChainId.MAINNET].address,
|
|
||||||
fee: FeeAmount.MEDIUM,
|
|
||||||
tickLower: -100,
|
|
||||||
tickUpper: 100,
|
|
||||||
liquidity: BigNumber.from('9000'),
|
|
||||||
feeGrowthInside0LastX128: BigNumber.from('0'),
|
|
||||||
feeGrowthInside1LastX128: BigNumber.from('0'),
|
|
||||||
tokensOwed0: BigNumber.from('0'),
|
|
||||||
tokensOwed1: BigNumber.from('0'),
|
|
||||||
}
|
|
||||||
const useMultiChainPositionsReturnValue = {
|
|
||||||
positions: [
|
|
||||||
{
|
|
||||||
owner,
|
|
||||||
chainId: ChainId.MAINNET,
|
|
||||||
position,
|
|
||||||
pool,
|
|
||||||
details,
|
|
||||||
inRange: true,
|
|
||||||
closed: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
loading: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocked(useMultiChainPositions).mockReturnValue(useMultiChainPositionsReturnValue)
|
mocked(useMultiChainPositions).mockReturnValue(useMultiChainPositionsReturnValue)
|
||||||
})
|
})
|
||||||
|
63
src/pages/PoolDetails/PoolDetailsStatsButtons.test.tsx
Normal file
63
src/pages/PoolDetails/PoolDetailsStatsButtons.test.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import userEvent from '@testing-library/user-event'
|
||||||
|
import useMultiChainPositions from 'components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions'
|
||||||
|
import { mocked } from 'test-utils/mocked'
|
||||||
|
import { useMultiChainPositionsReturnValue, validPoolToken0, validPoolToken1 } from 'test-utils/pools/fixtures'
|
||||||
|
import { act, render, screen } from 'test-utils/render'
|
||||||
|
|
||||||
|
import { PoolDetailsStatsButtons } from './PoolDetailsStatsButtons'
|
||||||
|
|
||||||
|
jest.mock('components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions')
|
||||||
|
|
||||||
|
describe('PoolDetailsStatsButton', () => {
|
||||||
|
const mockProps = {
|
||||||
|
chainId: 1,
|
||||||
|
token0: validPoolToken0,
|
||||||
|
token1: validPoolToken1,
|
||||||
|
feeTier: 500,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockPropsTokensReversed = {
|
||||||
|
...mockProps,
|
||||||
|
token0: validPoolToken1,
|
||||||
|
token1: validPoolToken0,
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mocked(useMultiChainPositions).mockReturnValue(useMultiChainPositionsReturnValue)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders both buttons correctly', () => {
|
||||||
|
const { asFragment } = render(<PoolDetailsStatsButtons {...mockProps} />)
|
||||||
|
expect(asFragment()).toMatchSnapshot()
|
||||||
|
|
||||||
|
expect(screen.getByTestId('pool-details-add-liquidity-button')).toBeVisible()
|
||||||
|
expect(screen.getByTestId('pool-details-swap-button')).toBeVisible()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clicking swap goes to correct url', async () => {
|
||||||
|
render(<PoolDetailsStatsButtons {...mockProps} />)
|
||||||
|
|
||||||
|
await act(() => userEvent.click(screen.getByTestId('pool-details-swap-button')))
|
||||||
|
expect(global.window.location.href).toContain(
|
||||||
|
'/swap?inputCurrency=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&outputCurrency=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clicking swap goes to correct url with tokens reversed', async () => {
|
||||||
|
render(<PoolDetailsStatsButtons {...mockPropsTokensReversed} />)
|
||||||
|
|
||||||
|
await act(() => userEvent.click(screen.getByTestId('pool-details-swap-button')))
|
||||||
|
expect(global.window.location.href).toContain(
|
||||||
|
'/swap?inputCurrency=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2&outputCurrency=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clicking add liquidity goes to correct url', async () => {
|
||||||
|
render(<PoolDetailsStatsButtons {...mockPropsTokensReversed} />)
|
||||||
|
|
||||||
|
await act(() => userEvent.click(screen.getByTestId('pool-details-add-liquidity-button')))
|
||||||
|
expect(global.window.location.href).toContain(
|
||||||
|
'/increase/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/500'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
89
src/pages/PoolDetails/PoolDetailsStatsButtons.tsx
Normal file
89
src/pages/PoolDetails/PoolDetailsStatsButtons.tsx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { Trans } from '@lingui/macro'
|
||||||
|
import { useWeb3React } from '@web3-react/core'
|
||||||
|
import { PositionInfo } from 'components/AccountDrawer/MiniPortfolio/Pools/cache'
|
||||||
|
import useMultiChainPositions from 'components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions'
|
||||||
|
import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button'
|
||||||
|
import Row from 'components/Row'
|
||||||
|
import { Token } from 'graphql/thegraph/__generated__/types-and-hooks'
|
||||||
|
import { useCurrency } from 'hooks/Tokens'
|
||||||
|
import { useSwitchChain } from 'hooks/useSwitchChain'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import { BREAKPOINTS } from 'theme'
|
||||||
|
import { currencyId } from 'utils/currencyId'
|
||||||
|
|
||||||
|
const PoolDetailsStatsButtonsRow = styled(Row)`
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
@media (max-width: ${BREAKPOINTS.lg - 1}px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const PoolButton = styled(ThemeButton)`
|
||||||
|
padding: 12px 16px 12px 12px;
|
||||||
|
border-radius: 900px;
|
||||||
|
width: 50%;
|
||||||
|
`
|
||||||
|
|
||||||
|
interface PoolDetailsStatsButtonsProps {
|
||||||
|
chainId?: number
|
||||||
|
token0?: Token
|
||||||
|
token1?: Token
|
||||||
|
feeTier?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function findMatchingPosition(positions: PositionInfo[], token0?: Token, token1?: Token, feeTier?: number) {
|
||||||
|
return positions?.find(
|
||||||
|
(position) =>
|
||||||
|
(position?.details.token0.toLowerCase() === token0?.id ||
|
||||||
|
position?.details.token0.toLowerCase() === token1?.id) &&
|
||||||
|
(position?.details.token1.toLowerCase() === token0?.id ||
|
||||||
|
position?.details.token1.toLowerCase() === token1?.id) &&
|
||||||
|
position?.details.fee == feeTier &&
|
||||||
|
!position.closed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PoolDetailsStatsButtons({ chainId, token0, token1, feeTier }: PoolDetailsStatsButtonsProps) {
|
||||||
|
const { chainId: walletChainId, connector, account } = useWeb3React()
|
||||||
|
const { positions: userOwnedPositions } = useMultiChainPositions(account ?? '', chainId ? [chainId] : undefined)
|
||||||
|
const position = userOwnedPositions && findMatchingPosition(userOwnedPositions, token0, token1, feeTier)
|
||||||
|
const tokenId = position?.details.tokenId
|
||||||
|
const switchChain = useSwitchChain()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const currency0 = useCurrency(token0?.id, chainId)
|
||||||
|
const currency1 = useCurrency(token1?.id, chainId)
|
||||||
|
const handleOnClick = async (toSwap: boolean) => {
|
||||||
|
if (currency0 && currency1) {
|
||||||
|
if (walletChainId !== chainId && chainId) await switchChain(connector, chainId)
|
||||||
|
navigate(
|
||||||
|
toSwap
|
||||||
|
? `/swap?inputCurrency=${currencyId(currency0)}&outputCurrency=${currencyId(currency1)}`
|
||||||
|
: `/increase/${currencyId(currency0)}/${currencyId(currency1)}/${feeTier}${tokenId ? `/${tokenId}` : ''}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!currency0 || !currency1) return null
|
||||||
|
return (
|
||||||
|
<PoolDetailsStatsButtonsRow>
|
||||||
|
<PoolButton
|
||||||
|
size={ButtonSize.medium}
|
||||||
|
emphasis={ButtonEmphasis.highSoft}
|
||||||
|
onClick={() => handleOnClick(false)}
|
||||||
|
data-testid="pool-details-add-liquidity-button"
|
||||||
|
>
|
||||||
|
<Trans>Add liquidity</Trans>
|
||||||
|
</PoolButton>
|
||||||
|
|
||||||
|
<PoolButton
|
||||||
|
size={ButtonSize.medium}
|
||||||
|
emphasis={ButtonEmphasis.highSoft}
|
||||||
|
onClick={() => handleOnClick(true)}
|
||||||
|
data-testid="pool-details-swap-button"
|
||||||
|
>
|
||||||
|
<Trans>Swap</Trans>
|
||||||
|
</PoolButton>
|
||||||
|
</PoolDetailsStatsButtonsRow>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`PoolDetailsStatsButton renders both buttons correctly 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
.c0 {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c1 {
|
||||||
|
width: 100%;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-box-pack: start;
|
||||||
|
-webkit-justify-content: flex-start;
|
||||||
|
-ms-flex-pack: start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c6 {
|
||||||
|
background-color: transparent;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
height: 100%;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
-webkit-transition: 150ms ease background-color;
|
||||||
|
transition: 150ms ease background-color;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3 {
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #FFEFFF;
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 0;
|
||||||
|
color: #FC72FF;
|
||||||
|
cursor: pointer;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-flex-direction: row;
|
||||||
|
-ms-flex-direction: row;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 535;
|
||||||
|
gap: 12px;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
position: relative;
|
||||||
|
-webkit-transition: 150ms ease opacity;
|
||||||
|
transition: 150ms ease opacity;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3:active .c5 {
|
||||||
|
background-color: #B8C0DC3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3:focus .c5 {
|
||||||
|
background-color: #B8C0DC3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3:hover .c5 {
|
||||||
|
background-color: #98A1C014;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3:disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3:disabled:active .c5,
|
||||||
|
.c3:disabled:focus .c5,
|
||||||
|
.c3:disabled:hover .c5 {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c2 {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c4 {
|
||||||
|
padding: 12px 16px 12px 12px;
|
||||||
|
border-radius: 900px;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:1023px) {
|
||||||
|
.c2 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="c0 c1 c2"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="c3 c4"
|
||||||
|
data-testid="pool-details-add-liquidity-button"
|
||||||
|
size="1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="c5 c6"
|
||||||
|
/>
|
||||||
|
Add liquidity
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="c3 c4"
|
||||||
|
data-testid="pool-details-swap-button"
|
||||||
|
size="1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="c5 c6"
|
||||||
|
/>
|
||||||
|
Swap
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
@ -17,7 +17,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
width: max-content;
|
width: max-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c26 {
|
.c31 {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@ -82,7 +82,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c27 {
|
.c32 {
|
||||||
width: -webkit-max-content;
|
width: -webkit-max-content;
|
||||||
width: -moz-max-content;
|
width: -moz-max-content;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
@ -124,6 +124,78 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.c21 {
|
||||||
|
background-color: transparent;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
height: 100%;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
-webkit-transition: 150ms ease background-color;
|
||||||
|
transition: 150ms ease background-color;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c18 {
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #FFEFFF;
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 0;
|
||||||
|
color: #FC72FF;
|
||||||
|
cursor: pointer;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-flex-direction: row;
|
||||||
|
-ms-flex-direction: row;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 535;
|
||||||
|
gap: 12px;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
position: relative;
|
||||||
|
-webkit-transition: 150ms ease opacity;
|
||||||
|
transition: 150ms ease opacity;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c18:active .c20 {
|
||||||
|
background-color: #B8C0DC3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c18:focus .c20 {
|
||||||
|
background-color: #B8C0DC3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c18:hover .c20 {
|
||||||
|
background-color: #98A1C014;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c18:disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c18:disabled:active .c20,
|
||||||
|
.c18:disabled:focus .c20,
|
||||||
|
.c18:disabled:hover .c20 {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.c4 {
|
.c4 {
|
||||||
gap: 36px;
|
gap: 36px;
|
||||||
}
|
}
|
||||||
@ -207,17 +279,17 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c28 {
|
.c33 {
|
||||||
color: #FF5F52;
|
color: #FF5F52;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c18 {
|
.c23 {
|
||||||
font-weight: 485;
|
font-weight: 485;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c17 {
|
.c22 {
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
@ -225,7 +297,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c19 {
|
.c24 {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
-webkit-flex: 1;
|
-webkit-flex: 1;
|
||||||
-ms-flex: 1;
|
-ms-flex: 1;
|
||||||
@ -233,14 +305,14 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c20 {
|
.c25 {
|
||||||
-webkit-box-pack: justify;
|
-webkit-box-pack: justify;
|
||||||
-webkit-justify-content: space-between;
|
-webkit-justify-content: space-between;
|
||||||
-ms-flex-pack: justify;
|
-ms-flex-pack: justify;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c21 {
|
.c26 {
|
||||||
font-weight: 485;
|
font-weight: 485;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
@ -249,7 +321,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
width: max-content;
|
width: max-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c22 {
|
.c27 {
|
||||||
height: 8px;
|
height: 8px;
|
||||||
width: 40.698463777008904%;
|
width: 40.698463777008904%;
|
||||||
background: #2172E5;
|
background: #2172E5;
|
||||||
@ -258,7 +330,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
border-right: 1px solid #F9F9F9;
|
border-right: 1px solid #F9F9F9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c23 {
|
.c28 {
|
||||||
height: 8px;
|
height: 8px;
|
||||||
width: 59.3015362229911%;
|
width: 59.3015362229911%;
|
||||||
background: #2172E5;
|
background: #2172E5;
|
||||||
@ -267,7 +339,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
border-left: 1px solid #F9F9F9;
|
border-left: 1px solid #F9F9F9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c24 {
|
.c29 {
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
-webkit-align-items: flex-end;
|
-webkit-align-items: flex-end;
|
||||||
@ -276,13 +348,23 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c25 {
|
.c30 {
|
||||||
color: #222222;
|
color: #222222;
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
font-weight: 485;
|
font-weight: 485;
|
||||||
line-height: 44px;
|
line-height: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.c17 {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c19 {
|
||||||
|
padding: 12px 16px 12px 12px;
|
||||||
|
border-radius: 900px;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.c2 {
|
.c2 {
|
||||||
padding: 48px;
|
padding: 48px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -300,13 +382,13 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width:1023px) {
|
@media (max-width:1023px) {
|
||||||
.c18 {
|
.c23 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width:1023px) {
|
@media (max-width:1023px) {
|
||||||
.c17 {
|
.c22 {
|
||||||
-webkit-flex-direction: row;
|
-webkit-flex-direction: row;
|
||||||
-ms-flex-direction: row;
|
-ms-flex-direction: row;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -323,13 +405,13 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width:640px) {
|
@media (max-width:640px) {
|
||||||
.c19 {
|
.c24 {
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width:1023px) {
|
@media (max-width:1023px) {
|
||||||
.c20 {
|
.c25 {
|
||||||
-webkit-flex-direction: column;
|
-webkit-flex-direction: column;
|
||||||
-ms-flex-direction: column;
|
-ms-flex-direction: column;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -337,7 +419,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width:1023px) {
|
@media (max-width:1023px) {
|
||||||
.c21 {
|
.c26 {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
line-height: 28px;
|
line-height: 28px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -345,7 +427,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width:1023px) {
|
@media (max-width:1023px) {
|
||||||
.c24 {
|
.c29 {
|
||||||
-webkit-flex-direction: column;
|
-webkit-flex-direction: column;
|
||||||
-ms-flex-direction: column;
|
-ms-flex-direction: column;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -358,12 +440,18 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width:1023px) {
|
@media (max-width:1023px) {
|
||||||
.c25 {
|
.c30 {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
line-height: 28px;
|
line-height: 28px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width:1023px) {
|
||||||
|
.c17 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width:1023px) {
|
@media (max-width:1023px) {
|
||||||
.c2 {
|
.c2 {
|
||||||
-webkit-flex-direction: column;
|
-webkit-flex-direction: column;
|
||||||
@ -485,15 +573,39 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
class="c3 c16"
|
class="c3 c16"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c3 c17"
|
class="c0 c1 c17"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="c18 c19"
|
||||||
|
data-testid="pool-details-add-liquidity-button"
|
||||||
|
size="1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="c20 c21"
|
||||||
|
/>
|
||||||
|
Add liquidity
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="c18 c19"
|
||||||
|
data-testid="pool-details-swap-button"
|
||||||
|
size="1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="c20 c21"
|
||||||
|
/>
|
||||||
|
Swap
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="c3 c22"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c18 css-vurnku"
|
class="c23 css-vurnku"
|
||||||
>
|
>
|
||||||
Stats
|
Stats
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c3 c19"
|
class="c3 c24"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c6 css-1urox24"
|
class="c6 css-1urox24"
|
||||||
@ -501,15 +613,15 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
Pool balances
|
Pool balances
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c0 c1 c20"
|
class="c0 c1 c25"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c0 c1 c21"
|
class="c0 c1 c26"
|
||||||
>
|
>
|
||||||
90.93M USDC
|
90.93M USDC
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c0 c1 c21"
|
class="c0 c1 c26"
|
||||||
>
|
>
|
||||||
82,526.49 WETH
|
82,526.49 WETH
|
||||||
</div>
|
</div>
|
||||||
@ -519,15 +631,15 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
data-testid="pool-balance-chart"
|
data-testid="pool-balance-chart"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c22"
|
class="c27"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="c23"
|
class="c28"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c3 c19"
|
class="c3 c24"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c6 css-1urox24"
|
class="c6 css-1urox24"
|
||||||
@ -535,20 +647,20 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
TVL
|
TVL
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c0 c1 c24"
|
class="c0 c1 c29"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c25 css-vurnku"
|
class="c30 css-vurnku"
|
||||||
>
|
>
|
||||||
$223.2M
|
$223.2M
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c26 c27"
|
class="c31 c32"
|
||||||
width="max-content"
|
width="max-content"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
aria-label="down"
|
aria-label="down"
|
||||||
class="c28"
|
class="c33"
|
||||||
fill="none"
|
fill="none"
|
||||||
height="16"
|
height="16"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -569,7 +681,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c3 c19"
|
class="c3 c24"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c6 css-1urox24"
|
class="c6 css-1urox24"
|
||||||
@ -577,20 +689,20 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
24H volume
|
24H volume
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c0 c1 c24"
|
class="c0 c1 c29"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c25 css-vurnku"
|
class="c30 css-vurnku"
|
||||||
>
|
>
|
||||||
$233.4M
|
$233.4M
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c26 c27"
|
class="c31 c32"
|
||||||
width="max-content"
|
width="max-content"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
aria-label="down"
|
aria-label="down"
|
||||||
class="c28"
|
class="c33"
|
||||||
fill="none"
|
fill="none"
|
||||||
height="16"
|
height="16"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -611,7 +723,7 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c3 c19"
|
class="c3 c24"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c6 css-1urox24"
|
class="c6 css-1urox24"
|
||||||
@ -619,10 +731,10 @@ exports[`PoolDetailsPage pool header is displayed when data is received from the
|
|||||||
24H fees
|
24H fees
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="c0 c1 c24"
|
class="c0 c1 c29"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="c25 css-vurnku"
|
class="c30 css-vurnku"
|
||||||
>
|
>
|
||||||
$116.7K
|
$116.7K
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,6 +11,7 @@ import { isAddress } from 'utils'
|
|||||||
|
|
||||||
import { PoolDetailsHeader } from './PoolDetailsHeader'
|
import { PoolDetailsHeader } from './PoolDetailsHeader'
|
||||||
import { PoolDetailsStats } from './PoolDetailsStats'
|
import { PoolDetailsStats } from './PoolDetailsStats'
|
||||||
|
import { PoolDetailsStatsButtons } from './PoolDetailsStatsButtons'
|
||||||
|
|
||||||
const PageWrapper = styled(Row)`
|
const PageWrapper = styled(Row)`
|
||||||
padding: 48px;
|
padding: 48px;
|
||||||
@ -67,6 +68,7 @@ export default function PoolDetailsPage() {
|
|||||||
toggleReversed={toggleReversed}
|
toggleReversed={toggleReversed}
|
||||||
/>
|
/>
|
||||||
<RightColumn>
|
<RightColumn>
|
||||||
|
<PoolDetailsStatsButtons chainId={chainId} token0={token0} token1={token1} feeTier={poolData?.feeTier} />
|
||||||
{poolData && <PoolDetailsStats poolData={poolData} isReversed={isReversed} chainId={chainId} />}
|
{poolData && <PoolDetailsStats poolData={poolData} isReversed={isReversed} chainId={chainId} />}
|
||||||
</RightColumn>
|
</RightColumn>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
@ -1,6 +1,76 @@
|
|||||||
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
|
import { ChainId, WETH9 } from '@uniswap/sdk-core'
|
||||||
|
import { FeeAmount, Pool, Position } from '@uniswap/v3-sdk'
|
||||||
|
import { USDC_MAINNET } from 'constants/tokens'
|
||||||
import { Token } from 'graphql/thegraph/__generated__/types-and-hooks'
|
import { Token } from 'graphql/thegraph/__generated__/types-and-hooks'
|
||||||
|
|
||||||
export const validParams = { poolAddress: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', chainName: 'ethereum' }
|
export const validParams = { poolAddress: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', chainName: 'ethereum' }
|
||||||
|
|
||||||
|
export const validPoolToken0 = {
|
||||||
|
id: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||||
|
symbol: 'USDC',
|
||||||
|
name: 'USD Coin',
|
||||||
|
decimals: '6',
|
||||||
|
derivedETH: '0.0006240873011635544626425964678706127',
|
||||||
|
__typename: 'Token',
|
||||||
|
} as Token
|
||||||
|
|
||||||
|
export const validPoolToken1 = {
|
||||||
|
id: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
|
||||||
|
symbol: 'WETH',
|
||||||
|
name: 'Wrapped Ether',
|
||||||
|
decimals: '18',
|
||||||
|
derivedETH: '1',
|
||||||
|
__typename: 'Token',
|
||||||
|
} as Token
|
||||||
|
|
||||||
|
export const owner = '0xf5b6bb25f5beaea03dd014c6ef9fa9f3926bf36c'
|
||||||
|
|
||||||
|
const pool = new Pool(
|
||||||
|
USDC_MAINNET,
|
||||||
|
WETH9[ChainId.MAINNET],
|
||||||
|
FeeAmount.MEDIUM,
|
||||||
|
'1851127709498178402383049949138810',
|
||||||
|
'7076437181775065414',
|
||||||
|
201189
|
||||||
|
)
|
||||||
|
|
||||||
|
const position = new Position({
|
||||||
|
pool,
|
||||||
|
liquidity: 1341008833950736,
|
||||||
|
tickLower: 200040,
|
||||||
|
tickUpper: 202560,
|
||||||
|
})
|
||||||
|
const details = {
|
||||||
|
nonce: BigNumber.from('0'),
|
||||||
|
tokenId: BigNumber.from('0'),
|
||||||
|
operator: '0x0',
|
||||||
|
token0: USDC_MAINNET.address,
|
||||||
|
token1: WETH9[ChainId.MAINNET].address,
|
||||||
|
fee: FeeAmount.MEDIUM,
|
||||||
|
tickLower: -100,
|
||||||
|
tickUpper: 100,
|
||||||
|
liquidity: BigNumber.from('9000'),
|
||||||
|
feeGrowthInside0LastX128: BigNumber.from('0'),
|
||||||
|
feeGrowthInside1LastX128: BigNumber.from('0'),
|
||||||
|
tokensOwed0: BigNumber.from('0'),
|
||||||
|
tokensOwed1: BigNumber.from('0'),
|
||||||
|
}
|
||||||
|
export const useMultiChainPositionsReturnValue = {
|
||||||
|
positions: [
|
||||||
|
{
|
||||||
|
owner,
|
||||||
|
chainId: ChainId.MAINNET,
|
||||||
|
position,
|
||||||
|
pool,
|
||||||
|
details,
|
||||||
|
inRange: true,
|
||||||
|
closed: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
|
||||||
export const validPoolDataResponse = {
|
export const validPoolDataResponse = {
|
||||||
data: {
|
data: {
|
||||||
id: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
|
id: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
|
||||||
@ -8,22 +78,8 @@ export const validPoolDataResponse = {
|
|||||||
liquidity: parseFloat('26414803986874770777'),
|
liquidity: parseFloat('26414803986874770777'),
|
||||||
sqrtPrice: parseFloat('1977320351696380862605029898750440'),
|
sqrtPrice: parseFloat('1977320351696380862605029898750440'),
|
||||||
tick: 202508,
|
tick: 202508,
|
||||||
token0: {
|
token0: validPoolToken0,
|
||||||
id: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
token1: validPoolToken1,
|
||||||
symbol: 'USDC',
|
|
||||||
name: 'USD Coin',
|
|
||||||
decimals: '6',
|
|
||||||
derivedETH: '0.0006240873011635544626425964678706127',
|
|
||||||
__typename: 'Token',
|
|
||||||
} as Token,
|
|
||||||
token1: {
|
|
||||||
id: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
|
|
||||||
symbol: 'WETH',
|
|
||||||
name: 'Wrapped Ether',
|
|
||||||
decimals: '18',
|
|
||||||
derivedETH: '1',
|
|
||||||
__typename: 'Token',
|
|
||||||
} as Token,
|
|
||||||
token0Price: 1605.481,
|
token0Price: 1605.481,
|
||||||
token1Price: 0.000622,
|
token1Price: 0.000622,
|
||||||
volumeUSD: 233379442.64648438,
|
volumeUSD: 233379442.64648438,
|
||||||
|
Loading…
Reference in New Issue
Block a user