Explorar o código

feat(staking): sort, filter, and paginate publishers

Connor Prussin hai 1 ano
pai
achega
40991be2cd

+ 2 - 2
apps/staking/src/api.ts

@@ -38,7 +38,7 @@ type Data = {
     cooldown2: bigint;
   };
   integrityStakingPublishers: {
-    name: string;
+    name: string | undefined;
     publicKey: PublicKey;
     isSelf: boolean;
     selfStake: bigint;
@@ -196,7 +196,7 @@ export const loadData = async (
     integrityStakingPublishers: publishers.map(({ pubkey: publisher }) => ({
       apyHistory: [], // TODO
       isSelf: false, // TODO
-      name: publisher.toString(),
+      name: undefined, // TODO
       numFeeds: 0, // TODO
       poolCapacity: 100n, // TODO
       poolUtilization: 0n, // TODO

+ 2 - 2
apps/staking/src/components/Footer/index.tsx

@@ -36,12 +36,12 @@ export const Footer = ({
 }: Omit<HTMLAttributes<HTMLElement>, "children">) => (
   <footer
     className={clsx(
-      "sticky bottom-0 mt-4 px-4 text-xs font-light text-neutral-400",
+      "sticky bottom-0 mt-4 text-xs font-light text-neutral-400 sm:px-4",
       className,
     )}
     {...props}
   >
-    <div className="border-x border-t border-neutral-600/50 bg-pythpurple-800">
+    <div className="border-t border-neutral-600/50 bg-pythpurple-800 sm:border-x">
       <MaxWidth className="flex h-16 items-center justify-between sm:-mx-4">
         <div>© 2024 Pyth Data Association</div>
         <div className="relative -right-3 flex h-full items-center">

+ 2 - 2
apps/staking/src/components/Header/index.tsx

@@ -12,10 +12,10 @@ export const Header = ({
   ...props
 }: Omit<HTMLAttributes<HTMLElement>, "children">) => (
   <header
-    className={clsx("sticky top-0 mb-4 w-full px-4", className)}
+    className={clsx("sticky top-0 mb-4 w-full sm:px-4", className)}
     {...props}
   >
-    <div className="border-x border-b border-neutral-600/50 bg-pythpurple-800">
+    <div className="border-b border-neutral-600/50 bg-pythpurple-800 sm:border-x">
       <MaxWidth className="flex h-16 items-center justify-between gap-8 sm:-mx-4">
         <Logo className="max-h-full py-4 text-pythpurple-100" />
         <WalletButton className="flex-none" />

+ 4 - 1
apps/staking/src/components/MaxWidth/index.tsx

@@ -1,3 +1,6 @@
 import { Styled } from "../Styled";
 
-export const MaxWidth = Styled("div", "w-full px-6 sm:px-12 overflow-hidden");
+export const MaxWidth = Styled(
+  "div",
+  "min-w-full px-6 sm:px-12 overflow-hidden",
+);

+ 303 - 46
apps/staking/src/components/OracleIntegrityStaking/index.tsx

@@ -1,7 +1,25 @@
+import {
+  ChevronUpIcon,
+  XMarkIcon,
+  MagnifyingGlassIcon,
+} from "@heroicons/react/24/outline";
 import type { PythStakingClient } from "@pythnetwork/staking-sdk";
 import { PublicKey } from "@solana/web3.js";
 import clsx from "clsx";
-import { useMemo, useCallback } from "react";
+import {
+  useMemo,
+  useCallback,
+  useState,
+  type ComponentProps,
+  type Dispatch,
+  type SetStateAction,
+} from "react";
+import { useFilter } from "react-aria";
+import {
+  SearchField,
+  Input,
+  Button as BaseButton,
+} from "react-aria-components";
 
 import {
   delegateIntegrityStaking,
@@ -9,6 +27,7 @@ import {
   unstakeIntegrityStaking,
   calculateApy,
 } from "../../api";
+import { Button } from "../Button";
 import { ProgramSection } from "../ProgramSection";
 import { SparkChart } from "../SparkChart";
 import { StakingTimeline } from "../StakingTimeline";
@@ -16,6 +35,8 @@ import { Styled } from "../Styled";
 import { Tokens } from "../Tokens";
 import { AmountType, TransferButton } from "../TransferButton";
 
+const PAGE_SIZE = 10;
+
 type Props = {
   availableToStake: bigint;
   locked: bigint;
@@ -99,49 +120,276 @@ export const OracleIntegrityStaking = ({
           { "mt-6": self === undefined },
         )}
       >
-        <div className="relative w-full overflow-x-auto">
-          <h3 className="sticky left-0 mb-4 pl-4 text-2xl font-light sm:pb-4 sm:pl-10 sm:pt-6">
-            {self ? "Other Publishers" : "Publishers"}
-          </h3>
-
-          <table className="min-w-full text-sm">
-            <thead className="bg-pythpurple-100/30 font-light">
-              <tr>
-                <PublisherTableHeader className="pl-4 text-left sm:pl-10">
-                  Publisher
-                </PublisherTableHeader>
-                <PublisherTableHeader>Self stake</PublisherTableHeader>
-                <PublisherTableHeader>Pool</PublisherTableHeader>
-                <PublisherTableHeader>Last epoch APY</PublisherTableHeader>
-                <PublisherTableHeader>Historical APY</PublisherTableHeader>
-                <PublisherTableHeader>Number of feeds</PublisherTableHeader>
-                <PublisherTableHeader
-                  className={clsx({ "pr-4 sm:pr-10": availableToStake <= 0n })}
-                >
-                  Quality ranking
-                </PublisherTableHeader>
-                {availableToStake > 0n && (
-                  <PublisherTableHeader className="pr-4 sm:pr-10" />
-                )}
-              </tr>
-            </thead>
-            <tbody className="bg-white/5">
-              {otherPublishers.map((publisher) => (
-                <Publisher
-                  key={publisher.publicKey.toBase58()}
-                  availableToStake={availableToStake}
-                  publisher={publisher}
-                  totalStaked={staked}
-                />
-              ))}
-            </tbody>
-          </table>
-        </div>
+        <PublisherList
+          title={self ? "Other Publishers" : "Publishers"}
+          availableToStake={availableToStake}
+          publishers={otherPublishers}
+          totalStaked={staked}
+        />
       </div>
     </ProgramSection>
   );
 };
 
+type PublisherListProps = {
+  title: string;
+  availableToStake: bigint;
+  totalStaked: bigint;
+  publishers: PublisherProps["publisher"][];
+};
+
+const PublisherList = ({
+  title,
+  availableToStake,
+  publishers,
+  totalStaked,
+}: PublisherListProps) => {
+  const [search, setSearch] = useState("");
+  const [sort, setSort] = useState({
+    field: SortField.PoolUtilization,
+    descending: false,
+  });
+  const filter = useFilter({ sensitivity: "base", usage: "search" });
+  const [currentPage, setPage] = useState(0);
+  const filteredSortedPublishers = useMemo(() => {
+    const sorted = publishers
+      .filter(
+        (publisher) =>
+          filter.contains(publisher.publicKey.toBase58(), search) ||
+          (publisher.name !== undefined &&
+            filter.contains(publisher.name, search)),
+      )
+      .sort((a, b) => {
+        switch (sort.field) {
+          case SortField.PublisherName: {
+            return (a.name ?? a.publicKey.toBase58()).localeCompare(
+              b.name ?? b.publicKey.toBase58(),
+            );
+          }
+          case SortField.LastEpochAPY: {
+            return (
+              calculateApy(a.poolCapacity, a.poolUtilization, false) -
+              calculateApy(b.poolCapacity, b.poolUtilization, false)
+            );
+          }
+          case SortField.NumberOfFeeds: {
+            return Number(a.numFeeds - b.numFeeds);
+          }
+          case SortField.PoolUtilization: {
+            return Number(
+              a.poolUtilization * b.poolCapacity -
+                b.poolUtilization * a.poolCapacity,
+            );
+          }
+          case SortField.QualityRanking: {
+            return Number(a.qualityRanking - b.qualityRanking);
+          }
+          case SortField.SelfStake: {
+            return Number(a.selfStake - b.selfStake);
+          }
+        }
+      });
+    return sort.descending ? sorted.reverse() : sorted;
+  }, [publishers, search, sort.field, sort.descending, filter]);
+
+  const paginatedPublishers = useMemo(
+    () =>
+      filteredSortedPublishers.slice(
+        currentPage * PAGE_SIZE,
+        (currentPage + 1) * PAGE_SIZE,
+      ),
+    [filteredSortedPublishers, currentPage],
+  );
+
+  const updateSearch = useCallback<typeof setSearch>(
+    (newSearch) => {
+      setSearch(newSearch);
+      setPage(0);
+    },
+    [setSearch, setPage],
+  );
+
+  const updateSort = useCallback<typeof setSort>(
+    (newSort) => {
+      setSort(newSort);
+      setPage(0);
+    },
+    [setSort, setPage],
+  );
+
+  return (
+    <div className="relative w-full overflow-x-auto">
+      <div className="sticky left-0 mb-4 flex flex-row items-center justify-between gap-6 px-4 text-2xl sm:px-10 sm:pb-4 sm:pt-6">
+        <h3 className="font-light">{title}</h3>
+
+        <SearchField
+          value={search}
+          onChange={updateSearch}
+          aria-label="Search"
+          className="group relative w-full max-w-96"
+        >
+          <Input
+            className="group-focused:ring-0 group-focused:border-pythpurple-400 group-focused:outline-none w-full truncate border border-pythpurple-600 bg-pythpurple-600/10 py-2 pl-10 pr-8 focus:border-pythpurple-400 focus:outline-none focus:ring-0 focus-visible:border-pythpurple-400 focus-visible:outline-none focus-visible:ring-0 search-cancel:appearance-none search-decoration:appearance-none"
+            placeholder="Search"
+          />
+          <div className="absolute inset-y-0 left-4 grid place-content-center">
+            <MagnifyingGlassIcon className="size-4 text-pythpurple-400" />
+          </div>
+          <div className="absolute inset-y-0 right-2 grid place-content-center">
+            <BaseButton className="p-2 group-empty:hidden">
+              <XMarkIcon className="size-4" />
+            </BaseButton>
+          </div>
+        </SearchField>
+      </div>
+
+      <table className="min-w-full text-sm">
+        <thead className="bg-pythpurple-100/30 font-light">
+          <tr>
+            <SortablePublisherTableHeader
+              field={SortField.PublisherName}
+              sort={sort}
+              setSort={updateSort}
+              className="pl-4 text-left sm:pl-10"
+            >
+              Publisher
+            </SortablePublisherTableHeader>
+            <SortablePublisherTableHeader
+              field={SortField.SelfStake}
+              sort={sort}
+              setSort={updateSort}
+            >
+              Self stake
+            </SortablePublisherTableHeader>
+            <SortablePublisherTableHeader
+              field={SortField.PoolUtilization}
+              sort={sort}
+              setSort={updateSort}
+            >
+              Pool
+            </SortablePublisherTableHeader>
+            <SortablePublisherTableHeader
+              field={SortField.LastEpochAPY}
+              sort={sort}
+              setSort={updateSort}
+            >
+              Last epoch APY
+            </SortablePublisherTableHeader>
+            <PublisherTableHeader>Historical APY</PublisherTableHeader>
+            <SortablePublisherTableHeader
+              field={SortField.NumberOfFeeds}
+              sort={sort}
+              setSort={updateSort}
+            >
+              Number of feeds
+            </SortablePublisherTableHeader>
+            <SortablePublisherTableHeader
+              field={SortField.QualityRanking}
+              sort={sort}
+              setSort={updateSort}
+              className={clsx({ "pr-4 sm:pr-10": availableToStake <= 0n })}
+            >
+              Quality ranking
+            </SortablePublisherTableHeader>
+            {availableToStake > 0n && (
+              <PublisherTableHeader className="pr-4 sm:pr-10" />
+            )}
+          </tr>
+        </thead>
+
+        <tbody className="bg-white/5">
+          {paginatedPublishers.map((publisher) => (
+            <Publisher
+              key={publisher.publicKey.toBase58()}
+              availableToStake={availableToStake}
+              publisher={publisher}
+              totalStaked={totalStaked}
+            />
+          ))}
+        </tbody>
+      </table>
+
+      {filteredSortedPublishers.length > PAGE_SIZE && (
+        <div className="sticky inset-x-0 flex flex-row items-center justify-end gap-2 border-t border-neutral-600/50 p-4">
+          {range(Math.ceil(filteredSortedPublishers.length / PAGE_SIZE)).map(
+            (page) =>
+              page === currentPage ? (
+                <span
+                  key={page}
+                  className="grid size-8 place-content-center border border-pythpurple-600 bg-pythpurple-600"
+                >
+                  {page + 1}
+                </span>
+              ) : (
+                <Button
+                  key={page}
+                  onClick={() => {
+                    setPage(page);
+                  }}
+                  nopad
+                  className="grid size-8 place-content-center"
+                >
+                  {page + 1}
+                </Button>
+              ),
+          )}
+        </div>
+      )}
+    </div>
+  );
+};
+
+const range = (length: number) => [...Array.from({ length }).keys()];
+
+type SortablePublisherTableHeaderProps = Omit<
+  ComponentProps<typeof BaseButton>,
+  "children"
+> & {
+  children: string;
+  field: SortField;
+  sort: { field: SortField; descending: boolean };
+  setSort: Dispatch<SetStateAction<{ field: SortField; descending: boolean }>>;
+};
+
+const SortablePublisherTableHeader = ({
+  field,
+  sort,
+  setSort,
+  children,
+  className,
+  ...props
+}: SortablePublisherTableHeaderProps) => {
+  const updateSort = useCallback(() => {
+    setSort((cur) => ({
+      field,
+      descending: cur.field === field ? !cur.descending : false,
+    }));
+  }, [setSort, field]);
+
+  return (
+    <th>
+      <PublisherTableHeader
+        as={BaseButton}
+        className={clsx(
+          "flex size-full flex-row items-center gap-2 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400",
+          { "bg-black/20": sort.field === field },
+          className,
+        )}
+        onPress={updateSort}
+        {...props}
+      >
+        <span>{children}</span>
+        <ChevronUpIcon
+          className={clsx("size-4 transition-transform", {
+            "rotate-180": sort.descending,
+            "opacity-0": sort.field !== field,
+          })}
+        />
+      </PublisherTableHeader>
+    </th>
+  );
+};
+
 const PublisherTableHeader = Styled(
   "th",
   "py-2 font-normal px-5 whitespace-nowrap",
@@ -152,7 +400,7 @@ type PublisherProps = {
   totalStaked: bigint;
   isSelf?: boolean;
   publisher: {
-    name: string;
+    name: string | undefined;
     publicKey: PublicKey;
     isSelf: boolean;
     selfStake: bigint;
@@ -213,8 +461,8 @@ const Publisher = ({
       <tr className="border-t border-neutral-600/50 first:border-0">
         {!isSelf && (
           <>
-            <PublisherTableCell className="py-4 pl-4 font-medium sm:pl-10">
-              {publisher.name}
+            <PublisherTableCell className="truncate py-4 pl-4 font-medium sm:pl-10">
+              {publisher.name ?? publisher.publicKey.toBase58()}
             </PublisherTableCell>
             <PublisherTableCell className="text-center">
               <Tokens>{publisher.selfStake}</Tokens>
@@ -322,7 +570,7 @@ const Publisher = ({
                           small
                           secondary
                           className="w-28"
-                          actionDescription={`Cancel tokens that are in warmup for staking to ${publisher.name}`}
+                          actionDescription={`Cancel tokens that are in warmup for staking to ${publisher.name ?? publisher.publicKey.toBase58()}`}
                           actionName="Cancel"
                           submitButtonText="Cancel Warmup"
                           title="Cancel Warmup"
@@ -349,7 +597,7 @@ const Publisher = ({
                           small
                           secondary
                           className="w-28"
-                          actionDescription={`Unstake tokens from ${publisher.name}`}
+                          actionDescription={`Unstake tokens from ${publisher.name ?? publisher.publicKey.toBase58()}`}
                           actionName="Unstake"
                           max={staked}
                           transfer={unstake}
@@ -372,7 +620,7 @@ const Publisher = ({
 const PublisherTableCell = Styled("td", "py-4 px-5 whitespace-nowrap");
 
 type StakeToPublisherButtonProps = {
-  publisherName: string;
+  publisherName: string | undefined;
   publisherKey: PublicKey;
   availableToStake: bigint;
   poolCapacity: bigint;
@@ -396,7 +644,7 @@ const StakeToPublisherButton = ({
   return (
     <TransferButton
       small
-      actionDescription={`Stake to ${publisherName}`}
+      actionDescription={`Stake to ${publisherName ?? publisherKey.toBase58()}`}
       actionName="Stake"
       max={availableToStake}
       transfer={delegate}
@@ -436,3 +684,12 @@ const useTransferActionForPublisher = (
       action(client, stakingAccount, publisher, amount),
     [action, publisher],
   );
+
+enum SortField {
+  PublisherName,
+  PoolUtilization,
+  LastEpochAPY,
+  SelfStake,
+  NumberOfFeeds,
+  QualityRanking,
+}

+ 1 - 1
apps/staking/src/components/Root/index.tsx

@@ -50,7 +50,7 @@ export const Root = ({ children }: Props) => (
           dir="ltr"
           className={clsx(redHatText.variable, redHatMono.variable)}
         >
-          <body className="grid min-h-dvh grid-rows-[auto_1fr_auto] text-pythpurple-100 [background:radial-gradient(113.49%_134.57%_at_5.57%_97.67%,_rgba(17,_15,_35,_0.00)_0%,_rgba(119,_49,_234,_0.20)_100%),_#0A0814] selection:bg-pythpurple-600/60">
+          <body className="grid min-h-dvh grid-rows-[auto_1fr_auto] text-pythpurple-100 [background:radial-gradient(20rem_50rem_at_50rem_10rem,_rgba(119,_49,_234,_0.20)_0%,_rgba(17,_15,_35,_0.00)_100rem),_#0A0814] selection:bg-pythpurple-600/60">
             <Header className="z-10" />
             <MaxWidth className="my-4">{children}</MaxWidth>
             <Footer className="z-10" />

+ 10 - 1
apps/staking/tailwind.config.ts

@@ -1,12 +1,21 @@
 import forms from "@tailwindcss/forms";
 import type { Config } from "tailwindcss";
+import tailwindPlugin from "tailwindcss/plugin";
 import animate from "tailwindcss-animate";
 import reactAria from "tailwindcss-react-aria-components";
 
 const tailwindConfig = {
   darkMode: "class",
   content: ["src/components/**/*.{ts,tsx}", "src/markdown-components.tsx"],
-  plugins: [forms, animate, reactAria],
+  plugins: [
+    forms,
+    animate,
+    reactAria,
+    tailwindPlugin(({ addVariant }) => {
+      addVariant("search-cancel", "&::-webkit-search-cancel-button");
+      addVariant("search-decoration", "&::-webkit-search-decoration");
+    }),
+  ],
   theme: {
     extend: {
       backgroundImage: {

+ 0 - 112
pnpm-lock.yaml

@@ -1573,49 +1573,6 @@ importers:
         specifier: ^1.0.0-rc.1
         version: 1.1.3(prettier@2.8.8)
 
-  target_chains/ethereum/examples/coin_flip/app:
-    dependencies:
-      '@pythnetwork/pyth-evm-js':
-        specifier: workspace:*
-        version: link:../../../sdk/js
-      '@pythnetwork/pyth-sdk-solidity':
-        specifier: workspace:*
-        version: link:../../../sdk/solidity
-      '@truffle/hdwallet-provider':
-        specifier: ^2.1.15
-        version: 2.1.15(@babel/core@7.24.7)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@types/jest':
-        specifier: ^27.5.2
-        version: 27.5.2
-      '@types/node':
-        specifier: ^16.11.64
-        version: 16.18.60
-      buffer:
-        specifier: ^6.0.3
-        version: 6.0.3
-      ethers:
-        specifier: ^5.7.2
-        version: 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)
-      prettier:
-        specifier: ^2.7.1
-        version: 2.8.8
-      typescript:
-        specifier: ^4.8.4
-        version: 4.9.5
-      web3:
-        specifier: ^1.8.1
-        version: 1.10.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      yargs:
-        specifier: ^17.7.2
-        version: 17.7.2
-    devDependencies:
-      '@types/yargs':
-        specifier: ^17.0.32
-        version: 17.0.32
-      ts-node:
-        specifier: ^10.9.1
-        version: 10.9.1(@types/node@16.18.60)(typescript@4.9.5)
-
   target_chains/ethereum/sdk/js:
     dependencies:
       '@pythnetwork/price-service-client':
@@ -8460,9 +8417,6 @@ packages:
   '@types/node@16.18.11':
     resolution: {integrity: sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==}
 
-  '@types/node@16.18.60':
-    resolution: {integrity: sha512-ZUGPWx5vKfN+G2/yN7pcSNLkIkXEvlwNaJEd4e0ppX7W2S8XAkdc/37hM4OUNJB9sa0p12AOvGvxL4JCPiz9DA==}
-
   '@types/node@18.11.18':
     resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
 
@@ -33332,27 +33286,6 @@ snapshots:
       - supports-color
       - utf-8-validate
 
-  '@truffle/hdwallet-provider@2.1.15(@babel/core@7.24.7)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
-    dependencies:
-      '@ethereumjs/common': 2.6.5
-      '@ethereumjs/tx': 3.5.2
-      '@metamask/eth-sig-util': 4.0.1
-      '@truffle/hdwallet': 0.1.4
-      '@types/ethereum-protocol': 1.0.2
-      '@types/web3': 1.0.20
-      '@types/web3-provider-engine': 14.0.1
-      ethereum-cryptography: 1.1.2
-      ethereum-protocol: 1.0.1
-      ethereumjs-util: 7.1.5
-      web3: 1.10.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      web3-provider-engine: 16.0.3(@babel/core@7.24.7)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-    transitivePeerDependencies:
-      - '@babel/core'
-      - bufferutil
-      - encoding
-      - supports-color
-      - utf-8-validate
-
   '@truffle/hdwallet-provider@2.1.5(@babel/core@7.24.7)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
       '@ethereumjs/common': 2.6.5
@@ -33805,8 +33738,6 @@ snapshots:
 
   '@types/node@16.18.11': {}
 
-  '@types/node@16.18.60': {}
-
   '@types/node@18.11.18': {}
 
   '@types/node@18.15.13': {}
@@ -50529,24 +50460,6 @@ snapshots:
       v8-compile-cache-lib: 3.0.1
       yn: 3.1.1
 
-  ts-node@10.9.1(@types/node@16.18.60)(typescript@4.9.5):
-    dependencies:
-      '@cspotcode/source-map-support': 0.8.1
-      '@tsconfig/node10': 1.0.9
-      '@tsconfig/node12': 1.0.11
-      '@tsconfig/node14': 1.0.3
-      '@tsconfig/node16': 1.0.3
-      '@types/node': 16.18.60
-      acorn: 8.11.3
-      acorn-walk: 8.2.0
-      arg: 4.1.3
-      create-require: 1.1.1
-      diff: 4.0.2
-      make-error: 1.3.6
-      typescript: 4.9.5
-      v8-compile-cache-lib: 3.0.1
-      yn: 3.1.1
-
   ts-node@10.9.1(@types/node@22.5.1)(typescript@4.9.5):
     dependencies:
       '@cspotcode/source-map-support': 0.8.1
@@ -51606,16 +51519,6 @@ snapshots:
       - supports-color
       - utf-8-validate
 
-  web3-bzz@1.10.0(bufferutil@4.0.8)(utf-8-validate@5.0.10):
-    dependencies:
-      '@types/node': 12.20.55
-      got: 12.1.0
-      swarm-js: 0.1.42(bufferutil@4.0.8)(utf-8-validate@5.0.10)
-    transitivePeerDependencies:
-      - bufferutil
-      - supports-color
-      - utf-8-validate
-
   web3-bzz@1.10.4(bufferutil@4.0.7)(utf-8-validate@6.0.3):
     dependencies:
       '@types/node': 12.20.55
@@ -52688,21 +52591,6 @@ snapshots:
       - supports-color
       - utf-8-validate
 
-  web3@1.10.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10):
-    dependencies:
-      web3-bzz: 1.10.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
-      web3-core: 1.10.0(encoding@0.1.13)
-      web3-eth: 1.10.0(encoding@0.1.13)
-      web3-eth-personal: 1.10.0(encoding@0.1.13)
-      web3-net: 1.10.0(encoding@0.1.13)
-      web3-shh: 1.10.0(encoding@0.1.13)
-      web3-utils: 1.10.0
-    transitivePeerDependencies:
-      - bufferutil
-      - encoding
-      - supports-color
-      - utf-8-validate
-
   web3@1.10.4(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@6.0.3):
     dependencies:
       web3-bzz: 1.10.4(bufferutil@4.0.7)(utf-8-validate@6.0.3)