Skip to content

Commit 6609b15

Browse files
authored
Fix broken Rewards tooltip due to missing chainId (#1438)
1 parent 5eaa737 commit 6609b15

File tree

4 files changed

+341
-329
lines changed

4 files changed

+341
-329
lines changed
Lines changed: 2 additions & 325 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,6 @@
1-
import { fixed } from "@delvtech/fixed-point-wasm";
2-
import { ClockIcon } from "@heroicons/react/24/outline";
3-
import { HyperdriveConfig, findBaseToken } from "@hyperdrive/appconfig";
4-
import { Link, useNavigate } from "@tanstack/react-router";
5-
import classNames from "classnames";
6-
import { ReactElement, ReactNode } from "react";
7-
import Skeleton from "react-loading-skeleton";
8-
import { formatRate } from "src/base/formatRate";
9-
import { isTestnetChain } from "src/chains/isTestnetChain";
10-
import { useAppConfig } from "src/ui/appconfig/useAppConfig";
11-
import { Well } from "src/ui/base/components/Well/Well";
12-
import { formatCompact } from "src/ui/base/formatting/formatCompact";
13-
import { useIsNewPool } from "src/ui/hyperdrive/hooks/useIsNewPool";
14-
import { useLpApy } from "src/ui/hyperdrive/hooks/useLpApy";
15-
import { usePresentValue } from "src/ui/hyperdrive/hooks/usePresentValue";
16-
import { useFixedRate } from "src/ui/hyperdrive/longs/hooks/useFixedRate";
1+
import { ReactElement } from "react";
172
import { Hero } from "src/ui/landing/Hero/Hero";
18-
import { AssetStack } from "src/ui/markets/AssetStack";
19-
import { formatTermLength2 } from "src/ui/markets/formatTermLength";
20-
import { MARKET_DETAILS_ROUTE } from "src/ui/markets/routes";
21-
import { RewardsTooltip } from "src/ui/rewards/RewardsTooltip";
22-
import { useTokenFiatPrice } from "src/ui/token/hooks/useTokenFiatPrice";
23-
import { useYieldSourceRate } from "src/ui/vaults/useYieldSourceRate";
3+
import { PoolRows } from "src/ui/markets/PoolRow/PoolRows";
244

255
export function Landing(): ReactElement | null {
266
return (
@@ -49,306 +29,3 @@ export function Landing(): ReactElement | null {
4929
</div>
5030
);
5131
}
52-
53-
function PoolRows() {
54-
const appConfig = useAppConfig();
55-
return (
56-
<div className="flex w-full flex-col gap-5">
57-
{
58-
// Show the newest pools first
59-
[...appConfig.hyperdrives]
60-
.sort(
61-
(a, b) =>
62-
Number(b.initializationBlock) - Number(a.initializationBlock),
63-
)
64-
.map((hyperdrive) => (
65-
<PoolRow
66-
// Combine address and chainId for a unique key, as addresses may overlap across chains (e.g. cloudchain and mainnet)
67-
key={`${hyperdrive.address}-${hyperdrive.chainId}`}
68-
hyperdrive={hyperdrive}
69-
/>
70-
))
71-
}
72-
</div>
73-
);
74-
}
75-
function PoolRow({ hyperdrive }: { hyperdrive: HyperdriveConfig }) {
76-
const navigate = useNavigate();
77-
const appConfig = useAppConfig();
78-
const { yieldSources, chains } = appConfig;
79-
80-
const chainInfo = chains[hyperdrive.chainId];
81-
const { fixedApr, fixedRateStatus } = useFixedRate({
82-
chainId: hyperdrive.chainId,
83-
hyperdriveAddress: hyperdrive.address,
84-
});
85-
const { vaultRate, vaultRateStatus } = useYieldSourceRate({
86-
chainId: hyperdrive.chainId,
87-
hyperdriveAddress: hyperdrive.address,
88-
});
89-
const { lpApy, lpApyStatus } = useLpApy({
90-
hyperdriveAddress: hyperdrive.address,
91-
chainId: hyperdrive.chainId,
92-
});
93-
94-
// if the pool was deployed less than one historical period ago, it's new.
95-
const isYoungerThanOneDay = useIsNewPool({ hyperdrive });
96-
97-
const isLpApyNew =
98-
isYoungerThanOneDay || (lpApyStatus !== "loading" && lpApy === undefined);
99-
100-
// Display TVL as base value on testnet due to lack of reliable fiat pricing.
101-
// On mainnet and others, use DeFiLlama's fiat price.
102-
const { presentValue } = usePresentValue({
103-
chainId: hyperdrive.chainId,
104-
hyperdriveAddress: hyperdrive.address,
105-
});
106-
const isFiatPriceEnabled = !isTestnetChain(chainInfo.id);
107-
const baseToken = findBaseToken({
108-
hyperdriveChainId: hyperdrive.chainId,
109-
hyperdriveAddress: hyperdrive.address,
110-
appConfig,
111-
});
112-
const { fiatPrice } = useTokenFiatPrice({
113-
chainId: baseToken.chainId,
114-
tokenAddress: isFiatPriceEnabled
115-
? hyperdrive.poolConfig.baseToken
116-
: undefined,
117-
});
118-
let tvlLabel = `${formatCompact({
119-
value: presentValue || 0n,
120-
decimals: hyperdrive.decimals,
121-
})} ${baseToken.symbol}`;
122-
123-
if (isFiatPriceEnabled) {
124-
const presentValueFiat =
125-
presentValue && fiatPrice && isFiatPriceEnabled
126-
? fixed(presentValue, hyperdrive.decimals).mul(fiatPrice).bigint
127-
: 0n;
128-
tvlLabel = `$${formatCompact({
129-
value: presentValueFiat || 0n,
130-
decimals: hyperdrive.decimals,
131-
})}`;
132-
}
133-
134-
return (
135-
<Well
136-
block
137-
onClick={() => {
138-
navigate({
139-
to: MARKET_DETAILS_ROUTE,
140-
resetScroll: true,
141-
params: {
142-
address: hyperdrive.address,
143-
chainId: hyperdrive.chainId.toString(),
144-
},
145-
});
146-
}}
147-
>
148-
<div className="flex flex-col justify-between gap-6 lg:flex-row lg:gap-4">
149-
{/* Left side */}
150-
<div className="flex items-center gap-6 lg:w-[440px]">
151-
<div
152-
className={
153-
// Set a fixed width so pools with one or two asset icons still
154-
// line up
155-
"w-16"
156-
}
157-
>
158-
<AssetStack hyperdriveAddress={hyperdrive.address} />
159-
</div>
160-
<div className="flex flex-col gap-1">
161-
<h4 className="text-left">
162-
{yieldSources[hyperdrive.yieldSource].shortName}
163-
</h4>
164-
<div className="flex flex-wrap gap-5 gap-y-2">
165-
<div className="flex items-center gap-1.5 text-sm">
166-
<ClockIcon className="size-4 text-gray-500" />{" "}
167-
<span className="text-neutral-content">
168-
{formatTermLength2(
169-
Number(hyperdrive.poolConfig.positionDuration * 1000n),
170-
)}
171-
</span>
172-
</div>
173-
<div className="flex items-center gap-1.5 text-sm">
174-
<span className="text-gray-500">TVL</span>{" "}
175-
<span className="font-dmMono text-neutral-content">
176-
{tvlLabel}
177-
</span>
178-
</div>
179-
<div className="flex items-center gap-1.5 text-sm">
180-
<img className="size-4 rounded-full" src={chainInfo.iconUrl} />
181-
<span className="text-neutral-content">{chainInfo.name}</span>
182-
</div>
183-
</div>
184-
</div>
185-
</div>
186-
187-
{/* Right side */}
188-
<div className="flex shrink-0 justify-between gap-10 lg:items-end lg:justify-start">
189-
<PoolStat
190-
label={"Fixed APR"}
191-
isLoading={fixedRateStatus === "loading"}
192-
value={
193-
fixedApr ? (
194-
<PercentLabel value={formatRate(fixedApr.apr, 18, false)} />
195-
) : (
196-
"-"
197-
)
198-
}
199-
variant="gradient"
200-
action={
201-
<Link
202-
to="/market/$chainId/$address"
203-
params={{
204-
address: hyperdrive.address,
205-
chainId: hyperdrive.chainId.toString(),
206-
}}
207-
search={{ position: "longs" }}
208-
className="daisy-btn daisy-btn-sm rounded-full bg-gray-600"
209-
onClick={(e) => {
210-
e.stopPropagation();
211-
}}
212-
>
213-
Long
214-
</Link>
215-
}
216-
/>
217-
<PoolStat
218-
label={"Variable APY"}
219-
isNew={isLpApyNew}
220-
isLoading={vaultRateStatus === "loading"}
221-
value={
222-
vaultRate ? (
223-
<RewardsTooltip
224-
hyperdriveAddress={hyperdrive.address}
225-
chainId={hyperdrive.chainId}
226-
positionType="short"
227-
>
228-
<PercentLabel
229-
value={formatRate(vaultRate.vaultRate, 18, false)}
230-
/>
231-
</RewardsTooltip>
232-
) : (
233-
"-"
234-
)
235-
}
236-
action={
237-
<Link
238-
to="/market/$chainId/$address"
239-
params={{
240-
address: hyperdrive.address,
241-
chainId: hyperdrive.chainId.toString(),
242-
}}
243-
search={{ position: "shorts" }}
244-
className="daisy-btn daisy-btn-sm rounded-full bg-gray-600"
245-
onClick={(e) => {
246-
e.stopPropagation();
247-
}}
248-
>
249-
Short
250-
</Link>
251-
}
252-
/>
253-
<PoolStat
254-
label={`LP APY (${yieldSources[hyperdrive.yieldSource].historicalRatePeriod}d)`}
255-
isLoading={lpApyStatus === "loading"}
256-
isNew={isLpApyNew}
257-
value={
258-
// TODO: Fix useLpApy to have the same interface as
259-
// useYieldSourceRate and useFixedRate
260-
lpApy && !isLpApyNew ? (
261-
<RewardsTooltip
262-
positionType="lp"
263-
chainId={hyperdrive.chainId}
264-
hyperdriveAddress={hyperdrive.address}
265-
>
266-
<PercentLabel value={`${(lpApy * 100).toFixed(2)}`} />
267-
</RewardsTooltip>
268-
) : (
269-
"-"
270-
)
271-
}
272-
action={
273-
<Link
274-
to="/market/$chainId/$address"
275-
params={{
276-
address: hyperdrive.address,
277-
chainId: hyperdrive.chainId.toString(),
278-
}}
279-
search={{ position: "lp" }}
280-
className="daisy-btn daisy-btn-sm rounded-full bg-gray-600"
281-
onClick={(e) => {
282-
e.stopPropagation();
283-
}}
284-
>
285-
Supply
286-
</Link>
287-
}
288-
/>
289-
</div>
290-
</div>
291-
</Well>
292-
);
293-
}
294-
295-
function PoolStat({
296-
label,
297-
labelTooltip,
298-
value,
299-
isNew = false,
300-
variant = "default",
301-
isLoading = false,
302-
action,
303-
}: {
304-
label: string;
305-
labelTooltip?: string;
306-
value: ReactNode;
307-
isLoading?: boolean;
308-
isNew?: boolean;
309-
variant?: "default" | "gradient";
310-
action?: ReactNode;
311-
}): ReactElement {
312-
let displayValue;
313-
if (isLoading) {
314-
displayValue = <Skeleton width={70} />;
315-
} else if (isNew) {
316-
displayValue = "✨New✨";
317-
} else {
318-
displayValue = value;
319-
}
320-
321-
return (
322-
<div className="flex w-24 flex-col items-start gap-1.5">
323-
<p
324-
data-tip={labelTooltip}
325-
className={
326-
"group daisy-tooltip cursor-help text-sm text-neutral-content before:z-40 before:max-w-56 before:p-2 before:text-start"
327-
}
328-
>
329-
{label}
330-
</p>
331-
<div
332-
className={classNames("font-dmMono text-h4 font-medium", {
333-
"gradient-text": variant === "gradient",
334-
})}
335-
>
336-
{displayValue}
337-
</div>
338-
<div>{action}</div>
339-
</div>
340-
);
341-
}
342-
343-
function PercentLabel({ value }: { value: string }) {
344-
return (
345-
<div
346-
className={classNames(
347-
"font-dmMono text-h4 font-medium",
348-
"after:text-h5 after:content-['%']",
349-
)}
350-
>
351-
{value}
352-
</div>
353-
);
354-
}

0 commit comments

Comments
 (0)