Skip to content

Commit dbfb55b

Browse files
authored
fix: apr estimation display (#2958)
* fix: apr estimation display * fix: format number * fix: format number * fix: loading * fix: format number * fix: format amount * fix: reduce 5% native for gas * fix: amount if native token is in pair
1 parent 0e4a2b6 commit dbfb55b

File tree

14 files changed

+197
-172
lines changed

14 files changed

+197
-172
lines changed

apps/kyberswap-interface/src/components/ProgressBar/index.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@ const Wrapper = styled.div<{ height: string; width: string; background?: string
2020
background: ${({ background }) => background || 'rgba(182, 182, 182, 0.2)'};
2121
position: relative;
2222
`
23-
const Bar = styled.div<{ percent: number; color?: string; loading?: boolean }>`
23+
const Bar = styled.div<{ percent: number; color?: string; $loading?: boolean }>`
2424
border-radius: 999px;
2525
height: 100%;
26-
background: ${({ theme, color, loading }) => (loading ? theme.tableHeader : color || theme.primary)};
27-
width: ${({ percent, loading }) => (loading ? '100%' : percent + '%')};
28-
${({ percent, loading }) => !loading && percent !== 0 && 'min-width: 8px;'};
26+
background: ${({ theme, color, $loading }) => ($loading ? theme.tableHeader : color || theme.primary)};
27+
width: ${({ percent, $loading }) => ($loading ? '100%' : percent + '%')};
28+
${({ percent, $loading }) => !$loading && percent !== 0 && 'min-width: 8px;'};
2929
position: absolute;
3030
left: 0;
3131
top: 0;
3232
overflow: hidden;
3333
34-
${({ loading, theme }) =>
35-
loading
34+
${({ $loading, theme }) =>
35+
$loading
3636
? css`
3737
::after {
3838
content: '';
@@ -80,7 +80,7 @@ export default function ProgressBar({
8080
</Flex>
8181
) : null}
8282
<Wrapper height={height} width={width ?? 'unset'} background={backgroundColor}>
83-
<Bar loading={loading} percent={loading ? 0 : normalizedPercent < 0.5 ? 0 : normalizedPercent} color={color} />
83+
<Bar $loading={loading} percent={loading ? 0 : normalizedPercent < 0.5 ? 0 : normalizedPercent} color={color} />
8484
</Wrapper>
8585
</Flex>
8686
)

packages/liquidity-widgets/src/Widget.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,26 @@ export default function Widget() {
5555
<div className="mt-5 flex gap-5 max-sm:flex-col">
5656
<div className="w-[55%] max-sm:w-full">
5757
<PoolStat />
58-
<PriceInfo />
59-
{!positionId && isUniV3 && (initializing ? <LiquidityChartSkeleton /> : <LiquidityChart />)}
60-
{positionId ? <PositionPriceRange /> : <PriceRange />}
61-
{!positionId ? (
62-
isUniV3 && (
63-
<div className="flex gap-4 w-full">
64-
<PriceInput type={PriceType.MinPrice} />
65-
<PriceInput type={PriceType.MaxPrice} />
66-
</div>
67-
)
68-
) : (
69-
<>
70-
<PositionLiquidity />
71-
{isUniv4 && <PositionFee />}
72-
</>
73-
)}
74-
{!isUniV3 && <TokenInput className="mt-4" />}
75-
<PositionApr />
58+
<div className="flex flex-col gap-4 border border-stroke rounded-md px-4 py-3">
59+
<PriceInfo />
60+
{!positionId && isUniV3 && (initializing ? <LiquidityChartSkeleton /> : <LiquidityChart />)}
61+
{positionId ? <PositionPriceRange /> : <PriceRange />}
62+
{!positionId ? (
63+
isUniV3 && (
64+
<div className="flex gap-4 w-full">
65+
<PriceInput type={PriceType.MinPrice} />
66+
<PriceInput type={PriceType.MaxPrice} />
67+
</div>
68+
)
69+
) : (
70+
<>
71+
<PositionLiquidity />
72+
{isUniv4 && <PositionFee />}
73+
</>
74+
)}
75+
{!isUniV3 && <TokenInput className="mt-4" />}
76+
<PositionApr />
77+
</div>
7678
<LeftWarning />
7779
</div>
7880

packages/liquidity-widgets/src/components/Content/PriceInfo.tsx

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,30 @@ export default function PriceInfo() {
2424

2525
return (
2626
<>
27-
<div className="rounded-md border border-stroke py-3 px-4 mt-[6px]">
28-
<div className="flex justify-between">
29-
<div className="flex items-center justify-start gap-1 text-sm flex-wrap">
30-
<span className="text-subText">
31-
<Trans>Current price</Trans>
32-
</span>
33-
{initializing ? (
34-
<Skeleton className="w-20 h-5" />
35-
) : (
36-
<>
37-
<span>1</span>
38-
<TokenSymbol symbol={token0.symbol} maxWidth={100} />
39-
<span>=</span>
40-
<span>{formatDisplayNumber(poolPrice, { significantDigits: 8 })}</span>
27+
<div className="flex justify-between">
28+
<div className="flex items-center justify-start gap-1 text-sm flex-wrap">
29+
<span className="text-subText">
30+
<Trans>Current price</Trans>
31+
</span>
32+
{initializing ? (
33+
<Skeleton className="w-20 h-5" />
34+
) : (
35+
<>
36+
<span>1</span>
37+
<TokenSymbol symbol={token0.symbol} maxWidth={100} />
38+
<span>=</span>
39+
<span>{formatDisplayNumber(poolPrice, { significantDigits: 8 })}</span>
4140

42-
<TokenSymbol symbol={token1.symbol} maxWidth={100} />
43-
</>
44-
)}
45-
</div>
41+
<TokenSymbol symbol={token1.symbol} maxWidth={100} />
42+
</>
43+
)}
44+
</div>
4645

47-
<div
48-
className="flex items-center justify-center rounded-full bg-[#ffffff14] w-6 h-6"
49-
onClick={toggleRevertPrice}
50-
>
51-
<RevertPriceIcon className="cursor-pointer" role="button" />
52-
</div>
46+
<div
47+
className="flex items-center justify-center rounded-full bg-[#ffffff14] w-6 h-6"
48+
onClick={toggleRevertPrice}
49+
>
50+
<RevertPriceIcon className="cursor-pointer" role="button" />
5351
</div>
5452
</div>
5553

packages/liquidity-widgets/src/components/Content/PriceInput.tsx

Lines changed: 47 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from 'react';
33
import { Trans } from '@lingui/macro';
44

55
import { univ3PoolNormalize } from '@kyber/schema';
6-
import { Skeleton, TokenSymbol } from '@kyber/ui';
6+
import { Skeleton } from '@kyber/ui';
77
import { formatNumber } from '@kyber/utils/number';
88
import { MAX_TICK, MIN_TICK, nearestUsableTick, priceToClosestTick } from '@kyber/utils/uniswapv3';
99

@@ -106,68 +106,54 @@ export default function PriceInput({ type }: { type: PriceType }) {
106106
}, [isMaxTick, isMinTick, maxPrice, minPrice, pool, positionId, revertPrice, type]);
107107

108108
return (
109-
<div className="mt-[0.6rem] w-1/2 p-3 border rounded-md border-stroke flex flex-col gap-1 items-center">
110-
<div className="flex justify-between items-end gap-1">
111-
<button
112-
className="w-6 h-6 rounded-[4px] border border-stroke bg-layer2 text-subText flex items-center justify-center cursor-pointer hover:enabled:brightness-150 active:enabled:scale-95 disabled:cursor-not-allowed disabled:opacity-60 outline-none"
113-
role="button"
114-
onClick={handleDecreasePrice}
115-
disabled={isFullRange || positionId !== undefined}
116-
>
117-
-
118-
</button>
119-
120-
<div className="flex flex-col items-center gap-[6px] w-fit text-sm font-medium text-subText">
121-
<span>
122-
{type === PriceType.MinPrice ? (
123-
<Trans>Min price</Trans>
124-
) : type === PriceType.MaxPrice ? (
125-
<Trans>Max price</Trans>
126-
) : null}
127-
</span>
128-
{initializing ? (
129-
<Skeleton className="w-20 h-6 mx-4" />
130-
) : (
131-
<input
132-
className="bg-transparent w-[110px] text-center text-text text-base p-0 border-none outline-none disabled:cursor-not-allowed disabled:opacity-60"
133-
value={localValue}
134-
autoFocus={false}
135-
onChange={onPriceChange}
136-
onBlur={e => wrappedCorrectPrice(e.target.value)}
137-
inputMode="decimal"
138-
autoComplete="off"
139-
autoCorrect="off"
140-
disabled={positionId !== undefined}
141-
type="text"
142-
pattern="^[0-9]*[.,]?[0-9]*$"
143-
placeholder="0.0"
144-
minLength={1}
145-
maxLength={79}
146-
spellCheck="false"
147-
/>
148-
)}
149-
</div>
150-
151-
<button
152-
className="w-6 h-6 rounded-[4px] border border-stroke bg-layer2 text-subText flex items-center justify-center cursor-pointer hover:enabled:brightness-150 active:enabled:scale-95 disabled:cursor-not-allowed disabled:opacity-60 outline-none"
153-
onClick={handleIncreasePrice}
154-
disabled={isFullRange || positionId !== undefined}
155-
>
156-
+
157-
</button>
109+
<div className="w-full flex items-center justify-center gap-2 rounded-sm px-2 bg-[#ffffff0a] flex-1 min-w-0">
110+
<button
111+
className="w-6 h-6 !rounded-[4px] border border-stroke bg-layer2 text-subText flex items-center justify-center cursor-pointer hover:enabled:brightness-150 active:enabled:scale-95 disabled:cursor-not-allowed disabled:opacity-60 outline-none"
112+
role="button"
113+
onClick={handleDecreasePrice}
114+
disabled={isFullRange || positionId !== undefined}
115+
>
116+
-
117+
</button>
118+
119+
<div className="flex flex-col items-center py-2 flex-1 min-w-0 gap-1">
120+
<p className="text-sm text-subText whitespace-nowrap">
121+
{type === PriceType.MinPrice ? (
122+
<Trans>Min price</Trans>
123+
) : type === PriceType.MaxPrice ? (
124+
<Trans>Max price</Trans>
125+
) : null}
126+
</p>
127+
{initializing ? (
128+
<Skeleton className="w-20 h-6 mx-4" />
129+
) : (
130+
<input
131+
className="bg-transparent text-text text-center border-none outline-none max-w-[200px] md:max-w-[80px] w-full"
132+
value={localValue}
133+
autoFocus={false}
134+
onChange={onPriceChange}
135+
onBlur={e => wrappedCorrectPrice(e.target.value)}
136+
inputMode="decimal"
137+
autoComplete="off"
138+
autoCorrect="off"
139+
disabled={positionId !== undefined}
140+
type="text"
141+
pattern="^[0-9]*[.,]?[0-9]*$"
142+
placeholder="0.0"
143+
minLength={1}
144+
maxLength={79}
145+
spellCheck="false"
146+
/>
147+
)}
158148
</div>
159149

160-
{initializing ? (
161-
<Skeleton className="w-24 h-5 mt-1" />
162-
) : (
163-
<div className="w-max text-sm font-medium text-subText flex items-center gap-1">
164-
<Trans>
165-
<TokenSymbol symbol={!revertPrice ? pool.token1.symbol : pool.token0.symbol} maxWidth={80} />
166-
<span>per</span>
167-
<TokenSymbol symbol={!revertPrice ? pool.token0.symbol : pool.token1.symbol} maxWidth={80} />
168-
</Trans>
169-
</div>
170-
)}
150+
<button
151+
className="w-6 h-6 !rounded-[4px] border border-stroke bg-layer2 text-subText flex items-center justify-center cursor-pointer hover:enabled:brightness-150 active:enabled:scale-95 disabled:cursor-not-allowed disabled:opacity-60 outline-none"
152+
onClick={handleIncreasePrice}
153+
disabled={isFullRange || positionId !== undefined}
154+
>
155+
+
156+
</button>
171157
</div>
172158
);
173159
}

packages/liquidity-widgets/src/components/LiquidityChart/LiquidityChartSkeleton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const barColors = ['bg-layer2', 'bg-layer2'];
44

55
export default function LiquidityChartSkeleton() {
66
return (
7-
<div className="w-full h-[180px] pt-2 mt-4 relative rounded-md flex flex-col justify-end overflow-hidden">
7+
<div className="w-full h-[180px] pt-2 relative rounded-md flex flex-col justify-end overflow-hidden">
88
{/* Axis */}
99
<div className="absolute bottom-0 left-0 w-full h-[2px] bg-layer2 z-[1]" />
1010
{/* Bars */}

packages/liquidity-widgets/src/components/LiquidityChart/index.tsx

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -123,35 +123,33 @@ export default function LiquidityChart() {
123123
);
124124

125125
return (
126-
<div className="mt-4">
127-
<LiquidityChartRangeInput
128-
id="zap-widget-liquidity-chart"
129-
pool={{
130-
fee,
131-
tickCurrent,
132-
tickSpacing,
133-
ticks,
134-
liquidity,
135-
token0,
136-
token1,
137-
category,
138-
}}
139-
price={{
140-
current: poolPrice ?? undefined,
141-
lower: minPrice,
142-
upper: maxPrice,
143-
}}
144-
ticksAtLimit={ticksAtLimit}
145-
revertPrice={revertPrice}
146-
onBrushDomainChange={onBrushDomainChange}
147-
zoomPosition={{
148-
top: '0px',
149-
left: undefined,
150-
right: '0px',
151-
bottom: undefined,
152-
gap: '8px',
153-
}}
154-
/>
155-
</div>
126+
<LiquidityChartRangeInput
127+
id="zap-widget-liquidity-chart"
128+
pool={{
129+
fee,
130+
tickCurrent,
131+
tickSpacing,
132+
ticks,
133+
liquidity,
134+
token0,
135+
token1,
136+
category,
137+
}}
138+
price={{
139+
current: poolPrice ?? undefined,
140+
lower: minPrice,
141+
upper: maxPrice,
142+
}}
143+
ticksAtLimit={ticksAtLimit}
144+
revertPrice={revertPrice}
145+
onBrushDomainChange={onBrushDomainChange}
146+
zoomPosition={{
147+
top: '0px',
148+
left: undefined,
149+
right: '0px',
150+
bottom: undefined,
151+
gap: '8px',
152+
}}
153+
/>
156154
);
157155
}

packages/liquidity-widgets/src/components/PositionApr.tsx

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Trans } from '@lingui/macro';
22

3-
import { defaultTheme } from '@kyber/schema';
4-
import { InfoHelper, Skeleton } from '@kyber/ui';
3+
import { MouseoverTooltip, Skeleton } from '@kyber/ui';
54
import { formatAprNumber } from '@kyber/utils/number';
65

76
import { useEstimatedPositionApr } from '@/hooks/useEstimatedPositionApr';
@@ -64,23 +63,19 @@ export const PositionApr = () => {
6463
if (!pool?.isFarming) return null;
6564

6665
return (
67-
<div className="flex items-center justify-end text-sm mt-2 gap-2">
68-
<div className="text-subText">
69-
<Trans>Est. Position APR</Trans>
70-
</div>
71-
{loading && !data ? (
72-
<Skeleton className="w-16 h-5" />
73-
) : (
74-
<div className="flex items-center" style={{ color: defaultTheme.blue }}>
75-
{!data ? '--' : data.totalApr === 0 ? '~0%' : `${formatAprNumber(data.totalApr)}%`}
76-
<InfoHelper
77-
placement="top"
78-
width={!data ? 'fit-content' : '320px'}
79-
color={defaultTheme.blue}
80-
text={tooltipContent}
81-
/>
66+
<MouseoverTooltip placement="top" width={!data ? 'fit-content' : '320px'} text={tooltipContent}>
67+
<div className="flex items-center justify-start text-sm gap-2 bg-accent-100 rounded-[12px] px-3.5 py-2 w-full">
68+
<div className="text-text">
69+
<Trans>Est. Position APR</Trans>
8270
</div>
83-
)}
84-
</div>
71+
{loading && !data ? (
72+
<Skeleton className="w-16 h-5" />
73+
) : (
74+
<p className="text-accent">
75+
{!data ? '--' : data.totalApr === 0 ? '~0%' : `${formatAprNumber(data.totalApr)}%`}
76+
</p>
77+
)}
78+
</div>
79+
</MouseoverTooltip>
8580
);
8681
};

packages/liquidity-widgets/src/components/PositionFee.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const PositionFee = () => {
4646
if (!hasFee || !feeToken0 || !feeToken1) return null;
4747

4848
return (
49-
<div className="px-4 py-3 mt-4 border border-stroke rounded-md">
49+
<div className="px-4 py-3 border border-stroke rounded-md">
5050
<p className="text-subText mb-4 text-sm">
5151
<Trans>Your Position Fee</Trans>
5252
</p>

packages/liquidity-widgets/src/components/PositionLiquidity/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const PositionLiquidity = () => {
1717
const amount1 = positionNotExist ? '0' : formatTokenAmount(position.amount1, pool.token1.decimals, 6);
1818

1919
return (
20-
<div className="px-4 py-3 mt-4 border border-stroke rounded-md">
20+
<div className="px-4 py-3 border border-stroke rounded-md">
2121
<p className="text-subText mb-4 text-sm">
2222
<Trans>Your Position Liquidity</Trans>
2323
</p>

0 commit comments

Comments
 (0)