Skip to content

Commit

Permalink
Adds Morpho Rewards endpoint (#1544)
Browse files Browse the repository at this point in the history
* rates working, need to adjust scaling factor

* dynamic morpho rate working

* change to morpho rate

* set mainnet pool id

* cleaned up

* use correct market name

* relative path

* cleanup hook

* remove position type

* remove position type

* update pool row

* updates per comments
  • Loading branch information
jackburrus authored Oct 4, 2024
1 parent eca55d0 commit 90c02f8
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 75 deletions.
2 changes: 0 additions & 2 deletions apps/hyperdrive-trading/src/ui/markets/PoolRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ export function PoolRow({
<RewardsTooltip
hyperdriveAddress={hyperdrive.address}
chainId={hyperdrive.chainId}
positionType="short"
>
{`${calculateMarketYieldMultiplier(longPrice).format({ decimals: 2, rounding: "trunc" })}x`}
</RewardsTooltip>
Expand Down Expand Up @@ -211,7 +210,6 @@ export function PoolRow({
value={
!lpApy.isNew ? (
<RewardsTooltip
positionType="lp"
chainId={hyperdrive.chainId}
hyperdriveAddress={hyperdrive.address}
>
Expand Down
4 changes: 1 addition & 3 deletions apps/hyperdrive-trading/src/ui/rewards/RewardsTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,18 @@ import { Address } from "viem";
export function RewardsTooltip({
hyperdriveAddress,
chainId,
positionType,
children,
}: PropsWithChildren<{
hyperdriveAddress: Address;
chainId: number;
positionType: "lp" | "short";
}>): ReactNode {
const hyperdrive = findHyperdriveConfig({
hyperdrives: appConfig.hyperdrives,
hyperdriveAddress: hyperdriveAddress,
hyperdriveChainId: chainId,
});

const rewards = useRewards(hyperdrive, positionType);
const rewards = useRewards(hyperdrive);

if (!rewards || (rewards && rewards.length === 0)) {
return children;
Expand Down
63 changes: 63 additions & 0 deletions apps/hyperdrive-trading/src/ui/rewards/useMorphoRate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { fixed, FixedPoint } from "@delvtech/fixed-point-wasm";
import { useQuery } from "@tanstack/react-query";
import { Address } from "viem";

const marketPoolIds: Record<Address, string> = {
// Key: Hyperdrive contract address for the market
// Value: Corresponding Morpho pool ID
// Market:Base 182d Morpho cbETH/USDC
"0x2a1ca35Ded36C531F77c614b5AAA0d4F86edbB06":
"0xdba352d93a64b17c71104cbddc6aef85cd432322a1446b5b65163cbbc615cd0c",
};

export function useMorphoRate({
chainId,
hyperdriveAddress,
}: {
chainId: number;
hyperdriveAddress: Address;
}): {
morphoRate: FixedPoint | undefined;
} {
const { data: rewardsData } = useQuery<
{
current_rates: {
per_dollar_per_year: string;
pool_ids: string[];
}[];
},
Error
>({
queryKey: ["morphoRate", chainId, hyperdriveAddress],
staleTime: Infinity,
retry: 3,
queryFn: async () => {
const response = await fetch(
`https://rewards.morpho.org/v1/programs/?chains=${chainId}&active=true&type=uniform-reward`,
);
const result = await response.json();
return result.data[0];
},
});

let morphoRate: FixedPoint | undefined = undefined;

if (rewardsData) {
const poolId = marketPoolIds[hyperdriveAddress];
let matchingRate = rewardsData.current_rates.find((rate) =>
rate.pool_ids.some((id) => id.toLowerCase().startsWith(poolId)),
)?.per_dollar_per_year;

// If there is no matching rate, just use the first one in the current_rates array
if (!matchingRate) {
matchingRate = rewardsData.current_rates[0].per_dollar_per_year;
}

// The morpho rate is formatted to 15 decimal places
morphoRate = fixed(matchingRate ?? 0, 15);
}

return {
morphoRate,
};
}
78 changes: 8 additions & 70 deletions apps/hyperdrive-trading/src/ui/rewards/useRewards.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { fixed, FixedPoint, parseFixed } from "@delvtech/fixed-point-wasm";
import { PoolConfig, PoolInfo } from "@delvtech/hyperdrive-viem";
import { HyperdriveConfig } from "@hyperdrive/appconfig";
import { usePoolInfo } from "src/ui/hyperdrive/hooks/usePoolInfo";
import { usePresentValue } from "src/ui/hyperdrive/hooks/usePresentValue";
import { useMorphoRate } from "src/ui/rewards/useMorphoRate";
import { Address } from "viem";
import { base, linea, mainnet } from "viem/chains";

Expand Down Expand Up @@ -30,19 +27,6 @@ const eligibleMarketsForLineaRewards: Record<number, Address[]> = {
],
};

// Source: https://docs.morpho.org/rewards/concepts/programs
// Mainnet Reward Rates
const MorphoFlatRatePerDay = 1.45e-4;

// Base Reward Rates
const MorphoBaseFlatRatePerDay = 2.2e-4;

// Convert to yearly rates
const MorphoFlatRatePerYear = parseFixed(MorphoFlatRatePerDay * 365 * 1000);
const MorphoBaseFlatRatePerYear = parseFixed(
MorphoBaseFlatRatePerDay * 365 * 1000,
);

type RewardType = "MorphoFlatRate" | "LineaLXPL";

type Reward = {
Expand All @@ -51,37 +35,8 @@ type Reward = {
amount: string;
};

function getWeightMorpho(
poolConfig: PoolConfig,
positionType: "short" | "lp",
poolInfo?: PoolInfo,
presentValue?: bigint,
): FixedPoint {
if (!poolInfo || !presentValue) {
return parseFixed(0);
}

if (positionType === "short") {
return parseFixed(1, 18);
}

// Morpho share price is in 24 decimals, but FixedPoint only supports 18 max.
const shareReserves = fixed(poolInfo.shareReserves / BigInt(1e6));
const minShareReserves = fixed(poolConfig.minimumShareReserves / BigInt(1e6));
const netShareReserves = shareReserves.sub(minShareReserves);

return netShareReserves.div(presentValue);
}

export function useRewards(
hyperdrive: HyperdriveConfig,
positionType: "short" | "lp",
): Reward[] | undefined {
const { poolInfo } = usePoolInfo({
chainId: hyperdrive.chainId,
hyperdriveAddress: hyperdrive.address,
});
const { presentValue } = usePresentValue({
export function useRewards(hyperdrive: HyperdriveConfig): Reward[] | undefined {
const { morphoRate } = useMorphoRate({
chainId: hyperdrive.chainId,
hyperdriveAddress: hyperdrive.address,
});
Expand All @@ -94,31 +49,14 @@ export function useRewards(
hyperdrive.address,
)
) {
const morphoRate =
hyperdrive.chainId === base.id
? MorphoBaseFlatRatePerYear.mul(
getWeightMorpho(
hyperdrive.poolConfig,
positionType,
poolInfo,
presentValue,
),
)
: MorphoFlatRatePerYear.mul(
getWeightMorpho(
hyperdrive.poolConfig,
positionType,
poolInfo,
presentValue,
),
);

const morphoReward: Reward = {
id: "MorphoFlatRate",
name: "MORPHO",
amount: morphoRate.format({
decimals: 2,
}),
amount: morphoRate
? morphoRate.format({
decimals: 2,
})
: "0",
};
rewards.push(morphoReward);
}
Expand Down

0 comments on commit 90c02f8

Please sign in to comment.