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
4 changes: 4 additions & 0 deletions apps/hyperdrive-trading/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ VITE_CAPSULE_ENV= # BETA or PROD
VITE_ADDRESS_SCREEN_URL=
##################################################


# Debugging options
# logs why a component re-rendered, keep this off in production!
VITE_ENABLE_WHY_DID_YOU_RENDER=
1 change: 1 addition & 0 deletions apps/hyperdrive-trading/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@rollbar/react": "^0.11.1",
"@tanstack/query-core": "^4.36.1",
"@tanstack/react-query": "^4.29.12",
"@welldone-software/why-did-you-render": "^10.0.1",
"@tanstack/react-router": "^1.87.7",
"@tanstack/react-table": "^8.20.5",
"@tanstack/router-devtools": "^1.87.7",
Expand Down
39 changes: 39 additions & 0 deletions apps/hyperdrive-trading/src/ui/base/debugging/wdyr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as React from "react";

if (
import.meta.env.DEV &&
import.meta.env.VITE_ENABLE_WHY_DID_YOU_RENDER === "true"
) {
const { default: wdyr } = await import(
"@welldone-software/why-did-you-render"
);

/**
* Why Did You Render is a tool to help you understand what's causing your
* React application to re-render. It does this by monkey-patching React and
* tracking the props that are changing across renders.
*
* If you want to target a specific component to be monitored, just add this
* to the component:
* MyComponent.whyDidYouRender = true;
*
* @see https://github.com/welldone-software/why-did-you-render
*/

wdyr(React, {
// Uncomment the next line to include all re-renders
// Useful for the early stages of debugging where you need to see everything
// include: [/./],

// Not all re-renders are bad! You can specify a list of components to
// ignore here.
// exclude: [
// /^BrowserRouter/,
// /^Link/,
// /^Route/,
// /Icon$/,
// ],
trackHooks: true,
trackAllPureComponents: true,
});
}
10 changes: 10 additions & 0 deletions apps/hyperdrive-trading/src/ui/base/memo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React, { FunctionComponent } from "react";

export function memoComponent<P extends object>(
displayName: string,
Component: FunctionComponent<P>,
): React.NamedExoticComponent<P> {
const MemoizedComponent = React.memo(Component);
MemoizedComponent.displayName = displayName;
return MemoizedComponent;
}
5 changes: 5 additions & 0 deletions apps/hyperdrive-trading/src/ui/main.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// Importing Why Did You Render (WDYR) must happen before anything that
// imports React. This is because WDYR monkeypatches React's render method to
// detect unnecessary re-renders.
import "src/ui/base/debugging/wdyr";

import { RainbowKitProvider } from "@rainbow-me/rainbowkit";
import "@rainbow-me/rainbowkit/styles.css";
import "@usecapsule/react-sdk/styles.css";
Expand Down
137 changes: 79 additions & 58 deletions apps/hyperdrive-trading/src/ui/markets/hooks/usePoolsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import { getHyperdrive } from "@delvtech/hyperdrive-js";
import { QueryStatus } from "@tanstack/query-core";
import { useIsFetching, useQuery } from "@tanstack/react-query";
import { getPublicClient } from "@wagmi/core";
import { useState } from "react";
import { useCallback, useState } from "react";
import { makeQueryKey2 } from "src/base/makeQueryKey";
import { isTestnetChain } from "src/chains/isTestnetChain";
import { getDrift } from "src/drift/getDrift";
import { calculateMarketYieldMultiplier } from "src/hyperdrive/calculateMarketYieldMultiplier";
import { getDepositAssets } from "src/hyperdrive/getDepositAssets";
import { getLpApy } from "src/hyperdrive/getLpApy";
import { getLpApy, LpApyResult } from "src/hyperdrive/getLpApy";
import { wagmiConfig } from "src/network/wagmiClient";
import { getYieldSourceRate } from "src/rewards/getYieldSourceRate";
import { useAppConfigForConnectedChain } from "src/ui/appconfig/useAppConfigForConnectedChain";
Expand Down Expand Up @@ -111,6 +111,22 @@ export function usePoolsList({
};
}

type PoolsListResult = {
hyperdrive: HyperdriveConfig;
fixedApr: bigint;
lpApy: LpApyResult;
tvl: {
base: bigint;
fiat: bigint | undefined;
};
yieldSourceRate: {
rate: bigint;
ratePeriodDays: number;
netRate: bigint;
};
longPrice: bigint;
}[];

function useSortedPools({
pools,
enabled,
Expand Down Expand Up @@ -174,65 +190,70 @@ function useSortedPools({
);
}
: undefined,
select: (poolsWithData) => {
const filteredPools = !!filters.tvl
? poolsWithData.filter((pool) => {
const tvl = pool.tvl.fiat
? fixed(pool.tvl.fiat)
: fixed(pool.tvl.base, pool.hyperdrive.decimals);
return tvl.gte(filters.tvl!);
})
: poolsWithData;
return filteredPools
.toSorted((a, b) => {
switch (sortOption) {
case "Chain":
const chainA = appConfig.chains[a.hyperdrive.chainId] || {};
const chainB = appConfig.chains[b.hyperdrive.chainId] || {};
return chainA.name.localeCompare(chainB.name);
case "Fixed APR":
return Number(b.fixedApr - a.fixedApr);
case "LP APY":
return Number(
(b.lpApy.netLpApy ?? 0n) - (a.lpApy.netLpApy ?? 0n),
);
case "Variable APY":
return Number(
b.yieldSourceRate.netRate - a.yieldSourceRate.netRate,
);
case "Yield Multiplier":
return Number(
calculateMarketYieldMultiplier(b.longPrice).bigint -
calculateMarketYieldMultiplier(a.longPrice).bigint,
);
// Memoize this to prevent unnecessary re-renders when a new list is
// returned
select: useCallback(
(poolsWithData: PoolsListResult) => {
const filteredPools = !!filters.tvl
? poolsWithData.filter((pool) => {
const tvl = pool.tvl.fiat
? fixed(pool.tvl.fiat)
: fixed(pool.tvl.base, pool.hyperdrive.decimals);
return tvl.gte(filters.tvl!);
})
: poolsWithData;
return filteredPools
.toSorted((a, b) => {
switch (sortOption) {
case "Chain":
const chainA = appConfig.chains[a.hyperdrive.chainId] || {};
const chainB = appConfig.chains[b.hyperdrive.chainId] || {};
return chainA.name.localeCompare(chainB.name);
case "Fixed APR":
return Number(b.fixedApr - a.fixedApr);
case "LP APY":
return Number(
(b.lpApy.netLpApy ?? 0n) - (a.lpApy.netLpApy ?? 0n),
);
case "Variable APY":
return Number(
b.yieldSourceRate.netRate - a.yieldSourceRate.netRate,
);
case "Yield Multiplier":
return Number(
calculateMarketYieldMultiplier(b.longPrice).bigint -
calculateMarketYieldMultiplier(a.longPrice).bigint,
);

// By default we sort by TVL, with the caveat that pinned pools
// should always be at the top
case "TVL":
default: {
const aIsPinned = PINNED_POOLS.includes(a.hyperdrive.address);
const bIsPinned = PINNED_POOLS.includes(b.hyperdrive.address);
if (aIsPinned && !bIsPinned && !sortOption) {
return -1;
}
if (!aIsPinned && bIsPinned && !sortOption) {
return 1;
}
// By default we sort by TVL, with the caveat that pinned pools
// should always be at the top
case "TVL":
default: {
const aIsPinned = PINNED_POOLS.includes(a.hyperdrive.address);
const bIsPinned = PINNED_POOLS.includes(b.hyperdrive.address);
if (aIsPinned && !bIsPinned && !sortOption) {
return -1;
}
if (!aIsPinned && bIsPinned && !sortOption) {
return 1;
}

const tvlA =
b.tvl.fiat ??
fixed(b.tvl.base).div(b.hyperdrive.decimals, 0) ??
0;
const tvlB =
a.tvl.fiat ??
fixed(a.tvl.base).div(a.hyperdrive.decimals, 0) ??
0;
return fixed(tvlA).sub(tvlB).toNumber();
const tvlA =
b.tvl.fiat ??
fixed(b.tvl.base).div(b.hyperdrive.decimals, 0) ??
0;
const tvlB =
a.tvl.fiat ??
fixed(a.tvl.base).div(a.hyperdrive.decimals, 0) ??
0;
return fixed(tvlA).sub(tvlB).toNumber();
}
}
}
})
.map((pool) => pool.hyperdrive);
},
})
.map((pool) => pool.hyperdrive);
},
[appConfig.chains, filters.tvl, sortOption],
),
});

return {
Expand Down
9 changes: 8 additions & 1 deletion apps/hyperdrive-trading/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ export default defineConfig({
target: "esnext",
},
plugins: [
react(),
react({
jsxImportSource:
// eslint-disable-next-line turbo/no-undeclared-env-vars
process.env.NODE_ENV === "development"
? "@welldone-software/why-did-you-render"
: "react",
}),

tsconfigPaths(),
TanStackRouterVite({ routesDirectory: "./src/ui/routes" }),
nodePolyfills({
Expand Down
3 changes: 2 additions & 1 deletion turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"VITE_SEPOLIA_RPC_URL",
"VITE_VPN_SCREEN_URL",
"VITE_WALLET_CONNECT_PROJECT_ID",
"VITE_REWARDS_BASE_URL"
"VITE_REWARDS_BASE_URL",
"VITE_ENABLE_WHY_DID_YOU_RENDER"
],
"outputs": ["dist/**", ".next/**"]
},
Expand Down
9 changes: 8 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8207,6 +8207,13 @@
"@webassemblyjs/ast" "1.12.1"
"@xtuc/long" "4.2.2"

"@welldone-software/why-did-you-render@^10.0.1":
version "10.0.1"
resolved "https://registry.yarnpkg.com/@welldone-software/why-did-you-render/-/why-did-you-render-10.0.1.tgz#4513c1883add0496b98bcdcdcd243ff10c0f5ece"
integrity sha512-tMgGkt30iVYeLMUKExNmtm019QgyjLtA7lwB0QAizYNEuihlCG2eoAWBBaz/bDeI7LeqAJ9msC6hY3vX+JB97g==
dependencies:
lodash "^4"

"@xobotyi/scrollbar-width@^1.9.5":
version "1.9.5"
resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d"
Expand Down Expand Up @@ -14996,7 +15003,7 @@ lodash.uniqby@^4.7.0:
resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302"
integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==

lodash@4.17.21, lodash@^4.17.20, lodash@^4.17.21:
lodash@4.17.21, lodash@^4, lodash@^4.17.20, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
Expand Down
Loading