= {
export function PoolRow({ hyperdrive }: PoolRowProps): ReactElement {
const navigate = useNavigate();
const appConfig = useAppConfigForConnectedChain();
+ const { isFlagEnabled: isNewDesign } = useFeatureFlag("new-design");
const { chains } = appConfig;
const chainInfo = chains[hyperdrive.chainId];
@@ -175,13 +177,29 @@ export function PoolRow({ hyperdrive }: PoolRowProps): ReactElement {
{/* Right side */}
-
+
-
+
-
diff --git a/apps/hyperdrive-trading/src/ui/markets/PoolRow/PoolStat.tsx b/apps/hyperdrive-trading/src/ui/markets/PoolRow/PoolStat.tsx
index 69e253bd0..f3aa1943c 100644
--- a/apps/hyperdrive-trading/src/ui/markets/PoolRow/PoolStat.tsx
+++ b/apps/hyperdrive-trading/src/ui/markets/PoolRow/PoolStat.tsx
@@ -12,6 +12,11 @@ export interface PoolStatProps {
overlay?: ReactNode;
value: ReactNode;
isLoading?: boolean;
+
+ /**
+ * @deprecated
+ */
+ action?: ReactNode;
isNew?: boolean;
variant?: "default" | "gradient";
}
@@ -22,6 +27,7 @@ export function PoolStat({
overlay,
isNew = false,
variant = "default",
+ action,
isLoading = false,
}: PoolStatProps): ReactElement {
let displayValue;
@@ -43,6 +49,7 @@ export function PoolStat({
>
{displayValue}
+ {action}
);
diff --git a/apps/hyperdrive-trading/src/ui/markets/PoolRow/VariableApyCta.tsx b/apps/hyperdrive-trading/src/ui/markets/PoolRow/VariableApyCta.tsx
index 7cd53ef4b..1d1122461 100644
--- a/apps/hyperdrive-trading/src/ui/markets/PoolRow/VariableApyCta.tsx
+++ b/apps/hyperdrive-trading/src/ui/markets/PoolRow/VariableApyCta.tsx
@@ -2,6 +2,9 @@ import { fixed } from "@delvtech/fixed-point-wasm";
import { HyperdriveConfig } from "@delvtech/hyperdrive-appconfig";
import { Link } from "@tanstack/react-router";
import { ReactElement } from "react";
+import { calculateMarketYieldMultiplier } from "src/hyperdrive/calculateMarketYieldMultiplier";
+import { useFeatureFlag } from "src/ui/base/featureFlags/featureFlags";
+import { useCurrentLongPrice } from "src/ui/hyperdrive/longs/hooks/useCurrentLongPrice";
import { PoolStat } from "src/ui/markets/PoolRow/PoolStat";
import { VariableApyStat } from "src/ui/markets/PoolRow/VariableApyStat";
import { useOpenShortRewards } from "src/ui/rewards/hooks/useOpenShortRewards";
@@ -17,12 +20,23 @@ export function VariableApyCta({
hyperdrive,
}: YieldMultiplierCtaProps): ReactElement {
const { address: account } = useAccount();
+ const { isFlagEnabled: isNewDesign } = useFeatureFlag("new-design");
const { vaultRate: yieldSourceRate } = useYieldSourceRate({
chainId: hyperdrive.chainId,
hyperdriveAddress: hyperdrive.address,
});
+
const { rewards } = useOpenShortRewards({ hyperdriveConfig: hyperdrive });
+ const { longPrice, longPriceStatus } = useCurrentLongPrice({
+ chainId: hyperdrive.chainId,
+ hyperdriveAddress: hyperdrive.address,
+ });
+ const multiplier =
+ longPriceStatus === "success" && longPrice
+ ? calculateMarketYieldMultiplier(longPrice)
+ : undefined;
+
const label = yieldSourceRate
? `Variable APY (${yieldSourceRate.ratePeriodDays}d)`
: "Variable APY";
@@ -70,6 +84,37 @@ export function VariableApyCta({
chainId={hyperdrive.chainId}
/>
}
+ action={
+
+ {isNewDesign ? null : (
+ {
+ e.stopPropagation();
+ window.plausible("positionCtaClick", {
+ props: {
+ chainId: hyperdrive.chainId,
+ poolAddress: hyperdrive.address,
+ positionType: "short",
+ statName: label,
+ statValue: multiplier ? multiplier.toString() : "",
+ connectedWallet: account,
+ },
+ });
+ }}
+ >
+ Open Short
+
+ )}
+ {`${multiplier?.format({ decimals: 0 })}x yield exposure`}
+
+ }
/>
);
diff --git a/apps/hyperdrive-trading/src/ui/markets/PoolRow/VariableApyStat.tsx b/apps/hyperdrive-trading/src/ui/markets/PoolRow/VariableApyStat.tsx
index 865a5e028..88373a057 100644
--- a/apps/hyperdrive-trading/src/ui/markets/PoolRow/VariableApyStat.tsx
+++ b/apps/hyperdrive-trading/src/ui/markets/PoolRow/VariableApyStat.tsx
@@ -3,9 +3,7 @@ import { getHyperdriveConfig } from "@delvtech/hyperdrive-appconfig";
import { ReactNode } from "react";
import Skeleton from "react-loading-skeleton";
import { formatRate } from "src/base/formatRate";
-import { calculateMarketYieldMultiplier } from "src/hyperdrive/calculateMarketYieldMultiplier";
import { useAppConfigForConnectedChain } from "src/ui/appconfig/useAppConfigForConnectedChain";
-import { useCurrentLongPrice } from "src/ui/hyperdrive/longs/hooks/useCurrentLongPrice";
import { useShortRate } from "src/ui/hyperdrive/shorts/hooks/useShortRate";
import { PercentLabel } from "src/ui/markets/PoolRow/PercentLabel";
import { useOpenShortRewards } from "src/ui/rewards/hooks/useOpenShortRewards";
@@ -30,10 +28,6 @@ export function VariableApyStat({
chainId,
hyperdriveAddress,
});
- const { longPrice, longPriceStatus } = useCurrentLongPrice({
- chainId: hyperdrive.chainId,
- hyperdriveAddress: hyperdrive.address,
- });
const { shortApr, shortRateStatus } = useShortRate({
chainId: hyperdrive.chainId,
@@ -44,11 +38,6 @@ export function VariableApyStat({
variableApy: yieldSourceRate?.netVaultRate,
});
- const multiplierLabel =
- longPriceStatus === "success" && longPrice
- ? `${calculateMarketYieldMultiplier(longPrice).format({ decimals: 0 })}x`
- : undefined;
-
if (yieldSourceRateStatus !== "success" || shortRateStatus !== "success") {
return
;
}
@@ -64,7 +53,6 @@ export function VariableApyStat({
/>
{rewards?.length ?
⚡ : null}
- {`Up to ${multiplierLabel} exposure`}
);
}
diff --git a/apps/hyperdrive-trading/src/ui/markets/PositionPicker.tsx b/apps/hyperdrive-trading/src/ui/markets/PositionPicker.tsx
index 8c9b5b4b6..51c2de4e5 100644
--- a/apps/hyperdrive-trading/src/ui/markets/PositionPicker.tsx
+++ b/apps/hyperdrive-trading/src/ui/markets/PositionPicker.tsx
@@ -2,6 +2,7 @@ import { HyperdriveConfig } from "@delvtech/hyperdrive-appconfig";
import { Link, useSearch } from "@tanstack/react-router";
import classNames from "classnames";
import { ReactElement } from "react";
+import { useFeatureFlag } from "src/ui/base/featureFlags/featureFlags";
import { formatTermLength2 } from "src/ui/markets/formatTermLength";
import { MARKET_DETAILS_ROUTE } from "src/ui/markets/routes";
import { useAccount } from "wagmi";
@@ -12,6 +13,7 @@ export function PositionPicker({
hyperdrive: HyperdriveConfig;
}): ReactElement {
const { address: account } = useAccount();
+ const { isFlagEnabled: isNewDesign } = useFeatureFlag("new-design");
const { position: activePosition = "long" } = useSearch({
from: MARKET_DETAILS_ROUTE,
});
@@ -67,7 +69,7 @@ export function PositionPicker({
});
}}
>
- Fixed
+ {isNewDesign ? "Fixed" : "Long"}
+ Open a Long and hold it to maturity.
- When you open a fixed rate position in Hyperdrive, you're buying
- tokens at a discount. These tokens are redeemable at maturity for
- their full value, giving you a fixed return.
+ When you open a Long in Hyperdrive, you're buying tokens at a
+ discount. These tokens are redeemable at maturity for their full
+ value, giving you a fixed return.
- Opening a fixed rate position has an immediate impact on the market.
- If more people buy the fixed rate, the fixed rate goes down. If they
- close their position, the fixed rate goes up.
+ Opening Longs has an immediate impact on the market. If more people
+ open Longs, the fixed rate goes down. If they close Longs, the fixed
+ rate goes up.
- Users can also take speculative fixed rate positions where they bet on
- the short-term movement of rates. Read our docs to learn more about{" "}
+ Users can also take speculative Long positions where they bet on the
+ short-term movement of rates. Read our docs to learn more about{" "}
,
- label: "Fixed Rates",
+ label: isNewDesign ? "Fixed Rates" : "Long",
onClick: () => {
navigate({
search: (prev) => ({ ...prev, position: "longs" }),
diff --git a/packages/hyperdrive-js/package.json b/packages/hyperdrive-js/package.json
index dba2ebf49..db5503577 100644
--- a/packages/hyperdrive-js/package.json
+++ b/packages/hyperdrive-js/package.json
@@ -32,6 +32,7 @@
"abitype": "^1.0.5",
"dotenv": "^16.4.5",
"prettier": "3.3.3",
+ "p-retry": "^6.2.1",
"prettier-plugin-organize-imports": "4.0.0",
"sinon": "^18.0.0",
"tsconfig-paths": "^4.2.0",
diff --git a/packages/hyperdrive-js/src/hyperdrive/ReadHyperdrive.ts b/packages/hyperdrive-js/src/hyperdrive/ReadHyperdrive.ts
index d51aa0256..6ab224d30 100644
--- a/packages/hyperdrive-js/src/hyperdrive/ReadHyperdrive.ts
+++ b/packages/hyperdrive-js/src/hyperdrive/ReadHyperdrive.ts
@@ -10,6 +10,7 @@ import {
ReadContract,
} from "@delvtech/drift";
import { fixed } from "@delvtech/fixed-point-wasm";
+import retry from "p-retry";
import { HyperdriveSdkError } from "src/HyperdriveSdkError";
import { assertNever } from "src/base/assertNever";
import { calculateAprFromPrice } from "src/base/calculateAprFromPrice";
@@ -188,13 +189,34 @@ export class ReadHyperdrive extends ReadClient {
fromBlock?: BlockTag | bigint;
toBlock?: BlockTag | bigint;
}): Promise {
- const events = await this.contract.getEvents("Initialize", options);
+ const events = await retry(
+ async () => {
+ // On Gnosischain, the Initialize event request sometimes comes back as
+ // an empty array due to Alchemy blips. We throw an error in this case
+ // so that we trigger a retry.
+ const events = await this.contract.getEvents("Initialize", options);
+ if (!events.length || events[0].blockNumber === undefined) {
+ // We need to clear the cache otherwise we'll get the same empty array
+ // back from the cache.
+ this.contract.cache.clear();
+ throw new HyperdriveSdkError(
+ `Pool has not been initialized, no block found. ${this.address}`,
+ );
+ }
+ return events;
+ },
+ {
+ retries: 10,
+ onFailedAttempt: async (error) => {
+ // TODO: Remove retry logic all together once we stop seeing retry
+ // logs in the console all the time.
+ console.log(
+ `getInitializationBlock failed on Hyperdrive ${this.address}, chainId: ${await this.drift.getChainId()}. There are ${error.retriesLeft} retries left.`,
+ );
+ },
+ },
+ );
- if (!events.length || events[0].blockNumber === undefined) {
- throw new HyperdriveSdkError(
- `Pool has not been initialized, no block found. ${this.address}`,
- );
- }
const blockNumber = events[0].blockNumber;
return getBlockOrThrow(this.drift, { blockNumber });