Skip to content

Commit b1ff9e7

Browse files
chore(price-feed): added update parameters as a column in each table for EVM (#739)
* added update parameters as a column in each table for evm Signed-off-by: nidhi-singh02 <nidhi2894@gmail.com> * apply pre-commit/prettier formatting * pretty pretty * show 7 items at once if more Signed-off-by: nidhi-singh02 <nidhi2894@gmail.com> * helper mapValues and using max height for table * typescript version * update param define structure Signed-off-by: nidhi-singh02 <nidhi2894@gmail.com> * put values in each row and remove fixed row * pre commit --------- Signed-off-by: nidhi-singh02 <nidhi2894@gmail.com>
1 parent 5673408 commit b1ff9e7

File tree

5 files changed

+1641
-204
lines changed

5 files changed

+1641
-204
lines changed

components/SponsoredFeedsTable.tsx

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import { useState } from "react";
2+
import CopyIcon from "./icons/CopyIcon";
3+
import { mapValues } from "../utils/ObjectHelpers";
4+
5+
interface UpdateParameters {
6+
heartbeatLength: number;
7+
heartbeatUnit: "second" | "minute" | "hour";
8+
priceDeviation: number;
9+
}
10+
11+
interface SponsoredFeed {
12+
name: string;
13+
priceFeedId: string;
14+
updateParameters: UpdateParameters;
15+
}
16+
17+
interface SponsoredFeedsTableProps {
18+
feeds: SponsoredFeed[];
19+
networkName: string;
20+
}
21+
22+
/**
23+
* Helper functions
24+
*/
25+
26+
// Format update parameters as a string for grouping
27+
const formatUpdateParams = (params: UpdateParameters): string => {
28+
return `${params.heartbeatLength} ${params.heartbeatUnit} heartbeat / ${params.priceDeviation}% price deviation`;
29+
};
30+
31+
// Render update parameters with proper styling
32+
const renderUpdateParams = (params: UpdateParameters, isDefault: boolean) => (
33+
<div className="flex items-start gap-1.5">
34+
<div
35+
className={`w-1.5 h-1.5 rounded-full mt-1 flex-shrink-0 ${
36+
isDefault ? "bg-green-500" : "bg-orange-500"
37+
}`}
38+
></div>
39+
<span
40+
className={`text-xs leading-relaxed font-medium ${
41+
isDefault
42+
? "text-gray-700 dark:text-gray-300"
43+
: "text-orange-600 dark:text-orange-400"
44+
}`}
45+
>
46+
<strong>{params.heartbeatLength}</strong> {params.heartbeatUnit} heartbeat
47+
<br />
48+
<strong>{params.priceDeviation}%</strong> price deviation
49+
</span>
50+
</div>
51+
);
52+
53+
export const SponsoredFeedsTable = ({
54+
feeds,
55+
networkName,
56+
}: SponsoredFeedsTableProps) => {
57+
const [copiedId, setCopiedId] = useState<string | null>(null);
58+
59+
const copyToClipboard = (text: string) => {
60+
navigator.clipboard.writeText(text).then(() => {
61+
setCopiedId(text);
62+
setTimeout(() => setCopiedId(null), 2000);
63+
});
64+
};
65+
66+
// Calculate parameter statistics
67+
const paramCounts = mapValues(
68+
Object.groupBy(feeds, (feed) => formatUpdateParams(feed.updateParameters)),
69+
(feeds: SponsoredFeed[]) => feeds.length
70+
);
71+
72+
const defaultParams = Object.entries(paramCounts).sort(
73+
([, a], [, b]) => b - a
74+
)[0][0];
75+
76+
return (
77+
<div className="my-6">
78+
<p className="mb-3">
79+
The price feeds listed in the table below are currently sponsored in{" "}
80+
<strong>{networkName}</strong>.
81+
</p>
82+
83+
<div className="border border-gray-200 dark:border-gray-700 rounded-lg">
84+
{/* Summary bar */}
85+
<div className="bg-blue-50 dark:bg-blue-900/20 px-3 py-2 border-b border-gray-200 dark:border-gray-600">
86+
<div className="flex flex-wrap items-center gap-4 text-sm">
87+
<div className="flex items-center gap-1.5">
88+
<div className="w-1.5 h-1.5 bg-green-500 rounded-full flex-shrink-0"></div>
89+
<span className="font-medium">Default:</span>
90+
<span>{defaultParams}</span>
91+
<span className="text-gray-500">
92+
({paramCounts[defaultParams]})
93+
</span>
94+
</div>
95+
{Object.entries(paramCounts)
96+
.filter(([params]) => params !== defaultParams)
97+
.map(([params, count]) => (
98+
<div key={params} className="flex items-center gap-1.5">
99+
<div className="w-1.5 h-1.5 bg-orange-500 rounded-full flex-shrink-0"></div>
100+
<span className="font-medium">Exception:</span>
101+
<span>{params}</span>
102+
<span className="text-gray-500">({count})</span>
103+
</div>
104+
))}
105+
</div>
106+
</div>
107+
108+
{/* Table */}
109+
<div className="overflow-x-auto">
110+
<div className="overflow-y-auto max-h-96">
111+
<table className="w-full text-sm min-w-full">
112+
<thead className="sticky top-0 bg-gray-50 dark:bg-gray-800 z-30">
113+
<tr>
114+
<th className="text-left px-3 py-2 font-semibold text-gray-900 dark:text-gray-100 border-b border-gray-200 dark:border-gray-600 min-w-[100px]">
115+
Name
116+
</th>
117+
<th className="text-left px-3 py-2 font-semibold text-gray-900 dark:text-gray-100 border-b border-gray-200 dark:border-gray-600 min-w-[400px]">
118+
Price Feed Id
119+
</th>
120+
<th className="text-left px-3 py-2 font-semibold text-gray-900 dark:text-gray-100 border-b border-gray-200 dark:border-gray-600 min-w-[200px]">
121+
Update Parameters
122+
</th>
123+
</tr>
124+
</thead>
125+
<tbody className="bg-white dark:bg-gray-900">
126+
{feeds.map((feed, index) => {
127+
const formattedParams = formatUpdateParams(
128+
feed.updateParameters
129+
);
130+
const isDefault = formattedParams === defaultParams;
131+
132+
return (
133+
<tr
134+
key={feed.priceFeedId}
135+
className="border-b border-gray-100 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/30"
136+
>
137+
<td className="px-3 py-2 align-top">
138+
<span className="font-medium text-gray-900 dark:text-gray-100">
139+
{feed.name}
140+
</span>
141+
</td>
142+
<td className="px-3 py-2 align-top">
143+
<div className="flex items-start gap-2">
144+
<code className="text-xs font-mono text-gray-600 dark:text-gray-400 flex-1 break-all leading-relaxed">
145+
{feed.priceFeedId}
146+
</code>
147+
<button
148+
onClick={() => copyToClipboard(feed.priceFeedId)}
149+
className="p-1 hover:bg-gray-200 dark:hover:bg-gray-600 rounded flex-shrink-0 mt-0.5"
150+
title="Copy Price Feed ID"
151+
>
152+
{copiedId === feed.priceFeedId ? (
153+
<span className="text-green-500 text-xs font-bold">
154+
155+
</span>
156+
) : (
157+
<CopyIcon className="w-3 h-3 text-gray-400" />
158+
)}
159+
</button>
160+
</div>
161+
</td>
162+
<td className="px-3 py-2 align-top">
163+
{renderUpdateParams(feed.updateParameters, isDefault)}
164+
</td>
165+
</tr>
166+
);
167+
})}
168+
</tbody>
169+
</table>
170+
</div>
171+
</div>
172+
</div>
173+
</div>
174+
);
175+
};

package-lock.json

Lines changed: 11 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,6 @@
5656
"solc": "^0.8.20",
5757
"tailwindcss": "^3.4.3",
5858
"ts-node": "^10.9.1",
59-
"typescript": "^5.1.6"
59+
"typescript": "^5.8.3"
6060
}
6161
}

0 commit comments

Comments
 (0)