Skip to content

Commit

Permalink
Add default Yield Multiplier to PoolRow and OpenShortForm (#1511)
Browse files Browse the repository at this point in the history
* Adds yield multiplier to pool row

* replace variably apy with multiplier

* check for loading

* Skeleton loading

* adds commend for multiplier calc

* switch to parseFixed

* Move calc into separate function
  • Loading branch information
jackburrus committed Sep 23, 2024
1 parent 10f9450 commit 5d70cd7
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { parseFixed } from "@delvtech/fixed-point-wasm";
/**
* Calculates the yield multiplier for a Hyperdrive market based on the long price.
*
* The yield multiplier represents how much the underlying yield is amplified for short positions.
* It is inversely proportional to the long price, increasing as the long price approaches 1.
*
* Yield Multiplier calculation:
* Yield Multiplier = 1 / (1 - longPrice)
*
* Examples:
* - If longPrice = 0.9:
* Yield Multiplier = 1 / (1 - 0.9) = 1 / 0.1 = 10x
* The short position amplifies the underlying yield by 10 times.
*
* - If longPrice = 0.96:
* Yield Multiplier = 1 / (1 - 0.96) = 1 / 0.04 = 25x
* The short position amplifies the underlying yield by 25 times.
*
* @param longPrice The current price of a long position, represented as a bigint.
* @returns The calculated yield multiplier as a string, formatted to 2 decimal places.
*/

export function calculateMarketYieldMultiplier(longPrice: bigint): string {
return parseFixed(1)
.div(parseFixed(1).sub(longPrice))
.format({ decimals: 2, rounding: "trunc" });
}
17 changes: 13 additions & 4 deletions apps/hyperdrive-trading/src/ui/base/components/PrimaryStat.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { InformationCircleIcon } from "@heroicons/react/24/outline";
import classNames from "classnames";
import { ReactNode } from "react";
import Skeleton from "react-loading-skeleton";

export function PrimaryStat({
label,
Expand All @@ -11,6 +12,7 @@ export function PrimaryStat({
tooltipPosition = "top",
valueClassName,
unitClassName,
valueLoading = false,
}: {
label: string;
value: ReactNode;
Expand All @@ -20,6 +22,7 @@ export function PrimaryStat({
tooltipPosition?: "top" | "bottom" | "left" | "right";
valueClassName?: string;
unitClassName?: string;
valueLoading?: boolean;
}): JSX.Element {
return (
<div className="flex flex-col gap-1">
Expand All @@ -43,10 +46,16 @@ export function PrimaryStat({
)}
</div>
<div className={valueClassName}>
<div className="text-h3 font-bold">{value}</div>
{valueUnit ? (
<div className={`ml-1 ${unitClassName}`}>{valueUnit}</div>
) : null}
{valueLoading ? (
<Skeleton width={100} className="h-8" />
) : (
<>
<div className="text-h3 font-bold">{value}</div>
{valueUnit ? (
<div className={`ml-1 ${unitClassName}`}>{valueUnit}</div>
) : null}
</>
)}
</div>
{subValue && (
<div className="text-sm text-neutral-content">{subValue}</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { MouseEvent, ReactElement, useState } from "react";
import { MAX_UINT256 } from "src/base/constants";
import { formatRate } from "src/base/formatRate";
import { isTestnetChain } from "src/chains/isTestnetChain";
import { calculateMarketYieldMultiplier } from "src/hyperdrive/calculateMarketYieldMultiplier";
import { getIsValidTradeSize } from "src/hyperdrive/getIsValidTradeSize";
import { getHasEnoughAllowance } from "src/token/getHasEnoughAllowance";
import { getHasEnoughBalance } from "src/token/getHasEnoughBalance";
Expand Down Expand Up @@ -82,7 +83,7 @@ export function OpenShortForm({
tokenAddress: baseToken.address,
decimals: baseToken.decimals,
});
const { longPrice } = useCurrentLongPrice({
const { longPrice, longPriceStatus } = useCurrentLongPrice({
chainId: hyperdrive.chainId,
hyperdriveAddress: hyperdrive.address,
});
Expand Down Expand Up @@ -274,7 +275,7 @@ export function OpenShortForm({
? fixed(amountOfBondsToShortAsBigInt, activeToken.decimals)
.div(traderDeposit, activeToken.decimals)
.format({ decimals: 2, rounding: "trunc" })
: "0";
: calculateMarketYieldMultiplier(longPrice ?? 0n);

const maturesOnLabel = formatDate(
Date.now() + Number(hyperdrive.poolConfig.positionDuration * 1000n),
Expand Down Expand Up @@ -423,6 +424,7 @@ export function OpenShortForm({
valueUnit="x"
unitClassName="text-h3"
subValue={`Matures on ${maturesOnLabel}`}
valueLoading={longPriceStatus === "loading"}
/>
<div className="daisy-divider daisy-divider-horizontal" />
<PrimaryStat
Expand Down
19 changes: 13 additions & 6 deletions apps/hyperdrive-trading/src/ui/markets/PoolRow/PoolRow.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { ClockIcon } from "@heroicons/react/16/solid";
import {
HyperdriveConfig,
appConfig,
findBaseToken,
findToken,
HyperdriveConfig,
} from "@hyperdrive/appconfig";
import { Link, useNavigate } from "@tanstack/react-router";
import classNames from "classnames";
import { ReactElement, ReactNode } from "react";
import Skeleton from "react-loading-skeleton";
import { formatRate } from "src/base/formatRate";
import { calculateMarketYieldMultiplier } from "src/hyperdrive/calculateMarketYieldMultiplier";
import { LpApyResult } from "src/hyperdrive/getLpApy";
import { Well } from "src/ui/base/components/Well/Well";
import { formatCompact } from "src/ui/base/formatting/formatCompact";
import { useCurrentLongPrice } from "src/ui/hyperdrive/longs/hooks/useCurrentLongPrice";
import { AssetStack } from "src/ui/markets/AssetStack";
import { formatTermLength2 } from "src/ui/markets/formatTermLength";
import { MARKET_DETAILS_ROUTE } from "src/ui/markets/routes";
import { RewardsTooltip } from "src/ui/rewards/RewardsTooltip";

export interface PoolRowProps {
hyperdrive: HyperdriveConfig;
tvl: bigint;
Expand Down Expand Up @@ -51,6 +52,11 @@ export function PoolRow({
tokenAddress: hyperdrive.poolConfig.vaultSharesToken,
});

const { longPrice, longPriceStatus } = useCurrentLongPrice({
chainId: hyperdrive.chainId,
hyperdriveAddress: hyperdrive.address,
});

return (
<Well
as="div"
Expand Down Expand Up @@ -168,17 +174,18 @@ export function PoolRow({
</Link>
}
/>

<PoolStat
label={"Variable APY"}
label={"Yield Multiplier"}
isNew={lpApy.isNew}
value={
vaultRate ? (
longPriceStatus === "success" && longPrice ? (
<RewardsTooltip
hyperdriveAddress={hyperdrive.address}
chainId={hyperdrive.chainId}
positionType="short"
>
<PercentLabel value={formatRate(vaultRate, 18, false)} />
{`${calculateMarketYieldMultiplier(longPrice)}x`}
</RewardsTooltip>
) : (
"-"
Expand Down Expand Up @@ -267,7 +274,7 @@ function PoolStat({
}

return (
<div className="flex w-24 flex-col items-start gap-1.5">
<div className="flex w-28 flex-col items-start gap-1.5">
<p
data-tip={labelTooltip}
className={
Expand Down

0 comments on commit 5d70cd7

Please sign in to comment.