Skip to content

Commit c73baf3

Browse files
committed
Implement PR feedback
1 parent 2dceecb commit c73baf3

File tree

12 files changed

+123
-52
lines changed

12 files changed

+123
-52
lines changed

apps/api-reference/src/apis/evm/common.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,27 @@ export const ETHUSD =
3535
const HERMES_URL = "https://hermes.pyth.network";
3636

3737
export const getLatestPriceFeed = async (feedId: string) => {
38-
const url = new URL("/api/latest_price_feeds", HERMES_URL);
38+
const url = new URL("/v2/updates/price/latest", HERMES_URL);
3939
url.searchParams.set("ids[]", feedId);
4040
url.searchParams.set("target_chain", "evm");
4141
url.searchParams.set("binary", "true");
4242
return safeFetch(priceFeedSchema, url);
4343
};
4444

45-
const priceFeedSchema = singletonArray(
46-
z.object({
47-
vaa: z.string().transform((value) => toZeroXPrefixedHex(value)),
48-
price: z.object({
49-
publish_time: z.number(),
50-
}),
45+
const priceFeedSchema = z.object({
46+
binary: z.object({
47+
data: singletonArray(z.string()).transform((value) =>
48+
toZeroXPrefixedHex(value),
49+
),
5150
}),
52-
);
51+
parsed: singletonArray(
52+
z.object({
53+
price: z.object({
54+
publish_time: z.number(),
55+
}),
56+
}),
57+
),
58+
});
5359

5460
const toZeroXPrefixedHex = (value: string) =>
5561
`0x${Buffer.from(value, "base64").toString("hex")}`;

apps/api-reference/src/apis/evm/get-update-fee.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,5 @@ const [feeAmount] = await contract.getUpdateFee(updateData);
6363

6464
const getParams = async (feedId: string) => {
6565
const feed = await getLatestPriceFeed(feedId);
66-
return { updateData: feed.vaa };
66+
return { updateData: feed.binary.data };
6767
};

apps/api-reference/src/apis/evm/parse-price-feed-updates-unique.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,15 @@ const getParams = async (
115115
},
116116
) => {
117117
const feed = await getLatestPriceFeed(priceId);
118-
const fee = await ctx.readContract("getUpdateFee", [[feed.vaa]]);
118+
const fee = await ctx.readContract("getUpdateFee", [[feed.binary.data]]);
119119
if (typeof fee !== "bigint") {
120120
throw new TypeError("Invalid fee");
121121
}
122122
return {
123-
updateData: feed.vaa,
123+
updateData: feed.binary.data,
124124
priceId,
125-
minPublishTime: (feed.price.publish_time - 5).toString(),
126-
maxPublishTime: (feed.price.publish_time + 5).toString(),
125+
minPublishTime: (feed.parsed.price.publish_time - 5).toString(),
126+
maxPublishTime: (feed.parsed.price.publish_time + 5).toString(),
127127
fee: fee.toString(),
128128
};
129129
};

apps/api-reference/src/apis/evm/parse-price-feed-updates.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,15 @@ const getParams = async (
113113
},
114114
) => {
115115
const feed = await getLatestPriceFeed(priceId);
116-
const fee = await ctx.readContract("getUpdateFee", [[feed.vaa]]);
116+
const fee = await ctx.readContract("getUpdateFee", [[feed.binary.data]]);
117117
if (typeof fee !== "bigint") {
118118
throw new TypeError("Invalid fee");
119119
}
120120
return {
121-
updateData: feed.vaa,
121+
updateData: feed.binary.data,
122122
priceId,
123-
minPublishTime: (feed.price.publish_time - 5).toString(),
124-
maxPublishTime: (feed.price.publish_time + 5).toString(),
123+
minPublishTime: (feed.parsed.price.publish_time - 5).toString(),
124+
maxPublishTime: (feed.parsed.price.publish_time + 5).toString(),
125125
fee: fee.toString(),
126126
};
127127
};

apps/api-reference/src/apis/evm/update-price-feeds-if-necessary.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,14 @@ const getParams = async (
108108
},
109109
) => {
110110
const feed = await getLatestPriceFeed(priceId);
111-
const fee = await ctx.readContract("getUpdateFee", [[feed.vaa]]);
111+
const fee = await ctx.readContract("getUpdateFee", [[feed.binary.data]]);
112112
if (typeof fee !== "bigint") {
113113
throw new TypeError("Invalid fee");
114114
}
115115
return {
116-
updateData: feed.vaa,
116+
updateData: feed.binary.data,
117117
priceId,
118-
publishTime: feed.price.publish_time.toString(),
118+
publishTime: feed.parsed.price.publish_time.toString(),
119119
fee: fee.toString(),
120120
};
121121
};

apps/api-reference/src/apis/evm/update-price-feeds.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ const getParams = async (
8282
},
8383
) => {
8484
const feed = await getLatestPriceFeed(feedId);
85-
const fee = await ctx.readContract("getUpdateFee", [[feed.vaa]]);
85+
const fee = await ctx.readContract("getUpdateFee", [[feed.binary.data]]);
8686
if (typeof fee !== "bigint") {
8787
throw new TypeError("Invalid fee");
8888
}
8989
return {
90-
updateData: feed.vaa,
90+
updateData: feed.binary.data,
9191
fee: fee.toString(),
9292
};
9393
};

apps/api-reference/src/components/Button/index.tsx

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,65 @@
1+
"use client";
2+
13
import clsx from "clsx";
2-
import type { ComponentProps, ElementType } from "react";
4+
import {
5+
type ComponentProps,
6+
type ElementType,
7+
type MouseEvent,
8+
useState,
9+
useCallback,
10+
type CSSProperties,
11+
} from "react";
312

413
type ButtonProps<T extends ElementType> = Omit<ComponentProps<T>, "as"> & {
514
as?: T;
615
loading?: boolean | undefined;
16+
gradient?: boolean | undefined;
717
};
818

919
export const Button = <T extends ElementType>({
1020
as,
1121
className,
1222
loading,
1323
disabled,
24+
gradient,
1425
...props
1526
}: ButtonProps<T>) => {
1627
const Component = as ?? "button";
28+
const [mouse, setMouse] = useState({ x: 0, y: 0 });
29+
30+
const updateMouse = useCallback((e: MouseEvent<HTMLButtonElement>) => {
31+
setMouse({
32+
x: e.pageX - e.currentTarget.offsetLeft,
33+
y: e.pageY - e.currentTarget.offsetTop,
34+
});
35+
}, []);
36+
1737
return (
1838
<Component
1939
disabled={loading === true || disabled === true}
40+
onMouseMove={updateMouse}
41+
style={
42+
gradient
43+
? ({
44+
"--gradient-left": `${mouse.x.toString()}px`,
45+
"--gradient-top": `${mouse.y.toString()}px`,
46+
} as CSSProperties)
47+
: {}
48+
}
2049
className={clsx(
21-
"rounded-lg border text-sm font-medium transition-all duration-300",
50+
"relative overflow-hidden rounded-lg border text-sm font-medium transition-all duration-300",
2251
{
23-
"border-neutral-400 bg-pythpurple-600/5 hover:border-pythpurple-600 hover:bg-pythpurple-600/15 hover:shadow-md dark:border-neutral-600 dark:bg-pythpurple-400/5 dark:hover:border-pythpurple-400 dark:hover:bg-pythpurple-400/15 dark:hover:shadow-white/20":
52+
"border-neutral-400 hover:border-pythpurple-600 hover:shadow-md dark:border-neutral-600 dark:hover:border-pythpurple-400 dark:hover:shadow-white/20":
2453
!loading && !disabled,
25-
},
26-
{
54+
"before:absolute before:left-[var(--gradient-left)] before:top-[var(--gradient-top)] before:-ml-[20rem] before:-mt-[20rem] before:block before:size-[40rem] before:scale-0 before:bg-gradient-radial before:from-pythpurple-400/30 before:to-70% before:opacity-50 before:transition before:duration-500 hover:before:scale-100 hover:before:opacity-100 dark:before:from-pythpurple-600/30":
55+
gradient && !loading && !disabled,
56+
"bg-pythpurple-600/5 hover:bg-pythpurple-600/15 dark:bg-pythpurple-400/5 dark:hover:bg-pythpurple-400/15":
57+
!gradient && !loading && !disabled,
2758
"border-neutral-200 bg-neutral-100 text-neutral-400 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-500":
2859
loading === true || disabled === true,
60+
"cursor-not-allowed": disabled === true && loading !== true,
61+
"cursor-wait": loading === true,
2962
},
30-
{ "cursor-not-allowed": disabled === true && loading !== true },
31-
{ "cursor-wait": loading === true },
3263
className,
3364
)}
3465
{...props}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ExclamationCircleIcon } from "@heroicons/react/24/solid";
2+
import clsx from "clsx";
3+
import type { ReactNode } from "react";
4+
5+
import { Tooltip } from "../Tooltip";
6+
7+
type Props = {
8+
children: ReactNode;
9+
className?: string | undefined;
10+
};
11+
12+
export const ErrorTooltip = ({ className, children }: Props) => (
13+
<Tooltip arrow={{ width: 6, height: 10 }} gap={0} placement="top-end">
14+
<Tooltip.Trigger
15+
as={ExclamationCircleIcon}
16+
className={clsx("text-red-500 dark:text-red-700", className)}
17+
/>
18+
<Tooltip.Content className="z-50 whitespace-pre-line rounded-md border border-red-500 bg-red-50 px-3 py-2 text-red-800 shadow-md dark:border-red-900 dark:bg-red-950 dark:text-red-200 dark:shadow-white/5">
19+
<Tooltip.Arrow className="fill-red-500 dark:fill-red-700" />
20+
<div className="max-w-40 text-xs">{children}</div>
21+
</Tooltip.Content>
22+
</Tooltip>
23+
);

apps/api-reference/src/components/EvmApi/index.tsx

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Field,
1010
Label,
1111
} from "@headlessui/react";
12+
import { ArrowPathIcon } from "@heroicons/react/24/outline";
1213
import PythAbi from "@pythnetwork/pyth-sdk-solidity/abis/IPyth.json";
1314
import PythErrorsAbi from "@pythnetwork/pyth-sdk-solidity/abis/PythErrors.json";
1415
import { ChainIcon } from "connectkit";
@@ -32,6 +33,7 @@ import { ParameterInput } from "./parameter-input";
3233
import { type EvmApiType, RunButton } from "./run-button";
3334
import { useIsMounted } from "../../use-is-mounted";
3435
import { type SupportedLanguage, Code } from "../Code";
36+
import { ErrorTooltip } from "../ErrorTooltip";
3537
import { InlineLink } from "../InlineLink";
3638
import { Select } from "../Select";
3739

@@ -258,9 +260,12 @@ const Example = <ParameterName extends string>({
258260
setParamValues,
259261
}: ExampleProps<ParameterName>) => {
260262
const config = useConfig();
263+
const [error, setError] = useState<string | undefined>(undefined);
264+
const [loading, setLoading] = useState(false);
261265

262266
const updateValues = useCallback(() => {
263267
if (typeof example.parameters === "function") {
268+
setError(undefined);
264269
const address = getContractAddress(config.state.chainId);
265270
if (!address) {
266271
throw new Error(
@@ -272,12 +277,18 @@ const Example = <ParameterName extends string>({
272277
readContract(config, { abi, address, functionName, args }),
273278
});
274279
if (params instanceof Promise) {
280+
setLoading(true);
275281
params
276282
.then((paramsResolved) => {
277283
setParamValues(paramsResolved);
278284
})
279285
.catch(() => {
280-
/* TODO add some UI when this errors */
286+
setError(
287+
"An error occurred while fetching data for this example, please try again",
288+
);
289+
})
290+
.finally(() => {
291+
setLoading(false);
281292
});
282293
} else {
283294
setParamValues(params);
@@ -289,13 +300,17 @@ const Example = <ParameterName extends string>({
289300
const Icon = example.icon;
290301

291302
return (
292-
<InlineLink
293-
as="button"
294-
onClick={updateValues}
295-
className="flex flex-row items-center gap-2"
296-
>
297-
{Icon && <Icon className="h-4" />}
298-
<span>{example.name}</span>
299-
</InlineLink>
303+
<div className="flex flex-row items-center gap-2">
304+
<InlineLink
305+
as="button"
306+
onClick={updateValues}
307+
className="flex flex-row items-center gap-2"
308+
>
309+
{Icon && <Icon className="h-4" />}
310+
<span>{example.name}</span>
311+
</InlineLink>
312+
{error && <ErrorTooltip className="size-4">{error}</ErrorTooltip>}
313+
{loading && <ArrowPathIcon className="size-4 animate-spin" />}
314+
</div>
300315
);
301316
};

apps/api-reference/src/components/Home/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { MaxWidth } from "../MaxWidth";
99

1010
export const Home = () => (
1111
<main className="grid size-full place-content-center py-16 text-center">
12-
<h1 className="mb-24 text-6xl font-semibold text-pythpurple-600 dark:text-pythpurple-400">
12+
<h1 className="mb-16 text-4xl font-semibold text-pythpurple-600 dark:text-pythpurple-400">
1313
Pyth Network API Reference
1414
</h1>
1515
<MaxWidth>
@@ -62,7 +62,8 @@ const ProductLink = ({
6262
<Button
6363
as={Link}
6464
href={href}
65-
className="flex flex-col items-center gap-6 p-6 text-left sm:flex-row"
65+
gradient
66+
className="flex flex-col items-center gap-2 p-6 text-center sm:flex-row sm:gap-6 sm:pr-12 sm:text-left"
6667
>
6768
<Icon className="h-24 p-3 text-pythpurple-600 dark:text-pythpurple-400" />
6869
<div className="flex flex-col gap-2">

0 commit comments

Comments
 (0)