Skip to content

Commit ae72b83

Browse files
ZapBasedPreview (#1745)
* preview close long form updated * Refactor testnet chain detection and token fiat price query * fix preview * fix preview Co-authored-by: Danny Delott <[email protected]> * update query key * move toast inside query client provider * uniqu by --------- Co-authored-by: Danny Delott <[email protected]>
1 parent 02ec97a commit ae72b83

File tree

9 files changed

+133
-14
lines changed

9 files changed

+133
-14
lines changed

apps/hyperdrive-trading/src/chains/isTestnetChain.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@ import { foundry, sepolia } from "viem/chains";
55
* Checks if the given chain ID corresponds to a testnet chain.
66
* @param chainId - The chain ID to check.
77
* @returns True if the chain ID corresponds to a testnet chain, false otherwise.
8+
* @deprecated testnet chains should not include a check on fork chains, use isTestnetChain2 instead
89
*/
910
export function isTestnetChain(chainId: number): boolean {
1011
const testnetChainIds = [sepolia.id, foundry.id] as number[];
1112
return isForkChain(chainId) || testnetChainIds.includes(chainId);
1213
}
14+
15+
export function isTestnetChain2(chainId: number): boolean {
16+
const testnetChainIds = [sepolia.id, foundry.id] as number[];
17+
return testnetChainIds.includes(chainId);
18+
}

apps/hyperdrive-trading/src/ui/appconfig/useAppConfigForConnectedChain.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,33 @@ import {
44
mainnetAppConfig,
55
testnetAppConfig,
66
} from "@delvtech/hyperdrive-appconfig";
7+
import uniqBy from "lodash.uniqby";
8+
import { useFeatureFlag } from "src/ui/base/featureFlags/featureFlags";
9+
import { useTokenList } from "src/ui/tokenlist/useTokenList";
710
import { useChainId } from "wagmi";
811

912
export function useAppConfigForConnectedChain(): AppConfig {
1013
const connectedChainId = useChainId();
1114

12-
return isMainnetChain(connectedChainId) ? mainnetAppConfig : testnetAppConfig;
15+
const appConfig = isMainnetChain(connectedChainId)
16+
? mainnetAppConfig
17+
: testnetAppConfig;
18+
19+
// Add any zap tokens to the appConfig using uniswap's tokenlist
20+
const { isFlagEnabled } = useFeatureFlag("zaps");
21+
const { tokenList } = useTokenList({
22+
chainId: connectedChainId,
23+
enabled: isFlagEnabled,
24+
});
25+
if (tokenList) {
26+
return {
27+
...appConfig,
28+
tokens: uniqBy(
29+
[...appConfig.tokens, ...tokenList],
30+
(token) => `${token.address}-${token.chainId}`,
31+
),
32+
};
33+
}
34+
35+
return appConfig;
1336
}

apps/hyperdrive-trading/src/ui/hyperdrive/longs/CloseLongForm/CloseLongForm.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export function CloseLongForm({
128128
chainId: hyperdrive.chainId,
129129
hyperdriveAddress: hyperdrive.address,
130130
maturityTime: long.maturity,
131+
tokenOutAddress: activeWithdrawToken.address,
131132
bondAmountIn: bondAmountAsBigInt,
132133
asBase: activeWithdrawToken.address === hyperdrive.poolConfig.baseToken,
133134
});

apps/hyperdrive-trading/src/ui/hyperdrive/longs/hooks/usePreviewCloseLong.ts

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
import { fixed } from "@delvtech/fixed-point-wasm";
2+
import {
3+
getBaseToken,
4+
getHyperdriveConfig,
5+
} from "@delvtech/hyperdrive-appconfig";
16
import { useQuery } from "@tanstack/react-query";
2-
import { makeQueryKey } from "src/base/makeQueryKey";
7+
import { makeQueryKey2 } from "src/base/makeQueryKey";
38
import { QueryStatusWithIdle, getStatus } from "src/base/queryStatus";
9+
import { getDepositAssets } from "src/hyperdrive/getDepositAssets";
410
import { useAppConfigForConnectedChain } from "src/ui/appconfig/useAppConfigForConnectedChain";
511
import { prepareSharesOut } from "src/ui/hyperdrive/hooks/usePrepareSharesOut";
612
import { useReadHyperdrive } from "src/ui/hyperdrive/hooks/useReadHyperdrive";
13+
import { useTokenFiatPrice } from "src/ui/token/hooks/useTokenFiatPrice";
714
import { Address } from "viem";
815
interface UsePreviewCloseLongOptions {
916
chainId: number;
@@ -13,6 +20,7 @@ interface UsePreviewCloseLongOptions {
1320
*/
1421
maturityTime: bigint | undefined;
1522
bondAmountIn: bigint | undefined;
23+
tokenOutAddress: Address | undefined;
1624
asBase?: boolean;
1725
enabled?: boolean;
1826
}
@@ -27,6 +35,7 @@ interface UsePreviewCloseLongResult {
2735
export function usePreviewCloseLong({
2836
hyperdriveAddress,
2937
chainId,
38+
tokenOutAddress,
3039
maturityTime,
3140
bondAmountIn,
3241
asBase = true,
@@ -39,29 +48,96 @@ export function usePreviewCloseLong({
3948
const appConfig = useAppConfigForConnectedChain();
4049
const queryEnabled =
4150
!!hyperdriveAddress &&
42-
!!appConfig &&
4351
!!maturityTime &&
4452
!!bondAmountIn &&
4553
!!readHyperdrive &&
54+
!!tokenOutAddress &&
4655
enabled;
4756

57+
const baseToken = getBaseToken({
58+
hyperdriveChainId: chainId,
59+
hyperdriveAddress: hyperdriveAddress!,
60+
appConfig,
61+
});
62+
63+
const hyperdriveConfig = getHyperdriveConfig({
64+
hyperdriveChainId: chainId,
65+
hyperdriveAddress: hyperdriveAddress!,
66+
appConfig,
67+
});
68+
69+
const depositAssets = getDepositAssets(hyperdriveConfig, appConfig);
70+
const isZapping = !depositAssets.some(
71+
(asset) => asset.address === tokenOutAddress,
72+
);
73+
74+
// If we're zapping, we'll need to convert the zap token to fiat and then into
75+
// base so we can correctly preview the tx using the sdk. To do this, we need
76+
// the fiat price of both the zap and base token
77+
const { fiatPrice: zapTokenPrice } = useTokenFiatPrice({
78+
tokenAddress: tokenOutAddress,
79+
chainId,
80+
enabled: isZapping,
81+
});
82+
83+
const { fiatPrice: baseTokenPrice } = useTokenFiatPrice({
84+
tokenAddress: baseToken.address,
85+
chainId,
86+
enabled: isZapping,
87+
});
88+
4889
const { data, status, fetchStatus, error } = useQuery({
49-
queryKey: makeQueryKey("previewCloseLong", {
50-
chainId,
51-
hyperdriveAddress,
52-
maturityTime: maturityTime?.toString(),
53-
bondAmountIn: bondAmountIn?.toString(),
54-
asBase,
90+
queryKey: makeQueryKey2({
91+
namespace: "hyperdrive",
92+
queryId: "previewCloseLong",
93+
params: {
94+
chainId,
95+
hyperdriveAddress: hyperdriveAddress!,
96+
maturityTime,
97+
bondAmountIn,
98+
asBase,
99+
zapTokenPrice,
100+
baseTokenPrice,
101+
tokenOutAddress,
102+
},
55103
}),
56104
enabled: queryEnabled,
57105
queryFn: queryEnabled
58106
? async () => {
107+
if (isZapping) {
108+
const resultInBase = await readHyperdrive.previewCloseLong({
109+
maturityTime,
110+
bondAmountIn,
111+
asBase: true, // Safe to hardcode to true because previewCloseLong uses the Rust SDK, which doesn't perform checks on if the pool has a base or shares token
112+
});
113+
114+
// Step 1: Calculate fiat value of the base amount
115+
const fiatValueOfAmountOut = baseTokenPrice
116+
? fixed(baseTokenPrice).mul(
117+
resultInBase.amountOut,
118+
hyperdriveConfig.decimals,
119+
)
120+
: 0n;
121+
122+
// Step 2: Convert that fiat value into the ZAP token amount
123+
const zapAmountOut = zapTokenPrice
124+
? fixed(fiatValueOfAmountOut).div(
125+
zapTokenPrice,
126+
hyperdriveConfig.decimals,
127+
)
128+
: 0n;
129+
130+
return {
131+
...resultInBase,
132+
amountOut: zapAmountOut ? zapAmountOut.bigint : 0n,
133+
};
134+
}
135+
59136
const result = await readHyperdrive.previewCloseLong({
60137
maturityTime,
61138
bondAmountIn,
62139
asBase,
63140
});
64-
65141
if (!asBase) {
66142
return {
67143
...result,

apps/hyperdrive-trading/src/ui/hyperdrive/queryKeys.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ interface HyperdriveQueryKeys {
2323
hyperdriveAddress: Address;
2424
blockNumber: bigint | undefined;
2525
};
26+
previewCloseLong: {
27+
chainId: number;
28+
hyperdriveAddress: Address;
29+
maturityTime: bigint | undefined;
30+
bondAmountIn: bigint | undefined;
31+
asBase: boolean;
32+
zapTokenPrice: bigint | undefined;
33+
baseTokenPrice: bigint | undefined;
34+
tokenOutAddress: Address | undefined;
35+
};
2636
}
2737
declare module "src/base/makeQueryKey" {
2838
interface QueryKeys {

apps/hyperdrive-trading/src/ui/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ logAppVersion();
3737
root.render(
3838
<WagmiProvider config={wagmiConfig}>
3939
<Plausible />
40-
<ToastProvider />
4140
<QueryClientProvider client={queryClient}>
41+
<ToastProvider />
4242
<RainbowKitProvider
4343
appInfo={{
4444
appName: "Hyperdrive",

apps/hyperdrive-trading/src/ui/portfolio/longs/OpenLongsTable/CurrentValueCell.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function CurrentValueCell({
3232
hyperdriveAddress: hyperdrive.address,
3333
maturityTime: row.maturity,
3434
bondAmountIn: row.details?.bondAmount || 0n,
35+
tokenOutAddress: baseToken.address,
3536
});
3637

3738
const currentValueLabel = formatBalance({

apps/hyperdrive-trading/src/ui/token/hooks/useTokenFiatPrice.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useQuery, UseQueryOptions } from "@tanstack/react-query";
33
import { getPublicClient } from "@wagmi/core";
44
import { ZERO_ADDRESS } from "src/base/constants";
55
import { makeQueryKey2 } from "src/base/makeQueryKey";
6-
import { isTestnetChain } from "src/chains/isTestnetChain";
6+
import { isTestnetChain2 } from "src/chains/isTestnetChain";
77
import { wagmiConfig } from "src/network/wagmiClient";
88
import { useAppConfigForConnectedChain } from "src/ui/appconfig/useAppConfigForConnectedChain";
99
import { Address, PublicClient } from "viem";
@@ -20,10 +20,11 @@ export function useTokenFiatPrice({
2020
} {
2121
const appConfig = useAppConfigForConnectedChain();
2222
const { data } = useQuery(
23-
makeTokenFiatPriceQuery({ appConfig, chainId, tokenAddress, enabled }),
23+
makeTokenFiatPriceQuery({ chainId, tokenAddress, enabled, appConfig }),
2424
);
2525
return { fiatPrice: data };
2626
}
27+
2728
export function makeTokenFiatPriceQuery({
2829
appConfig,
2930
chainId,
@@ -36,7 +37,7 @@ export function makeTokenFiatPriceQuery({
3637
enabled?: boolean;
3738
}): UseQueryOptions<bigint> {
3839
const queryEnabled =
39-
!isTestnetChain(chainId) &&
40+
!isTestnetChain2(chainId) &&
4041
!!tokenAddress &&
4142
tokenAddress !== ZERO_ADDRESS &&
4243
enabled;

packages/hyperdrive-appconfig/src/tokens/priceOracles/defillama.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const defiLlamaChainNameIdentifier: Record<number, string> = {
99
[gnosis.id]: "gnosis",
1010
[linea.id]: "linea",
1111
[base.id]: "base",
12+
[707]: "ethereum",
1213
};
1314

1415
export const fetchDefiLlamaTokenPrice: PriceOracleFn = async ({

0 commit comments

Comments
 (0)