Bladeren bron

Merge branch 'main' into feat/table-grid

Alexandru Cambose 1 maand geleden
bovenliggende
commit
dc0c5b567b
30 gewijzigde bestanden met toevoegingen van 110 en 76 verwijderingen
  1. 1 1
      apps/insights/src/components/PriceComponentsCard/index.tsx
  2. 3 3
      apps/insights/src/components/PriceFeed/header.tsx
  3. 4 4
      apps/insights/src/components/PriceFeed/price-feed-select.tsx
  4. 2 2
      apps/insights/src/components/PriceFeeds/coming-soon-list.tsx
  5. 2 2
      apps/insights/src/components/PriceFeeds/index.tsx
  6. 5 5
      apps/insights/src/components/PriceFeeds/price-feeds-card.tsx
  7. 2 2
      apps/insights/src/components/Publisher/performance.tsx
  8. 3 3
      apps/insights/src/components/Publisher/price-feeds.tsx
  9. 2 2
      apps/insights/src/components/Publisher/top-feeds-table.tsx
  10. 1 1
      apps/insights/src/components/Publishers/publishers-card.tsx
  11. 3 3
      apps/insights/src/components/Root/search-button.tsx
  12. 0 7
      contract_manager/store/chains/EvmChains.json
  13. 0 5
      contract_manager/store/contracts/EvmExecutorContracts.json
  14. 0 5
      contract_manager/store/contracts/EvmLazerContracts.json
  15. 0 5
      contract_manager/store/contracts/EvmWormholeContracts.json
  16. 1 1
      governance/xc_admin/packages/xc_admin_common/src/chains.ts
  17. 1 1
      lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts
  18. 1 1
      lazer/contracts/sui/sdk/js/package.json
  19. 3 3
      lazer/sdk/js/examples/history.ts
  20. 1 1
      lazer/sdk/js/examples/streaming.ts
  21. 3 3
      lazer/sdk/js/examples/symbols.ts
  22. 1 1
      lazer/sdk/js/package.json
  23. 5 5
      lazer/sdk/js/src/client.ts
  24. 6 0
      packages/component-library/package.json
  25. 2 2
      packages/component-library/src/SymbolPairTag/index.module.scss
  26. 35 0
      packages/component-library/src/SymbolPairTag/index.stories.tsx
  27. 8 6
      packages/component-library/src/SymbolPairTag/index.tsx
  28. 6 0
      packages/component-library/src/omit-keys.ts
  29. 3 2
      packages/component-library/src/useQueryParamsPagination/index.ts
  30. 6 0
      pnpm-lock.yaml

+ 1 - 1
apps/insights/src/components/PriceComponentsCard/index.tsx

@@ -16,6 +16,7 @@ import type {
 } from "@pythnetwork/component-library/Table";
 import { Table } from "@pythnetwork/component-library/Table";
 import { useLogger } from "@pythnetwork/component-library/useLogger";
+import { useQueryParamFilterPagination } from "@pythnetwork/component-library/useQueryParamsPagination";
 import clsx from "clsx";
 import { useQueryState, parseAsStringEnum, parseAsBoolean } from "nuqs";
 import type { ReactNode } from "react";
@@ -23,7 +24,6 @@ import { Fragment, Suspense, useMemo, useCallback } from "react";
 import { useFilter, useCollator } from "react-aria";
 
 import styles from "./index.module.scss";
-import { useQueryParamFilterPagination } from "../../hooks/use-query-param-filter-pagination";
 import { Cluster } from "../../services/pyth";
 import type { StatusName } from "../../status";
 import {

+ 3 - 3
apps/insights/src/components/PriceFeed/header.tsx

@@ -3,6 +3,7 @@ import { Breadcrumbs } from "@pythnetwork/component-library/Breadcrumbs";
 import { Button } from "@pythnetwork/component-library/Button";
 import { Skeleton } from "@pythnetwork/component-library/Skeleton";
 import { StatCard } from "@pythnetwork/component-library/StatCard";
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import { Suspense } from "react";
 
 import { Cluster } from "../../services/pyth";
@@ -16,7 +17,6 @@ import {
   YesterdaysPricesProvider,
 } from "../PriceFeedChangePercent";
 import { PriceFeedIcon } from "../PriceFeedIcon";
-import { PriceFeedTag } from "../PriceFeedTag";
 import { PriceName } from "../PriceName";
 import { getFeed } from "./get-feed";
 import styles from "./header.module.scss";
@@ -93,7 +93,7 @@ const PriceFeedHeaderImpl = (props: PriceFeedHeaderImplProps) => (
                 })),
             })}
       >
-        <PriceFeedTag
+        <SymbolPairTag
           {...(props.isLoading
             ? { isLoading: true }
             : {
@@ -108,7 +108,7 @@ const PriceFeedHeaderImpl = (props: PriceFeedHeaderImplProps) => (
               })}
         />
       </PriceFeedSelect>
-      <PriceFeedTag
+      <SymbolPairTag
         className={styles.priceFeedTag}
         {...(props.isLoading
           ? { isLoading: true }

+ 4 - 4
apps/insights/src/components/PriceFeed/price-feed-select.tsx

@@ -1,9 +1,10 @@
 "use client";
 
 import { DropdownCaretDown } from "@pythnetwork/component-library/DropdownCaretDown";
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import {
-  Virtualizer,
   ListLayout,
+  Virtualizer,
 } from "@pythnetwork/component-library/Virtualizer";
 import { Button } from "@pythnetwork/component-library/unstyled/Button";
 import { Dialog } from "@pythnetwork/component-library/unstyled/Dialog";
@@ -20,9 +21,8 @@ import { matchSorter } from "match-sorter";
 import type { ReactNode } from "react";
 import { useMemo, useState } from "react";
 
-import styles from "./price-feed-select.module.scss";
 import { AssetClassBadge } from "../AssetClassBadge";
-import { PriceFeedTag } from "../PriceFeedTag";
+import styles from "./price-feed-select.module.scss";
 
 type Props = {
   className: string | undefined;
@@ -111,7 +111,7 @@ const ResolvedPriceFeedSelect = ({
                     }
                     prefetch={false}
                   >
-                    <PriceFeedTag
+                    <SymbolPairTag
                       displaySymbol={displaySymbol}
                       description={description}
                       icon={icon}

+ 2 - 2
apps/insights/src/components/PriceFeeds/coming-soon-list.tsx

@@ -3,6 +3,7 @@
 import { NoResults } from "@pythnetwork/component-library/NoResults";
 import { SearchInput } from "@pythnetwork/component-library/SearchInput";
 import { Select } from "@pythnetwork/component-library/Select";
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import { Table } from "@pythnetwork/component-library/Table";
 import type { ReactNode } from "react";
 import { useMemo, useState } from "react";
@@ -10,7 +11,6 @@ import { useCollator, useFilter } from "react-aria";
 
 import styles from "./coming-soon-list.module.scss";
 import { AssetClassBadge } from "../AssetClassBadge";
-import { PriceFeedTag } from "../PriceFeedTag";
 
 type Props = {
   comingSoonFeeds: {
@@ -65,7 +65,7 @@ export const ComingSoonList = ({ comingSoonFeeds }: Props) => {
           href: `/price-feeds/${encodeURIComponent(symbol)}`,
           data: {
             priceFeedName: (
-              <PriceFeedTag
+              <SymbolPairTag
                 description={description}
                 displaySymbol={displaySymbol}
                 icon={icon}

+ 2 - 2
apps/insights/src/components/PriceFeeds/index.tsx

@@ -8,6 +8,7 @@ import { Button } from "@pythnetwork/component-library/Button";
 import type { Props as CardProps } from "@pythnetwork/component-library/Card";
 import { Card } from "@pythnetwork/component-library/Card";
 import { StatCard } from "@pythnetwork/component-library/StatCard";
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import { TabList } from "@pythnetwork/component-library/TabList";
 import {
   TabPanel as UnstyledTabPanel,
@@ -30,7 +31,6 @@ import {
   PriceFeedChangePercent,
 } from "../PriceFeedChangePercent";
 import { PriceFeedIcon } from "../PriceFeedIcon";
-import { PriceFeedTag } from "../PriceFeedTag";
 
 const PRICE_FEEDS_ANCHOR = "priceFeeds";
 
@@ -260,7 +260,7 @@ const FeaturedFeedsCard = <T extends ElementType>({
           href={`/price-feeds/${encodeURIComponent(feed.symbol)}`}
         >
           <div className={styles.feedCardContents}>
-            <PriceFeedTag
+            <SymbolPairTag
               displaySymbol={feed.product.display_symbol}
               description={feed.product.description}
               icon={

+ 5 - 5
apps/insights/src/components/PriceFeeds/price-feeds-card.tsx

@@ -8,19 +8,20 @@ import { NoResults } from "@pythnetwork/component-library/NoResults";
 import { Paginator } from "@pythnetwork/component-library/Paginator";
 import { SearchInput } from "@pythnetwork/component-library/SearchInput";
 import { Select } from "@pythnetwork/component-library/Select";
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import type {
   RowConfig,
   SortDescriptor,
 } from "@pythnetwork/component-library/Table";
 import { Table } from "@pythnetwork/component-library/Table";
 import { useLogger } from "@pythnetwork/component-library/useLogger";
+import { useQueryParamFilterPagination } from "@pythnetwork/component-library/useQueryParamsPagination";
 import { matchSorter } from "match-sorter";
 import { parseAsString, useQueryState } from "nuqs";
 import type { ReactNode } from "react";
 import { Suspense, useCallback, useMemo } from "react";
 import { useCollator } from "react-aria";
 
-import { useQueryParamFilterPagination } from "../../hooks/use-query-param-filter-pagination";
 import { Cluster } from "../../services/pyth";
 import { AssetClassBadge } from "../AssetClassBadge";
 import { FeedKey } from "../FeedKey";
@@ -30,7 +31,6 @@ import {
   LiveValue,
   SKELETON_WIDTH,
 } from "../LivePrices";
-import { PriceFeedTag } from "../PriceFeedTag";
 import { PriceName } from "../PriceName";
 import styles from "./price-feeds-card.module.scss";
 
@@ -137,7 +137,7 @@ const ResolvedPriceFeedsCard = ({ priceFeeds, ...props }: Props) => {
               <LiveConfidence feedKey={key} cluster={Cluster.Pythnet} />
             ),
             priceFeedName: (
-              <PriceFeedTag
+              <SymbolPairTag
                 description={description}
                 displaySymbol={displaySymbol}
                 icon={icon}
@@ -296,7 +296,7 @@ const PriceFeedsCardContents = ({ id, ...props }: PriceFeedsCardContents) => (
     <EntityList
       label="Price Feeds"
       className={styles.entityList ?? ""}
-      headerLoadingSkeleton={<PriceFeedTag isLoading />}
+      headerLoadingSkeleton={<SymbolPairTag isLoading />}
       fields={[
         { id: "assetClass", name: "Asset Class" },
         { id: "priceFeedId", name: "Price Feed ID" },
@@ -331,7 +331,7 @@ const PriceFeedsCardContents = ({ id, ...props }: PriceFeedsCardContents) => (
           name: "PRICE FEED",
           isRowHeader: true,
           alignment: "left",
-          loadingSkeleton: <PriceFeedTag isLoading />,
+          loadingSkeleton: <SymbolPairTag isLoading />,
           allowsSorting: true,
         },
         {

+ 2 - 2
apps/insights/src/components/Publisher/performance.tsx

@@ -7,6 +7,7 @@ import { EntityList } from "@pythnetwork/component-library/EntityList";
 import { Link } from "@pythnetwork/component-library/Link";
 import type { Variant as NoResultsVariant } from "@pythnetwork/component-library/NoResults";
 import { NoResults } from "@pythnetwork/component-library/NoResults";
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import { Table } from "@pythnetwork/component-library/Table";
 import { lookup } from "@pythnetwork/known-publishers";
 import { notFound } from "next/navigation";
@@ -25,7 +26,6 @@ import {
   ExplainAverage,
 } from "../Explanations";
 import { PriceFeedIcon } from "../PriceFeedIcon";
-import { PriceFeedTag } from "../PriceFeedTag";
 import { PublisherIcon } from "../PublisherIcon";
 import { PublisherTag } from "../PublisherTag";
 import { Ranking } from "../Ranking";
@@ -365,7 +365,7 @@ const TopFeedsCard = ({
       <TopFeedsTable
         label={`${title} Feeds`}
         publisherScoreWidth={PUBLISHER_SCORE_WIDTH}
-        nameLoadingSkeleton={<PriceFeedTag isLoading />}
+        nameLoadingSkeleton={<SymbolPairTag isLoading />}
         {...(props.isLoading
           ? { isLoading: true }
           : {

+ 3 - 3
apps/insights/src/components/Publisher/price-feeds.tsx

@@ -1,3 +1,4 @@
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import { notFound } from "next/navigation";
 
 import { getPriceFeeds } from "./get-price-feeds";
@@ -7,7 +8,6 @@ import { AssetClassBadge } from "../AssetClassBadge";
 import type { PriceComponent } from "../PriceComponentsCard";
 import { PriceComponentsCard } from "../PriceComponentsCard";
 import { PriceFeedIcon } from "../PriceFeedIcon";
-import { PriceFeedTag } from "../PriceFeedTag";
 
 type Props = {
   params: Promise<{
@@ -36,7 +36,7 @@ export const PriceFeeds = async ({ params }: Props) => {
       priceFeeds={feeds.map(({ ranking, feed, status }) => ({
         symbol: feed.symbol,
         name: (
-          <PriceFeedTag
+          <SymbolPairTag
             displaySymbol={feed.product.display_symbol}
             description={feed.product.description}
             icon={
@@ -80,7 +80,7 @@ const PriceFeedsCard = (props: PriceFeedsCardProps) => (
   <PriceComponentsCard
     label="Price Feeds"
     searchPlaceholder="Feed symbol"
-    nameLoadingSkeleton={<PriceFeedTag isLoading />}
+    nameLoadingSkeleton={<SymbolPairTag isLoading />}
     extraColumns={[
       {
         id: "assetClassBadge",

+ 2 - 2
apps/insights/src/components/Publisher/top-feeds-table.tsx

@@ -1,6 +1,7 @@
 "use client";
 
 import { EntityList } from "@pythnetwork/component-library/EntityList";
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import type { RowConfig } from "@pythnetwork/component-library/Table";
 import { Table } from "@pythnetwork/component-library/Table";
 import type { ReactNode } from "react";
@@ -11,7 +12,6 @@ import type { Cluster } from "../../services/pyth";
 import type { Status } from "../../status";
 import { AssetClassBadge } from "../AssetClassBadge";
 import { usePriceComponentDrawer } from "../PriceComponentDrawer";
-import { PriceFeedTag } from "../PriceFeedTag";
 import { Score } from "../Score";
 
 type Props =
@@ -53,7 +53,7 @@ const ResolvedTopFeedsTable = ({
     () =>
       feeds.map((feed) => ({
         name: (
-          <PriceFeedTag
+          <SymbolPairTag
             displaySymbol={feed.displaySymbol}
             description={feed.description}
             icon={feed.icon}

+ 1 - 1
apps/insights/src/components/Publishers/publishers-card.tsx

@@ -16,6 +16,7 @@ import type {
 } from "@pythnetwork/component-library/Table";
 import { Table } from "@pythnetwork/component-library/Table";
 import { useLogger } from "@pythnetwork/component-library/useLogger";
+import { useQueryParamFilterPagination } from "@pythnetwork/component-library/useQueryParamsPagination";
 import clsx from "clsx";
 import { useQueryState, parseAsStringEnum } from "nuqs";
 import type { ReactNode } from "react";
@@ -23,7 +24,6 @@ import { Suspense, useMemo, useCallback } from "react";
 import { useFilter, useCollator } from "react-aria";
 
 import styles from "./publishers-card.module.scss";
-import { useQueryParamFilterPagination } from "../../hooks/use-query-param-filter-pagination";
 import { CLUSTER_NAMES } from "../../services/pyth";
 import {
   ExplainPermissioned,

+ 3 - 3
apps/insights/src/components/Root/search-button.tsx

@@ -8,6 +8,7 @@ import { NoResults } from "@pythnetwork/component-library/NoResults";
 import { SearchButton as SearchButtonComponent } from "@pythnetwork/component-library/SearchButton";
 import { SearchInput } from "@pythnetwork/component-library/SearchInput";
 import { SingleToggleGroup } from "@pythnetwork/component-library/SingleToggleGroup";
+import { SymbolPairTag } from "@pythnetwork/component-library/SymbolPairTag";
 import {
   ListLayout,
   Virtualizer,
@@ -25,7 +26,6 @@ import { useCallback, useEffect, useMemo, useState } from "react";
 
 import { Cluster, ClusterToName } from "../../services/pyth";
 import { AssetClassBadge } from "../AssetClassBadge";
-import { PriceFeedTag } from "../PriceFeedTag";
 import { PublisherTag } from "../PublisherTag";
 import { Score } from "../Score";
 import styles from "./search-button.module.scss";
@@ -241,7 +241,7 @@ const SearchDialogContents = ({
               >
                 <div className={styles.smallScreen}>
                   {result.type === ResultType.PriceFeed ? (
-                    <PriceFeedTag
+                    <SymbolPairTag
                       className={styles.itemTag}
                       displaySymbol={result.displaySymbol}
                       description={result.description}
@@ -316,7 +316,7 @@ const SearchDialogContents = ({
                   </div>
                   {result.type === ResultType.PriceFeed ? (
                     <>
-                      <PriceFeedTag
+                      <SymbolPairTag
                         displaySymbol={result.displaySymbol}
                         description={result.description}
                         icon={result.icon}

+ 0 - 7
contract_manager/store/chains/EvmChains.json

@@ -1315,13 +1315,6 @@
     "networkId": 16661,
     "type": "EvmChain"
   },
-  {
-    "id": "itsnotreal",
-    "mainnet": true,
-    "rpcUrl": "https://rpc.itsnotreal.lol",
-    "networkId": 1380270412,
-    "type": "EvmChain"
-  },
   {
     "id": "giwa_testnet",
     "mainnet": false,

+ 0 - 5
contract_manager/store/contracts/EvmExecutorContracts.json

@@ -224,11 +224,6 @@
     "address": "0x26DD80569a8B23768A1d80869Ed7339e07595E85",
     "type": "EvmExecutorContract"
   },
-  {
-    "chain": "itsnotreal",
-    "address": "0x98046Bd286715D3B0BC227Dd7a956b83D8978603",
-    "type": "EvmExecutorContract"
-  },
   {
     "chain": "giwa_testnet",
     "address": "0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c",

+ 0 - 5
contract_manager/store/contracts/EvmLazerContracts.json

@@ -59,11 +59,6 @@
     "address": "0x4D4772F06c595F69FB57039599a180536FDE8245",
     "type": "EvmLazerContract"
   },
-  {
-    "chain": "itsnotreal",
-    "address": "0xACeA761c27A909d4D3895128EBe6370FDE2dF481",
-    "type": "EvmLazerContract"
-  },
   {
     "chain": "itsnotreal2",
     "address": "0xACeA761c27A909d4D3895128EBe6370FDE2dF481",

+ 0 - 5
contract_manager/store/contracts/EvmWormholeContracts.json

@@ -874,11 +874,6 @@
     "address": "0xb27e5ca259702f209a29225d0eDdC131039C9933",
     "type": "EvmWormholeContract"
   },
-  {
-    "chain": "itsnotreal",
-    "address": "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
-    "type": "EvmWormholeContract"
-  },
   {
     "chain": "giwa_testnet",
     "address": "0xb27e5ca259702f209a29225d0eDdC131039C9933",

+ 1 - 1
governance/xc_admin/packages/xc_admin_common/src/chains.ts

@@ -117,7 +117,7 @@ export const RECEIVER_CHAINS = {
   camp_network: 60086,
   spiderman: 60087,
   zero_gravity: 60088,
-  itsnotreal: 60089,
+  itsnotreal: 60089, // Deprecated
   plasma: 60090,
   itsnotreal2: 60091,
 

+ 1 - 1
lazer/contracts/sui/sdk/js/examples/fetch-and-verify-update.ts

@@ -12,7 +12,7 @@ async function getOneLeEcdsaUpdate(token: string) {
     token,
   });
 
-  const latestPrice = await lazer.get_latest_price({
+  const latestPrice = await lazer.getLatestPrice({
     priceFeedIds: [1],
     properties: ["price", "bestBidPrice", "bestAskPrice", "exponent"],
     formats: ["leEcdsa"],

+ 1 - 1
lazer/contracts/sui/sdk/js/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/pyth-lazer-sui-js",
-  "version": "0.1.1",
+  "version": "0.1.2",
   "description": "TypeScript SDK for the Pyth Lazer Sui contract",
   "license": "Apache-2.0",
   "type": "module",

+ 3 - 3
lazer/sdk/js/examples/history.ts

@@ -10,7 +10,7 @@ const client = await PythLazerClient.create({
 
 // Example 1: Get latest price for BTC using feed IDs
 console.log("\n=== Example 1: Latest BTC price (requested with feed ID) ===");
-const response1 = await client.get_latest_price({
+const response1 = await client.getLatestPrice({
   priceFeedIds: [1],
   properties: ["price", "confidence", "exponent"],
   formats: [],
@@ -22,7 +22,7 @@ displayParsedPrices(response1);
 
 // Example 2: Get latest price using symbols
 console.log("\n=== Example 2: Latest ETH price (requested with symbols) ===");
-const response2 = await client.get_latest_price({
+const response2 = await client.getLatestPrice({
   priceFeedIds: [2],
   properties: ["price", "confidence", "exponent"],
   formats: [],
@@ -37,7 +37,7 @@ const timestamp = 1_754_348_458_565_000;
 console.log(
   `Requesting price from timestamp: ${timestamp.toString()} (${new Date(timestamp / 1000).toISOString()})`,
 );
-const response3 = await client.get_price({
+const response3 = await client.getPrice({
   timestamp: timestamp,
   priceFeedIds: [1],
   properties: ["price", "confidence", "exponent"],

+ 1 - 1
lazer/sdk/js/examples/streaming.ts

@@ -40,7 +40,7 @@ const client = await PythLazerClient.create({
 });
 
 // Fetch current map of price feeds
-void client.get_symbols().then((symbols) => {
+void client.getSymbols().then((symbols) => {
   for (const symbol of symbols) {
     symbolsMap.set(symbol.pyth_lazer_id, symbol.symbol);
   }

+ 3 - 3
lazer/sdk/js/examples/symbols.ts

@@ -9,19 +9,19 @@ const client = await PythLazerClient.create({
 
 // Example 1: Get latest price for BTC using feed IDs
 console.log("\n=== Example 1: Search feeds by name/symbol ===");
-const response1 = await client.get_symbols({ query: "BTC" });
+const response1 = await client.getSymbols({ query: "BTC" });
 console.log(response1);
 
 // Example 2: Get latest price using symbols
 console.log("\n=== Example 2: Get feeds by asset type ===");
-const response2 = await client.get_symbols({
+const response2 = await client.getSymbols({
   asset_type: "equity",
 });
 console.log(response2);
 
 // Example 3: Get feeds by asset type and query
 console.log("\n=== Example 3: Get feeds by asset type and name/symbol ===");
-const response3 = await client.get_symbols({
+const response3 = await client.getSymbols({
   asset_type: "equity",
   query: "AAPL",
 });

+ 1 - 1
lazer/sdk/js/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/pyth-lazer-sdk",
-  "version": "3.0.1",
+  "version": "4.0.0",
   "description": "Pyth Lazer SDK",
   "publishConfig": {
     "access": "public"

+ 5 - 5
lazer/sdk/js/src/client.ts

@@ -222,7 +222,7 @@ export class PythLazerClient {
    * @param params - Optional query parameters to filter symbols
    * @returns Promise resolving to array of symbol information
    */
-  async get_symbols(params?: SymbolsQueryParams): Promise<SymbolResponse[]> {
+  async getSymbols(params?: SymbolsQueryParams): Promise<SymbolResponse[]> {
     const url = new URL(`${this.metadataServiceUrl}/v1/symbols`);
 
     if (params?.query) {
@@ -252,12 +252,12 @@ export class PythLazerClient {
    * @param params - Parameters for the latest price request
    * @returns Promise resolving to JsonUpdate with current price data
    */
-  async get_latest_price(params: LatestPriceRequest): Promise<JsonUpdate> {
+  async getLatestPrice(params: LatestPriceRequest): Promise<JsonUpdate> {
     const url = `${this.priceServiceUrl}/v1/latest_price`;
 
     try {
       const body = JSON.stringify(params);
-      this.logger.debug("get_latest_price", { url, body });
+      this.logger.debug("getLatestPrice", { url, body });
       const response = await this.authenticatedFetch(url, {
         method: "POST",
         headers: {
@@ -283,12 +283,12 @@ export class PythLazerClient {
    * @param params - Parameters for the price request including timestamp
    * @returns Promise resolving to JsonUpdate with price data at the specified time
    */
-  async get_price(params: PriceRequest): Promise<JsonUpdate> {
+  async getPrice(params: PriceRequest): Promise<JsonUpdate> {
     const url = `${this.priceServiceUrl}/v1/price`;
 
     try {
       const body = JSON.stringify(params);
-      this.logger.debug("get_price", { url, body });
+      this.logger.debug("getPrice", { url, body });
       const response = await this.authenticatedFetch(url, {
         method: "POST",
         headers: {

+ 6 - 0
packages/component-library/package.json

@@ -15,6 +15,10 @@
       "types": "./dist/esm/useData/index.d.ts",
       "default": "./dist/esm/useData/index.js"
     },
+    "./useQueryParamsPagination": {
+      "types": "./dist/esm/useQueryParamsPagination/index.d.ts",
+      "default": "./dist/esm/useQueryParamsPagination/index.js"
+    },
     "./theme": "./dist/esm/theme.scss"
   },
   "scripts": {
@@ -49,6 +53,7 @@
     "modern-normalize": "catalog:",
     "motion": "catalog:",
     "next-themes": "catalog:",
+    "nuqs": "catalog:",
     "pino": "catalog:",
     "react-aria": "catalog:",
     "react-aria-components": "catalog:",
@@ -76,6 +81,7 @@
     "autoprefixer": "catalog:",
     "babel-plugin-react-compiler": "catalog:",
     "copyfiles": "catalog:",
+    "cryptocurrency-icons": "catalog:",
     "css-loader": "catalog:",
     "eslint": "catalog:",
     "jest": "catalog:",

+ 2 - 2
apps/insights/src/components/PriceFeedTag/index.module.scss → packages/component-library/src/SymbolPairTag/index.module.scss

@@ -1,6 +1,6 @@
-@use "@pythnetwork/component-library/theme";
+@use "../theme";
 
-.priceFeedTag {
+.symbolPairTag {
   display: flex;
   flex-flow: row nowrap;
   gap: theme.spacing(3);

+ 35 - 0
packages/component-library/src/SymbolPairTag/index.stories.tsx

@@ -0,0 +1,35 @@
+import type { Meta, StoryObj } from "@storybook/react";
+import CryptoIcon from "cryptocurrency-icons/svg/color/btc.svg";
+
+import { SymbolPairTag as SymbolPairTagComponent } from "./index.jsx";
+const meta = {
+  component: SymbolPairTagComponent,
+  argTypes: {
+    isLoading: {
+      control: "boolean",
+      table: {
+        category: "State",
+      },
+    },
+    icon: {
+      description: "The icon to display",
+      disable: true,
+    },
+    displaySymbol: {
+      control: "text",
+    },
+    description: {
+      control: "text",
+    },
+  },
+} satisfies Meta<typeof SymbolPairTagComponent>;
+export default meta;
+
+export const SymbolPairTag = {
+  args: {
+    displaySymbol: "BTC/USD",
+    isLoading: false,
+    icon: <CryptoIcon width="100%" height="100%" viewBox="0 0 32 32" />,
+    description: "Bitcoin",
+  },
+} satisfies StoryObj<typeof SymbolPairTagComponent>;

+ 8 - 6
apps/insights/src/components/PriceFeedTag/index.tsx → packages/component-library/src/SymbolPairTag/index.tsx

@@ -1,10 +1,12 @@
-import { Skeleton } from "@pythnetwork/component-library/Skeleton";
+"use client";
+
 import clsx from "clsx";
 import type { ComponentProps, ReactNode } from "react";
 import { Fragment } from "react";
 
 import styles from "./index.module.scss";
-import { omitKeys } from "../../omit-keys";
+import { Skeleton } from "../Skeleton/index.jsx";
+import { omitKeys } from "../omit-keys";
 
 type OwnProps =
   | { isLoading: true }
@@ -17,9 +19,9 @@ type OwnProps =
 
 type Props = Omit<ComponentProps<"div">, keyof OwnProps> & OwnProps;
 
-export const PriceFeedTag = ({ className, ...props }: Props) => (
+export const SymbolPairTag = ({ className, ...props }: Props) => (
   <div
-    className={clsx(styles.priceFeedTag, className)}
+    className={clsx(styles.symbolPairTag, className)}
     data-loading={props.isLoading ? "" : undefined}
     {...omitKeys(props, ["displaySymbol", "description", "isLoading"])}
   >
@@ -33,7 +35,7 @@ export const PriceFeedTag = ({ className, ...props }: Props) => (
         {props.isLoading ? (
           <Skeleton width={30} />
         ) : (
-          <FeedName displaySymbol={props.displaySymbol} />
+          <SymbolName displaySymbol={props.displaySymbol} />
         )}
       </div>
       <div className={styles.description}>
@@ -47,7 +49,7 @@ export const PriceFeedTag = ({ className, ...props }: Props) => (
   </div>
 );
 
-const FeedName = ({ displaySymbol }: { displaySymbol: string }) => {
+const SymbolName = ({ displaySymbol }: { displaySymbol: string }) => {
   const [firstPart, ...rest] = displaySymbol.split("/");
   return (
     <>

+ 6 - 0
packages/component-library/src/omit-keys.ts

@@ -0,0 +1,6 @@
+export const omitKeys = (obj: Record<string, unknown>, keys: string[]) => {
+  const omitSet = new Set(keys);
+  return Object.fromEntries(
+    Object.entries(obj).filter(([key]) => !omitSet.has(key)),
+  );
+};

+ 3 - 2
apps/insights/src/hooks/use-query-param-filter-pagination.ts → packages/component-library/src/useQueryParamsPagination/index.ts

@@ -1,7 +1,5 @@
 "use client";
 
-import type { SortDescriptor } from "@pythnetwork/component-library/unstyled/Table";
-import { useLogger } from "@pythnetwork/component-library/useLogger";
 import { usePathname } from "next/navigation";
 import {
   parseAsString,
@@ -12,6 +10,9 @@ import {
 } from "nuqs";
 import { useCallback, useMemo } from "react";
 
+import type { SortDescriptor } from "../unstyled/Table";
+import { useLogger } from "../useLogger";
+
 export const useQueryParamFilterPagination = <T>(
   items: T[],
   predicate: (item: T, search: string) => boolean,

+ 6 - 0
pnpm-lock.yaml

@@ -2193,6 +2193,9 @@ importers:
       next-themes:
         specifier: 'catalog:'
         version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+      nuqs:
+        specifier: 'catalog:'
+        version: 2.4.1(next@15.5.0(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(react@19.1.0)
       pino:
         specifier: 'catalog:'
         version: 9.6.0
@@ -2269,6 +2272,9 @@ importers:
       copyfiles:
         specifier: 'catalog:'
         version: 2.4.1
+      cryptocurrency-icons:
+        specifier: 'catalog:'
+        version: 0.18.1
       css-loader:
         specifier: 'catalog:'
         version: 7.1.2(webpack@5.98.0(@swc/core@1.13.2)(esbuild@0.25.9))