Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug causing incorrect Short balance to show #212

Merged
merged 5 commits into from
Jul 11, 2023
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
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { getFixedAPRQuery } from "@hyperdrive/core";
import { getCurrentFixedAPRQuery } from "@hyperdrive/core";
import { useQuery } from "@tanstack/react-query";
import { Hyperdrive } from "src/appconfig/types";
import { queryClient } from "src/network/queryClient";
import { useAppConfig } from "src/ui/appconfig/useAppConfig";
import { usePublicClient } from "wagmi";

export function useFixedAPR(hyperdrive: Hyperdrive): {
export function useCurrentFixedAPR(hyperdrive: Hyperdrive): {
fixedAPR: { apr: bigint; formatted: string } | undefined;
fixedAPRStatus: "loading" | "error" | "success";
} {
const { appConfig } = useAppConfig();
const publicClient = usePublicClient();

const { data, status } = useQuery(
getFixedAPRQuery({
getCurrentFixedAPRQuery({
hyperdriveAddress: hyperdrive.address,
hyperdriveMathAddress: appConfig?.hyperdriveMath,
publicClient: publicClient as any,
queryClient,
}),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ReactElement } from "react";
import { Hyperdrive } from "src/appconfig/types";
import { convertMillisecondsToDays } from "src/base/convertMillisecondsToDays";
import { Stat } from "src/ui/base/components/Stat";
import { useFixedAPR } from "src/ui/hyperdrive/longs/hooks/useFixedAPR";
import { useCurrentFixedAPR } from "src/ui/hyperdrive/longs/hooks/useCurrentFixedAPR";

export function MarketStats({
hyperdrive,
Expand All @@ -11,7 +11,7 @@ export function MarketStats({
}): ReactElement {
const formattedTermLength = formatTermLength(hyperdrive.termLengthMS);

const { fixedAPR } = useFixedAPR(hyperdrive);
const { fixedAPR } = useCurrentFixedAPR(hyperdrive);

return (
<div className="flex w-full flex-wrap items-center justify-start gap-16">
Expand Down
50 changes: 50 additions & 0 deletions packages/hyperdrive/src/amm/getPoolConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
PublicClient,
Address,
Transport,
Chain,
ContractFunctionResult,
} from "viem";
import { HyperdriveABI } from "src/abis/Hyperdrive";
import { QueryObserverOptions } from "@tanstack/query-core";

interface GetPoolConfigOptions {
hyperdriveAddress: Address;
publicClient: PublicClient<Transport, Chain>;
}

export async function getPoolConfig({
publicClient,
hyperdriveAddress,
}: GetPoolConfigOptions): Promise<
ContractFunctionResult<typeof HyperdriveABI, "getPoolConfig">
> {
return await publicClient.readContract({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if readContract fails here? Maybe add some error handling.

address: hyperdriveAddress,
abi: HyperdriveABI,
functionName: "getPoolConfig",
});
}

export function getPoolConfigQuery({
hyperdriveAddress,
publicClient,
}: Partial<GetPoolConfigOptions>): QueryObserverOptions<
Awaited<ReturnType<typeof getPoolConfig>>
> {
const queryEnabled = !!hyperdriveAddress && !!publicClient;

return {
enabled: queryEnabled,
queryKey: ["@hyperdrive/core", "getPoolConfig", { hyperdriveAddress }],
queryFn: queryEnabled
? async () =>
getPoolConfig({
hyperdriveAddress,
publicClient,
})
: undefined,
// pool config is static constants, so it never needs to be refreshed
staleTime: Infinity,
};
}
48 changes: 48 additions & 0 deletions packages/hyperdrive/src/amm/getPoolInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
PublicClient,
Transport,
Chain,
Address,
ContractFunctionResult,
} from "viem";
import { HyperdriveABI } from "src/abis/Hyperdrive";
import { QueryObserverOptions } from "@tanstack/query-core";

interface GetPoolInfoOptions {
hyperdriveAddress: Address;
publicClient: PublicClient<Transport, Chain>;
}

export async function getPoolInfo({
publicClient,
hyperdriveAddress,
}: GetPoolInfoOptions): Promise<
ContractFunctionResult<typeof HyperdriveABI, "getPoolInfo">
> {
return publicClient.readContract({
Copy link
Contributor

@jackburrus jackburrus Jul 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, although this one is not being awaited.

address: hyperdriveAddress,
abi: HyperdriveABI,
functionName: "getPoolInfo",
});
}

export function getPoolInfoQuery({
hyperdriveAddress,
publicClient,
}: Partial<GetPoolInfoOptions>): QueryObserverOptions<
Awaited<ReturnType<typeof getPoolInfo>>
> {
const queryEnabled = !!hyperdriveAddress && !!publicClient;

return {
enabled: queryEnabled,
queryKey: ["@hyperdrive/core", "getPoolInfo", { hyperdriveAddress }],
queryFn: queryEnabled
? async () =>
getPoolInfo({
hyperdriveAddress,
publicClient,
})
: undefined,
};
}
110 changes: 76 additions & 34 deletions packages/hyperdrive/src/amm/longs/getFixedAPR.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,89 @@
import { PublicClient, Address, Transport, Chain, formatUnits } from "viem";
import { HyperdriveMathABI } from "src/abis/HyperdriveMath";
import { HyperdriveABI } from "src/abis/Hyperdrive";
import { QueryObserverOptions } from "@tanstack/query-core";
import { QueryClient, QueryObserverOptions } from "@tanstack/query-core";
import { getPoolConfigQuery } from "src/amm/getPoolConfig";
import { getPoolInfoQuery } from "src/amm/getPoolInfo";

export interface GetFixedAPROptions {
hyperdriveAddress: Address;
hyperdriveMathAddress: Address;
/**
* Comes from getPoolInfo
*/
shareReserves: bigint;
/**
* Comes from getPoolInfo
*/
bondReserves: bigint;
/**
* Comes from getPoolConfig
*/
initialSharePrice: bigint;
/**
* Comes from getPoolConfig
*/
positionDuration: bigint;
/**
* Comes from getPoolConfig
*/
timeStretch: bigint;
publicClient: PublicClient<Transport, Chain>;
}

export async function getFixedAPR({
hyperdriveAddress,
hyperdriveMathAddress,
publicClient,
shareReserves,
bondReserves,
initialSharePrice,
positionDuration,
timeStretch,
}: GetFixedAPROptions): Promise<{ apr: bigint; formatted: string }> {
// TODO: Move to own method
const poolConfig = await publicClient.readContract({
address: hyperdriveAddress,
abi: HyperdriveABI,
functionName: "getPoolConfig",
});

// TODO: Move to own method
const poolInfo = await publicClient.readContract({
address: hyperdriveAddress,
abi: HyperdriveABI,
functionName: "getPoolInfo",
});

const apr = await publicClient.readContract({
address: hyperdriveMathAddress,
abi: HyperdriveMathABI,
functionName: "calculateAPRFromReserves",
args: [
poolInfo.shareReserves,
poolInfo.bondReserves,
poolConfig.initialSharePrice,
poolConfig.positionDuration,
poolConfig.timeStretch,
shareReserves,
bondReserves,
initialSharePrice,
positionDuration,
timeStretch,
],
});

const formatted = formatAPR(apr);

return {
apr,
formatted,
};
}

function formatAPR(apr: bigint) {
// APR is stored in 18 decimals, so to avoid rounding errors, eg:
// 0.049999999999999996 * 100 = 5, we just take the first 4 characters after
// the decimal, and format those to a percent, eg: 0.0499 * 100 = 4.99.
const truncatedAPR = +formatUnits(apr, 18).slice(0, 6);
const formatted = `${(100 * truncatedAPR).toFixed(2)}`;
return formatted;
}

return {
apr,
formatted,
};
interface GetCurrentFixedAPRQueryOptions {
hyperdriveAddress: Address | undefined;
hyperdriveMathAddress: Address | undefined;
publicClient: PublicClient<Transport, Chain>;
queryClient: QueryClient;
}

/**
* TODO: Move this to its own @hyperdrive/queries package eventually.
*/
export function getFixedAPRQuery({
export function getCurrentFixedAPRQuery({
hyperdriveAddress,
hyperdriveMathAddress,
publicClient,
}: Partial<GetFixedAPROptions>): QueryObserverOptions<
queryClient,
}: GetCurrentFixedAPRQueryOptions): QueryObserverOptions<
Awaited<ReturnType<typeof getFixedAPR>>
> {
const queryEnabled =
Expand All @@ -74,12 +97,31 @@ export function getFixedAPRQuery({
{ hyperdriveAddress, hyperdriveMathAddress },
],
queryFn: queryEnabled
? async () =>
getFixedAPR({
hyperdriveAddress,
hyperdriveMathAddress,
? async () => {
const { initialSharePrice, positionDuration, timeStretch } =
await queryClient.fetchQuery(
getPoolConfigQuery({
publicClient,
hyperdriveAddress,
}),
);
const { bondReserves, shareReserves } = await queryClient.fetchQuery(
getPoolInfoQuery({
publicClient,
hyperdriveAddress,
}),
);

return getFixedAPR({
publicClient,
})
hyperdriveMathAddress,
bondReserves,
shareReserves,
initialSharePrice,
timeStretch,
positionDuration,
});
}
: undefined,
};
}
2 changes: 1 addition & 1 deletion packages/hyperdrive/src/amm/shorts/getOpenShorts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export async function getOpenShorts({
).filter(
(transferSingleEvent) =>
decodeAssetFromTransferSingleEventData(transferSingleEvent.eventLog.data)
.assetType === "LONG",
.assetType === "SHORT",
);
const shortsRedeemedOrSentById = mapValues(
groupBy(shortsRedeemedOrSent, (event) => event.eventData.id),
Expand Down
14 changes: 6 additions & 8 deletions packages/hyperdrive/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
/** Address lists */
// Address lists
export type { AddressesJson } from "src/addresses/types";
export { HyperdriveGoerliAddresses } from "src/addresses/goerli";

/** ABIs */
// ABIs
export { ERC20_ABI } from "src/abis/ERC20";
export { ERC20MintableABI } from "src/abis/ERC20Mintable";

export { HyperdriveMathABI } from "src/abis/HyperdriveMath";

// TODO: Contracts team to supply a single ABI for the hyperdrive pool soon.
// Use HyperdriveABI for read methods, eg: getPoolConfig
export { HyperdriveABI } from "src/abis/Hyperdrive";

// AMM
export { getPoolConfig, getPoolConfigQuery } from "src/amm/getPoolConfig";
export { getPoolInfo, getPoolInfoQuery } from "src/amm/getPoolInfo";
export { getTransferSingleEvents } from "src/amm/events/getTransferSingleEvents";

/** Longs */
// Longs
export { getOpenLongs, getOpenLongsQuery } from "src/amm/longs/getOpenLongs";
export type { GetOpenLongsOptions } from "src/amm/longs/getOpenLongs";
export {
Expand All @@ -24,7 +22,7 @@ export {
} from "src/amm/longs/getClosedLongs";
export type { GetClosedLongsOptions as GetCloseLongsOptions } from "src/amm/longs/getClosedLongs";
export type { Long, ClosedLong } from "src/amm/longs/types";
export { getFixedAPRQuery } from "src/amm/longs/getFixedAPR";
export { getCurrentFixedAPRQuery } from "src/amm/longs/getFixedAPR";

// Shorts
export {
Expand Down