diff --git a/src/components/NewPosition/PoolInit/PoolInit.tsx b/src/components/NewPosition/PoolInit/PoolInit.tsx index 7aaf80e2..c1a8fc69 100644 --- a/src/components/NewPosition/PoolInit/PoolInit.tsx +++ b/src/components/NewPosition/PoolInit/PoolInit.tsx @@ -6,6 +6,7 @@ import { getMinTick, getMaxTick, calculateTickDelta } from '@invariant-labs/sdk/ import { PositionOpeningMethod } from '@store/consts/types' import { calcPriceByTickIndex, + calculateConcentration, calculateConcentrationRange, calculateSqrtPriceFromBalance, calculateTickFromBalance, @@ -20,6 +21,7 @@ import ConcentrationSlider from '../ConcentrationSlider/ConcentrationSlider' import { BN } from '@project-serum/anchor' import { Button, Grid, Typography } from '@mui/material' import AnimatedNumber from '@components/AnimatedNumber/AnimatedNumber' +import icons from '@static/icons' export interface IPoolInit { tokenASymbol: string @@ -320,7 +322,16 @@ export const PoolInit: React.FC = ({ - Set price range + + Set price range + {positionOpeningMethod === 'range' && ( + + Concentration + Concentration + {calculateConcentration(leftRange, rightRange).toFixed(2)}x + + )} + { [theme.breakpoints.down('sm')]: { paddingBottom: 24 } + }, + rangeConcentration: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + backgroundColor: colors.invariant.newDark, + gap: 8, + borderRadius: 11, + padding: '6px 12px', + + '& p:first-of-type': { + color: colors.invariant.textGrey, + ...typography.body2 + }, + + '& p:last-of-type': { + color: colors.invariant.text, + ...typography.body3, + minWidth: 82, + textAlign: 'center' + } } } }) diff --git a/src/components/NewPosition/RangeSelector/RangeSelector.tsx b/src/components/NewPosition/RangeSelector/RangeSelector.tsx index 5585b9ef..a6bd5cc0 100644 --- a/src/components/NewPosition/RangeSelector/RangeSelector.tsx +++ b/src/components/NewPosition/RangeSelector/RangeSelector.tsx @@ -15,10 +15,12 @@ import { nearestTickIndex, toMaxNumericPlaces, TokenPriceData, - getConcentrationIndex + getConcentrationIndex, + calculateConcentration } from '@utils/utils' import { getMaxTick, getMinTick } from '@invariant-labs/sdk/lib/utils' import { Button, Grid, Tooltip, Typography } from '@mui/material' +import icons from '@static/icons' export interface IRangeSelector { updatePath: (concIndex: number) => void @@ -526,7 +528,16 @@ export const RangeSelector: React.FC = ({ /> */} - Set price range + + Set price range + {positionOpeningMethod === 'range' && ( + + Concentration + Concentration + {calculateConcentration(leftRange, rightRange).toFixed(2)}x + + )} + { ...typography.caption2, textAlign: 'right', marginLeft: 4 + }, + rangeConcentration: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + backgroundColor: colors.invariant.newDark, + gap: 8, + borderRadius: 11, + padding: '6px 12px', + + '& p:first-of-type': { + color: colors.invariant.textGrey, + ...typography.body2 + }, + + '& p:last-of-type': { + color: colors.invariant.text, + ...typography.body3, + minWidth: 82, + textAlign: 'center' + } } } }) diff --git a/src/static/icons.ts b/src/static/icons.ts index 205949ed..1b6e7273 100644 --- a/src/static/icons.ts +++ b/src/static/icons.ts @@ -55,6 +55,7 @@ import telegramFill from './svg/telegramFill.svg' import githubFill from './svg/githubFill.svg' import mediumFill from './svg/MediumFill.svg' import docsFill from './svg/docsFill.svg' +import boostPoints from './svg/boostPoints.svg' const icons: { [key: string]: string } = { docsFill, @@ -113,7 +114,8 @@ const icons: { [key: string]: string } = { newTabBtn, airdrop, airdropRainbow, - audit + audit, + boostPoints } export default icons diff --git a/src/static/svg/boostPoints.svg b/src/static/svg/boostPoints.svg new file mode 100644 index 00000000..b99bbc6e --- /dev/null +++ b/src/static/svg/boostPoints.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 3fd9cc49..a6f4629a 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -7,7 +7,13 @@ import { TICK_VIRTUAL_CROSSES_PER_IX, Tickmap } from '@invariant-labs/sdk/lib/market' -import { getMaxTick, getMinTick, PRICE_SCALE, Range } from '@invariant-labs/sdk/lib/utils' +import { + CONCENTRATION_FACTOR, + getMaxTick, + getMinTick, + PRICE_SCALE, + Range +} from '@invariant-labs/sdk/lib/utils' import { Decimal, PoolStructure, Tick } from '@invariant-labs/sdk/src/market' import { calculateTickDelta, @@ -1094,8 +1100,11 @@ export const calculateConcentrationRange = ( isXToY: boolean ) => { const tickDelta = calculateTickDelta(tickSpacing, minimumRange, concentration) - const lowerTick = currentTick - (minimumRange / 2 + tickDelta) * tickSpacing - const upperTick = currentTick + (minimumRange / 2 + tickDelta) * tickSpacing + + const parsedTickDelta = Math.abs(tickDelta) === 0 ? 0 : Math.abs(tickDelta) - 1 + + const lowerTick = currentTick - (minimumRange / 2 + parsedTickDelta) * tickSpacing + const upperTick = currentTick + (minimumRange / 2 + parsedTickDelta) * tickSpacing return { leftRange: isXToY ? lowerTick : upperTick, @@ -1103,12 +1112,20 @@ export const calculateConcentrationRange = ( } } +export const calculateConcentration = (lowerTick: number, upperTick: number) => { + const deltaPrice = Math.pow(1.0001, -Math.abs(lowerTick - upperTick)) + + const denominator = 1 - Math.pow(deltaPrice, 1 / 4) + const result = 1 / denominator + + return Math.abs(result / CONCENTRATION_FACTOR) +} + export enum PositionTokenBlock { None, A, B } - export const determinePositionTokenBlock = ( currentSqrtPrice: BN, lowerTick: number,