Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/loud-radios-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@delvtech/hyperdrive-appconfig": patch
---

Export token icon for use in rewards modal
4 changes: 3 additions & 1 deletion apps/hyperdrive-trading/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
},
"dependencies": {
"@delvtech/fixed-point-wasm": "^0.0.6",
"@delvtech/hyperdrive-appconfig": "^0.0.1",
"@delvtech/hyperdrive-viem": "^3.0.6",
"@headlessui/react": "^2.1.5",
"@heroicons/react": "^2.0.16",
"@delvtech/hyperdrive-appconfig": "^0.0.1",
"@radix-ui/react-tooltip": "^1.1.2",
"@rainbow-me/rainbowkit": "^2.1.3",
"@rollbar/react": "^0.11.1",
Expand All @@ -52,6 +52,8 @@
"daisyui": "^4.12.2",
"dnum": "^2.9.0",
"fuse.js": "^7.0.0",
"graphql": "^16.9.0",
"graphql-request": "^7.1.0",
"lodash.sortby": "^4.7.0",
"process": "^0.11.10",
"react": "^18.2.0",
Expand Down
23 changes: 23 additions & 0 deletions apps/hyperdrive-trading/src/ui/rewards/RewardsTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,29 @@ export function RewardsTooltip({
</div>
</div>
);

case "MorphoVault":
return (
<div
key={reward.id}
className="flex items-center justify-between border-b border-neutral-content/30 p-3 [&:nth-last-child(2)]:border-none"
>
<div className="flex items-center gap-1">
<img
src={reward.iconUrl}
alt={`${reward.name} logo`}
className="h-4"
/>
{reward.name}
</div>

<div className="grid justify-items-end">
<p className="flex items-center gap-1">
+{reward.amount}
</p>
</div>
</div>
);
case "LineaLXPL":
return (
<div
Expand Down
94 changes: 92 additions & 2 deletions apps/hyperdrive-trading/src/ui/rewards/useMorphoRate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { fixed, FixedPoint } from "@delvtech/fixed-point-wasm";
import {
HyperdriveConfig,
WELL_ICON_URL,
} from "@delvtech/hyperdrive-appconfig";
import { useQuery } from "@tanstack/react-query";
import { Address } from "viem";

import { request } from "graphql-request";

const marketPoolIds: Record<Address, string> = {
// Key: Hyperdrive contract address for the market
// Value: Corresponding Morpho vault address (for vault rewards) or pool id (for market rewards)
Expand Down Expand Up @@ -39,7 +45,7 @@ export function useMorphoRate({
retry: 3,
queryFn: async () => {
const response = await fetch(
`https://rewards.morpho.org/v1/programs/?chains=${chainId}&active=true&type=uniform-reward`,
`https://rewards.morpho.org/v1/programs/?chains=${chainId}&active=true&type=uniform-reward`
);
const result = await response.json();
return result.data[0];
Expand All @@ -51,7 +57,7 @@ export function useMorphoRate({
if (rewardsData) {
const poolId = marketPoolIds[hyperdriveAddress];
let matchingRate = rewardsData.current_rates.find((rate) =>
rate.pool_ids.some((id) => id.toLowerCase().startsWith(poolId)),
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
Expand All @@ -67,3 +73,87 @@ export function useMorphoRate({
morphoRate,
};
}

const vaultAddresses: Record<
Address,
{ vaultAddress: string; assetIcon: string }
> = {
// Key: Hyperdrive contract address for the market
// Value: Morpho vault address and asset icon
// Market: 182d Moonwell Flagship ETH
"0xceD9F810098f8329472AEFbaa1112534E96A5c7b": {
vaultAddress: "0xa0E430870c4604CcfC7B38Ca7845B1FF653D0ff1",
assetIcon: WELL_ICON_URL,
},
};

const endpoint = "https://blue-api.morpho.org/graphql";

type SupplyRewardsResponse = {
vaultByAddress: {
state: {
rewards: {
supplyApr: number;
asset: {
name: string;
};
}[];
};
};
};

export function useMorphoVaultRewards({
hyperdrive,
enabled,
}: {
hyperdrive: HyperdriveConfig;
enabled: boolean;
}): {
morphoVaultReward:
| SupplyRewardsResponse["vaultByAddress"]["state"]["rewards"][0]
| undefined;
isLoading: boolean;
} {
const morphoVault = vaultAddresses[hyperdrive.address];
const queryEnabled = !!morphoVault?.vaultAddress && enabled;
const { data: morphoVaultRewards, isLoading } = useQuery({
queryKey: [
"morphoVaultRewards",
hyperdrive.address,
hyperdrive.chainId,
morphoVault?.vaultAddress,
],
enabled: queryEnabled,
staleTime: Infinity,
retry: 3,
queryFn: queryEnabled
? async () => {
const supplyRewards: SupplyRewardsResponse = await request(
endpoint,
`query SupplyRewards($address: String!, $chainId: Int!) {
vaultByAddress(address: $address, chainId: $chainId) {
address
state {
rewards {
supplyApr
asset {
address
symbol
}
}
}
}
}`,
{ address: morphoVault.vaultAddress, chainId: hyperdrive.chainId }
);
return supplyRewards;
}
: undefined,
});

return {
// Return the first reward in the rewards array
morphoVaultReward: morphoVaultRewards?.vaultByAddress?.state?.rewards[0],
isLoading,
};
}
48 changes: 42 additions & 6 deletions apps/hyperdrive-trading/src/ui/rewards/useRewards.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { HyperdriveConfig } from "@delvtech/hyperdrive-appconfig";
import { useMorphoRate } from "src/ui/rewards/useMorphoRate";
import {
HyperdriveConfig,
WELL_ICON_URL,
} from "@delvtech/hyperdrive-appconfig";
import {
useMorphoRate,
useMorphoVaultRewards,
} from "src/ui/rewards/useMorphoRate";
import { Address } from "viem";
import { base, linea, mainnet } from "viem/chains";

Expand All @@ -20,6 +26,13 @@ const eligibleMarketsForMorphoRewards: Record<number, Address[]> = {
],
};

const eligibleMarketsForMorphoVaultRewards: Record<number, Address[]> = {
[base.id]: [
// 182d Moonwell Flagship ETH
"0xceD9F810098f8329472AEFbaa1112534E96A5c7b",
],
};

const eligibleMarketsForLineaRewards: Record<number, Address[]> = {
[linea.id]: [
// 182d KelpDAO rsETH
Expand All @@ -29,12 +42,13 @@ const eligibleMarketsForLineaRewards: Record<number, Address[]> = {
],
};

type RewardType = "MorphoFlatRate" | "LineaLXPL";
type RewardType = "MorphoFlatRate" | "MorphoVault" | "LineaLXPL";

type Reward = {
id: RewardType;
name: string;
amount: string;
iconUrl?: string;
};

export function useRewards(hyperdrive: HyperdriveConfig): Reward[] | undefined {
Expand All @@ -43,7 +57,15 @@ export function useRewards(hyperdrive: HyperdriveConfig): Reward[] | undefined {
hyperdriveAddress: hyperdrive.address,
enabled:
eligibleMarketsForMorphoRewards[hyperdrive.chainId]?.includes(
hyperdrive.address,
hyperdrive.address
) ?? false,
});

const { morphoVaultReward } = useMorphoVaultRewards({
hyperdrive,
enabled:
eligibleMarketsForMorphoVaultRewards[base.id]?.includes(
hyperdrive.address
) ?? false,
});

Expand All @@ -52,7 +74,7 @@ export function useRewards(hyperdrive: HyperdriveConfig): Reward[] | undefined {
// Add any morpho rewards for this market
if (
eligibleMarketsForMorphoRewards[hyperdrive.chainId]?.includes(
hyperdrive.address,
hyperdrive.address
)
) {
const morphoReward: Reward = {
Expand All @@ -70,7 +92,7 @@ export function useRewards(hyperdrive: HyperdriveConfig): Reward[] | undefined {
// Add any linea rewards for this market
if (
eligibleMarketsForLineaRewards[hyperdrive.chainId]?.includes(
hyperdrive.address,
hyperdrive.address
)
) {
const lineaReward: Reward = {
Expand All @@ -81,5 +103,19 @@ export function useRewards(hyperdrive: HyperdriveConfig): Reward[] | undefined {
rewards.push(lineaReward);
}

if (
eligibleMarketsForMorphoVaultRewards[base.id]?.includes(hyperdrive.address)
) {
const vaultReward: Reward = {
id: "MorphoVault",
name: morphoVaultReward?.asset.name ?? "WELL",
iconUrl: WELL_ICON_URL,
amount: morphoVaultReward?.supplyApr
? `${(morphoVaultReward.supplyApr * 100).toFixed(2)}%`
: "0%",
};
rewards.push(vaultReward);
}

return rewards;
}
1 change: 1 addition & 0 deletions packages/hyperdrive-appconfig/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type { HyperdriveConfig } from "src/hyperdrives/HyperdriveConfig";

// tokens
export type { TokenConfig } from "src/tokens/getTokenConfig";
export { WELL_ICON_URL } from "src/tokens/tokenIconsUrls";

// yield sources
export { yieldSources } from "src/yieldSources";
Expand Down
Loading
Loading