From fcda4105cfc59e0b5a9f517f3ea433c0abb391f0 Mon Sep 17 00:00:00 2001
From: 0xeye <97349378+0xeye@users.noreply.github.com>
Date: Tue, 10 Feb 2026 10:32:30 +0000
Subject: [PATCH 01/11] chore: init
From 71adc6e7f7a284b8f1de0c11412b13c2fb013ae0 Mon Sep 17 00:00:00 2001
From: 0xeye <97349378+0xeye@users.noreply.github.com>
Date: Tue, 10 Feb 2026 10:34:26 +0000
Subject: [PATCH 02/11] chore: cleanup (#1053)
* feat: dedupe reused code
* chore: remove deadcode
* chore: lock and loaded
* chore: bump
---
bun.lock | 342 +-----------
declaration.d.ts | 1 -
package.json | 6 -
.../landing/components/common/Header.tsx | 37 --
.../landing/components/sections/About.tsx | 0
.../pages/landing/utils/scrollToHash.ts | 4 -
.../portfolio/components/EmptySectionCard.tsx | 27 +-
src/components/pages/vaults/Mark.tsx | 493 ------------------
.../vaults/components/SuggestedVaultCard.tsx | 8 -
.../vaults/components/TrendingVaults.tsx | 331 ------------
.../pages/vaults/components/VaultChainTag.tsx | 48 --
.../components/compare/VaultsCompareModal.tsx | 7 -
.../components/detail/MobileStickyHeader.tsx | 72 ---
.../components/filters/VaultsAssetFilter.tsx | 111 ++--
.../vaults/components/list/HoldingsPill.tsx | 108 ----
.../components/list/VaultsListEmpty.tsx | 93 ++--
.../list/VaultsListInternalMigrationRow.tsx | 70 ---
.../vaults/components/table/APYSparkline.tsx | 60 ---
.../components/widget/deposit/index.tsx | 12 +-
.../components/widget/migrate/index.tsx | 12 +-
.../components/widget/rewards/RewardRow.tsx | 1 +
.../components/widget/shared/WidgetHeader.tsx | 7 +
.../components/widget/withdraw/index.tsx | 12 +-
src/components/pages/vaults/constants/menu.ts | 11 -
.../vaults/domain/reports/findLatestAPY.ts | 19 -
.../domain/reports/findLatestReportApr.ts | 57 --
.../domain/reports/kongReports.schema.ts | 58 ---
.../vaults/domain/reports/reports.schema.ts | 27 -
.../pages/vaults/hooks/actions/useDeposit.ts | 106 ----
.../pages/vaults/hooks/actions/useStake.ts | 79 ---
.../pages/vaults/hooks/actions/useUnstake.ts | 53 --
.../pages/vaults/hooks/actions/useWithdraw.ts | 79 ---
.../pages/vaults/hooks/actions/useZapIn.ts | 63 ---
.../vaults/hooks/solvers/useSolverCowswap.ts | 150 ------
.../solvers/useSolverGaugeStakingBooster.ts | 89 ----
.../pages/vaults/hooks/useCowswapOrder.ts | 106 ----
.../pages/vaults/hooks/useVaultsPageModel.ts | 7 -
.../pages/vaults/utils/handleYBold.ts | 31 --
src/components/pages/vaults/utils/index.ts | 18 -
.../vaults/utils/useAvailableToDeposit.ts | 32 --
.../shared/components/CarouselSlideArrows.tsx | 39 --
src/components/shared/components/Counter.tsx | 86 ---
src/components/shared/components/Cutaway.tsx | 31 --
src/components/shared/components/Dropdown.tsx | 184 -------
.../shared/components/EmptyState.tsx | 55 ++
.../shared/components/InfoTooltip.tsx | 47 --
src/components/shared/components/Input.tsx | 78 ---
.../shared/components/LauncherDropdown.tsx | 213 --------
src/components/shared/components/ListHead.tsx | 165 ------
.../shared/components/ModalMobileMenu.tsx | 148 ------
.../shared/components/MotionDiv.tsx | 24 -
.../shared/components/Pagination.tsx | 89 ----
.../shared/components/ShareButton.tsx | 45 --
src/components/shared/components/Switch.tsx | 44 --
src/components/shared/components/Tabs.tsx | 133 -----
.../shared/components/TokenDropdown.tsx | 165 ------
src/components/shared/contexts/useSearch.tsx | 48 --
.../hooks/useFetchYearnEarnedForUser.ts | 41 --
.../shared/hooks/useFilteredVaults.ts | 257 ---------
.../shared/hooks/useInitialQueryParam.ts | 40 --
.../shared/hooks/useRateLimitedContract.ts | 91 ----
.../shared/hooks/useV2VaultFilter.ts | 294 +----------
.../shared/hooks/useV3VaultFilter.ts | 317 +----------
src/components/shared/hooks/useVaultFilter.ts | 371 +++++++++++++
.../shared/hooks/useYearnBalance.ts | 20 -
src/components/shared/hooks/useYearnToken.ts | 18 -
.../shared/types/optionalRenderProps.ts | 6 -
src/components/shared/utils/animations.ts | 15 -
src/components/shared/utils/calculations.ts | 14 -
src/components/shared/utils/opacity.ts | 10 -
.../shared/utils/schemas/coinGeckoSchemas.ts | 5 -
.../shared/utils/schemas/curveSchemas.ts | 95 ----
.../schemas/yDaemonGaugeRewardsFeedSchema.ts | 19 -
.../utils/schemas/yDaemonTokensSchema.ts | 20 -
.../shared/utils/tools.identifier.ts | 6 -
.../shared/utils/wagmi/ethersAdapter.ts | 63 ---
src/hooks/useScrollDirection.ts | 69 ---
src/types/router.ts | 8 -
vite.config.ts | 8 +-
79 files changed, 631 insertions(+), 5597 deletions(-)
delete mode 100644 declaration.d.ts
delete mode 100644 src/components/pages/landing/components/common/Header.tsx
delete mode 100644 src/components/pages/landing/components/sections/About.tsx
delete mode 100644 src/components/pages/landing/utils/scrollToHash.ts
delete mode 100644 src/components/pages/vaults/Mark.tsx
delete mode 100644 src/components/pages/vaults/components/TrendingVaults.tsx
delete mode 100644 src/components/pages/vaults/components/VaultChainTag.tsx
delete mode 100644 src/components/pages/vaults/components/detail/MobileStickyHeader.tsx
delete mode 100644 src/components/pages/vaults/components/list/HoldingsPill.tsx
delete mode 100755 src/components/pages/vaults/components/list/VaultsListInternalMigrationRow.tsx
delete mode 100644 src/components/pages/vaults/components/table/APYSparkline.tsx
create mode 100644 src/components/pages/vaults/components/widget/shared/WidgetHeader.tsx
delete mode 100644 src/components/pages/vaults/constants/menu.ts
delete mode 100644 src/components/pages/vaults/domain/reports/findLatestAPY.ts
delete mode 100644 src/components/pages/vaults/domain/reports/findLatestReportApr.ts
delete mode 100644 src/components/pages/vaults/domain/reports/kongReports.schema.ts
delete mode 100644 src/components/pages/vaults/domain/reports/reports.schema.ts
delete mode 100644 src/components/pages/vaults/hooks/actions/useDeposit.ts
delete mode 100644 src/components/pages/vaults/hooks/actions/useStake.ts
delete mode 100644 src/components/pages/vaults/hooks/actions/useUnstake.ts
delete mode 100644 src/components/pages/vaults/hooks/actions/useWithdraw.ts
delete mode 100644 src/components/pages/vaults/hooks/actions/useZapIn.ts
delete mode 100644 src/components/pages/vaults/hooks/solvers/useSolverCowswap.ts
delete mode 100644 src/components/pages/vaults/hooks/solvers/useSolverGaugeStakingBooster.ts
delete mode 100644 src/components/pages/vaults/hooks/useCowswapOrder.ts
delete mode 100644 src/components/pages/vaults/utils/handleYBold.ts
delete mode 100644 src/components/pages/vaults/utils/index.ts
delete mode 100644 src/components/pages/vaults/utils/useAvailableToDeposit.ts
delete mode 100644 src/components/shared/components/CarouselSlideArrows.tsx
delete mode 100644 src/components/shared/components/Counter.tsx
delete mode 100644 src/components/shared/components/Cutaway.tsx
delete mode 100644 src/components/shared/components/Dropdown.tsx
create mode 100644 src/components/shared/components/EmptyState.tsx
delete mode 100644 src/components/shared/components/InfoTooltip.tsx
delete mode 100644 src/components/shared/components/Input.tsx
delete mode 100644 src/components/shared/components/LauncherDropdown.tsx
delete mode 100644 src/components/shared/components/ListHead.tsx
delete mode 100644 src/components/shared/components/ModalMobileMenu.tsx
delete mode 100644 src/components/shared/components/MotionDiv.tsx
delete mode 100644 src/components/shared/components/Pagination.tsx
delete mode 100644 src/components/shared/components/ShareButton.tsx
delete mode 100644 src/components/shared/components/Switch.tsx
delete mode 100644 src/components/shared/components/Tabs.tsx
delete mode 100755 src/components/shared/components/TokenDropdown.tsx
delete mode 100644 src/components/shared/contexts/useSearch.tsx
delete mode 100644 src/components/shared/hooks/useFetchYearnEarnedForUser.ts
delete mode 100644 src/components/shared/hooks/useFilteredVaults.ts
delete mode 100644 src/components/shared/hooks/useInitialQueryParam.ts
delete mode 100644 src/components/shared/hooks/useRateLimitedContract.ts
create mode 100644 src/components/shared/hooks/useVaultFilter.ts
delete mode 100644 src/components/shared/hooks/useYearnBalance.ts
delete mode 100644 src/components/shared/hooks/useYearnToken.ts
delete mode 100644 src/components/shared/types/optionalRenderProps.ts
delete mode 100644 src/components/shared/utils/animations.ts
delete mode 100644 src/components/shared/utils/calculations.ts
delete mode 100644 src/components/shared/utils/opacity.ts
delete mode 100644 src/components/shared/utils/schemas/coinGeckoSchemas.ts
delete mode 100644 src/components/shared/utils/schemas/curveSchemas.ts
delete mode 100644 src/components/shared/utils/schemas/yDaemonGaugeRewardsFeedSchema.ts
delete mode 100644 src/components/shared/utils/schemas/yDaemonTokensSchema.ts
delete mode 100644 src/components/shared/utils/tools.identifier.ts
delete mode 100644 src/components/shared/utils/wagmi/ethersAdapter.ts
delete mode 100644 src/hooks/useScrollDirection.ts
delete mode 100644 src/types/router.ts
diff --git a/bun.lock b/bun.lock
index ea04d2b20..1033b0c91 100644
--- a/bun.lock
+++ b/bun.lock
@@ -4,30 +4,24 @@
"": {
"name": "yearnfi",
"dependencies": {
- "@cowprotocol/cow-sdk": "5.10.3",
"@headlessui/react": "2.2.9",
"@plausible-analytics/tracker": "^0.4.4",
"@rainbow-me/rainbowkit": "2.2.9",
"@react-hookz/web": "24.0.4",
"@tanstack/react-query": "5.90.20",
"@tanstack/react-virtual": "3.13.12",
- "cross-fetch": "4.1.0",
"ethers": "5.7.2",
"framer-motion": "12.29.2",
- "graphql": "16.12.0",
"react": "19.2.3",
"react-dom": "19.2.3",
"react-hot-toast": "2.6.0",
"react-markdown": "10.1.0",
- "react-paginate": "8.3.0",
"react-rewards": "2.1.0",
"react-router": "7.13.0",
"recharts": "2.15.4",
"use-indexeddb": "2.0.2",
- "vaul": "1.1.2",
"viem": "2.45.0",
"wagmi": "2.18.2",
- "xxhashjs": "0.2.2",
"zod": "4.3.6",
},
"devDependencies": {
@@ -58,8 +52,6 @@
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
- "@assemblyscript/loader": ["@assemblyscript/loader@0.9.4", "", {}, "sha512-HazVq9zwTVwGmqdwYzu7WyQ6FQVZ7SwET0KKQuKm55jD0IfUpZgN0OPIiZG3zV1iSrVYcN0bdwLRXI/VNCYsUA=="],
-
"@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
"@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="],
@@ -126,12 +118,6 @@
"@coinbase/wallet-sdk": ["@coinbase/wallet-sdk@4.3.6", "", { "dependencies": { "@noble/hashes": "1.4.0", "clsx": "1.2.1", "eventemitter3": "5.0.1", "idb-keyval": "6.2.1", "ox": "0.6.9", "preact": "10.24.2", "viem": "^2.27.2", "zustand": "5.0.3" } }, "sha512-4q8BNG1ViL4mSAAvPAtpwlOs1gpC+67eQtgIwNvT3xyeyFFd+guwkc8bcX5rTmQhXpqnhzC4f0obACbP9CqMSA=="],
- "@cowprotocol/app-data": ["@cowprotocol/app-data@2.5.1", "", { "dependencies": { "ajv": "^8.11.0", "cross-fetch": "^3.1.5", "ipfs-only-hash": "^4.0.0", "json-stringify-deterministic": "^1.0.8", "multiformats": "^9.6.4" }, "peerDependencies": { "ethers": "^5.0.0" } }, "sha512-GvcLQ44ZUHKdSAXiZ+YCaIehtme/OIvbvL/4go1UqNLTj3jDTDkagPh7CH/z2IPwFWTADyNZO/RSzKrW5UDNaA=="],
-
- "@cowprotocol/contracts": ["@cowprotocol/contracts@1.8.0", "", { "peerDependencies": { "ethers": "^5.4.0" } }, "sha512-rMEHo1UBB6k4kRoWejHZNGggg6IBVt7vAd8x0FhEvjxhbq3zlAex61f9HpAcDExJNuvfwwDjsOc/7UGztCzhSw=="],
-
- "@cowprotocol/cow-sdk": ["@cowprotocol/cow-sdk@5.10.3", "", { "dependencies": { "@cowprotocol/app-data": "^2.4.0", "@cowprotocol/contracts": "^1.6.0", "@ethersproject/abstract-signer": "^5.7.0", "@openzeppelin/merkle-tree": "^1.0.5", "cross-fetch": "^3.1.5", "exponential-backoff": "^3.1.1", "graphql": "^16.3.0", "graphql-request": "^4.3.0", "limiter": "^3.0.0" }, "peerDependencies": { "ethers": "^5.7.2" } }, "sha512-whnfufOmJqJWw7u2HqLt6k+rw8eMH+ywmB++oxG6U6zLBdQihk18mIMz1wrNwfTUk0FFtn8g8nhrQL14oV27rg=="],
-
"@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="],
"@ecies/ciphers": ["@ecies/ciphers@0.2.5", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A=="],
@@ -312,8 +298,6 @@
"@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@2.0.3", "", { "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg=="],
- "@metamask/abi-utils": ["@metamask/abi-utils@2.0.4", "", { "dependencies": { "@metamask/superstruct": "^3.1.0", "@metamask/utils": "^9.0.0" } }, "sha512-StnIgUB75x7a7AgUhiaUZDpCsqGp7VkNnZh2XivXkJ6mPkE83U8ARGQj5MbRis7VJY8BC5V1AbB1fjdh0hupPQ=="],
-
"@metamask/eth-json-rpc-provider": ["@metamask/eth-json-rpc-provider@1.0.1", "", { "dependencies": { "@metamask/json-rpc-engine": "^7.0.0", "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^5.0.1" } }, "sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA=="],
"@metamask/json-rpc-engine": ["@metamask/json-rpc-engine@8.0.2", "", { "dependencies": { "@metamask/rpc-errors": "^6.2.1", "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^8.3.0" } }, "sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA=="],
@@ -340,9 +324,7 @@
"@metamask/superstruct": ["@metamask/superstruct@3.2.1", "", {}, "sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g=="],
- "@metamask/utils": ["@metamask/utils@9.3.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.1.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "debug": "^4.3.4", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g=="],
-
- "@multiformats/base-x": ["@multiformats/base-x@4.0.1", "", {}, "sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw=="],
+ "@metamask/utils": ["@metamask/utils@11.9.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.1.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "@types/lodash": "^4.17.20", "debug": "^4.3.4", "lodash": "^4.17.21", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-wRnoSDD9jTWOge/+reFviJQANhS+uy8Y+OEwRanp5mQeGTjBFmK1r2cTOnei2UCZRV1crXHzeJVSFEoDDcgRbA=="],
"@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="],
@@ -356,66 +338,10 @@
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
- "@openzeppelin/merkle-tree": ["@openzeppelin/merkle-tree@1.0.8", "", { "dependencies": { "@metamask/abi-utils": "^2.0.4", "ethereum-cryptography": "^3.0.0" } }, "sha512-E2c9/Y3vjZXwVvPZKqCKUn7upnvam1P1ZhowJyZVQSkzZm5WhumtaRr+wkUXrZVfkIc7Gfrl7xzabElqDL09ow=="],
-
"@paulmillr/qr": ["@paulmillr/qr@0.2.1", "", {}, "sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ=="],
"@plausible-analytics/tracker": ["@plausible-analytics/tracker@0.4.4", "", {}, "sha512-fz0NOYUEYXtg1TBaPEEvtcBq3FfmLFuTe1VZw4M8sTWX129br5dguu3M15+plOQnc181ShYe67RfwhKgK89VnA=="],
- "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
-
- "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
-
- "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="],
-
- "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
-
- "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
-
- "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
-
- "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="],
-
- "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
-
- "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
-
- "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
-
- "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
-
- "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
-
- "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
-
- "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
-
- "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
-
- "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
-
- "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
-
- "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
-
- "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
-
- "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
-
- "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
-
- "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
-
- "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
"@rainbow-me/rainbowkit": ["@rainbow-me/rainbowkit@2.2.9", "", { "dependencies": { "@vanilla-extract/css": "1.17.3", "@vanilla-extract/dynamic": "2.1.4", "@vanilla-extract/sprinkles": "1.6.4", "clsx": "2.1.1", "cuer": "0.0.3", "react-remove-scroll": "2.6.2", "ua-parser-js": "^1.0.37" }, "peerDependencies": { "@tanstack/react-query": ">=5.0.0", "react": ">=18", "react-dom": ">=18", "viem": "2.x", "wagmi": "^2.9.0" } }, "sha512-zXAeqkqpznpj9yEs1bTbpZbq0pVYKdJUnqqK/nI8xyYFDWchIOyBoEb/4+goT5RaHfGbDe9dp6pIEu/KelKE6A=="],
"@react-aria/focus": ["@react-aria/focus@3.21.3", "", { "dependencies": { "@react-aria/interactions": "^3.26.0", "@react-aria/utils": "^3.32.0", "@react-types/shared": "^3.32.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-FsquWvjSCwC2/sBk4b+OqJyONETUIXQ2vM0YdPAuC+QFQh2DT6TIBo6dOZVSezlhudDla69xFBd6JvCFq1AbUw=="],
@@ -618,20 +544,14 @@
"@types/lodash": ["@types/lodash@4.17.23", "", {}, "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA=="],
- "@types/long": ["@types/long@4.0.2", "", {}, "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="],
-
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
"@types/minimatch": ["@types/minimatch@6.0.0", "", { "dependencies": { "minimatch": "*" } }, "sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA=="],
- "@types/minimist": ["@types/minimist@1.2.5", "", {}, "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag=="],
-
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@20.19.10", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-iAFpG6DokED3roLSP0K+ybeDdIX6Bc0Vd3mLW5uDqThPWtNos3E+EqOM11mPQHKzfWHqEBuLjIlsBQQ8CsISmQ=="],
- "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="],
-
"@types/react": ["@types/react@19.2.9", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
@@ -746,12 +666,8 @@
"arg": ["arg@4.1.3", "", {}, "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="],
- "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
-
"aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="],
- "arrify": ["arrify@1.0.1", "", {}, "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA=="],
-
"assertion-error": ["assertion-error@1.1.0", "", {}, "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="],
"async-listen": ["async-listen@3.0.0", "", {}, "sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg=="],
@@ -784,10 +700,6 @@
"bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="],
- "bl": ["bl@5.1.0", "", { "dependencies": { "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ=="],
-
- "blakejs": ["blakejs@1.2.1", "", {}, "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ=="],
-
"bn.js": ["bn.js@5.2.2", "", {}, "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw=="],
"bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="],
@@ -820,8 +732,6 @@
"camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="],
- "camelcase-keys": ["camelcase-keys@6.2.2", "", { "dependencies": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", "quick-lru": "^4.0.1" } }, "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg=="],
-
"caniuse-lite": ["caniuse-lite@1.0.30001767", "", {}, "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ=="],
"cbw-sdk": ["@coinbase/wallet-sdk@3.9.3", "", { "dependencies": { "bn.js": "^5.2.1", "buffer": "^6.0.3", "clsx": "^1.2.1", "eth-block-tracker": "^7.1.0", "eth-json-rpc-filters": "^6.0.0", "eventemitter3": "^5.0.1", "keccak": "^3.0.3", "preact": "^10.16.0", "sha.js": "^2.4.11" } }, "sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw=="],
@@ -846,8 +756,6 @@
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
- "cids": ["cids@1.1.9", "", { "dependencies": { "multibase": "^4.0.1", "multicodec": "^3.0.1", "multihashes": "^4.0.1", "uint8arrays": "^3.0.0" } }, "sha512-l11hWRfugIcbGuTZwAM5PwpjPPjyb6UZOGwlHSnOBV5o07XhQ4gNpBN67FbODvpjyHtd+0Xs6KNvUcGBiDRsdg=="],
-
"cjs-module-lexer": ["cjs-module-lexer@1.2.3", "", {}, "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ=="],
"clean-css": ["clean-css@5.3.3", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg=="],
@@ -910,8 +818,6 @@
"cuer": ["cuer@0.0.3", "", { "dependencies": { "qr": "~0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18", "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-f/UNxRMRCYtfLEGECAViByA3JNflZImOk11G9hwSd+44jvzrc99J35u5l+fbdQ2+ZG441GvOpaeGYBmWquZsbQ=="],
- "cuint": ["cuint@0.2.2", "", {}, "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw=="],
-
"d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
"d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
@@ -942,8 +848,6 @@
"decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="],
- "decamelize-keys": ["decamelize-keys@1.1.1", "", { "dependencies": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" } }, "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg=="],
-
"decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
"decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="],
@@ -1014,10 +918,6 @@
"environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="],
- "err-code": ["err-code@3.0.1", "", {}, "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA=="],
-
- "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="],
-
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
@@ -1048,7 +948,7 @@
"eth-rpc-errors": ["eth-rpc-errors@4.0.3", "", { "dependencies": { "fast-safe-stringify": "^2.0.6" } }, "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg=="],
- "ethereum-cryptography": ["ethereum-cryptography@3.2.0", "", { "dependencies": { "@noble/ciphers": "1.3.0", "@noble/curves": "1.9.0", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0" } }, "sha512-Urr5YVsalH+Jo0sYkTkv1MyI9bLYZwW8BENZCeE1QYaTHETEYx0Nv/SVsWkSqpYrzweg6d8KMY1wTjH/1m/BIg=="],
+ "ethereum-cryptography": ["ethereum-cryptography@2.2.1", "", { "dependencies": { "@noble/curves": "1.4.2", "@noble/hashes": "1.4.0", "@scure/bip32": "1.4.0", "@scure/bip39": "1.3.0" } }, "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg=="],
"ethers": ["ethers@5.7.2", "", { "dependencies": { "@ethersproject/abi": "5.7.0", "@ethersproject/abstract-provider": "5.7.0", "@ethersproject/abstract-signer": "5.7.0", "@ethersproject/address": "5.7.0", "@ethersproject/base64": "5.7.0", "@ethersproject/basex": "5.7.0", "@ethersproject/bignumber": "5.7.0", "@ethersproject/bytes": "5.7.0", "@ethersproject/constants": "5.7.0", "@ethersproject/contracts": "5.7.0", "@ethersproject/hash": "5.7.0", "@ethersproject/hdnode": "5.7.0", "@ethersproject/json-wallets": "5.7.0", "@ethersproject/keccak256": "5.7.0", "@ethersproject/logger": "5.7.0", "@ethersproject/networks": "5.7.1", "@ethersproject/pbkdf2": "5.7.0", "@ethersproject/properties": "5.7.0", "@ethersproject/providers": "5.7.2", "@ethersproject/random": "5.7.0", "@ethersproject/rlp": "5.7.0", "@ethersproject/sha2": "5.7.0", "@ethersproject/signing-key": "5.7.0", "@ethersproject/solidity": "5.7.0", "@ethersproject/strings": "5.7.0", "@ethersproject/transactions": "5.7.0", "@ethersproject/units": "5.7.0", "@ethersproject/wallet": "5.7.0", "@ethersproject/web": "5.7.1", "@ethersproject/wordlists": "5.7.0" } }, "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg=="],
@@ -1060,14 +960,10 @@
"execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
- "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="],
-
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
"extension-port-stream": ["extension-port-stream@3.0.0", "", { "dependencies": { "readable-stream": "^3.6.2 || ^4.4.2", "webextension-polyfill": ">=0.10.0 <1.0" } }, "sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw=="],
- "extract-files": ["extract-files@9.0.0", "", {}, "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ=="],
-
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-equals": ["fast-equals@5.4.0", "", {}, "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw=="],
@@ -1078,8 +974,6 @@
"fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="],
- "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
-
"fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
@@ -1136,16 +1030,8 @@
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
- "graphql": ["graphql@16.12.0", "", {}, "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ=="],
-
- "graphql-request": ["graphql-request@4.3.0", "", { "dependencies": { "cross-fetch": "^3.1.5", "extract-files": "^9.0.0", "form-data": "^3.0.0" }, "peerDependencies": { "graphql": "14 - 16" } }, "sha512-2v6hQViJvSsifK606AliqiNiijb1uwWp6Re7o0RTyH+uRTv/u7Uqm2g4Fjq/LgZIzARB38RZEvVBFOQOVdlBow=="],
-
"h3": ["h3@1.15.5", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg=="],
- "hamt-sharding": ["hamt-sharding@2.0.1", "", { "dependencies": { "sparse-array": "^1.3.1", "uint8arrays": "^3.0.0" } }, "sha512-vnjrmdXG9dDs1m/H4iJ6z0JFI2NtgsW5keRkTcM85NGak69Mkf5PHUqBz+Xs0T4sg0ppvj9O5EGAJo40FTxmmA=="],
-
- "hard-rejection": ["hard-rejection@2.1.0", "", {}, "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA=="],
-
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
@@ -1170,8 +1056,6 @@
"hookified": ["hookified@1.15.1", "", {}, "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg=="],
- "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="],
-
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
@@ -1184,24 +1068,12 @@
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
- "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="],
-
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
- "interface-ipld-format": ["interface-ipld-format@1.0.1", "", { "dependencies": { "cids": "^1.1.6", "multicodec": "^3.0.1", "multihashes": "^4.0.2" } }, "sha512-WV/ar+KQJVoQpqRDYdo7YPGYIUHJxCuOEhdvsRpzLqoOIVCqPKdMMYmsLL1nCRsF3yYNio+PAJbCKiv6drrEAg=="],
-
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
- "ipfs-only-hash": ["ipfs-only-hash@4.0.0", "", { "dependencies": { "ipfs-unixfs-importer": "^7.0.1", "meow": "^9.0.0" }, "bin": { "ipfs-only-hash": "cli.js" } }, "sha512-TE1DZCvfw8i3gcsTq3P4TFx3cKFJ3sluu/J3XINkJhIN9OwJgNMqKA+WnKx6ByCb1IoPXsTp1KM7tupElb6SyA=="],
-
- "ipfs-unixfs": ["ipfs-unixfs@4.0.3", "", { "dependencies": { "err-code": "^3.0.1", "protobufjs": "^6.10.2" } }, "sha512-hzJ3X4vlKT8FQ3Xc4M1szaFVjsc1ZydN+E4VQ91aXxfpjFn9G2wsMo1EFdAXNq/BUnN5dgqIOMP5zRYr3DTsAw=="],
-
- "ipfs-unixfs-importer": ["ipfs-unixfs-importer@7.0.3", "", { "dependencies": { "bl": "^5.0.0", "cids": "^1.1.5", "err-code": "^3.0.1", "hamt-sharding": "^2.0.0", "ipfs-unixfs": "^4.0.3", "ipld-dag-pb": "^0.22.2", "it-all": "^1.0.5", "it-batch": "^1.0.8", "it-first": "^1.0.6", "it-parallel-batch": "^1.0.9", "merge-options": "^3.0.4", "multihashing-async": "^2.1.0", "rabin-wasm": "^0.1.4", "uint8arrays": "^2.1.2" } }, "sha512-qeFOlD3AQtGzr90sr5Tq1Bi8pT5Nr2tSI8z310m7R4JDYgZc6J1PEZO3XZQ8l1kuGoqlAppBZuOYmPEqaHcVQQ=="],
-
- "ipld-dag-pb": ["ipld-dag-pb@0.22.3", "", { "dependencies": { "cids": "^1.0.0", "interface-ipld-format": "^1.0.0", "multicodec": "^3.0.1", "multihashing-async": "^2.0.0", "protobufjs": "^6.10.2", "stable": "^0.1.8", "uint8arrays": "^2.0.5" } }, "sha512-dfG5C5OVAR4FEP7Al2CrHWvAyIM7UhAQrjnOYOIxXGQz5NlEj6wGX0XQf6Ru6or1na6upvV3NQfstapQG8X2rg=="],
-
"iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
"is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
@@ -1210,12 +1082,8 @@
"is-arguments": ["is-arguments@1.2.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA=="],
- "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
-
"is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="],
- "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
-
"is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
@@ -1244,14 +1112,6 @@
"isows": ["isows@1.0.7", "", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="],
- "it-all": ["it-all@1.0.6", "", {}, "sha512-3cmCc6Heqe3uWi3CVM/k51fa/XbMFpQVzFoDsV0IZNHSQDyAXl3c4MjHkFX5kF3922OGj7Myv1nSEUgRtcuM1A=="],
-
- "it-batch": ["it-batch@1.0.9", "", {}, "sha512-7Q7HXewMhNFltTsAMdSz6luNhyhkhEtGGbYek/8Xb/GiqYMtwUmopE1ocPSiJKKp3rM4Dt045sNFoUu+KZGNyA=="],
-
- "it-first": ["it-first@1.0.7", "", {}, "sha512-nvJKZoBpZD/6Rtde6FXqwDqDZGF1sCADmr2Zoc0hZsIvnE449gRFnGctxDf09Bzc/FWnHXAdaHVIetY6lrE0/g=="],
-
- "it-parallel-batch": ["it-parallel-batch@1.0.11", "", { "dependencies": { "it-batch": "^1.0.9" } }, "sha512-UWsWHv/kqBpMRmyZJzlmZeoAMA0F3SZr08FBdbhtbe+MtoEBgr/ZUAKrnenhXCBrsopy76QjRH2K/V8kNdupbQ=="],
-
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"js-sha3": ["js-sha3@0.8.0", "", {}, "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="],
@@ -1260,8 +1120,6 @@
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
- "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
-
"json-rpc-engine": ["json-rpc-engine@6.1.0", "", { "dependencies": { "@metamask/safe-event-emitter": "^2.0.0", "eth-rpc-errors": "^4.0.2" } }, "sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ=="],
"json-rpc-random-id": ["json-rpc-random-id@1.0.1", "", {}, "sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA=="],
@@ -1270,8 +1128,6 @@
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
- "json-stringify-deterministic": ["json-stringify-deterministic@1.0.12", "", {}, "sha512-q3PN0lbUdv0pmurkBNdJH3pfFvOTL/Zp0lquqpvcjfKzt6Y0j49EPHAmVHCAS4Ceq/Y+PejWTzyiVpoY71+D6g=="],
-
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
"keccak": ["keccak@3.0.4", "", { "dependencies": { "node-addon-api": "^2.0.0", "node-gyp-build": "^4.2.0", "readable-stream": "^3.6.0" } }, "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q=="],
@@ -1280,8 +1136,6 @@
"keyvaluestorage-interface": ["keyvaluestorage-interface@1.0.0", "", {}, "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g=="],
- "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="],
-
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
@@ -1306,10 +1160,6 @@
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
- "limiter": ["limiter@3.0.0", "", {}, "sha512-hev7DuXojsTFl2YwyzUJMDnZ/qBDd3yZQLSH3aD4tdL1cqfc3TMnoecEJtWFaQFdErZsKoFMBTxF/FBSkgDbEg=="],
-
- "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
-
"lint-staged": ["lint-staged@16.2.7", "", { "dependencies": { "commander": "^14.0.2", "listr2": "^9.0.5", "micromatch": "^4.0.8", "nano-spawn": "^2.0.0", "pidtree": "^0.6.0", "string-argv": "^0.3.2", "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow=="],
"listr2": ["listr2@9.0.5", "", { "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g=="],
@@ -1328,8 +1178,6 @@
"log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="],
- "long": ["long@4.0.0", "", {}, "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="],
-
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
@@ -1344,8 +1192,6 @@
"make-error": ["make-error@1.3.6", "", {}, "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="],
- "map-obj": ["map-obj@4.3.0", "", {}, "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ=="],
-
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
"mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="],
@@ -1366,10 +1212,6 @@
"media-query-parser": ["media-query-parser@2.0.2", "", { "dependencies": { "@babel/runtime": "^7.12.5" } }, "sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w=="],
- "meow": ["meow@9.0.0", "", { "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", "decamelize": "^1.2.0", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", "normalize-package-data": "^3.0.0", "read-pkg-up": "^7.0.1", "redent": "^3.0.0", "trim-newlines": "^3.0.0", "type-fest": "^0.18.0", "yargs-parser": "^20.2.3" } }, "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ=="],
-
- "merge-options": ["merge-options@3.0.4", "", { "dependencies": { "is-plain-obj": "^2.1.0" } }, "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ=="],
-
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
@@ -1428,18 +1270,12 @@
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
- "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="],
-
"minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="],
"minimalistic-crypto-utils": ["minimalistic-crypto-utils@1.0.1", "", {}, "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg=="],
"minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="],
- "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
-
- "minimist-options": ["minimist-options@4.1.0", "", { "dependencies": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", "kind-of": "^6.0.3" } }, "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A=="],
-
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
"minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="],
@@ -1460,18 +1296,8 @@
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
- "multibase": ["multibase@4.0.6", "", { "dependencies": { "@multiformats/base-x": "^4.0.1" } }, "sha512-x23pDe5+svdLz/k5JPGCVdfn7Q5mZVMBETiC+ORfO+sor9Sgs0smJzAjfTbM5tckeCqnaUuMYoz+k3RXMmJClQ=="],
-
- "multicodec": ["multicodec@3.2.1", "", { "dependencies": { "uint8arrays": "^3.0.0", "varint": "^6.0.0" } }, "sha512-+expTPftro8VAW8kfvcuNNNBgb9gPeNYV9dn+z1kJRWF2vih+/S79f2RVeIwmrJBUJ6NT9IUPWnZDQvegEh5pw=="],
-
"multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="],
- "multihashes": ["multihashes@4.0.3", "", { "dependencies": { "multibase": "^4.0.1", "uint8arrays": "^3.0.0", "varint": "^5.0.2" } }, "sha512-0AhMH7Iu95XjDLxIeuCOOE4t9+vQZsACyKZ9Fxw2pcsRmlX4iCn1mby0hS0bb+nQOVpdQYWPpnyusw4da5RPhA=="],
-
- "multihashing-async": ["multihashing-async@2.1.4", "", { "dependencies": { "blakejs": "^1.1.0", "err-code": "^3.0.0", "js-sha3": "^0.8.0", "multihashes": "^4.0.1", "murmurhash3js-revisited": "^3.0.0", "uint8arrays": "^3.0.0" } }, "sha512-sB1MiQXPSBTNRVSJc2zM157PXgDtud2nMFUEIvBrsq5Wv96sUclMRK/ecjoP1T/W61UJBqt4tCTwMkUpt2Gbzg=="],
-
- "murmurhash3js-revisited": ["murmurhash3js-revisited@3.0.0", "", {}, "sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g=="],
-
"nano-spawn": ["nano-spawn@2.0.0", "", {}, "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
@@ -1490,8 +1316,6 @@
"nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="],
- "normalize-package-data": ["normalize-package-data@3.0.3", "", { "dependencies": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" } }, "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA=="],
-
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
"npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
@@ -1522,8 +1346,6 @@
"parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],
- "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
-
"parse-ms": ["parse-ms@2.1.0", "", {}, "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA=="],
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
@@ -1532,8 +1354,6 @@
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
- "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
-
"path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="],
"path-to-regexp": ["path-to-regexp@6.1.0", "", {}, "sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw=="],
@@ -1584,8 +1404,6 @@
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
- "protobufjs": ["protobufjs@6.11.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/long": "^4.0.1", "@types/node": ">=13.7.0", "long": "^4.0.0" }, "bin": { "pbjs": "bin/pbjs", "pbts": "bin/pbts" } }, "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw=="],
-
"proxy-compare": ["proxy-compare@2.6.0", "", {}, "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw=="],
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
@@ -1606,10 +1424,6 @@
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
- "quick-lru": ["quick-lru@4.0.1", "", {}, "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g=="],
-
- "rabin-wasm": ["rabin-wasm@0.1.5", "", { "dependencies": { "@assemblyscript/loader": "^0.9.4", "bl": "^5.0.0", "debug": "^4.3.1", "minimist": "^1.2.5", "node-fetch": "^2.6.1", "readable-stream": "^3.6.0" }, "bin": { "rabin-wasm": "cli/bin.js" } }, "sha512-uWgQTo7pim1Rnj5TuWcCewRDTf0PEFTSlaUjWP4eY9EbLV9em08v89oCz/WO+wRxpYuO36XEHp4wgYQnAgOHzA=="],
-
"radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
@@ -1622,8 +1436,6 @@
"react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="],
- "react-paginate": ["react-paginate@8.3.0", "", { "dependencies": { "prop-types": "^15" }, "peerDependencies": { "react": "^16 || ^17 || ^18 || ^19" } }, "sha512-TptZE37HPkT3R+7AszWA++LOTIsIHXcCSWMP9WW/abeF8sLpJzExFB/dVs7xbtqteJ5njF6kk+udTDC0AR3y5w=="],
-
"react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="],
"react-remove-scroll": ["react-remove-scroll@2.6.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw=="],
@@ -1640,10 +1452,6 @@
"react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="],
- "read-pkg": ["read-pkg@5.2.0", "", { "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", "parse-json": "^5.0.0", "type-fest": "^0.6.0" } }, "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg=="],
-
- "read-pkg-up": ["read-pkg-up@7.0.1", "", { "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", "type-fest": "^0.8.1" } }, "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg=="],
-
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
"readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
@@ -1654,8 +1462,6 @@
"recharts-scale": ["recharts-scale@0.4.5", "", { "dependencies": { "decimal.js-light": "^2.4.1" } }, "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w=="],
- "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="],
-
"remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="],
"remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="],
@@ -1666,8 +1472,6 @@
"require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="],
- "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
-
"resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
"restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
@@ -1726,22 +1530,10 @@
"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
- "sparse-array": ["sparse-array@1.3.2", "", {}, "sha512-ZT711fePGn3+kQyLuv1fpd3rNSkNF8vd5Kv2D+qnOANeyKs3fx6bUMGWRPvgTTcYV64QMqZKZwcuaQSP3AZ0tg=="],
-
- "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="],
-
- "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
-
- "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="],
-
- "spdx-license-ids": ["spdx-license-ids@3.0.22", "", {}, "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ=="],
-
"split-on-first": ["split-on-first@1.1.0", "", {}, "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="],
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
- "stable": ["stable@0.1.8", "", {}, "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w=="],
-
"stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
"std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
@@ -1762,8 +1554,6 @@
"strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
- "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="],
-
"strip-literal": ["strip-literal@2.1.1", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q=="],
"style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="],
@@ -1774,8 +1564,6 @@
"supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
- "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
-
"tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="],
"tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
@@ -1808,8 +1596,6 @@
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
- "trim-newlines": ["trim-newlines@3.0.1", "", {}, "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw=="],
-
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
"ts-morph": ["ts-morph@12.0.0", "", { "dependencies": { "@ts-morph/common": "~0.11.0", "code-block-writer": "^10.1.1" } }, "sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA=="],
@@ -1822,8 +1608,6 @@
"type-detect": ["type-detect@4.1.0", "", {}, "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw=="],
- "type-fest": ["type-fest@0.18.1", "", {}, "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw=="],
-
"typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
@@ -1834,7 +1618,7 @@
"ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
- "uint8arrays": ["uint8arrays@2.1.10", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-Q9/hhJa2836nQfEJSZTmr+pg9+cDJS9XEAp7N2Vg5MzL3bK/mkMVfjscRGYruP9jNda6MAdf4QD/y78gSzkp6A=="],
+ "uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
@@ -1878,14 +1662,8 @@
"v8-compile-cache-lib": ["v8-compile-cache-lib@3.0.1", "", {}, "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="],
- "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="],
-
"valtio": ["valtio@1.13.2", "", { "dependencies": { "derive-valtio": "0.1.0", "proxy-compare": "2.6.0", "use-sync-external-store": "1.2.0" }, "peerDependencies": { "@types/react": ">=16.8", "react": ">=16.8" }, "optionalPeers": ["@types/react", "react"] }, "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A=="],
- "varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="],
-
- "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="],
-
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
@@ -1928,8 +1706,6 @@
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
- "xxhashjs": ["xxhashjs@0.2.2", "", { "dependencies": { "cuint": "^0.2.2" } }, "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw=="],
-
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
@@ -1974,18 +1750,8 @@
"@coinbase/wallet-sdk/zustand": ["zustand@5.0.3", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg=="],
- "@cowprotocol/app-data/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
-
- "@cowprotocol/app-data/cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="],
-
- "@cowprotocol/cow-sdk/cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="],
-
"@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
- "@ethereumjs/tx/ethereum-cryptography": ["ethereum-cryptography@2.2.1", "", { "dependencies": { "@noble/curves": "1.4.2", "@noble/hashes": "1.4.0", "@scure/bip32": "1.4.0", "@scure/bip39": "1.3.0" } }, "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg=="],
-
- "@ethereumjs/util/ethereum-cryptography": ["ethereum-cryptography@2.2.1", "", { "dependencies": { "@noble/curves": "1.4.2", "@noble/hashes": "1.4.0", "@scure/bip32": "1.4.0", "@scure/bip39": "1.3.0" } }, "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg=="],
-
"@ethersproject/providers/ws": ["ws@7.4.6", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A=="],
"@gemini-wallet/core/eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
@@ -2010,8 +1776,6 @@
"@metamask/providers/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
- "@metamask/rpc-errors/@metamask/utils": ["@metamask/utils@11.9.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.1.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "@types/lodash": "^4.17.20", "debug": "^4.3.4", "lodash": "^4.17.21", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-wRnoSDD9jTWOge/+reFviJQANhS+uy8Y+OEwRanp5mQeGTjBFmK1r2cTOnei2UCZRV1crXHzeJVSFEoDDcgRbA=="],
-
"@metamask/sdk/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="],
"@metamask/sdk-communication-layer/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="],
@@ -2020,8 +1784,6 @@
"@metamask/utils/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
- "@radix-ui/react-dialog/react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="],
-
"@reown/appkit/@walletconnect/types": ["@walletconnect/types@2.21.0", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "events": "3.3.0" } }, "sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw=="],
"@reown/appkit/@walletconnect/universal-provider": ["@walletconnect/universal-provider@2.21.0", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/jsonrpc-http-connection": "1.0.8", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "@walletconnect/sign-client": "2.21.0", "@walletconnect/types": "2.21.0", "@walletconnect/utils": "2.21.0", "es-toolkit": "1.33.0", "events": "3.3.0" } }, "sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg=="],
@@ -2058,8 +1820,6 @@
"@wagmi/core/eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
- "@walletconnect/core/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@walletconnect/environment/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
"@walletconnect/events/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
@@ -2076,8 +1836,6 @@
"@walletconnect/relay-auth/@noble/hashes": ["@noble/hashes@1.7.0", "", {}, "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w=="],
- "@walletconnect/relay-auth/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@walletconnect/safe-json/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
"@walletconnect/time/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
@@ -2088,8 +1846,6 @@
"@walletconnect/utils/@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
- "@walletconnect/utils/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@walletconnect/utils/viem": ["viem@2.23.2", "", { "dependencies": { "@noble/curves": "1.8.1", "@noble/hashes": "1.7.1", "@scure/bip32": "1.6.2", "@scure/bip39": "1.5.4", "abitype": "1.0.8", "isows": "1.0.6", "ox": "0.6.7", "ws": "8.18.0" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA=="],
"@walletconnect/window-getters/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
@@ -2104,16 +1860,12 @@
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
- "cids/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"cli-truncate/string-width": ["string-width@8.1.1", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw=="],
"cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
- "decamelize-keys/map-obj": ["map-obj@1.0.1", "", {}, "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg=="],
-
"eciesjs/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
"edge-runtime/async-listen": ["async-listen@3.0.1", "", {}, "sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA=="],
@@ -2126,17 +1878,15 @@
"eth-json-rpc-filters/pify": ["pify@5.0.0", "", {}, "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA=="],
- "ethereum-cryptography/@noble/curves": ["@noble/curves@1.9.0", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg=="],
-
- "execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
+ "ethereum-cryptography/@noble/curves": ["@noble/curves@1.4.2", "", { "dependencies": { "@noble/hashes": "1.4.0" } }, "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw=="],
- "graphql-request/cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="],
+ "ethereum-cryptography/@noble/hashes": ["@noble/hashes@1.4.0", "", {}, "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg=="],
- "graphql-request/form-data": ["form-data@3.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35" } }, "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ=="],
+ "ethereum-cryptography/@scure/bip32": ["@scure/bip32@1.4.0", "", { "dependencies": { "@noble/curves": "~1.4.0", "@noble/hashes": "~1.4.0", "@scure/base": "~1.1.6" } }, "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg=="],
- "hamt-sharding/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
+ "ethereum-cryptography/@scure/bip39": ["@scure/bip39@1.3.0", "", { "dependencies": { "@noble/hashes": "~1.4.0", "@scure/base": "~1.1.6" } }, "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ=="],
- "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
+ "execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"json-rpc-engine/@metamask/safe-event-emitter": ["@metamask/safe-event-emitter@2.0.0", "", {}, "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q=="],
@@ -2146,26 +1896,10 @@
"loose-envify/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
- "meow/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="],
-
- "merge-options/is-plain-obj": ["is-plain-obj@2.1.0", "", {}, "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="],
-
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
- "minimist-options/is-plain-obj": ["is-plain-obj@1.1.0", "", {}, "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg=="],
-
"mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
- "multicodec/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
- "multihashes/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
- "multihashes/varint": ["varint@5.0.2", "", {}, "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow=="],
-
- "multihashing-async/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
- "normalize-package-data/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
-
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
"obj-multiplex/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
@@ -2194,14 +1928,6 @@
"qrcode/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="],
- "rabin-wasm/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
-
- "read-pkg/normalize-package-data": ["normalize-package-data@2.5.0", "", { "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA=="],
-
- "read-pkg/type-fest": ["type-fest@0.6.0", "", {}, "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="],
-
- "read-pkg-up/type-fest": ["type-fest@0.8.1", "", {}, "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="],
-
"restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
"restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
@@ -2236,26 +1962,6 @@
"@coinbase/wallet-sdk/ox/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
- "@cowprotocol/app-data/cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
-
- "@cowprotocol/cow-sdk/cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
-
- "@ethereumjs/tx/ethereum-cryptography/@noble/curves": ["@noble/curves@1.4.2", "", { "dependencies": { "@noble/hashes": "1.4.0" } }, "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw=="],
-
- "@ethereumjs/tx/ethereum-cryptography/@noble/hashes": ["@noble/hashes@1.4.0", "", {}, "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg=="],
-
- "@ethereumjs/tx/ethereum-cryptography/@scure/bip32": ["@scure/bip32@1.4.0", "", { "dependencies": { "@noble/curves": "~1.4.0", "@noble/hashes": "~1.4.0", "@scure/base": "~1.1.6" } }, "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg=="],
-
- "@ethereumjs/tx/ethereum-cryptography/@scure/bip39": ["@scure/bip39@1.3.0", "", { "dependencies": { "@noble/hashes": "~1.4.0", "@scure/base": "~1.1.6" } }, "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ=="],
-
- "@ethereumjs/util/ethereum-cryptography/@noble/curves": ["@noble/curves@1.4.2", "", { "dependencies": { "@noble/hashes": "1.4.0" } }, "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw=="],
-
- "@ethereumjs/util/ethereum-cryptography/@noble/hashes": ["@noble/hashes@1.4.0", "", {}, "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg=="],
-
- "@ethereumjs/util/ethereum-cryptography/@scure/bip32": ["@scure/bip32@1.4.0", "", { "dependencies": { "@noble/curves": "~1.4.0", "@noble/hashes": "~1.4.0", "@scure/base": "~1.1.6" } }, "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg=="],
-
- "@ethereumjs/util/ethereum-cryptography/@scure/bip39": ["@scure/bip39@1.3.0", "", { "dependencies": { "@noble/hashes": "~1.4.0", "@scure/base": "~1.1.6" } }, "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ=="],
-
"@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/rpc-errors": ["@metamask/rpc-errors@6.4.0", "", { "dependencies": { "@metamask/utils": "^9.0.0", "fast-safe-stringify": "^2.0.6" } }, "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg=="],
"@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/utils": ["@metamask/utils@8.5.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.0.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "debug": "^4.3.4", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ=="],
@@ -2278,10 +1984,6 @@
"@metamask/providers/@metamask/utils/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
- "@metamask/rpc-errors/@metamask/utils/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
-
- "@metamask/rpc-errors/@metamask/utils/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
-
"@metamask/sdk-communication-layer/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
"@metamask/sdk/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
@@ -2326,9 +2028,9 @@
"eth-block-tracker/@metamask/utils/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
- "graphql-request/cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
+ "ethereum-cryptography/@scure/bip32/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="],
- "hosted-git-info/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
+ "ethereum-cryptography/@scure/bip39/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="],
"log-update/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
@@ -2344,10 +2046,6 @@
"qrcode/yargs/yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="],
- "read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@2.8.9", "", {}, "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="],
-
- "read-pkg/normalize-package-data/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="],
-
"vite-node/vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
"vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="],
@@ -2408,14 +2106,6 @@
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
- "@ethereumjs/tx/ethereum-cryptography/@scure/bip32/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="],
-
- "@ethereumjs/tx/ethereum-cryptography/@scure/bip39/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="],
-
- "@ethereumjs/util/ethereum-cryptography/@scure/bip32/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="],
-
- "@ethereumjs/util/ethereum-cryptography/@scure/bip39/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="],
-
"@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/rpc-errors/@metamask/utils": ["@metamask/utils@9.3.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.1.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "debug": "^4.3.4", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g=="],
"@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/utils/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
@@ -2438,8 +2128,6 @@
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
- "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem": ["viem@2.23.2", "", { "dependencies": { "@noble/curves": "1.8.1", "@noble/hashes": "1.7.1", "@scure/bip32": "1.6.2", "@scure/bip39": "1.5.4", "abitype": "1.0.8", "isows": "1.0.6", "ox": "0.6.7", "ws": "8.18.0" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA=="],
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.21.0", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.21.0", "@walletconnect/utils": "2.21.0", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.33.0", "events": "3.3.0", "uint8arrays": "3.1.0" } }, "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw=="],
@@ -2450,8 +2138,6 @@
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
- "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem": ["viem@2.23.2", "", { "dependencies": { "@noble/curves": "1.8.1", "@noble/hashes": "1.7.1", "@scure/bip32": "1.6.2", "@scure/bip39": "1.5.4", "abitype": "1.0.8", "isows": "1.0.6", "ox": "0.6.7", "ws": "8.18.0" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA=="],
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.21.0", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.21.0", "@walletconnect/utils": "2.21.0", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.33.0", "events": "3.3.0", "uint8arrays": "3.1.0" } }, "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw=="],
@@ -2462,8 +2148,6 @@
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
- "@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem": ["viem@2.23.2", "", { "dependencies": { "@noble/curves": "1.8.1", "@noble/hashes": "1.7.1", "@scure/bip32": "1.6.2", "@scure/bip39": "1.5.4", "abitype": "1.0.8", "isows": "1.0.6", "ox": "0.6.7", "ws": "8.18.0" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA=="],
"@walletconnect/utils/viem/ox/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
@@ -2578,8 +2262,6 @@
"@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/rpc-errors/@metamask/utils/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
- "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/@scure/bip32": ["@scure/bip32@1.6.2", "", { "dependencies": { "@noble/curves": "~1.8.1", "@noble/hashes": "~1.7.1", "@scure/base": "~1.2.2" } }, "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw=="],
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/@scure/bip39": ["@scure/bip39@1.5.4", "", { "dependencies": { "@noble/hashes": "~1.7.1", "@scure/base": "~1.2.4" } }, "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA=="],
@@ -2592,8 +2274,6 @@
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
- "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/@scure/bip32": ["@scure/bip32@1.6.2", "", { "dependencies": { "@noble/curves": "~1.8.1", "@noble/hashes": "~1.7.1", "@scure/base": "~1.2.2" } }, "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw=="],
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/@scure/bip39": ["@scure/bip39@1.5.4", "", { "dependencies": { "@noble/hashes": "~1.7.1", "@scure/base": "~1.2.4" } }, "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA=="],
@@ -2606,8 +2286,6 @@
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
- "@reown/appkit/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="],
-
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/@scure/bip32": ["@scure/bip32@1.6.2", "", { "dependencies": { "@noble/curves": "~1.8.1", "@noble/hashes": "~1.7.1", "@scure/base": "~1.2.2" } }, "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw=="],
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/@scure/bip39": ["@scure/bip39@1.5.4", "", { "dependencies": { "@noble/hashes": "~1.7.1", "@scure/base": "~1.2.4" } }, "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA=="],
diff --git a/declaration.d.ts b/declaration.d.ts
deleted file mode 100644
index 8aea39f72..000000000
--- a/declaration.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-declare module 'xxhashjs'
diff --git a/package.json b/package.json
index 760f33da2..28d30b5b7 100644
--- a/package.json
+++ b/package.json
@@ -19,30 +19,24 @@
"prepare": "husky"
},
"dependencies": {
- "@cowprotocol/cow-sdk": "5.10.3",
"@headlessui/react": "2.2.9",
"@plausible-analytics/tracker": "^0.4.4",
"@rainbow-me/rainbowkit": "2.2.9",
"@react-hookz/web": "24.0.4",
"@tanstack/react-query": "5.90.20",
"@tanstack/react-virtual": "3.13.12",
- "cross-fetch": "4.1.0",
"ethers": "5.7.2",
"framer-motion": "12.29.2",
- "graphql": "16.12.0",
"react": "19.2.3",
"react-dom": "19.2.3",
"react-hot-toast": "2.6.0",
"react-markdown": "10.1.0",
- "react-paginate": "8.3.0",
"react-rewards": "2.1.0",
"react-router": "7.13.0",
"recharts": "2.15.4",
"use-indexeddb": "2.0.2",
- "vaul": "1.1.2",
"viem": "2.45.0",
"wagmi": "2.18.2",
- "xxhashjs": "0.2.2",
"zod": "4.3.6"
},
"devDependencies": {
diff --git a/src/components/pages/landing/components/common/Header.tsx b/src/components/pages/landing/components/common/Header.tsx
deleted file mode 100644
index 1a9725103..000000000
--- a/src/components/pages/landing/components/common/Header.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { LauncherDropdown } from '@shared/components/LauncherDropdown'
-import { IconChevron } from '@shared/icons/IconChevron'
-import { TypeMarkYearn as TypeMarkYearnFull } from '@shared/icons/TypeMarkYearn'
-import { TypeMarkYearn as TypeMarkYearnText } from '@shared/icons/TypeMarkYearn-text-only'
-import { cl } from '@shared/utils'
-import type { ReactElement } from 'react'
-import { useState } from 'react'
-
-export function LandingAppHeader(): ReactElement {
- const [isLauncherOpen, setIsLauncherOpen] = useState(false)
-
- return (
-
-
-
-
-
setIsLauncherOpen(!isLauncherOpen)}
- className={'flex items-center gap-1 transition-colors hover:opacity-80'}
- >
-
-
-
-
-
-
-
-
setIsLauncherOpen(false)} forceDark />
-
-
-
-
- )
-}
diff --git a/src/components/pages/landing/components/sections/About.tsx b/src/components/pages/landing/components/sections/About.tsx
deleted file mode 100644
index e69de29bb..000000000
diff --git a/src/components/pages/landing/utils/scrollToHash.ts b/src/components/pages/landing/utils/scrollToHash.ts
deleted file mode 100644
index aad3f012e..000000000
--- a/src/components/pages/landing/utils/scrollToHash.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export const scrollToHash = (id: string): void => {
- const element = document.getElementById(id)
- element?.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' })
-}
diff --git a/src/components/pages/portfolio/components/EmptySectionCard.tsx b/src/components/pages/portfolio/components/EmptySectionCard.tsx
index 956d3ad21..c00780dcd 100644
--- a/src/components/pages/portfolio/components/EmptySectionCard.tsx
+++ b/src/components/pages/portfolio/components/EmptySectionCard.tsx
@@ -1,4 +1,5 @@
import { Button } from '@shared/components/Button'
+import { EmptyState } from '@shared/components/EmptyState'
import type { ReactElement } from 'react'
import { Link } from 'react-router'
@@ -15,21 +16,15 @@ export function EmptySectionCard({
onClick,
href
}: TEmptySectionCardProps): ReactElement {
- return (
-
-
-
{title}
-
{description}
- {href ? (
-
- {ctaLabel}
-
- ) : (
-
- {ctaLabel}
-
- )}
-
-
+ const actionButton = href ? (
+
+ {ctaLabel}
+
+ ) : (
+
+ {ctaLabel}
+
)
+
+ return
}
diff --git a/src/components/pages/vaults/Mark.tsx b/src/components/pages/vaults/Mark.tsx
deleted file mode 100644
index 5b85a9743..000000000
--- a/src/components/pages/vaults/Mark.tsx
+++ /dev/null
@@ -1,493 +0,0 @@
-import type { ReactElement } from 'react'
-
-export function V3Mask(props: React.SVGProps): ReactElement {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export function V3Logo(props: React.SVGProps): ReactElement {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
diff --git a/src/components/pages/vaults/components/SuggestedVaultCard.tsx b/src/components/pages/vaults/components/SuggestedVaultCard.tsx
index d465b0213..8a1d18fd7 100644
--- a/src/components/pages/vaults/components/SuggestedVaultCard.tsx
+++ b/src/components/pages/vaults/components/SuggestedVaultCard.tsx
@@ -91,14 +91,6 @@ export function SuggestedVaultCard({ vault }: { vault: TYDaemonVault }): ReactEl
- {/*
- {'View vault'}
- {'→'}
-
*/}
)
}
diff --git a/src/components/pages/vaults/components/TrendingVaults.tsx b/src/components/pages/vaults/components/TrendingVaults.tsx
deleted file mode 100644
index 7bf2c01e1..000000000
--- a/src/components/pages/vaults/components/TrendingVaults.tsx
+++ /dev/null
@@ -1,331 +0,0 @@
-import Link from '@components/Link'
-import { SuggestedVaultCard } from '@pages/vaults/components/SuggestedVaultCard'
-import { useVaultApyData } from '@pages/vaults/hooks/useVaultApyData'
-import { RenderAmount } from '@shared/components/RenderAmount'
-import { TokenLogo } from '@shared/components/TokenLogo'
-import { useLocalStorage } from '@shared/hooks/useLocalStorage'
-import { IconChevron } from '@shared/icons/IconChevron'
-import { cl, toAddress } from '@shared/utils'
-import { formatPercent } from '@shared/utils/format'
-import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import { getNetwork } from '@shared/utils/wagmi'
-import type { CSSProperties, ReactElement } from 'react'
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-
-type TTrendingVaultsProps = {
- suggestedVaults: TYDaemonVault[]
-}
-
-const MAX_EXPANDED_VAULTS = 4
-const EXPANDED_CARD_WIDTH = 272
-const EXPANDED_CARD_GAP = 16
-
-function usePrefersReducedMotion(): boolean {
- const [prefersReducedMotion, setPrefersReducedMotion] = useState(false)
-
- useEffect(() => {
- if (typeof window === 'undefined' || typeof window.matchMedia === 'undefined') {
- return
- }
- const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)')
- const updatePreference = (): void => {
- setPrefersReducedMotion(mediaQuery.matches)
- }
- updatePreference()
- if (typeof mediaQuery.addEventListener === 'function') {
- mediaQuery.addEventListener('change', updatePreference)
- } else if (typeof mediaQuery.addListener === 'function') {
- mediaQuery.addListener(updatePreference)
- }
- return () => {
- if (typeof mediaQuery.removeEventListener === 'function') {
- mediaQuery.removeEventListener('change', updatePreference)
- } else if (typeof mediaQuery.removeListener === 'function') {
- mediaQuery.removeListener(updatePreference)
- }
- }
- }, [])
-
- return prefersReducedMotion
-}
-
-function TrendingVaultMarqueeItem({ vault }: { vault: TYDaemonVault }): ReactElement {
- const apyData = useVaultApyData(vault)
- const chain = getNetwork(vault.chainID)
- const tokenIcon = `${import.meta.env.VITE_BASE_YEARN_ASSETS_URI}/tokens/${vault.chainID}/${toAddress(
- vault.token.address
- ).toLowerCase()}/logo-128.png`
- const chainLogoSrc = `${import.meta.env.VITE_BASE_YEARN_ASSETS_URI}/chains/${vault.chainID}/logo-32.png`
-
- const apyDisplay = useMemo((): string => {
- if (apyData.mode === 'historical' || apyData.mode === 'noForward') {
- return formatPercent(apyData.netApr * 100, 2, 2)
- }
- if (apyData.mode === 'rewards' && vault.staking.source === 'VeYFI' && apyData.estAprRange) {
- return `${formatPercent(apyData.estAprRange[0] * 100, 2, 2)} – ${formatPercent(apyData.estAprRange[1] * 100, 2, 2)}`
- }
- if (apyData.mode === 'katana' && apyData.katanaEstApr !== undefined) {
- return formatPercent(apyData.katanaEstApr * 100, 2, 2)
- }
- const boostedApr = apyData.baseForwardApr + apyData.rewardsAprSum
- if (apyData.mode === 'rewards') {
- return formatPercent(boostedApr * 100, 2, 2)
- }
- return formatPercent(apyData.baseForwardApr * 100, 2, 2)
- }, [apyData, vault])
-
- return (
-
-
- {vault.name}
-
- {'|'}
-
- {apyDisplay}
-
- {'|'}
-
-
-
-
- {`on ${chain.name}`}
-
- )
-}
-
-function TrendingVaultsCollapsedMarquee({ suggestedVaults }: { suggestedVaults: TYDaemonVault[] }): ReactElement {
- const [isInteracting, setIsInteracting] = useState(false)
- const prefersReducedMotion = usePrefersReducedMotion()
- const marqueeDuration = `${Math.max(suggestedVaults.length * 6, 24)}s`
- const marqueeItems = useMemo((): ReactElement[] => {
- const vaultItems = suggestedVaults.map((vault) => (
-
- ))
-
- if (prefersReducedMotion) {
- return vaultItems
- }
-
- const vaultItemsDuplicate = suggestedVaults.map((vault) => (
-
- ))
-
- return [...vaultItemsDuplicate, ...vaultItems]
- }, [prefersReducedMotion, suggestedVaults])
-
- return (
- setIsInteracting(true)}
- onMouseLeave={(): void => setIsInteracting(false)}
- onFocusCapture={(): void => setIsInteracting(true)}
- onBlurCapture={(event): void => {
- if (!event.currentTarget.contains(event.relatedTarget as Node)) {
- setIsInteracting(false)
- }
- }}
- >
-
-
-
- {marqueeItems}
-
-
- )
-}
-
-function TrendingVaultsSkeleton(): ReactElement {
- const placeholderCards = ['one', 'two', 'three', 'four']
-
- return (
-
-
-
-
-
- {placeholderCards.map((key) => (
-
- ))}
-
-
-
-
- )
-}
-
-export function TrendingVaults({ suggestedVaults }: TTrendingVaultsProps): ReactElement | null {
- const [isTrendingExpanded, setIsTrendingExpanded] = useLocalStorage(
- 'yearn.fi/trending-vaults-expanded@0.0.1',
- false
- )
- const expandedCardsRef = useRef(null)
- const [visibleExpandedCards, setVisibleExpandedCards] = useState(() =>
- Math.min(MAX_EXPANDED_VAULTS, suggestedVaults.length)
- )
-
- useEffect(() => {
- setVisibleExpandedCards(Math.min(MAX_EXPANDED_VAULTS, suggestedVaults.length))
- }, [suggestedVaults.length])
-
- const updateVisibleExpandedCards = useCallback((): void => {
- const container = expandedCardsRef.current
- if (!container) {
- return
- }
- const availableWidth = container.clientWidth
- if (availableWidth <= 0) {
- return
- }
- const fitCount = Math.max(
- 1,
- Math.floor((availableWidth + EXPANDED_CARD_GAP) / (EXPANDED_CARD_WIDTH + EXPANDED_CARD_GAP))
- )
- const nextCount = Math.min(MAX_EXPANDED_VAULTS, suggestedVaults.length, fitCount)
- setVisibleExpandedCards((prev) => (prev === nextCount ? prev : nextCount))
- }, [suggestedVaults.length])
-
- useEffect(() => {
- if (!isTrendingExpanded) {
- return
- }
- updateVisibleExpandedCards()
- }, [isTrendingExpanded, updateVisibleExpandedCards])
-
- useEffect(() => {
- if (!isTrendingExpanded) {
- return
- }
- const container = expandedCardsRef.current
- if (!container) {
- return
- }
- if (typeof ResizeObserver !== 'undefined') {
- const observer = new ResizeObserver(() => updateVisibleExpandedCards())
- observer.observe(container)
- return () => observer.disconnect()
- }
- window.addEventListener('resize', updateVisibleExpandedCards)
- return () => {
- window.removeEventListener('resize', updateVisibleExpandedCards)
- }
- }, [isTrendingExpanded, updateVisibleExpandedCards])
-
- const expandedVaults = useMemo(
- () => suggestedVaults.slice(0, visibleExpandedCards),
- [suggestedVaults, visibleExpandedCards]
- )
-
- if (suggestedVaults.length === 0) {
- return
- }
-
- return (
-
-
-
-
-
- {!isTrendingExpanded ?
: null}
-
-
setIsTrendingExpanded((previous) => !previous)}
- >
-
-
-
- {isTrendingExpanded ? (
-
-
-
- {expandedVaults.map((vault, index) => {
- const key = `${vault.chainID}_${toAddress(vault.address)}_${index}`
- return (
-
-
-
- )
- })}
-
-
-
- ) : null}
-
-
- )
-}
diff --git a/src/components/pages/vaults/components/VaultChainTag.tsx b/src/components/pages/vaults/components/VaultChainTag.tsx
deleted file mode 100644
index a38fbda98..000000000
--- a/src/components/pages/vaults/components/VaultChainTag.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { opacityToHex } from '@shared/utils/opacity'
-
-import type { FC } from 'react'
-
-const ChainColors: { [key: number]: string } = {
- 1: '#627EEA',
- 10: '#C80016',
- 137: '#A726C1',
- 250: '#1969FF',
- 8453: '#1C55F5',
- 42161: '#2F3749',
- 747474: '#f6ff0d',
- 146: '#ffffff'
-}
-
-const ChainTextColors: { [key: number]: string } = {
- 747474: '#000000',
- 146: '#000000'
-}
-
-const ChainNames: { [key: number]: string } = {
- 1: 'Ethereum',
- 10: 'Optimism',
- 137: 'Polygon PoS',
- 250: 'Fantom',
- 8453: 'Base',
- 42161: 'Arbitrum',
- 747474: 'Katana',
- 146: 'Sonic'
-}
-
-export const VaultChainTag: FC<{
- chainID?: number
- backgroundOpacity?: number
-}> = ({ chainID = 1, backgroundOpacity = 1 }) => {
- const textOpacity = backgroundOpacity > 0.5 ? 1 : 0.8
- return (
-
- {ChainNames[chainID]}
-
- )
-}
diff --git a/src/components/pages/vaults/components/compare/VaultsCompareModal.tsx b/src/components/pages/vaults/components/compare/VaultsCompareModal.tsx
index 55810f5f8..4aad1d29e 100644
--- a/src/components/pages/vaults/components/compare/VaultsCompareModal.tsx
+++ b/src/components/pages/vaults/components/compare/VaultsCompareModal.tsx
@@ -76,13 +76,6 @@ function MetricValue({
)
}
-// function renderPercentValue(value: number | null | undefined): ReactElement {
-// if (value === null || value === undefined || Number.isNaN(value)) {
-// return {'—'}
-// }
-// return {formatApyDisplay(value)}
-// }
-
function hasAllocatedFunds(strategy: TVaultStrategyItem): boolean {
const { debtRatio, totalDebt } = strategy.details ?? {}
return Boolean(debtRatio && debtRatio > 0 && totalDebt && totalDebt !== '0')
diff --git a/src/components/pages/vaults/components/detail/MobileStickyHeader.tsx b/src/components/pages/vaults/components/detail/MobileStickyHeader.tsx
deleted file mode 100644
index e8c418a00..000000000
--- a/src/components/pages/vaults/components/detail/MobileStickyHeader.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import { useVaultApyData } from '@pages/vaults/hooks/useVaultApyData'
-import { ImageWithFallback } from '@shared/components/ImageWithFallback'
-import { cl, formatApyDisplay, formatTvlDisplay } from '@shared/utils'
-import { getVaultName } from '@shared/utils/helpers'
-import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import type { ReactElement } from 'react'
-import { useEffect, useState } from 'react'
-
-interface MobileStickyHeaderProps {
- currentVault: TYDaemonVault
-}
-
-export function MobileStickyHeader({ currentVault }: MobileStickyHeaderProps): ReactElement {
- const [isSticky, setIsSticky] = useState(false)
- const apyData = useVaultApyData(currentVault)
-
- const forwardAPY =
- apyData.mode === 'katana' && apyData.katanaEstApr !== undefined
- ? apyData.katanaEstApr
- : currentVault.apr.forwardAPR.netAPR
-
- const historicalAPY = currentVault.apr.netAPR
-
- useEffect(() => {
- const handleScroll = (): void => {
- const scrollThreshold = 120
- setIsSticky(window.scrollY > scrollThreshold)
- }
-
- handleScroll()
- window.addEventListener('scroll', handleScroll, { passive: true })
- return (): void => window.removeEventListener('scroll', handleScroll)
- }, [])
-
- const tokenLogoSrc = `${import.meta.env.VITE_BASE_YEARN_ASSETS_URI}/tokens/${
- currentVault.chainID
- }/${currentVault.token.address.toLowerCase()}/logo-128.png`
-
- return (
-
-
-
-
-
-
-
{getVaultName(currentVault)}
-
-
-
-
EST. APY
-
{formatApyDisplay(forwardAPY)}
-
-
-
30D APY
-
{formatApyDisplay(historicalAPY)}
-
-
-
TVL
-
{formatTvlDisplay(currentVault.tvl.tvl)}
-
-
-
-
- )
-}
diff --git a/src/components/pages/vaults/components/filters/VaultsAssetFilter.tsx b/src/components/pages/vaults/components/filters/VaultsAssetFilter.tsx
index 63d1825d6..cf30e4b6b 100644
--- a/src/components/pages/vaults/components/filters/VaultsAssetFilter.tsx
+++ b/src/components/pages/vaults/components/filters/VaultsAssetFilter.tsx
@@ -1,9 +1,11 @@
+import { useThrottledState } from '@react-hookz/web'
+import { EmptyState } from '@shared/components/EmptyState'
import type { TMultiSelectOptionProps } from '@shared/components/MultiSelectDropdown'
import { IconChevron } from '@shared/icons/IconChevron'
import { IconCross } from '@shared/icons/IconCross'
import { IconSearch } from '@shared/icons/IconSearch'
import { cl } from '@shared/utils'
-import type { ReactElement } from 'react'
+import type { ReactElement, ReactNode } from 'react'
import { useCallback, useMemo, useState } from 'react'
type TVaultsAssetFilterProps = {
@@ -12,12 +14,60 @@ type TVaultsAssetFilterProps = {
buttonLabel?: string
}
+function renderAssetOption(
+ option: TMultiSelectOptionProps,
+ onSelectSingle: (option: TMultiSelectOptionProps) => void,
+ onToggle: (option: TMultiSelectOptionProps) => void
+): ReactNode {
+ return (
+
+
onSelectSingle(option)}
+ >
+ {option.icon ? (
+
+ {option.icon}
+
+ ) : null}
+ {option.label}
+
+
onToggle(option)}
+ readOnly
+ />
+
+ )
+}
+
+function renderAssetFilterSelected(buttonTitle: string, isOpen: boolean): ReactNode {
+ return (
+ <>
+ {buttonTitle}
+
+ >
+ )
+}
+
export function VaultsAssetFilter({
options,
onSelect,
buttonLabel = 'Filter by assets'
}: TVaultsAssetFilterProps): ReactElement {
- const [isOpen, setIsOpen] = useState(false)
+ const [isOpen, setIsOpen] = useThrottledState(false, 400)
const [query, setQuery] = useState('')
const selectedOptions = useMemo(() => options.filter((option) => option.isSelected), [options])
@@ -35,7 +85,7 @@ export function VaultsAssetFilter({
const handleClose = useCallback((): void => {
setIsOpen(false)
setQuery('')
- }, [])
+ }, [setIsOpen])
const handleSelectSingle = useCallback(
(option: TMultiSelectOptionProps): void => {
@@ -73,11 +123,7 @@ export function VaultsAssetFilter({
'flex w-full items-center justify-between gap-3 rounded-lg border border-border bg-surface px-3 py-2 text-left'
}
>
- {buttonTitle}
-
+ {renderAssetFilterSelected(buttonTitle, isOpen)}
{isOpen ? (
@@ -140,46 +186,15 @@ export function VaultsAssetFilter({
{filteredOptions.length === 0 ? (
-
- ) : null}
- {filteredOptions.map((option) => (
-
-
handleSelectSingle(option)}
- >
- {option.icon ? (
-
- {option.icon}
-
- ) : null}
- {option.label}
-
-
handleToggleOption(option)}
- readOnly
- />
-
- ))}
+
+ ) : (
+ filteredOptions.map((option) => renderAssetOption(option, handleSelectSingle, handleToggleOption))
+ )}
diff --git a/src/components/pages/vaults/components/list/HoldingsPill.tsx b/src/components/pages/vaults/components/list/HoldingsPill.tsx
deleted file mode 100644
index c6809ae6e..000000000
--- a/src/components/pages/vaults/components/list/HoldingsPill.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import { useVaultApyData } from '@pages/vaults/hooks/useVaultApyData'
-import { ImageWithFallback } from '@shared/components/ImageWithFallback'
-import { formatAmount, formatApyDisplay, isZero, toAddress } from '@shared/utils'
-import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import type { ReactElement, ReactNode } from 'react'
-
-function HoldingsPill({ vault }: { vault: TYDaemonVault }): ReactElement {
- const data = useVaultApyData(vault)
-
- const isVeYfi = vault.staking.source === 'VeYFI'
- const boostedApr = data.baseForwardApr + data.rewardsAprSum
- const katanaApr = data.katanaEstApr ?? data.baseForwardApr
-
- const apyContent: ReactNode = (() => {
- if (data.mode === 'katana' && data.katanaEstApr !== undefined) {
- return (
- <>
- {'⚔️ '}
- {formatApyDisplay(katanaApr)}
- >
- )
- }
-
- if (data.mode === 'rewards') {
- if (isVeYfi && data.estAprRange) {
- return (
- <>
- {'⚡️ '}
- {formatApyDisplay(data.estAprRange[0])}
- {' → '}
- {formatApyDisplay(data.estAprRange[1])}
- >
- )
- }
-
- return (
- <>
- {'⚡️ '}
- {formatApyDisplay(boostedApr)}
- >
- )
- }
-
- if (data.mode === 'boosted' && data.isBoosted) {
- return (
- <>
- {'🚀 '}
- {formatApyDisplay(vault.apr.forwardAPR.netAPR)}
- {data.boost ? (
-
- {` • Boost ${formatAmount(data.boost, 2, 2)}x`}
-
- ) : null}
- >
- )
- }
-
- if (!isZero(data.baseForwardApr)) {
- return (
- <>
- {'APY '}
- {formatApyDisplay(data.baseForwardApr)}
- >
- )
- }
-
- return (
- <>
- {'Hist. '}
- {formatApyDisplay(data.netApr)}
- >
- )
- })()
-
- const tokenLogoSrc = `${import.meta.env.VITE_BASE_YEARN_ASSETS_URI}/tokens/${vault.chainID}/${toAddress(
- vault.token.address
- ).toLowerCase()}/logo-128.png`
-
- return (
-
- )
-}
-
-export default HoldingsPill
diff --git a/src/components/pages/vaults/components/list/VaultsListEmpty.tsx b/src/components/pages/vaults/components/list/VaultsListEmpty.tsx
index b2aa4b286..430bcdfd7 100644
--- a/src/components/pages/vaults/components/list/VaultsListEmpty.tsx
+++ b/src/components/pages/vaults/components/list/VaultsListEmpty.tsx
@@ -1,4 +1,5 @@
import { Button } from '@shared/components/Button'
+import { EmptyState } from '@shared/components/EmptyState'
import type { TYDaemonVaults } from '@shared/utils/schemas/yDaemonVaultsSchemas'
import type { ReactElement } from 'react'
@@ -41,12 +42,13 @@ export function VaultsListEmpty({
if (currentCategories?.length === 1 && currentCategories.includes('holdings')) {
return (
-
-
{'No vaults found'}
-
- {"You don't appear to have any Yearn Vaults deposits."}
-
-
+
)
}
@@ -56,50 +58,67 @@ export function VaultsListEmpty({
if (hasSearch && isFullCategorySelection) {
return (
-
-
{'No vaults found'}
-
{`The vault "${currentSearch}" does not exist`}
-
+
)
}
if (hasSearch && !isFullCategorySelection) {
+ const showAllAction =
+ potentialResultsCount > 0 ? (
+ <>
+
+ {`Found ${potentialResultsCount} vault${potentialResultsCount > 1 ? 's' : ''} when searching all categories.`}
+
+
+ {'Show all results'}
+
+ >
+ ) : (
+ {`The vault "${currentSearch}" does not exist.`}
+ )
+
return (
-
-
{'No vaults found'}
-
{`No results for "${currentSearch}" with current filters.`}
- {potentialResultsCount > 0 ? (
- <>
-
- {`Found ${potentialResultsCount} vault${potentialResultsCount > 1 ? 's' : ''} when searching all categories.`}
-
-
- {'Show all results'}
-
- >
- ) : (
-
{`The vault "${currentSearch}" does not exist.`}
- )}
-
+
)
}
return (
-
-
{'No vaults found'}
-
{'No vaults found that match your filters.'}
-
- {'Search all vaults'}
-
-
+
+ {'Search all vaults'}
+
+ }
+ size="lg"
+ unstyled
+ className="mx-auto h-96 w-full md:w-3/4"
+ />
)
}
export function VaultListEmptyExternalMigration(): ReactElement {
return (
-
-
{'We looked under the cushions...'}
-
{"Looks like you don't have any tokens to migrate."}
-
+
)
}
diff --git a/src/components/pages/vaults/components/list/VaultsListInternalMigrationRow.tsx b/src/components/pages/vaults/components/list/VaultsListInternalMigrationRow.tsx
deleted file mode 100755
index 8c50f2844..000000000
--- a/src/components/pages/vaults/components/list/VaultsListInternalMigrationRow.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { ImageWithFallback } from '@shared/components/ImageWithFallback'
-import { useYearnBalance } from '@shared/hooks/useYearnBalance'
-import { cl, formatAmount, toAddress } from '@shared/utils'
-import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import type { ReactElement } from 'react'
-import Link from '/src/components/Link'
-import { VaultChainTag } from '../VaultChainTag'
-
-export function VaultsListInternalMigrationRow({ currentVault }: { currentVault: TYDaemonVault }): ReactElement {
- const balanceToMigrate = useYearnBalance({
- address: currentVault.address,
- chainID: currentVault.chainID
- })
-
- return (
-
-
-
-
-
-
-
-
-
{currentVault.name}
-
{currentVault.token.name}
-
-
-
-
-
-
-
- {"Looks like you're holding tokens from a previous version of this vault.\n"}
- {'To keep earning yield on your assets, migrate to the current vault.'}
-
-
-
-
-
-
-
- {'Migrate '}
- {`${formatAmount(balanceToMigrate.normalized)} ${currentVault.token.symbol}`}
-
-
-
-
-
-
- )
-}
diff --git a/src/components/pages/vaults/components/table/APYSparkline.tsx b/src/components/pages/vaults/components/table/APYSparkline.tsx
deleted file mode 100644
index 7236312aa..000000000
--- a/src/components/pages/vaults/components/table/APYSparkline.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { useVaultChartTimeseries } from '@pages/vaults/hooks/useVaultChartTimeseries'
-import { transformVaultChartData } from '@pages/vaults/utils/charts'
-import type { ReactElement } from 'react'
-import { useId, useMemo } from 'react'
-import { Area, ComposedChart, ResponsiveContainer, YAxis } from 'recharts'
-
-interface APYSparklineProps {
- chainId: number
- vaultAddress: string
-}
-
-export function APYSparkline({ chainId, vaultAddress }: APYSparklineProps): ReactElement {
- const gradientId = useId().replace(/:/g, '')
- const { data: timeseries, isLoading } = useVaultChartTimeseries({
- chainId,
- address: vaultAddress
- })
-
- const chartData = useMemo(() => {
- if (!timeseries) {
- return []
- }
- const transformed = transformVaultChartData(timeseries)
- return transformed.aprApyData?.slice(-30) ?? []
- }, [timeseries])
-
- if (isLoading) {
- return
- }
-
- if (!chartData.length) {
- return {'—'}
- }
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
diff --git a/src/components/pages/vaults/components/widget/deposit/index.tsx b/src/components/pages/vaults/components/widget/deposit/index.tsx
index f58c0b84f..ada63d6ec 100644
--- a/src/components/pages/vaults/components/widget/deposit/index.tsx
+++ b/src/components/pages/vaults/components/widget/deposit/index.tsx
@@ -19,6 +19,7 @@ import { useAccount } from 'wagmi'
import { SettingsPanel } from '../SettingsPanel'
import { TokenSelectorOverlay } from '../shared/TokenSelectorOverlay'
import { TransactionOverlay, type TransactionStep } from '../shared/TransactionOverlay'
+import { WidgetHeader } from '../shared/WidgetHeader'
import { AnnualReturnOverlay } from './AnnualReturnOverlay'
import { ApprovalOverlay } from './ApprovalOverlay'
import { DepositDetails } from './DepositDetails'
@@ -372,8 +373,11 @@ export const WidgetDeposit: FC = ({
if (isLoadingVaultData) {
return (
-
-
+
)
}
@@ -480,9 +484,7 @@ export const WidgetDeposit: FC
= ({
className={cl('flex flex-col border border-border relative h-full', { 'rounded-lg': !disableBorderRadius })}
data-tour="vault-detail-deposit-widget"
>
-
-
Deposit
-
+
{/* Amount Section */}
= ({
// Loading state
if (isLoadingVaultData) {
return (
-
-
+
)
}
return (
-
-
Migrate
-
+
{/* Balance Section */}
diff --git a/src/components/pages/vaults/components/widget/rewards/RewardRow.tsx b/src/components/pages/vaults/components/widget/rewards/RewardRow.tsx
index 5dfb10cc5..084251ce1 100644
--- a/src/components/pages/vaults/components/widget/rewards/RewardRow.tsx
+++ b/src/components/pages/vaults/components/widget/rewards/RewardRow.tsx
@@ -58,6 +58,7 @@ export function RewardRow(props: TRewardRowProps): ReactElement {
+ {symbol}
diff --git a/src/components/pages/vaults/components/widget/shared/WidgetHeader.tsx b/src/components/pages/vaults/components/widget/shared/WidgetHeader.tsx
new file mode 100644
index 000000000..99b40b9bd
--- /dev/null
+++ b/src/components/pages/vaults/components/widget/shared/WidgetHeader.tsx
@@ -0,0 +1,7 @@
+import type { FC } from 'react'
+
+export const WidgetHeader: FC<{ title: string }> = ({ title }) => (
+
+
{title}
+
+)
diff --git a/src/components/pages/vaults/components/widget/withdraw/index.tsx b/src/components/pages/vaults/components/widget/withdraw/index.tsx
index 8ba06f92b..7470c3fb0 100644
--- a/src/components/pages/vaults/components/widget/withdraw/index.tsx
+++ b/src/components/pages/vaults/components/widget/withdraw/index.tsx
@@ -18,6 +18,7 @@ import { InputTokenAmount } from '../InputTokenAmount'
import { SettingsPanel } from '../SettingsPanel'
import { TokenSelectorOverlay } from '../shared/TokenSelectorOverlay'
import { TransactionOverlay, type TransactionStep } from '../shared/TransactionOverlay'
+import { WidgetHeader } from '../shared/WidgetHeader'
import { getPriorityTokens } from './constants'
import { SourceSelector } from './SourceSelector'
import type { WithdrawalSource, WithdrawWidgetProps } from './types'
@@ -388,8 +389,11 @@ export const WidgetWithdraw: FC<
if (isLoadingVaultData) {
return (
-
-
+
)
}
@@ -493,9 +497,7 @@ export const WidgetWithdraw: FC<
className={cl('flex flex-col relative border border-border h-full', { 'rounded-lg': !disableBorderRadius })}
data-tour="vault-detail-withdraw-widget"
>
-
-
Withdraw
-
+
{/* Withdraw From Selector */}
diff --git a/src/components/pages/vaults/constants/menu.ts b/src/components/pages/vaults/constants/menu.ts
deleted file mode 100644
index 126fd5d02..000000000
--- a/src/components/pages/vaults/constants/menu.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export const VAULTS_V3_MENU = [
- { path: '/v3', label: 'v3 Vaults' },
- { path: 'https://docs.yearn.fi/getting-started/products/yvaults/v3', label: 'Docs' },
- { path: 'https://discord.gg/yearn', label: 'Support', target: '_blank' },
- { path: 'https://blog.yearn.fi/', label: 'Blog', target: '_blank' },
- {
- path: 'https://gov.yearn.fi/',
- label: 'Discourse',
- target: '_blank'
- }
-]
diff --git a/src/components/pages/vaults/domain/reports/findLatestAPY.ts b/src/components/pages/vaults/domain/reports/findLatestAPY.ts
deleted file mode 100644
index d7d3a1b3b..000000000
--- a/src/components/pages/vaults/domain/reports/findLatestAPY.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { isZero } from '@shared/utils'
-
-import type { TYDaemonReport, TYDaemonReports } from './reports.schema'
-
-export function findLatestAPY(reports?: TYDaemonReports): number {
- if (!reports?.length) {
- return 0
- }
-
- const latestReport = reports.reduce((prev, curr): TYDaemonReport => {
- return prev.timestamp > curr.timestamp ? prev : curr
- })
-
- if (!latestReport.results || isZero(latestReport.results.length)) {
- return 0
- }
-
- return latestReport.results[0].APR
-}
diff --git a/src/components/pages/vaults/domain/reports/findLatestReportApr.ts b/src/components/pages/vaults/domain/reports/findLatestReportApr.ts
deleted file mode 100644
index 7fb307a5e..000000000
--- a/src/components/pages/vaults/domain/reports/findLatestReportApr.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { toAddress } from '@shared/utils'
-
-import type { TKongReport } from './kongReports.schema'
-
-export function findLatestReportApr(
- reports: TKongReport[] | undefined,
- strategyAddress: string,
- options?: { maxAgeSeconds?: number }
-): number | null {
- if (!reports?.length || !strategyAddress) {
- return null
- }
-
- const normalizedStrategy = toAddress(strategyAddress)
- const nowSeconds = Math.floor(Date.now() / 1000)
- const maxAgeSeconds = options?.maxAgeSeconds
- const filtered = reports.filter((report) => {
- if (toAddress(report.strategy) !== normalizedStrategy) {
- return false
- }
- if (!maxAgeSeconds) {
- return true
- }
- const reportTime = report.blockTime ?? 0
- const reportSeconds = reportTime > 1_000_000_000_000 ? Math.floor(reportTime / 1000) : reportTime
- return reportSeconds > 0 && nowSeconds - reportSeconds <= maxAgeSeconds
- })
- if (!filtered.length) {
- return null
- }
-
- const latest = filtered.reduce((prev, curr) => {
- const prevTime = prev.blockTime ?? 0
- const currTime = curr.blockTime ?? 0
- if (currTime > prevTime) {
- return curr
- }
- if (currTime < prevTime) {
- return prev
- }
-
- const prevBlock = prev.blockNumber ?? 0
- const currBlock = curr.blockNumber ?? 0
- if (currBlock > prevBlock) {
- return curr
- }
- if (currBlock < prevBlock) {
- return prev
- }
-
- const prevLog = prev.logIndex ?? 0
- const currLog = curr.logIndex ?? 0
- return currLog > prevLog ? curr : prev
- })
-
- return latest.apr?.net ?? null
-}
diff --git a/src/components/pages/vaults/domain/reports/kongReports.schema.ts b/src/components/pages/vaults/domain/reports/kongReports.schema.ts
deleted file mode 100644
index 6602cccc7..000000000
--- a/src/components/pages/vaults/domain/reports/kongReports.schema.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { addressSchema } from '@shared/types'
-import * as z from 'zod'
-
-const nullableStringSchema = z.string().nullable().optional()
-const nullableNumberSchema = z.union([z.number(), z.string(), z.null()]).transform((value) => {
- if (value === null || value === undefined) {
- return null
- }
- const asNumber = Number(value)
- return Number.isFinite(asNumber) ? asNumber : null
-})
-
-const kongReportSchema = z
- .object({
- chainId: z.number(),
- address: addressSchema,
- eventName: z.string().optional(),
- strategy: addressSchema,
- gain: nullableStringSchema,
- loss: nullableStringSchema,
- debtPaid: nullableStringSchema,
- totalGain: nullableStringSchema,
- totalLoss: nullableStringSchema,
- totalDebt: nullableStringSchema,
- debtAdded: nullableStringSchema,
- debtRatio: nullableStringSchema,
- currentDebt: nullableStringSchema,
- protocolFees: nullableStringSchema,
- totalFees: nullableStringSchema,
- totalRefunds: nullableStringSchema,
- gainUsd: nullableStringSchema,
- lossUsd: nullableStringSchema,
- debtPaidUsd: nullableStringSchema,
- totalGainUsd: nullableStringSchema,
- totalLossUsd: nullableStringSchema,
- totalDebtUsd: nullableStringSchema,
- debtAddedUsd: nullableStringSchema,
- currentDebtUsd: nullableStringSchema,
- protocolFeesUsd: nullableStringSchema,
- totalFeesUsd: nullableStringSchema,
- totalRefundsUsd: nullableStringSchema,
- apr: z
- .object({
- net: nullableNumberSchema,
- gross: nullableNumberSchema
- })
- .optional(),
- blockNumber: nullableNumberSchema,
- blockTime: nullableNumberSchema,
- logIndex: nullableNumberSchema,
- transactionHash: z.string().optional()
- })
- .passthrough()
-
-export const kongReportsSchema = z.array(kongReportSchema)
-
-export type TKongReport = z.infer
-export type TKongReports = z.infer
diff --git a/src/components/pages/vaults/domain/reports/reports.schema.ts b/src/components/pages/vaults/domain/reports/reports.schema.ts
deleted file mode 100644
index 2982ed0ea..000000000
--- a/src/components/pages/vaults/domain/reports/reports.schema.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as z from 'zod'
-
-const resultSchema = z.object({
- duration: z.coerce.number().optional(),
- durationPR: z.coerce.number().optional(),
- APR: z.coerce.number()
-})
-
-const yDaemonReportSchema = z.object({
- id: z.string().optional(),
- debtAdded: z.string().optional(),
- debtLimit: z.string().optional(),
- totalDebt: z.string().optional(),
- gain: z.string().optional(),
- totalGain: z.string().optional(),
- loss: z.string().optional(),
- totalLoss: z.string().optional(),
- debtPaid: z.string().optional(),
- timestamp: z.coerce.number(),
- results: z.array(resultSchema).nullable()
-})
-
-export const yDaemonReportsSchema = z.array(yDaemonReportSchema)
-
-export type TYDaemonReport = z.infer
-
-export type TYDaemonReports = z.infer
diff --git a/src/components/pages/vaults/hooks/actions/useDeposit.ts b/src/components/pages/vaults/hooks/actions/useDeposit.ts
deleted file mode 100644
index ab05ea2a8..000000000
--- a/src/components/pages/vaults/hooks/actions/useDeposit.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-import type { UseDepositReturn } from '@pages/vaults/types'
-import { erc4626Abi } from '@shared/contracts/abi/4626.abi'
-import { vaultAbi as _vaultAbi } from '@shared/contracts/abi/vaultV2.abi'
-import { type Abi, type Address, erc20Abi } from 'viem'
-import { type UseSimulateContractReturnType, useReadContracts, useSimulateContract } from 'wagmi'
-import { useTokenAllowance } from '../useTokenAllowance'
-
-interface Props {
- vaultType: 'v2' | 'v3'
- vaultAddress: Address
- assetAddress: Address
- amount: bigint
- account?: Address
- chainId?: number
-}
-
-// ** Deposit Action for V2 & V3 ** //
-
-export const useDeposit = ({
- vaultType,
- vaultAddress,
- assetAddress,
- amount,
- account,
- chainId
-}: Props): UseDepositReturn => {
- const { allowance: depositAllowance = 0n } = useTokenAllowance({
- account,
- token: assetAddress,
- spender: vaultAddress,
- watch: true,
- chainId
- })
-
- const { data: [expectedDepositAmount, balanceOf] = [0n, 0n] } = useReadContracts({
- contracts: [
- {
- abi: erc4626Abi,
- address: vaultAddress,
- functionName: 'previewDeposit',
- args: [amount],
- chainId
- },
- {
- abi: erc4626Abi,
- address: assetAddress,
- functionName: 'balanceOf',
- args: account ? [account] : undefined,
- chainId
- }
- ],
- query: { select: (data) => [data[0]?.result ?? 0n, data[1]?.result ?? 0n], enabled: !!account }
- })
-
- const isValidInput = amount > 0n
- const isDepositAllowanceSufficient = Boolean(depositAllowance >= amount)
- const prepareApproveEnabled = Boolean(!isDepositAllowanceSufficient && isValidInput)
- const prepareDepositEnabled = Boolean(isDepositAllowanceSufficient && isValidInput)
-
- const { abi, args, functionName } = (() => {
- if (vaultType === 'v2') {
- return {
- abi: _vaultAbi,
- functionName: 'deposit',
- args: [amount, account] as [bigint, Address]
- }
- }
- return {
- abi: erc4626Abi,
- functionName: 'deposit',
- args: [amount, account]
- }
- })()
-
- const prepareApprove: UseSimulateContractReturnType = useSimulateContract({
- abi: erc20Abi,
- functionName: 'approve',
- address: assetAddress,
- args: amount > 0n && vaultAddress ? [vaultAddress, amount] : undefined,
- chainId,
- query: { enabled: prepareApproveEnabled }
- })
-
- const prepareDeposit: UseSimulateContractReturnType = useSimulateContract({
- abi: abi as Abi,
- functionName,
- address: vaultAddress,
- args,
- account,
- chainId,
- query: { enabled: prepareDepositEnabled }
- })
-
- return {
- actions: {
- prepareApprove,
- prepareDeposit
- },
- periphery: {
- prepareApproveEnabled,
- prepareDepositEnabled,
- expectedDepositAmount,
- balanceOf
- }
- }
-}
diff --git a/src/components/pages/vaults/hooks/actions/useStake.ts b/src/components/pages/vaults/hooks/actions/useStake.ts
deleted file mode 100644
index 1cd3a7601..000000000
--- a/src/components/pages/vaults/hooks/actions/useStake.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { useTokenBalance } from '@pages/vaults/hooks/useTokenBalance'
-import type { UseStakeReturn } from '@pages/vaults/types'
-import { gaugeV2Abi } from '@shared/contracts/abi/gaugeV2.abi'
-import { toNormalizedBN, zeroNormalizedBN } from '@shared/utils'
-import { type Address, erc20Abi } from 'viem'
-import { type UseSimulateContractReturnType, useReadContract, useSimulateContract } from 'wagmi'
-import { useTokenAllowance } from '../useTokenAllowance'
-
-interface Props {
- vaultAddress: Address
- gaugeAddress: Address
- amount: bigint
- account?: Address
- chainId?: number
-}
-
-// ** Stake Action for V2 & V3 ** //
-
-export const useStake = ({ vaultAddress, gaugeAddress, amount, account, chainId }: Props): UseStakeReturn => {
- const { allowance: depositAllowance = 0n } = useTokenAllowance({
- account,
- token: vaultAddress,
- spender: gaugeAddress,
- watch: true,
- chainId
- })
-
- const { balance } = useTokenBalance({
- token: vaultAddress,
- watch: true,
- chainId
- })
-
- const isValidInput = amount > 0n
- const isStakeAllowanceSufficient = Boolean(depositAllowance >= amount)
- const prepareApproveEnabled = Boolean(!isStakeAllowanceSufficient && isValidInput)
- const prepareStakeEnabled = Boolean(isStakeAllowanceSufficient && isValidInput)
-
- const { data: expectedStakeAmount = zeroNormalizedBN } = useReadContract({
- abi: gaugeV2Abi,
- functionName: 'previewDeposit',
- address: gaugeAddress,
- args: [amount],
- chainId,
- query: { enabled: amount > 0n, select: (data) => toNormalizedBN(data, balance.decimals) }
- })
-
- const prepareApprove: UseSimulateContractReturnType = useSimulateContract({
- abi: erc20Abi,
- functionName: 'approve',
- address: vaultAddress,
- args: amount > 0n && vaultAddress ? [gaugeAddress, amount] : undefined,
- chainId,
- query: { enabled: prepareApproveEnabled }
- })
-
- const prepareStake: UseSimulateContractReturnType = useSimulateContract({
- abi: gaugeV2Abi,
- functionName: 'deposit',
- address: gaugeAddress,
- args: [amount],
- account,
- chainId,
- query: { enabled: prepareStakeEnabled }
- })
-
- return {
- actions: {
- prepareApprove,
- prepareStake
- },
- periphery: {
- prepareApproveEnabled,
- prepareStakeEnabled,
- balance,
- expectedStakeAmount
- }
- }
-}
diff --git a/src/components/pages/vaults/hooks/actions/useUnstake.ts b/src/components/pages/vaults/hooks/actions/useUnstake.ts
deleted file mode 100644
index a2ad107e0..000000000
--- a/src/components/pages/vaults/hooks/actions/useUnstake.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { useTokenBalance } from '@pages/vaults/hooks/useTokenBalance'
-import type { UseUnstakeReturn } from '@pages/vaults/types'
-import { gaugeV2Abi } from '@shared/contracts/abi/gaugeV2.abi'
-import { toNormalizedBN, zeroNormalizedBN } from '@shared/utils'
-import type { Address } from 'viem'
-import { type UseSimulateContractReturnType, useSimulateContract } from 'wagmi'
-
-interface Props {
- gaugeAddress: Address
- amount: bigint
- // Note 10-01-25: Current yearn logic uses vault decimal logic rather
- // than gauge decimal logic. So this keeps it in line with
- // that logic. Though it isn't necessarily the correct logic..
- decimals: number
- account?: Address
- chainId?: number
-}
-
-// ** Unstake Action for V2 & V3 ** //
-
-export const useUnstake = ({ gaugeAddress, amount, account, decimals, chainId }: Props): UseUnstakeReturn => {
- const { balance: _balance } = useTokenBalance({
- token: gaugeAddress,
- watch: true,
- chainId
- })
-
- // Note 10-01-25: Adjustment here related to above note.
- const balance = _balance.raw > 0n ? toNormalizedBN(_balance.raw, decimals) : zeroNormalizedBN
-
- const isValidInput = balance.raw > 0n
- const prepareUnstakeEnabled = Boolean(isValidInput)
-
- const prepareUnstake: UseSimulateContractReturnType = useSimulateContract({
- abi: gaugeV2Abi,
- functionName: 'withdraw',
- args: account ? [amount, account, account, false] : undefined,
- address: gaugeAddress,
- account,
- chainId,
- query: { enabled: prepareUnstakeEnabled }
- })
-
- return {
- actions: {
- prepareUnstake
- },
- periphery: {
- prepareUnstakeEnabled,
- balance
- }
- }
-}
diff --git a/src/components/pages/vaults/hooks/actions/useWithdraw.ts b/src/components/pages/vaults/hooks/actions/useWithdraw.ts
deleted file mode 100644
index 5d132a182..000000000
--- a/src/components/pages/vaults/hooks/actions/useWithdraw.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import type { UseWithdrawReturn } from '@pages/vaults/types'
-import { erc4626Abi } from '@shared/contracts/abi/4626.abi'
-import { vaultAbi as _vaultAbi } from '@shared/contracts/abi/vaultV2.abi'
-import { type Abi, type Address, zeroAddress } from 'viem'
-import { type UseSimulateContractReturnType, useReadContracts, useSimulateContract } from 'wagmi'
-
-interface Props {
- vaultType: 'v2' | 'v3'
- vaultAddress: Address
- amount: bigint
- account?: Address
- chainId?: number
-}
-
-// ** Withdraw Action for V2 & V3 ** //
-
-export const useWithdraw = ({ vaultType, vaultAddress, amount, account, chainId }: Props): UseWithdrawReturn => {
- const { data: [expectedWithdrawAmount, maxRedeem] = [0n, 0n, 0n] } = useReadContracts({
- contracts: [
- {
- abi: erc4626Abi,
- address: vaultAddress,
- functionName: 'previewWithdraw',
- args: [amount],
- chainId
- },
- {
- abi: erc4626Abi,
- address: vaultAddress,
- functionName: 'maxWithdraw',
- args: account ? [account] : undefined,
- chainId
- }
- ],
- query: {
- select: (data) => [data[0]?.result ?? 0n, data[1]?.result ?? 0n],
- enabled: !!account
- }
- })
-
- const { abi, args, functionName } = (() => {
- if (vaultType === 'v2') {
- return {
- abi: _vaultAbi,
- functionName: 'withdraw',
- args: [amount, account, account] as [bigint, Address, Address]
- }
- }
- return {
- abi: erc4626Abi,
- functionName: 'withdraw',
- args: [amount, account, account] as [bigint, Address, Address]
- }
- })()
-
- const prepareWithdrawEnabled = Boolean(amount > 0n && vaultAddress !== zeroAddress)
-
- const prepareWithdraw: UseSimulateContractReturnType = useSimulateContract({
- abi: abi as Abi,
- functionName,
- address: vaultAddress,
- args,
- chainId,
- query: {
- enabled: prepareWithdrawEnabled
- }
- })
-
- return {
- actions: {
- prepareWithdraw
- },
- periphery: {
- prepareWithdrawEnabled,
- expectedWithdrawAmount,
- maxRedeem
- }
- }
-}
diff --git a/src/components/pages/vaults/hooks/actions/useZapIn.ts b/src/components/pages/vaults/hooks/actions/useZapIn.ts
deleted file mode 100644
index e0893f0c3..000000000
--- a/src/components/pages/vaults/hooks/actions/useZapIn.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { erc4626Abi } from '@shared/contracts/abi/4626.abi'
-import { V3_REWARDS_ZAP_ABI } from '@shared/contracts/abi/V3RewardsZap.abi'
-import { V3_STAKING_ZAP_ADDRESS } from '@shared/utils'
-import type { Address } from 'viem'
-import { type UseSimulateContractReturnType, useChainId, useReadContracts, useSimulateContract } from 'wagmi'
-
-interface Props {
- vaultType: 'v2' | 'v3'
- vaultAddress: Address
- assetAddress: Address
- amount: bigint
- account?: Address
-}
-
-// ** ZapIn Action for V2 & V3 ** //
-
-// PARTIAL - INCOMPLETE
-
-export const useZapIn = ({ vaultAddress, assetAddress, amount, account }: Props): any => {
- const chainID = useChainId()
-
- const { data: [expectedDepositAmount, balanceOf] = [0n, 0n] } = useReadContracts({
- contracts: [
- {
- abi: erc4626Abi,
- address: vaultAddress,
- functionName: 'previewDeposit',
- args: [amount]
- },
- {
- abi: erc4626Abi,
- address: assetAddress,
- functionName: 'balanceOf',
- args: account ? [account] : undefined
- }
- ],
- query: { select: (data) => [data[0]?.result ?? 0n, data[1]?.result ?? 0n], enabled: !!account }
- })
-
- const isValidInput = amount > 0n
- const prepareDepositEnabled = Boolean(isValidInput)
-
- // Needs more
- const prepareDeposit: UseSimulateContractReturnType = useSimulateContract({
- abi: V3_REWARDS_ZAP_ABI,
- functionName: 'zapIn',
- address: chainID in V3_STAKING_ZAP_ADDRESS ? V3_STAKING_ZAP_ADDRESS[chainID] : undefined,
- args: [vaultAddress, amount, false],
- account,
- query: { enabled: prepareDepositEnabled }
- })
-
- return {
- actions: {
- prepareDeposit
- },
- periphery: {
- prepareDepositEnabled,
- expectedDepositAmount,
- balanceOf
- }
- }
-}
diff --git a/src/components/pages/vaults/hooks/solvers/useSolverCowswap.ts b/src/components/pages/vaults/hooks/solvers/useSolverCowswap.ts
deleted file mode 100644
index 84d0b2c3b..000000000
--- a/src/components/pages/vaults/hooks/solvers/useSolverCowswap.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-import type { OrderCreation, OrderQuoteResponse, SigningScheme } from '@cowprotocol/cow-sdk'
-import { OrderBookApi, OrderQuoteSideKindSell } from '@cowprotocol/cow-sdk'
-import type { TNormalizedBN } from '@shared/types'
-import { isZeroAddress, toBigInt, toNormalizedBN } from '@shared/utils'
-import { SOLVER_COW_VAULT_RELAYER_ADDRESS } from '@shared/utils/constants'
-import { useCallback, useState } from 'react'
-import type { Address } from 'viem'
-import { erc20Abi } from 'viem'
-import { type UseSimulateContractReturnType, useSimulateContract } from 'wagmi'
-import { useTokenAllowance } from '../useTokenAllowance'
-
-const orderBookApi = new OrderBookApi({ chainId: 1 })
-
-interface UseSolverCowswapProps {
- sellToken: Address
- buyToken: Address
- amount: bigint
- account?: Address
- chainId?: number
- enabled?: boolean
- decimals?: number
-}
-
-interface UseSolverCowswapReturn {
- actions: {
- prepareApprove: UseSimulateContractReturnType
- }
- periphery: {
- prepareApproveEnabled: boolean
- expectedOut: TNormalizedBN
- allowance: bigint
- quote: OrderQuoteResponse | undefined
- isLoadingQuote: boolean
- isLoadingAllowance: boolean
- }
- getQuote: () => Promise
- getCowswapOrderParams: () => Promise
-}
-
-export const useSolverCowswap = ({
- sellToken,
- buyToken,
- amount,
- account,
- chainId = 1,
- decimals = 18,
- enabled = true
-}: UseSolverCowswapProps): UseSolverCowswapReturn => {
- const [quote, setQuote] = useState()
- const [isLoadingQuote, setIsLoadingQuote] = useState(false)
-
- const { allowance = 0n, isLoading: isLoadingAllowance } = useTokenAllowance({
- account,
- token: sellToken,
- spender: SOLVER_COW_VAULT_RELAYER_ADDRESS,
- watch: true,
- chainId
- })
-
- const getQuote = useCallback(async () => {
- if (!enabled || chainId !== 1 || !account || amount <= 0n) return
-
- if (isZeroAddress(sellToken) || isZeroAddress(buyToken)) return
-
- setIsLoadingQuote(true)
- try {
- const YEARN_APP_DATA = '0x5d22bf49b708de1d2d9547a6cca9faccbdc2b162012e8573811c07103b163d4b'
- const quoteRequest = {
- from: account,
- sellToken: sellToken,
- buyToken: buyToken,
- receiver: account,
- appData: YEARN_APP_DATA,
- kind: OrderQuoteSideKindSell.SELL,
- partiallyFillable: false,
- validTo: Math.round(new Date().setMinutes(new Date().getMinutes() + 10) / 1000),
- sellAmountBeforeFee: toBigInt(amount).toString()
- }
-
- const result = await orderBookApi.getQuote(quoteRequest)
- setQuote(result)
- } catch (error) {
- console.error('Failed to get Cowswap quote:', error)
- setQuote(undefined)
- } finally {
- setIsLoadingQuote(false)
- }
- }, [sellToken, buyToken, amount, account, chainId, enabled])
-
- const getCowswapOrderParams = useCallback(async (): Promise => {
- if (!quote || !account) return undefined
-
- try {
- // This will be called when the user wants to execute the order
- // It returns the order parameters needed for Cowswap
- const buyAmount = toBigInt(quote.quote.buyAmount)
- const buyAmountWithSlippage = buyAmount - (buyAmount * BigInt(1)) / 100n
-
- const orderCreation: OrderCreation = {
- ...quote.quote,
- from: account,
- feeAmount: '0',
- buyAmount: buyAmountWithSlippage.toString(),
- sellAmount: (toBigInt(quote.quote.sellAmount) + toBigInt(quote.quote.feeAmount)).toString(),
- quoteId: quote.id,
- // Signature will be added by the custom hook
- signature: '',
- signingScheme: 'eip712' as SigningScheme
- }
-
- return orderCreation
- } catch (error) {
- console.error('Failed to prepare Cowswap order:', error)
- return undefined
- }
- }, [quote, account])
-
- const isValidInput = amount > 0n && chainId === 1
- const isAllowanceSufficient = allowance >= amount
- const prepareApproveEnabled = !isAllowanceSufficient && isValidInput && enabled
-
- const prepareApprove: UseSimulateContractReturnType = useSimulateContract({
- abi: erc20Abi,
- functionName: 'approve',
- address: sellToken,
- args: [SOLVER_COW_VAULT_RELAYER_ADDRESS, amount],
- chainId,
- query: { enabled: prepareApproveEnabled }
- })
-
- const expectedOut = quote?.quote
- ? toNormalizedBN(toBigInt(quote.quote.buyAmount), decimals)
- : toNormalizedBN(0n, decimals)
-
- return {
- actions: {
- prepareApprove
- },
- periphery: {
- prepareApproveEnabled,
- expectedOut,
- allowance,
- quote,
- isLoadingQuote,
- isLoadingAllowance
- },
- getQuote,
- getCowswapOrderParams
- }
-}
diff --git a/src/components/pages/vaults/hooks/solvers/useSolverGaugeStakingBooster.ts b/src/components/pages/vaults/hooks/solvers/useSolverGaugeStakingBooster.ts
deleted file mode 100644
index 37b258068..000000000
--- a/src/components/pages/vaults/hooks/solvers/useSolverGaugeStakingBooster.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { YGAUGE_ZAP_ABI } from '@shared/contracts/abi/yGaugeZap.abi'
-import { YGAUGES_ZAP_ADDRESS } from '@shared/utils/constants'
-import type { Address } from 'viem'
-import { erc20Abi } from 'viem'
-import { type UseSimulateContractReturnType, useSimulateContract } from 'wagmi'
-import { useTokenAllowance } from '../useTokenAllowance'
-
-interface UseGaugeStakingBoosterProps {
- vaultAddress: Address
- gaugeAddress: Address
- tokenAddress: Address
- amount: bigint
- account?: Address
- chainId?: number
- vaultVersion?: string
- enabled?: boolean
-}
-
-interface UseGaugeStakingBoosterReturn {
- actions: {
- prepareApprove: UseSimulateContractReturnType
- prepareZapIn: UseSimulateContractReturnType
- }
- periphery: {
- prepareApproveEnabled: boolean
- prepareZapInEnabled: boolean
- allowance: bigint
- isLoadingAllowance: boolean
- }
-}
-
-export const useSolverGaugeStakingBooster = ({
- vaultAddress,
- gaugeAddress,
- tokenAddress,
- amount,
- account,
- chainId,
- vaultVersion,
- enabled = true
-}: UseGaugeStakingBoosterProps): UseGaugeStakingBoosterReturn => {
- const { allowance = 0n, isLoading: isLoadingAllowance } = useTokenAllowance({
- account,
- token: tokenAddress,
- spender: YGAUGES_ZAP_ADDRESS,
- watch: true,
- chainId
- })
-
- const isValidInput = amount > 0n
- const isAllowanceSufficient = allowance >= amount
- const prepareApproveEnabled = !isAllowanceSufficient && isValidInput && enabled
- const prepareZapInEnabled = isAllowanceSufficient && isValidInput && enabled
-
- const prepareApprove: UseSimulateContractReturnType = useSimulateContract({
- abi: erc20Abi,
- functionName: 'approve',
- address: tokenAddress,
- args: [YGAUGES_ZAP_ADDRESS, amount],
- chainId,
- query: { enabled: prepareApproveEnabled }
- })
-
- // Determine function name based on vault version
- const functionName = vaultVersion?.startsWith('3') || vaultVersion?.startsWith('~3') ? 'zapIn' : 'zapInLegacy'
-
- const prepareZapIn: UseSimulateContractReturnType = useSimulateContract({
- abi: YGAUGE_ZAP_ABI,
- functionName,
- address: YGAUGES_ZAP_ADDRESS,
- args: [vaultAddress, amount, gaugeAddress],
- account,
- chainId,
- query: { enabled: prepareZapInEnabled }
- })
-
- return {
- actions: {
- prepareApprove,
- prepareZapIn
- },
- periphery: {
- prepareApproveEnabled,
- prepareZapInEnabled,
- allowance,
- isLoadingAllowance
- }
- }
-}
diff --git a/src/components/pages/vaults/hooks/useCowswapOrder.ts b/src/components/pages/vaults/hooks/useCowswapOrder.ts
deleted file mode 100644
index 5242a8b3e..000000000
--- a/src/components/pages/vaults/hooks/useCowswapOrder.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-import type { OrderCreation, UnsignedOrder } from '@cowprotocol/cow-sdk'
-import { OrderBookApi, OrderSigningUtils } from '@cowprotocol/cow-sdk'
-import { retrieveConfig } from '@shared/utils/wagmi'
-import { getEthersSigner } from '@shared/utils/wagmi/ethersAdapter'
-import { useCallback, useMemo, useState } from 'react'
-import type { UseSimulateContractReturnType } from 'wagmi'
-
-const orderBookApi = new OrderBookApi({ chainId: 1 })
-
-interface UseCowswapOrderProps {
- getCowswapOrderParams: () => Promise
- enabled?: boolean
-}
-
-interface UseCowswapOrderReturn {
- prepareCowswapOrder: UseSimulateContractReturnType
-}
-
-// This hook wraps Cowswap order execution to work like a regular contract interaction
-export const useCowswapOrder = ({
- getCowswapOrderParams,
- enabled = true
-}: UseCowswapOrderProps): UseCowswapOrderReturn => {
- const [isExecuting, setIsExecuting] = useState(false)
- const [error, setError] = useState(null)
-
- const executeOrder = useCallback(async () => {
- setIsExecuting(true)
- setError(null)
-
- try {
- const orderParams = await getCowswapOrderParams()
- if (!orderParams) throw new Error('No order parameters')
-
- // Sign the order
- const signer = await getEthersSigner(retrieveConfig(), { chainId: 1 })
- if (!signer) throw new Error('No signer available')
-
- const { signature, signingScheme } = await OrderSigningUtils.signOrder(orderParams as UnsignedOrder, 1, signer)
-
- // Submit the order
- const orderCreation: OrderCreation = {
- ...orderParams,
- signature,
- signingScheme: signingScheme as any
- }
-
- const orderUID = await orderBookApi.sendOrder(orderCreation)
-
- // Wait for order to be executed
- const maxIterations = 100
- for (let i = 0; i < maxIterations; i++) {
- const response = await fetch(`https://api.cow.fi/mainnet/api/v1/orders/${orderUID}`)
- const order = await response.json()
-
- if (order?.status === 'fulfilled') {
- setIsExecuting(false)
- return { success: true, orderUID }
- }
-
- if (order?.status === 'cancelled' || order?.status === 'expired') {
- throw new Error('Order was cancelled or expired')
- }
-
- await new Promise((resolve) => setTimeout(resolve, 3000))
- }
-
- throw new Error('Order timed out')
- } catch (err) {
- setError(err as Error)
- setIsExecuting(false)
- throw err
- }
- }, [getCowswapOrderParams])
-
- // Create a mock simulate contract result that TxButton can understand
- const prepareCowswapOrder: UseSimulateContractReturnType = useMemo(() => {
- return {
- data: enabled
- ? {
- request: {
- // Custom marker to identify this as a Cowswap order
- __isCowswapOrder: true,
- // Override writeContractAsync to execute our custom order
- writeContractAsync: executeOrder
- } as any
- }
- : undefined,
- error: error,
- isError: !!error,
- isLoading: isExecuting,
- isSuccess: !error && !isExecuting && enabled,
- isFetching: false,
- isPending: false,
- isRefetching: false,
- refetch: async () => ({ data: undefined, error: null }),
- status: isExecuting ? 'pending' : error ? 'error' : 'success',
- fetchStatus: 'idle',
- dataUpdatedAt: Date.now()
- } as UseSimulateContractReturnType
- }, [enabled, error, isExecuting, executeOrder])
-
- return {
- prepareCowswapOrder
- }
-}
diff --git a/src/components/pages/vaults/hooks/useVaultsPageModel.ts b/src/components/pages/vaults/hooks/useVaultsPageModel.ts
index 557635c71..c2affce4f 100644
--- a/src/components/pages/vaults/hooks/useVaultsPageModel.ts
+++ b/src/components/pages/vaults/hooks/useVaultsPageModel.ts
@@ -838,13 +838,6 @@ export function useVaultsPageModel(): TVaultsPageModel {
sortable: true,
className: hasWalletAddress ? 'col-span-4' : 'col-span-5'
},
- // {
- // type: 'toggle',
- // label: 'Available',
- // value: AVAILABLE_TOGGLE_VALUE,
- // className: 'col-span-3',
- // disabled: availableVaults.length === 0
- // },
...(hasWalletAddress
? ([
{
diff --git a/src/components/pages/vaults/utils/handleYBold.ts b/src/components/pages/vaults/utils/handleYBold.ts
deleted file mode 100644
index 13f4265f1..000000000
--- a/src/components/pages/vaults/utils/handleYBold.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-// Temp file, remove logic at a later date
-
-import { mergeYBoldVault, YBOLD_STAKING_ADDRESS, YBOLD_VAULT_ADDRESS } from '@pages/vaults/domain/normalizeVault'
-import { toAddress } from '@shared/utils'
-import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import { yDaemonVaultSchema } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import { isAddressEqual } from 'viem'
-
-const params = new URLSearchParams({
- strategiesDetails: 'withDetails',
- strategiesCondition: 'inQueue'
-})
-
-export const fetchYBoldVault = async (
- yDaemonBaseUri: string,
- vault?: TYDaemonVault
-): Promise => {
- if (!vault || !isAddressEqual(vault.address, YBOLD_VAULT_ADDRESS)) {
- return undefined
- }
-
- try {
- const res = await fetch(`${yDaemonBaseUri}/vaults/${toAddress(YBOLD_STAKING_ADDRESS)}?${params}`)
- const json = await res.json()
- const parsed: TYDaemonVault = yDaemonVaultSchema.parse(json)
- return mergeYBoldVault(vault, parsed)
- } catch (error) {
- console.error('Error handling yBold vault:', error)
- return undefined
- }
-}
diff --git a/src/components/pages/vaults/utils/index.ts b/src/components/pages/vaults/utils/index.ts
deleted file mode 100644
index c3d52df2b..000000000
--- a/src/components/pages/vaults/utils/index.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-export const getChainBgColor = (chainID: number): string => {
- switch (chainID) {
- case 1:
- return '#627EEA'
- case 10:
- return '#C80016'
- case 137:
- return 'linear-gradient(244deg, #7B3FE4 5.89%, #A726C1 94.11%)'
- case 250:
- return '#1969FF'
- case 8453:
- return '#1C55F5'
- case 42161:
- return '#2F3749'
- default:
- return '#627EEA'
- }
-}
diff --git a/src/components/pages/vaults/utils/useAvailableToDeposit.ts b/src/components/pages/vaults/utils/useAvailableToDeposit.ts
deleted file mode 100644
index af324b453..000000000
--- a/src/components/pages/vaults/utils/useAvailableToDeposit.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { getNativeTokenWrapperContract } from '@pages/vaults/utils/nativeTokens'
-import { useYearnBalance } from '@shared/hooks/useYearnBalance'
-import { toAddress } from '@shared/utils'
-import { ETH_TOKEN_ADDRESS } from '@shared/utils/constants'
-import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-
-/**
- * Returns the available amount to deposit for the given vault's asset.
- * For native wrappers (e.g., WETH, WFTM), combines native + wrapped balances.
- */
-export function useAvailableToDeposit(currentVault: TYDaemonVault): bigint {
- const balanceOfWant = useYearnBalance({
- chainID: currentVault.chainID,
- address: currentVault.token.address
- })
-
- const balanceOfCoin = useYearnBalance({
- chainID: currentVault.chainID,
- address: ETH_TOKEN_ADDRESS
- })
-
- const nativeWrapper = getNativeTokenWrapperContract(currentVault.chainID)
- const balanceOfWrappedCoin = useYearnBalance({
- chainID: currentVault.chainID,
- address: nativeWrapper
- })
-
- if (toAddress(currentVault.token.address) === toAddress(nativeWrapper)) {
- return balanceOfWrappedCoin.raw + balanceOfCoin.raw
- }
- return balanceOfWant.raw
-}
diff --git a/src/components/shared/components/CarouselSlideArrows.tsx b/src/components/shared/components/CarouselSlideArrows.tsx
deleted file mode 100644
index c120d7f72..000000000
--- a/src/components/shared/components/CarouselSlideArrows.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { cl } from '@shared/utils'
-import type { ReactElement } from 'react'
-import { IconChevron } from '../icons/IconChevron'
-
-type TCarouselSlideArrowsProps = {
- onScrollBack?: VoidFunction
- onScrollForward?: VoidFunction
- className?: string
-}
-
-export function CarouselSlideArrows({
- onScrollBack,
- onScrollForward,
- className
-}: TCarouselSlideArrowsProps): ReactElement {
- return (
-
- )
-}
diff --git a/src/components/shared/components/Counter.tsx b/src/components/shared/components/Counter.tsx
deleted file mode 100644
index f95999917..000000000
--- a/src/components/shared/components/Counter.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import { formatAmount, parseAmount } from '@shared/utils'
-import { animate } from 'framer-motion'
-import type { ReactElement } from 'react'
-import { useLayoutEffect, useRef } from 'react'
-
-export function Counter({
- value,
- decimals = 18,
- idealDecimals,
- decimalsToDisplay
-}: {
- value: number // Value to animate
- decimals: number // Number of decimals of that token
- idealDecimals?: number // Ideal decimals to display
- decimalsToDisplay?: number[] // Decimals to display
-}): ReactElement {
- const nodeRef = useRef(null)
- const valueRef = useRef(value || 0)
-
- useLayoutEffect((): (() => void) => {
- const node = nodeRef.current
- if (node) {
- const controls = animate(Number(valueRef.current || 0), value, {
- duration: 1,
- onUpdate(value) {
- let hasBeenSet = false
- valueRef.current = value
-
- if (value < 0.00001 && value > 0) {
- node.textContent = '<0.00001'
- return
- }
-
- if (Number.isNaN(value) || value === 0) {
- const formatedValue = formatAmount(0, idealDecimals, idealDecimals)
- node.textContent = formatedValue
- } else if (decimalsToDisplay && decimalsToDisplay.length > 0) {
- const allDecimalsToTests = [...decimalsToDisplay, decimals]
- if (idealDecimals) {
- allDecimalsToTests.unshift(idealDecimals)
- }
- for (const decimalToDisplay of allDecimalsToTests) {
- if (decimalToDisplay > decimals) {
- const formatedValue = formatAmount(value.toFixed(decimals), decimals, decimals)
- node.textContent = formatedValue
- hasBeenSet = true
- break
- }
- const formatedValue = formatAmount(value.toFixed(decimals), decimalToDisplay, decimalToDisplay)
- if (
- Number.isNaN(parseAmount(formatedValue)) ||
- formatedValue === 'NaN' ||
- parseAmount(formatedValue) === 0
- ) {
- continue
- }
- node.textContent = formatedValue
- hasBeenSet = true
- break
- }
- if (!hasBeenSet) {
- if (Number.isNaN(value) || value === 0) {
- const formatedValue = formatAmount(0, idealDecimals, idealDecimals)
- node.textContent = formatedValue
- } else {
- const formatedValue = formatAmount(value.toFixed(decimals), decimals, decimals)
- node.textContent = formatedValue
- }
- }
- } else {
- const formatedValue = formatAmount(
- value.toFixed(decimals),
- decimals || idealDecimals,
- decimals || idealDecimals
- )
- node.textContent = formatedValue
- }
- }
- })
- return () => controls.stop()
- }
- return () => undefined
- }, [value, decimals, decimalsToDisplay, idealDecimals])
-
- return
-}
diff --git a/src/components/shared/components/Cutaway.tsx b/src/components/shared/components/Cutaway.tsx
deleted file mode 100644
index 6e9094a40..000000000
--- a/src/components/shared/components/Cutaway.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import { IconShare } from '@shared/icons/IconShare'
-import type { ReactElement } from 'react'
-import Link from '/src/components/Link'
-
-type TCutawayProps = {
- title: string
- link: string
- icon: ReactElement
-}
-
-export function Cutaway(props: TCutawayProps): ReactElement {
- return (
-
-
-
-
-
-
- )
-}
diff --git a/src/components/shared/components/Dropdown.tsx b/src/components/shared/components/Dropdown.tsx
deleted file mode 100644
index 594511fe5..000000000
--- a/src/components/shared/components/Dropdown.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions, Transition } from '@headlessui/react'
-import { useThrottledState } from '@react-hookz/web'
-import { IconChevron } from '@shared/icons/IconChevron'
-import { cl } from '@shared/utils'
-import type { ReactElement } from 'react'
-import { useState } from 'react'
-import { ImageWithFallback } from './ImageWithFallback'
-
-const DropdownOption = (option: TDropdownOption): ReactElement => {
- const { label, description, icon } = option
- return (
-
- {({ active }): ReactElement => (
-
- {icon && (
-
-
-
- )}
-
-
{label}
- {description && (
-
{description}
- )}
-
-
- )}
-
- )
-}
-
-const DropdownEmpty = ({ isSearching }: { isSearching: boolean }): ReactElement => {
- if (!isSearching) {
- return (
-
- )
- }
-
- return (
-
- )
-}
-
-export type TDropdownOption = {
- id: string
- label: string
- description?: string
- icon?: string
-}
-
-export type TDropdownProps = {
- selected?: TDropdownOption
- options: TDropdownOption[]
- onChange?: (selected: TDropdownOption) => void
- label?: string
- legend?: string
- isDisabled?: boolean
- className?: string
-}
-
-export const Dropdown = ({
- selected,
- options,
- onChange,
- label,
- legend,
- isDisabled,
- className
-}: TDropdownProps): ReactElement => {
- const [isOpen, setIsOpen] = useThrottledState(false, 400)
- const [search, setSearch] = useState('')
-
- const isSearching = search !== ''
- const filteredOptions = isSearching
- ? options.filter(({ label }): boolean => label.toLowerCase().includes(search.toLowerCase()))
- : options
-
- return (
-
-
- {label &&
{label}
}
-
- {isOpen ? (
-
{
- e.stopPropagation()
- e.preventDefault()
- setIsOpen(false)
- }}
- />
- ) : null}
-
{
- if (!option) return
- if (onChange) {
- onChange(option)
- }
- setIsOpen(false)
- }}
- disabled={isDisabled}
- >
- setIsOpen((state: boolean): boolean => !state)}
- className={cl(
- 'flex min-h-[44px] w-full items-center justify-between p-2 text-base md:px-3',
- isDisabled ? 'bg-neutral-300 text-neutral-600' : 'bg-neutral-0 text-neutral-900'
- )}
- >
-
- {selected?.icon && (
-
-
-
- )}
-
- option?.label ?? '-'}
- spellCheck={false}
- onChange={(event): void => {
- setIsOpen(true)
- setSearch(event.target.value)
- }}
- />
-
-
-
-
-
-
- {
- setIsOpen(false)
- setSearch('')
- }}
- >
-
- {filteredOptions.length === 0 ? (
-
- ) : (
- filteredOptions.map(
- ({ id, label, description, icon }): ReactElement => (
-
- )
- )
- )}
-
-
-
-
- {legend &&
{legend}
}
-
-
- )
-}
diff --git a/src/components/shared/components/EmptyState.tsx b/src/components/shared/components/EmptyState.tsx
new file mode 100644
index 000000000..b232685b0
--- /dev/null
+++ b/src/components/shared/components/EmptyState.tsx
@@ -0,0 +1,55 @@
+import { cl } from '@shared/utils'
+import type { ReactElement, ReactNode } from 'react'
+
+type TEmptyStateSize = 'sm' | 'md' | 'lg'
+
+type TEmptyStateProps = {
+ title: string
+ description?: string
+ icon?: ReactNode
+ action?: ReactNode
+ size?: TEmptyStateSize
+ className?: string
+ unstyled?: boolean
+}
+
+const SIZE_CLASSES: Record
= {
+ sm: {
+ container: 'gap-2 px-4 py-8',
+ title: 'text-sm font-medium',
+ description: 'text-xs text-text-secondary'
+ },
+ md: {
+ container: 'gap-4 px-4 py-12 sm:px-6 sm:py-16',
+ title: 'text-base font-semibold sm:text-lg',
+ description: 'text-sm text-text-secondary'
+ },
+ lg: {
+ container: 'gap-2 px-10 py-2',
+ title: 'text-lg font-normal',
+ description: 'text-neutral-600'
+ }
+}
+
+export function EmptyState({
+ title,
+ description,
+ icon,
+ action,
+ size = 'md',
+ className,
+ unstyled = false
+}: TEmptyStateProps): ReactElement {
+ const sizeClasses = SIZE_CLASSES[size]
+
+ return (
+
+
+ {icon &&
{icon}
}
+
{title}
+ {description &&
{description}
}
+ {action}
+
+
+ )
+}
diff --git a/src/components/shared/components/InfoTooltip.tsx b/src/components/shared/components/InfoTooltip.tsx
deleted file mode 100644
index a62ed14ec..000000000
--- a/src/components/shared/components/InfoTooltip.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { IconQuestion } from '@shared/icons/IconQuestion'
-import { cl } from '@shared/utils'
-
-import type { ReactElement } from 'react'
-
-type TProps = {
- text: string | number
- size: 'sm' | 'md'
- className?: string
- iconClassName?: string
-}
-
-const getStyle = (
- size: TProps['size']
-): {
- iconStyle: string
- tooltipStyle: string
-} => {
- if (size === 'sm') {
- return {
- iconStyle: 'md:h-3 md:w-3 md:top-0',
- tooltipStyle: 'p-1 px-2 text-xs'
- }
- }
-
- return {
- iconStyle: 'md:h-4 md:w-4 md:top-1',
- tooltipStyle: 'p-2 px-4 text-sm'
- }
-}
-
-export const InfoTooltip = ({ text, size, iconClassName, className }: TProps): ReactElement => {
- const { iconStyle, tooltipStyle } = getStyle(size)
-
- return (
-
-
-
-
- {text}
-
-
-
- )
-}
diff --git a/src/components/shared/components/Input.tsx b/src/components/shared/components/Input.tsx
deleted file mode 100644
index c823232fd..000000000
--- a/src/components/shared/components/Input.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import { cl } from '@shared/utils'
-
-import type { ReactElement, ReactNode } from 'react'
-
-type TAmountInputProps = {
- value: string
- onChange?: (value: string) => void
- label?: string
- placeholder?: string
- legend?: string | ReactNode
- error?: string
- isDisabled?: boolean
- isLoading?: boolean
- className?: string
-}
-
-export function Input(props: TAmountInputProps): ReactElement {
- const { value, onChange, label, placeholder, legend, error, isDisabled, isLoading, className = '' } = props
- return (
-
- {label &&
{label}
}
-
- onChange(e.target.value) : undefined}
- placeholder={isLoading ? undefined : placeholder}
- disabled={isDisabled}
- />
-
- {(error ?? legend) && (
-
- {error ?? legend}
-
- )}
-
- )
-}
-
-export function FakeInput(
- props: Omit & {
- value: ReactNode
- }
-): ReactElement {
- const { value, label, legend, className = '' } = props
- return (
-
- {label &&
{label}
}
-
-
- {value || '0.00'}
-
-
- {legend && (
-
- {legend}
-
- )}
-
- )
-}
diff --git a/src/components/shared/components/LauncherDropdown.tsx b/src/components/shared/components/LauncherDropdown.tsx
deleted file mode 100644
index 68f7ea3c5..000000000
--- a/src/components/shared/components/LauncherDropdown.tsx
+++ /dev/null
@@ -1,213 +0,0 @@
-import { useThemePreference } from '@hooks/useThemePreference'
-import { IconChevron } from '@shared/icons/IconChevron'
-import { IconDiscord } from '@shared/icons/IconDiscord'
-import { IconTwitter } from '@shared/icons/IconTwitter'
-import { LogoGithub } from '@shared/icons/LogoGithub'
-import { cl } from '@shared/utils'
-import type { ReactElement } from 'react'
-import { useEffect, useRef, useState } from 'react'
-import { useLocation } from 'react-router'
-import Link from '/src/components/Link'
-import { DropdownPanel } from './DropdownPanel'
-import { APP_GROUPS, type TAppTile } from './YearnApps'
-
-function isExternalHref(href: string): boolean {
- return /^https?:\/\//i.test(href)
-}
-
-function findGroupItems(title: string): TAppTile[] {
- return APP_GROUPS.find((g) => g.title === title)?.items ?? []
-}
-
-const APPS = findGroupItems('Apps')
-const TOOLS = findGroupItems('Analytics and Tools')
-const RESOURCES = findGroupItems('Resources')
-const DEPRECATED = findGroupItems('Deprecated Projects')
-
-function AppTile({ item, isDark }: { item: TAppTile; isDark: boolean }): ReactElement {
- return (
-
-
-
- {item.icon}
-
-
-
- {item.name}
- {isExternalHref(item.href) && (
- {'↗'}
- )}
-
- {item.description && (
-
{item.description}
- )}
-
-
-
- )
-}
-
-function LinkItem({ item, isDark }: { item: TAppTile; isDark: boolean }): ReactElement {
- return (
-
-
- {item.name}
- {isExternalHref(item.href) && {'↗'} }
-
-
- )
-}
-
-type TLauncherDropdownProps = {
- isOpen: boolean
- onClose: () => void
- forceDark?: boolean
-}
-
-export function LauncherDropdown({ isOpen, onClose, forceDark }: TLauncherDropdownProps): ReactElement {
- const location = useLocation()
- const previousPathname = useRef(location.pathname)
- const [isDeprecatedExpanded, setIsDeprecatedExpanded] = useState(false)
- const themePreference = useThemePreference()
- const isDarkTheme = forceDark ?? themePreference !== 'light'
-
- useEffect(() => {
- const pathnameChanged = previousPathname.current !== location.pathname
- previousPathname.current = location.pathname
-
- if (pathnameChanged && isOpen) {
- onClose()
- }
- }, [isOpen, location.pathname, onClose])
-
- useEffect(() => {
- if (!isOpen) {
- setIsDeprecatedExpanded(false)
- }
- }, [isOpen])
-
- const sectionHeaderClass = cl(
- 'mb-2 px-2 text-xs font-semibold uppercase tracking-wider',
- isDarkTheme ? 'text-neutral-400' : 'text-neutral-500'
- )
-
- const dividerClass = cl('h-px', isDarkTheme ? 'bg-white/10' : 'bg-neutral-200')
-
- const socialIconClass = cl(
- 'flex size-8 items-center justify-center rounded-lg transition-colors',
- isDarkTheme
- ? 'text-neutral-400 hover:bg-white/10 hover:text-white'
- : 'text-neutral-500 hover:bg-neutral-100 hover:text-neutral-700'
- )
-
- return (
-
-
-
-
{'Apps'}
-
- {APPS.map((item) => (
-
- ))}
-
-
-
-
-
-
-
-
{'Tools'}
-
- {TOOLS.map((item) => (
-
-
-
- ))}
-
-
-
-
{'Resources'}
-
- {RESOURCES.map((item) => (
-
-
-
- ))}
-
-
-
-
-
-
-
-
-
setIsDeprecatedExpanded(!isDeprecatedExpanded)}
- className={cl(
- 'flex items-center gap-2 rounded-lg px-2 py-1.5 text-xs font-semibold uppercase tracking-wider transition-colors',
- isDarkTheme
- ? 'text-neutral-400 hover:bg-white/10 hover:text-white'
- : 'text-neutral-500 hover:bg-neutral-100 hover:text-neutral-700'
- )}
- >
- {'Deprecated'}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {isDeprecatedExpanded && (
-
- {DEPRECATED.map((item) => (
-
-
-
- ))}
-
- )}
-
-
-
- )
-}
diff --git a/src/components/shared/components/ListHead.tsx b/src/components/shared/components/ListHead.tsx
deleted file mode 100644
index 87ca9726e..000000000
--- a/src/components/shared/components/ListHead.tsx
+++ /dev/null
@@ -1,165 +0,0 @@
-import { IconChevron } from '@shared/icons/IconChevron'
-import { IconMinus } from '@shared/icons/IconMinus'
-import { IconPlus } from '@shared/icons/IconPlus'
-import type { TSortDirection } from '@shared/types'
-import { cl } from '@shared/utils'
-
-import type { ReactElement } from 'react'
-import { useCallback, useMemo } from 'react'
-
-type TSortableListHeadItem = {
- type?: 'sort'
- label: string | ReactElement
- value: string
- sortable?: boolean
- disabled?: boolean
- className?: string
-}
-
-type TToggleListHeadItem = {
- type: 'toggle'
- label: string | ReactElement
- value: string
- disabled?: boolean
- className?: string
-}
-
-type TListHeadItem = TSortableListHeadItem | TToggleListHeadItem
-
-export type TListHead = {
- items: TListHeadItem[]
- dataClassName?: string
- wrapperClassName?: string
- tokenClassName?: string
- sortBy: string
- sortDirection: TSortDirection
- onSort: (sortBy: string, sortDirection: TSortDirection) => void
- onToggle?: (value: string) => void
- activeToggleValues?: Iterable
-}
-
-export function ListHead({
- items,
- dataClassName,
- wrapperClassName,
- tokenClassName,
- sortBy,
- sortDirection,
- onSort,
- onToggle,
- activeToggleValues
-}: TListHead): ReactElement {
- const toggleSortDirection = (newSortBy: string): TSortDirection => {
- return sortBy === newSortBy ? (sortDirection === '' ? 'desc' : sortDirection === 'desc' ? 'asc' : 'desc') : 'desc'
- }
-
- const activeToggles = useMemo(() => new Set(activeToggleValues || []), [activeToggleValues])
-
- const isToggleItem = (item: TListHeadItem): item is TToggleListHeadItem => item.type === 'toggle'
-
- const renderChevron = useCallback(
- (shouldSortBy: boolean): ReactElement => {
- if (shouldSortBy && sortDirection === 'desc') {
- return
- }
- if (shouldSortBy && sortDirection === 'asc') {
- return
- }
- return
- },
- [sortDirection]
- )
-
- const renderSortItem = (
- item: TSortableListHeadItem,
- shouldHighlight: boolean,
- shouldIndent: boolean
- ): ReactElement => {
- const isSortable = item.sortable !== false
- return (
- onSort(item.value, toggleSortDirection(item.value))}
- disabled={!isSortable || item.disabled}
- className={cl('yearn--table-head-label-wrapper group', item.className)}
- datatype={'number'}
- >
-
- {shouldIndent ? <> {item.label}> : item.label}
-
- {isSortable ? renderChevron(shouldHighlight) : null}
-
- )
- }
-
- const renderToggleItem = (item: TToggleListHeadItem, shouldIndent: boolean): ReactElement => {
- const isActive = activeToggles.has(item.value)
- const isDisabled = item.disabled || !onToggle
-
- return (
- {
- if (isDisabled || !onToggle) return
- onToggle(item.value)
- }}
- disabled={isDisabled}
- aria-pressed={isActive}
- className={cl(
- 'yearn--table-head-label-wrapper group gap-1 justify-end text-right',
- isActive ? 'text-neutral-800' : 'text-neutral-800/60 hover:text-neutral-800',
- item.className
- )}
- >
-
- {shouldIndent ? <> {item.label}> : item.label}
-
-
- {isActive ? (
-
- ) : (
-
- )}
-
-
- )
- }
-
- const renderItem = (item: TListHeadItem, shouldHighlight: boolean, shouldIndent: boolean): ReactElement => {
- if (isToggleItem(item)) {
- return renderToggleItem(item, shouldIndent)
- }
- return renderSortItem(item, shouldHighlight, shouldIndent)
- }
-
- const [chain, token, ...rest] = items
- return (
-
-
-
-
{chain.label}
- {renderItem(token, !isToggleItem(token) && sortBy === token.value, false)}
-
-
-
-
- {rest.map((item): ReactElement => renderItem(item, !isToggleItem(item) && sortBy === item.value, true))}
-
-
-
- )
-}
diff --git a/src/components/shared/components/ModalMobileMenu.tsx b/src/components/shared/components/ModalMobileMenu.tsx
deleted file mode 100644
index bdfd4a6b2..000000000
--- a/src/components/shared/components/ModalMobileMenu.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-import { Dialog, Transition, TransitionChild } from '@headlessui/react'
-import { IconClose } from '@shared/icons/IconClose'
-import { IconDiscord } from '@shared/icons/IconDiscord'
-import { IconTwitter } from '@shared/icons/IconTwitter'
-import type React from 'react'
-import type { ReactElement, ReactNode } from 'react'
-import type { Chain } from 'viem'
-import Link from '/src/components/Link'
-import { LogoGithub } from '../icons/LogoGithub'
-
-type TMenu = { path: string; label: string | ReactElement; target?: string }
-
-const menu: TMenu[] = [
- { path: 'https://docs.yearn.fi/', label: 'Docs', target: '_blank' },
- { path: 'https://discord.gg/yearn', label: 'Support', target: '_blank' },
- { path: 'https://blog.yearn.fi/', label: 'Blog', target: '_blank' },
- {
- path: 'https://gov.yearn.fi/',
- label: 'Discourse',
- target: '_blank'
- }
-]
-
-export function FooterNav({ onClose }: { onClose?: () => void }): ReactElement {
- return (
-
-
- {menu.map((link) => (
- {
- // Close modal for internal navigation (not external links)
- if (!link.target && onClose) {
- onClose()
- }
- }}
- >
- {link.label}
- {'↗'}
-
- ))}
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-type TModalMobileMenu = {
- isOpen: boolean
- shouldUseWallets: boolean
- shouldUseNetworks: boolean
- onClose: () => void
- children: ReactNode
- supportedNetworks: Chain[]
-}
-
-export type TModal = {
- isOpen: boolean
- onClose: () => void
- children: ReactNode
-} & React.ComponentPropsWithoutRef<'div'>
-
-export function ModalMobileMenu(props: TModalMobileMenu): ReactElement {
- const { isOpen, onClose, children } = props
-
- return (
-
-
-
-
-
- )
-}
diff --git a/src/components/shared/components/MotionDiv.tsx b/src/components/shared/components/MotionDiv.tsx
deleted file mode 100644
index b29b837a3..000000000
--- a/src/components/shared/components/MotionDiv.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { variants } from '@shared/utils/animations'
-import type { MotionProps } from 'framer-motion'
-import { motion } from 'framer-motion'
-import type { ReactElement } from 'react'
-
-type TMotionDiv = {
- animate: MotionProps['animate']
- name: string
- children: ReactElement
-}
-
-export function MotionDiv({ animate, name, children }: TMotionDiv): ReactElement {
- return (
-
- {children}
-
- )
-}
diff --git a/src/components/shared/components/Pagination.tsx b/src/components/shared/components/Pagination.tsx
deleted file mode 100644
index fbab194ae..000000000
--- a/src/components/shared/components/Pagination.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import { IconPaginationArrow } from '@shared/icons/IconPaginationArrow'
-import type { ReactElement } from 'react'
-import ReactPaginate from 'react-paginate'
-
-type TProps = {
- range: [from: number, to: number]
- pageCount: number
- numberOfItems: number
- onPageChange: (selectedItem: { selected: number }) => void
- currentPage?: number
-}
-
-export function Pagination({
- range: [from, to],
- pageCount,
- numberOfItems,
- onPageChange,
- currentPage = 0
-}: TProps): ReactElement {
- const handlePrevious = (): void => {
- if (currentPage === 0) {
- return
- }
- onPageChange({ selected: currentPage - 1 })
- }
-
- const handleNext = (): void => {
- if (currentPage >= pageCount - 1) {
- return
- }
- onPageChange({ selected: currentPage + 1 })
- }
-
- return (
- <>
-
-
- {'Previous'}
-
- = pageCount - 1}
- className={
- 'hover:bg-gray-50 relative inline-flex min-h-[44px] min-w-[44px] items-center justify-center rounded-md bg-neutral-200 px-4 py-2 text-sm text-neutral-900 disabled:cursor-not-allowed disabled:opacity-40'
- }
- >
- {'Next'}
-
-
-
-
-
- {'Showing '}
- {from}
- {' to '}
- {to}
- {' of'} {numberOfItems} {'results'}
-
-
-
}
- nextLabel={
-
- }
- />
-
-
- >
- )
-}
diff --git a/src/components/shared/components/ShareButton.tsx b/src/components/shared/components/ShareButton.tsx
deleted file mode 100644
index dabaa94ce..000000000
--- a/src/components/shared/components/ShareButton.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { cl } from '@shared/utils'
-import type { ReactElement } from 'react'
-
-type TShareButtonProps = {
- onClick: () => void
- className?: string
- iconClassName?: string
- ariaLabel?: string
-}
-
-export function ShareButton({
- onClick,
- className,
- iconClassName,
- ariaLabel = 'Share'
-}: TShareButtonProps): ReactElement {
- return (
-
-
-
-
-
-
-
- )
-}
diff --git a/src/components/shared/components/Switch.tsx b/src/components/shared/components/Switch.tsx
deleted file mode 100644
index cb5da0b1e..000000000
--- a/src/components/shared/components/Switch.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { Switch as HeadlessSwitch } from '@headlessui/react'
-import { cl } from '@shared/utils'
-import type { KeyboardEvent, ReactElement } from 'react'
-import { useState } from 'react'
-
-type TSwitch = {
- isEnabled: boolean
- onSwitch?: () => void
- isDisabled?: boolean
-}
-
-export function Switch(props: TSwitch): ReactElement {
- const { isEnabled, onSwitch, isDisabled = false } = props
- const [isEnabledState, setIsEnabledState] = useState(isEnabled)
-
- function safeOnSwitch(): void {
- onSwitch ? onSwitch() : setIsEnabledState(!isEnabledState)
- }
-
- const isChecked = onSwitch ? isEnabled : isEnabledState
-
- function handleOnKeyDown({ key }: KeyboardEvent): void {
- if (key !== 'Enter') {
- return
- }
-
- safeOnSwitch()
- }
-
- return (
-
-
- {'Use setting'}
-
-
-
- )
-}
diff --git a/src/components/shared/components/Tabs.tsx b/src/components/shared/components/Tabs.tsx
deleted file mode 100644
index 66061f15b..000000000
--- a/src/components/shared/components/Tabs.tsx
+++ /dev/null
@@ -1,133 +0,0 @@
-import { Listbox, ListboxButton, ListboxOption, ListboxOptions, Transition } from '@headlessui/react'
-import { IconChevron } from '@shared/icons/IconChevron'
-import { AnimatePresence, motion } from 'framer-motion'
-import type { ReactElement } from 'react'
-import { useEffect, useState } from 'react'
-import { useLocation, useNavigate, useSearchParams } from 'react-router'
-
-const variants = {
- initial: { y: 10, opacity: 0 },
- enter: { y: 0, opacity: 1 },
- exit: { y: -10, opacity: 0 }
-}
-
-type TItem = {
- id: string
- label: string
- content: ReactElement
-}
-
-type TTabsProps = {
- items: TItem[]
- className?: string
-}
-
-export function Tabs({ items, className }: TTabsProps): ReactElement {
- const [selectedTabId, setSelectedTabId] = useState(items[0]?.id)
- const navigate = useNavigate()
- const location = useLocation()
- const [searchParams] = useSearchParams()
-
- useEffect((): void => {
- const tabParam = searchParams.get('tab')
- const tab = items.find((tab): boolean => tab.id === tabParam)
- if (tab?.id) {
- setSelectedTabId(tab?.id)
- }
- }, [items, searchParams])
-
- return (
-
-
- {items.map(
- ({ id, label }): ReactElement => (
- {
- const newSearchParams = new URLSearchParams(searchParams)
- newSearchParams.set('tab', id)
- navigate(`${location.pathname}?${newSearchParams.toString()}`, { replace: true })
- setSelectedTabId(id)
- }}
- >
-
- {label}
-
- {selectedTabId === id && (
-
- )}
- {selectedTabId !== id && (
-
- )}
-
- )
- )}
-
-
-
setSelectedTabId(value)}>
- {({ open }): ReactElement => (
- <>
-
-
- {items.find(({ id }): boolean => id === selectedTabId)?.label || 'Menu'}
-
-
-
-
-
-
-
- {items.map(
- ({ id, label }): ReactElement => (
-
- {label}
-
- )
- )}
-
-
- >
- )}
-
-
-
-
- {items.map(
- ({ id, content }): ReactElement => (
-
- {content}
-
- )
- )}
-
-
-
- )
-}
diff --git a/src/components/shared/components/TokenDropdown.tsx b/src/components/shared/components/TokenDropdown.tsx
deleted file mode 100755
index 67fb5f03e..000000000
--- a/src/components/shared/components/TokenDropdown.tsx
+++ /dev/null
@@ -1,165 +0,0 @@
-import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions, Transition } from '@headlessui/react'
-import { useThrottledState } from '@react-hookz/web'
-import { Renderable } from '@shared/components/Renderable'
-import { useWallet } from '@shared/contexts/useWallet'
-import { useWeb3 } from '@shared/contexts/useWeb3'
-import { IconChevron } from '@shared/icons/IconChevron'
-import type { TDropdownItemProps, TDropdownOption, TDropdownProps } from '@shared/types'
-import { cl, formatAmount } from '@shared/utils'
-
-import type { ReactElement } from 'react'
-import { cloneElement, useState } from 'react'
-
-function DropdownItem({ option }: TDropdownItemProps): ReactElement {
- const { getBalance } = useWallet()
- const balance = getBalance({ address: option.value, chainID: option.chainID })
-
- return (
-
- {({ active }): ReactElement => (
-
-
{option?.icon ? option.icon : null}
-
-
{option.symbol}
-
- {`${formatAmount(balance.normalized)} ${option.symbol}`}
-
-
-
- )}
-
- )
-}
-
-function DropdownEmpty({ query }: { query: string }): ReactElement {
- const { isActive, openLoginModal } = useWeb3()
-
- if (!isActive) {
- return (
- openLoginModal()}
- className={
- 'flex h-14 cursor-pointer flex-col items-center justify-center px-4 text-center transition-colors hover:bg-neutral-300'
- }
- >
- {'Connect Wallet'}
-
- )
- }
- if (query !== '') {
- return (
-
- )
- }
- return (
-
- )
-}
-
-export function Dropdown(props: TDropdownProps): ReactElement {
- const [isOpen, setIsOpen] = useThrottledState(false, 400)
- const [query, setQuery] = useState('')
-
- const filteredOptions =
- query === ''
- ? props.options
- : props.options.filter((option): boolean => {
- return option.symbol.toLowerCase().includes(query.toLowerCase())
- })
-
- return (
-
-
- {
- e.stopPropagation()
- e.preventDefault()
- setIsOpen(false)
- }}
- />
-
-
-
{
- if (!_selected) return
- props.onSelect(_selected)
- setIsOpen(false)
- }}
- >
- setIsOpen((o: boolean): boolean => !o)}
- className={cl(
- props.className,
- 'flex h-10 w-full items-center justify-between bg-neutral-0 p-2 text-base text-neutral-900 md:px-3'
- )}
- >
-
-
-
- {props.selected?.icon ? (
- cloneElement(props.selected.icon)
- ) : (
-
- )}
-
-
- option?.symbol}
- placeholder={props.placeholder || ''}
- spellCheck={false}
- onChange={(event): void => {
- setIsOpen(true)
- setQuery(event.target.value)
- }}
- />
-
-
-
-
-
-
-
- {
- setIsOpen(false)
- setQuery('')
- }}
- >
-
- 0} fallback={ }>
- {filteredOptions.map(
- (option): ReactElement => (
-
- )
- )}
-
-
-
-
-
- )
-}
diff --git a/src/components/shared/contexts/useSearch.tsx b/src/components/shared/contexts/useSearch.tsx
deleted file mode 100644
index c44f7832a..000000000
--- a/src/components/shared/contexts/useSearch.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { useDeepCompareMemo } from '@react-hookz/web'
-import type { TOptionalRenderProps } from '@shared/types/optionalRenderProps'
-import { optionalRenderProps } from '@shared/types/optionalRenderProps'
-
-import type { Dispatch, ReactElement, SetStateAction } from 'react'
-import { createContext, useContext, useState } from 'react'
-
-type TSearchContext = {
- configuration: TSearchConfiguration
- dispatch: Dispatch>
-}
-
-type TSearchConfiguration = {
- searchValue: string
-}
-
-const defaultProps = {
- configuration: {
- searchValue: ''
- },
- dispatch: (): void => undefined
-}
-
-const SearchContext = createContext(defaultProps)
-export const SearchContextApp = ({
- children
-}: {
- children: TOptionalRenderProps
-}): ReactElement => {
- const [configuration, setConfiguration] = useState(defaultProps.configuration)
-
- const contextValue = useDeepCompareMemo(
- (): TSearchContext => ({ configuration, dispatch: setConfiguration }),
- [configuration]
- )
-
- return (
- {optionalRenderProps(children, contextValue)}
- )
-}
-
-export const useSearch = (): TSearchContext => {
- const ctx = useContext(SearchContext)
- if (!ctx) {
- throw new Error('SearchContext not found')
- }
- return ctx
-}
diff --git a/src/components/shared/hooks/useFetchYearnEarnedForUser.ts b/src/components/shared/hooks/useFetchYearnEarnedForUser.ts
deleted file mode 100644
index 26f1955be..000000000
--- a/src/components/shared/hooks/useFetchYearnEarnedForUser.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { useDeepCompareMemo } from '@react-hookz/web'
-
-import { useWeb3 } from '../contexts/useWeb3'
-import type { TYDaemonEarned } from '../utils/schemas/yDaemonEarnedSchema'
-import { yDaemonEarnedSchema } from '../utils/schemas/yDaemonEarnedSchema'
-import { useFetch } from './useFetch'
-import { useYDaemonBaseURI } from './useYDaemonBaseURI'
-
-/******************************************************************************
- ** The useFetchYearnEarnedForUser hook is used to fetch an estimate of the
- ** amount earned by the user. This estimate is calculated by the yDaemon API
- ** based on the events emitted by the yearn contracts catched by the subgraph.
- *****************************************************************************/
-function useFetchYearnEarnedForUser(): TYDaemonEarned {
- const { address } = useWeb3()
- const { yDaemonBaseUri: yDaemonBaseUriWithoutChain } = useYDaemonBaseURI()
-
- const { data: earned } = useFetch({
- endpoint: address
- ? `${yDaemonBaseUriWithoutChain}/earned/${address}?${new URLSearchParams({
- chainIDs: [1, 10].join(',')
- })}`
- : null,
- schema: yDaemonEarnedSchema
- })
-
- const memorizedEarned = useDeepCompareMemo((): TYDaemonEarned => {
- if (!earned) {
- return {
- earned: {},
- totalRealizedGainsUSD: 0,
- totalUnrealizedGainsUSD: 0
- }
- }
- return earned
- }, [earned])
-
- return memorizedEarned
-}
-
-export { useFetchYearnEarnedForUser }
diff --git a/src/components/shared/hooks/useFilteredVaults.ts b/src/components/shared/hooks/useFilteredVaults.ts
deleted file mode 100644
index 9ce7db3eb..000000000
--- a/src/components/shared/hooks/useFilteredVaults.ts
+++ /dev/null
@@ -1,257 +0,0 @@
-import { useAppSettings } from '@pages/vaults/contexts/useAppSettings'
-import { useDeepCompareMemo } from '@react-hookz/web'
-import { useWallet } from '@shared/contexts/useWallet'
-import { useYearn } from '@shared/contexts/useYearn'
-import type { TDict } from '@shared/types'
-import { toAddress } from '@shared/utils'
-import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import { isAutomatedVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import { useCallback, useMemo } from 'react'
-
-export function useFilteredVaults(
- vaultMap: TDict,
- condition: (v: TYDaemonVault) => boolean
-): TYDaemonVault[] {
- return useDeepCompareMemo(
- (): TYDaemonVault[] => Object.values(vaultMap).filter((vault): boolean => condition(vault)),
- [vaultMap, condition]
- )
-}
-
-export function useVaultFilter(
- categories: string[] | null,
- _chains: number[] | null,
- v3?: boolean
-): {
- activeVaults: TYDaemonVault[]
- retiredVaults: TYDaemonVault[]
- migratableVaults: TYDaemonVault[]
-} {
- const { vaults, getPrice } = useYearn()
- const { getBalance } = useWallet()
- const { shouldHideDust } = useAppSettings()
-
- const visibleVaults = useMemo((): TDict => {
- const filteredVaults: TDict = {}
- for (const [address, vault] of Object.entries(vaults)) {
- if (!vault.info.isHidden) {
- filteredVaults[address] = vault
- }
- }
- return filteredVaults
- }, [vaults])
-
- const filterHoldingsCallback = useCallback(
- (vault: TYDaemonVault, isFactoryOnly: boolean, isForV3: boolean): boolean => {
- if (isForV3 && !vault.version?.startsWith('3') && !vault.version?.startsWith('~3')) {
- return false
- }
- if (!isForV3 && vault.version?.startsWith('3') && !vault.version?.startsWith('~3')) {
- return false
- }
- const vaultBalance = getBalance({ address: vault.address, chainID: vault.chainID })
- const vaultPrice = getPrice({ address: vault.address, chainID: vault.chainID })
- // Check the staking balance
- if (vault.staking.available) {
- const stakingBalance = getBalance({
- address: vault.staking.address,
- chainID: vault.chainID
- })
- const hasValidStakedBalance = stakingBalance.raw > 0n
- const stakedBalanceValue = Number(stakingBalance.normalized) * vaultPrice.normalized
- if (hasValidStakedBalance && !(shouldHideDust && stakedBalanceValue < 0.01)) {
- return true
- }
- }
-
- const hasValidBalance = vaultBalance.raw > 0n
- const balanceValue = vaultBalance.normalized * vaultPrice.normalized
- if (shouldHideDust && balanceValue < 0.01) {
- return false
- }
- if (hasValidBalance) {
- if (isFactoryOnly) {
- if (vault.category === 'Curve' && isAutomatedVault(vault)) {
- return true
- }
- return false
- }
- return true
- }
- return false
- },
- [shouldHideDust, getBalance, getPrice]
- )
- const filterMigrationCallback = useCallback(
- (vault: TYDaemonVault): boolean => {
- const isV3Vault = vault.version?.startsWith('3') || vault.version?.startsWith('~3')
- if ((v3 && !isV3Vault) || (!v3 && isV3Vault)) {
- return false
- }
- const vaultBalance = getBalance({ address: vault.address, chainID: vault.chainID })
- if (vault.staking.available) {
- const stakingBalance = getBalance({
- address: vault.staking.address,
- chainID: vault.chainID
- })
- const hasValidStakedBalance = stakingBalance.raw > 0n
- if (hasValidStakedBalance) {
- return true
- }
- }
- const hasValidBalance = vaultBalance.raw > 0n
- if (hasValidBalance) {
- return true
- }
- return false
- },
- [getBalance, v3]
- )
- // Specific filter
- const highlightedVaults = useFilteredVaults(visibleVaults, ({ info }): boolean => info.isHighlighted)
- const holdingsVaults = useFilteredVaults(vaults, (vault): boolean => filterHoldingsCallback(vault, false, false))
- const holdingsV3Vaults = useFilteredVaults(vaults, (vault): boolean => filterHoldingsCallback(vault, false, true))
- // V3 Filtered Vaults
- const singleVaults = useFilteredVaults(
- visibleVaults,
- ({ version, kind }): boolean =>
- ((version || '')?.split('.')?.[0] === '3' && kind === 'Single Strategy') ||
- ((version || '')?.split('.')?.[0] === '~3' && kind === 'Single Strategy')
- )
- const MultiVaults = useFilteredVaults(
- visibleVaults,
- ({ version, kind }): boolean =>
- ((version || '')?.split('.')?.[0] === '3' && kind === 'Multi Strategy') ||
- ((version || '')?.split('.')?.[0] === '~3' && kind === 'Multi Strategy')
- )
- //V2 Filtered Vaults
- const boostedVaults = useFilteredVaults(visibleVaults, ({ apr }) => apr.extra.stakingRewardsAPR > 0)
- const curveVaults = useFilteredVaults(visibleVaults, ({ category }) => category === 'Curve')
- const prismaVaults = useFilteredVaults(visibleVaults, ({ category }) => category === 'Prisma')
- const velodromeVaults = useFilteredVaults(visibleVaults, ({ category }) => category === 'Velodrome')
- const aerodromeVaults = useFilteredVaults(visibleVaults, ({ category }) => category === 'Aerodrome')
- const stablesVaults = useFilteredVaults(visibleVaults, ({ category }) => category === 'Stablecoin')
- const balancerVaults = useFilteredVaults(visibleVaults, ({ category }) => category === 'Balancer')
- const cryptoVaults = useFilteredVaults(visibleVaults, ({ category }) => category === 'Volatile')
- const curveFactoryVaults = useFilteredVaults(
- visibleVaults,
- (vault) => vault.category === 'Curve' && isAutomatedVault(vault)
- )
- const migratableVaults = useMemo((): TYDaemonVault[] => [], [])
- const retiredVaults = useFilteredVaults(
- visibleVaults,
- (vault) => Boolean(vault.info?.isRetired) && filterMigrationCallback(vault)
- )
- /* 🔵 - Yearn Finance **************************************************************************
- ** First, we need to determine in which category we are. The activeVaults function will
- ** decide which vaults to display based on the category. No extra filters are applied.
- ** The possible lists are memoized to avoid unnecessary re-renders.
- **********************************************************************************************/
- const activeVaults = useDeepCompareMemo((): TYDaemonVault[] => {
- let _vaultList: TYDaemonVault[] = []
- if (v3) {
- if (categories?.includes('highlight')) {
- _vaultList = [..._vaultList, ...highlightedVaults]
- }
- if (categories?.includes('single')) {
- _vaultList = [..._vaultList, ...singleVaults]
- }
- if (categories?.includes('multi')) {
- _vaultList = [..._vaultList, ...MultiVaults]
- }
-
- //Remove duplicates
- const alreadyInList: TDict = {}
- const noDuplicateVaultList = []
- for (const vault of holdingsV3Vaults) {
- if (!alreadyInList[`${toAddress(vault.address)}${vault.chainID}`]) {
- noDuplicateVaultList.push(vault)
- alreadyInList[`${toAddress(vault.address)}${vault.chainID}`] = true
- }
- }
- for (const vault of _vaultList) {
- if (!alreadyInList[`${toAddress(vault.address)}${vault.chainID}`]) {
- noDuplicateVaultList.push(vault)
- alreadyInList[`${toAddress(vault.address)}${vault.chainID}`] = true
- }
- }
- _vaultList = noDuplicateVaultList
- return [..._vaultList]
- }
-
- if (categories?.includes('featured')) {
- _vaultList = _vaultList
- .toSorted((a, b): number => (b.tvl.tvl || 0) * (b?.apr?.netAPR || 0) - (a.tvl.tvl || 0) * (a?.apr?.netAPR || 0))
- .slice(0, 10)
- }
- if (categories?.includes('curveF')) {
- _vaultList = [..._vaultList, ...curveFactoryVaults]
- }
- if (categories?.includes('curve')) {
- _vaultList = [..._vaultList, ...curveVaults]
- }
- if (categories?.includes('prisma')) {
- _vaultList = [..._vaultList, ...prismaVaults]
- }
- if (categories?.includes('balancer')) {
- _vaultList = [..._vaultList, ...balancerVaults]
- }
- if (categories?.includes('velodrome')) {
- _vaultList = [..._vaultList, ...velodromeVaults]
- }
- if (categories?.includes('aerodrome')) {
- _vaultList = [..._vaultList, ...aerodromeVaults]
- }
- if (categories?.includes('boosted')) {
- _vaultList = [..._vaultList, ...boostedVaults]
- }
- if (categories?.includes('stables')) {
- _vaultList = [..._vaultList, ...stablesVaults]
- }
- if (categories?.includes('crypto')) {
- _vaultList = [..._vaultList, ...cryptoVaults]
- }
- if (categories?.includes('holdings')) {
- _vaultList = [..._vaultList, ...holdingsVaults]
- }
-
- //remove duplicates
- _vaultList = _vaultList.filter(
- (vault, index, self): boolean => index === self.findIndex((v): boolean => v.address === vault.address)
- )
- // Remove v3 vaults
- _vaultList = _vaultList.filter(
- (vault): boolean => !vault.version?.startsWith('3') && !vault.version?.startsWith('~3')
- )
- // Remove duplicates
- const alreadyInList: TDict = {}
- const noDuplicateVaultList = []
- for (const vault of _vaultList) {
- if (!alreadyInList[`${toAddress(vault.address)}${vault.chainID}`]) {
- noDuplicateVaultList.push(vault)
- alreadyInList[`${toAddress(vault.address)}${vault.chainID}`] = true
- }
- }
- _vaultList = noDuplicateVaultList
- return _vaultList
- }, [
- v3,
- categories,
- holdingsVaults,
- holdingsV3Vaults,
- highlightedVaults,
- singleVaults,
- MultiVaults,
- curveFactoryVaults,
- curveVaults,
- prismaVaults,
- balancerVaults,
- velodromeVaults,
- aerodromeVaults,
- boostedVaults,
- stablesVaults,
- cryptoVaults
- ])
-
- return { activeVaults, migratableVaults, retiredVaults }
-}
diff --git a/src/components/shared/hooks/useInitialQueryParam.ts b/src/components/shared/hooks/useInitialQueryParam.ts
deleted file mode 100644
index 395604472..000000000
--- a/src/components/shared/hooks/useInitialQueryParam.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { useEffect, useState } from 'react'
-import { useLocation } from 'react-router'
-
-/************************************************************************************************
- ** useInitialQueryParam Hook
- **
- ** This custom hook is designed to retrieve and manage the initial query parameter from the URL.
- ** It handles both client-side and server-side rendering scenarios, ensuring that the query
- ** parameter is correctly retrieved regardless of the rendering context.
- **
- ** The hook performs the following tasks:
- ** 1. On the client-side, it initially checks the URL for the query parameter.
- ** 2. Once the router is ready, it updates the value based on the router's query object.
- ** 3. It returns the current value of the query parameter, which can be used in the component.
- **
- ** @param {string} key - The name of the query parameter to retrieve
- ** @returns {string | null} - The value of the query parameter, or null if not found
- ************************************************************************************************/
-export function useInitialQueryParam(key: string): string | null {
- const location = useLocation()
- const [value, setValue] = useState(null)
-
- useEffect(() => {
- if (typeof window !== 'undefined') {
- const urlParams = new URLSearchParams(window.location.search)
- const initialValue = urlParams.get(key)
- setValue(initialValue)
- }
- }, [key])
-
- useEffect(() => {
- const searchParams = new URLSearchParams(location.search)
- const queryValue = searchParams.get(key)
- if (queryValue && queryValue !== value) {
- setValue(queryValue)
- }
- }, [location.search, key, value])
-
- return value
-}
diff --git a/src/components/shared/hooks/useRateLimitedContract.ts b/src/components/shared/hooks/useRateLimitedContract.ts
deleted file mode 100644
index 11096fc25..000000000
--- a/src/components/shared/hooks/useRateLimitedContract.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import { useQuery } from '@tanstack/react-query'
-import type { Abi, ContractFunctionName } from 'viem'
-import type { ReadContractParameters, ReadContractsParameters } from 'wagmi/actions'
-import { readContract, readContracts } from 'wagmi/actions'
-import { retrieveConfig } from '../utils/wagmi'
-
-/*******************************************************************************
- ** Chain-specific rate limiting configuration
- ******************************************************************************/
-const CHAIN_RATE_LIMITS: Record = {
- 8453: { staleTime: 30 * 1000, gcTime: 5 * 60 * 1000 }, // Base: 30s stale, 5min cache
- 1: { staleTime: 5 * 1000, gcTime: 60 * 1000 } // Mainnet: 5s stale, 1min cache
-}
-
-const DEFAULT_RATE_LIMIT = { staleTime: 5 * 1000, gcTime: 60 * 1000 }
-
-/*******************************************************************************
- ** Get rate limit config for a specific chain
- ******************************************************************************/
-function getRateLimitConfig(chainId: number) {
- return CHAIN_RATE_LIMITS[chainId] || DEFAULT_RATE_LIMIT
-}
-
-/*******************************************************************************
- ** Rate-limited single contract read hook
- ******************************************************************************/
-export function useRateLimitedReadContract<
- TAbi extends Abi,
- TFunctionName extends ContractFunctionName
->(params: ReadContractParameters & { enabled?: boolean }) {
- const { chainId, enabled = true, ...contractParams } = params
- const config = getRateLimitConfig(chainId || 1)
-
- return useQuery({
- queryKey: ['contract-read', chainId, contractParams.address, contractParams.functionName, contractParams.args],
- queryFn: async () => {
- return await readContract(retrieveConfig(), {
- ...contractParams,
- chainId
- } as any)
- },
- enabled,
- staleTime: config.staleTime,
- gcTime: config.gcTime,
- retry: 2,
- retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000)
- })
-}
-
-/*******************************************************************************
- ** Rate-limited multiple contracts read hook
- ******************************************************************************/
-export function useRateLimitedReadContracts(params: {
- contracts: TContracts
- enabled?: boolean
-}) {
- const { contracts, enabled = true } = params
- const chainId = contracts[0]?.chainId || 1
- const config = getRateLimitConfig(chainId)
-
- return useQuery({
- queryKey: ['contracts-read', chainId, contracts],
- queryFn: async () => {
- // For Base chain, add a small delay between batched calls
- if (chainId === 8453) {
- await new Promise((resolve) => setTimeout(resolve, 100))
- }
- return await readContracts(retrieveConfig(), { contracts } as any)
- },
- enabled,
- staleTime: config.staleTime,
- gcTime: config.gcTime,
- retry: 2,
- retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000)
- })
-}
-
-/*******************************************************************************
- ** Hook to check if we should update based on block number for rate limiting
- ******************************************************************************/
-export function useShouldUpdateOnBlock(blockNumber: bigint | undefined, chainId: number): boolean {
- if (!blockNumber) return false
-
- // For Base chain, only update every 10 blocks
- if (chainId === 8453) {
- return Number(blockNumber) % 10 === 0
- }
-
- // For other chains, update on every block
- return true
-}
diff --git a/src/components/shared/hooks/useV2VaultFilter.ts b/src/components/shared/hooks/useV2VaultFilter.ts
index aa0cd2259..dfcbedc6a 100644
--- a/src/components/shared/hooks/useV2VaultFilter.ts
+++ b/src/components/shared/hooks/useV2VaultFilter.ts
@@ -1,44 +1,7 @@
-import { useAppSettings } from '@pages/vaults/contexts/useAppSettings'
-import { DEFAULT_MIN_TVL } from '@pages/vaults/utils/constants'
-import {
- deriveAssetCategory,
- deriveListKind,
- deriveV3Aggressiveness,
- expandUnderlyingAssetSelection,
- isAllocatorVaultOverride,
- normalizeUnderlyingAssetSymbol,
- type TVaultAggressiveness
-} from '@pages/vaults/utils/vaultListFacets'
-import { useDeepCompareMemo } from '@react-hookz/web'
-import { useWallet } from '@shared/contexts/useWallet'
-import { useYearn } from '@shared/contexts/useYearn'
+import type { TVaultAggressiveness } from '@pages/vaults/utils/vaultListFacets'
import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import { useMemo } from 'react'
-import {
- createCheckHasAvailableBalance,
- createCheckHasHoldings,
- getVaultKey,
- isV3Vault,
- type TVaultFlags
-} from './useVaultFilterUtils'
-
-type TVaultIndexEntry = {
- key: string
- vault: TYDaemonVault
- searchableText: string
- kind: ReturnType
- category: string
- aggressiveness: TVaultAggressiveness | null
- isHidden: boolean
- isActive: boolean
- isMigratable: boolean
- isRetired: boolean
-}
-
-type TVaultWalletFlags = {
- hasHoldings: boolean
- hasAvailableBalance: boolean
-}
+import { type TVaultFilterResult, useVaultFilter } from './useVaultFilter'
+import type { TVaultFlags } from './useVaultFilterUtils'
type TOptimizedV2VaultFilterResult = {
filteredVaults: TYDaemonVault[]
@@ -50,6 +13,18 @@ type TOptimizedV2VaultFilterResult = {
isLoading: boolean
}
+function toV2Result(result: TVaultFilterResult): TOptimizedV2VaultFilterResult {
+ return {
+ filteredVaults: result.filteredVaults,
+ holdingsVaults: result.holdingsVaults,
+ availableVaults: result.availableVaults,
+ vaultFlags: result.vaultFlags,
+ availableUnderlyingAssets: result.availableUnderlyingAssets,
+ underlyingAssetVaults: result.underlyingAssetVaults,
+ isLoading: result.isLoading
+ }
+}
+
export function useV2VaultFilter(
types: string[] | null,
chains: number[] | null,
@@ -61,239 +36,18 @@ export function useV2VaultFilter(
showHiddenVaults?: boolean,
enabled?: boolean
): TOptimizedV2VaultFilterResult {
- const { vaults, getPrice, isLoadingVaultList } = useYearn()
- const { getBalance } = useWallet()
- const { shouldHideDust } = useAppSettings()
- const isEnabled = enabled ?? true
- const searchValue = search ?? ''
- const minTvlValue = Number.isFinite(minTvl) ? Math.max(0, minTvl || 0) : DEFAULT_MIN_TVL
- const isSearchEnabled = isEnabled && searchValue !== ''
- const searchRegex = useMemo(() => {
- if (!isSearchEnabled) {
- return null
- }
- try {
- const escapedSearch = searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
- return new RegExp(escapedSearch, 'i')
- } catch {
- return null
- }
- }, [isSearchEnabled, searchValue])
- const lowercaseSearch = useMemo(
- () => (isSearchEnabled ? searchValue.toLowerCase() : ''),
- [isSearchEnabled, searchValue]
- )
- const normalizedUnderlyingAssets = useMemo(() => {
- if (!underlyingAssets || underlyingAssets.length === 0) {
- return new Set()
- }
- const normalized = underlyingAssets.map((asset) => normalizeUnderlyingAssetSymbol(asset)).filter(Boolean)
- return new Set(normalized)
- }, [underlyingAssets])
- const expandedUnderlyingAssets = useMemo(
- () => expandUnderlyingAssetSelection(normalizedUnderlyingAssets),
- [normalizedUnderlyingAssets]
- )
-
- const checkHasHoldings = useMemo(
- () => createCheckHasHoldings(getBalance, getPrice, shouldHideDust),
- [getBalance, getPrice, shouldHideDust]
- )
-
- const checkHasAvailableBalance = useMemo(() => createCheckHasAvailableBalance(getBalance), [getBalance])
-
- const vaultIndex = useDeepCompareMemo(() => {
- if (!isEnabled) {
- return new Map()
- }
- const vaultMap = new Map()
-
- const shouldIncludeVault = (vault: TYDaemonVault): boolean =>
- !isAllocatorVaultOverride(vault) && !isV3Vault(vault, false)
-
- const upsertVault = (
- vault: TYDaemonVault,
- updates: Partial>
- ): void => {
- const key = getVaultKey(vault)
- const existing = vaultMap.get(key)
- if (existing) {
- vaultMap.set(key, { ...existing, ...updates })
- return
- }
-
- const kind = deriveListKind(vault)
- vaultMap.set(key, {
- key,
- vault,
- searchableText:
- `${vault.name} ${vault.symbol} ${vault.token.name} ${vault.token.symbol} ${vault.address} ${vault.token.address}`.toLowerCase(),
- kind,
- category: deriveAssetCategory(vault),
- aggressiveness: deriveV3Aggressiveness(vault),
- isHidden: Boolean(vault.info?.isHidden),
- isActive: Boolean(updates.isActive),
- isMigratable: Boolean(updates.isMigratable),
- isRetired: Boolean(updates.isRetired)
- })
- }
-
- Object.values(vaults).forEach((vault) => {
- if (!shouldIncludeVault(vault)) {
- return
- }
- const isRetired = Boolean(vault.info?.isRetired)
- upsertVault(vault, { isActive: !isRetired, isRetired, isMigratable: Boolean(vault.migration?.available) })
- })
-
- return vaultMap
- }, [isEnabled, isEnabled ? vaults : null])
-
- const walletFlags = useMemo(() => {
- const flags = new Map()
- vaultIndex.forEach((entry, key) => {
- flags.set(key, {
- hasHoldings: checkHasHoldings(entry.vault),
- hasAvailableBalance: checkHasAvailableBalance(entry.vault)
- })
- })
- return flags
- }, [vaultIndex, checkHasHoldings, checkHasAvailableBalance])
-
- const holdingsVaults = useMemo(() => {
- return Array.from(vaultIndex.values())
- .filter(({ key }) => walletFlags.get(key)?.hasHoldings)
- .map(({ vault }) => vault)
- }, [vaultIndex, walletFlags])
-
- const availableVaults = useMemo(() => {
- return Array.from(vaultIndex.values())
- .filter(({ key, isActive }) => {
- const flags = walletFlags.get(key)
- return Boolean(flags?.hasAvailableBalance && (isActive || flags?.hasHoldings))
- })
- .map(({ vault }) => vault)
- }, [vaultIndex, walletFlags])
-
- const filteredResults = useMemo(() => {
- const filteredVaults: TYDaemonVault[] = []
- const vaultFlags: Record = {}
- const shouldShowHidden = Boolean(showHiddenVaults)
- const hasChainFilter = Boolean(chains?.length)
- const hasTypeFilter = Boolean(types?.length)
- const hasCategoryFilter = Boolean(categories?.length)
- const hasAggressivenessFilter = Boolean(aggressiveness?.length)
- const hasUnderlyingAssetFilter = normalizedUnderlyingAssets.size > 0
- const availableUnderlyingAssets = new Set()
- const underlyingAssetVaults: Record = {}
-
- const matchesSearch = (searchableText: string): boolean => {
- if (!isSearchEnabled) {
- return true
- }
- if (searchRegex) {
- return searchRegex.test(searchableText)
- }
- return searchableText.includes(lowercaseSearch)
- }
-
- vaultIndex.forEach((entry) => {
- const {
- key,
- vault,
- searchableText,
- kind,
- category,
- aggressiveness: aggressivenessScore,
- isHidden,
- isActive,
- isMigratable,
- isRetired
- } = entry
- const walletFlag = walletFlags.get(key)
- const hasHoldings = Boolean(walletFlag?.hasHoldings)
-
- if (!isActive && !hasHoldings) {
- return
- }
- if (!shouldShowHidden && isHidden) {
- return
- }
-
- if (!matchesSearch(searchableText)) {
- return
- }
-
- if (hasChainFilter && !chains?.includes(vault.chainID)) {
- return
- }
-
- const vaultTvl = vault.tvl?.tvl || 0
- if (vaultTvl < minTvlValue) {
- return
- }
-
- const isMigratableVault = Boolean(isMigratable && hasHoldings)
- const isRetiredVault = Boolean(isRetired && hasHoldings)
- const hasUserHoldings = hasHoldings || isMigratableVault || isRetiredVault
-
- vaultFlags[key] = {
- hasHoldings: hasUserHoldings,
- isMigratable: isMigratableVault,
- isRetired: isRetiredVault,
- isHidden
- }
-
- const matchesKind = !hasTypeFilter || Boolean(types?.includes(kind))
- const matchesCategory = !hasCategoryFilter || Boolean(categories?.includes(category))
- const matchesAggressiveness =
- !hasAggressivenessFilter ||
- (aggressivenessScore !== null && Boolean(aggressiveness?.includes(aggressivenessScore)))
-
- if (matchesKind && matchesCategory && matchesAggressiveness) {
- const assetKey = normalizeUnderlyingAssetSymbol(vault.token?.symbol)
- if (assetKey && !underlyingAssetVaults[assetKey]) {
- availableUnderlyingAssets.add(assetKey)
- underlyingAssetVaults[assetKey] = vault
- } else if (assetKey) {
- availableUnderlyingAssets.add(assetKey)
- }
-
- const matchesUnderlyingAsset = !hasUnderlyingAssetFilter || (assetKey && expandedUnderlyingAssets.has(assetKey))
- if (!matchesUnderlyingAsset) {
- return
- }
-
- filteredVaults.push(vault)
- }
- })
-
- return {
- filteredVaults,
- vaultFlags,
- availableUnderlyingAssets: Array.from(availableUnderlyingAssets),
- underlyingAssetVaults
- }
- }, [
- vaultIndex,
- walletFlags,
+ const result = useVaultFilter({
+ version: 'v2',
types,
chains,
+ search,
categories,
aggressiveness,
- normalizedUnderlyingAssets,
- expandedUnderlyingAssets,
- minTvlValue,
- searchRegex,
- lowercaseSearch,
- isSearchEnabled,
- showHiddenVaults
- ])
+ underlyingAssets,
+ minTvl,
+ showHiddenVaults,
+ enabled
+ })
- return {
- ...filteredResults,
- holdingsVaults,
- availableVaults,
- isLoading: isEnabled ? isLoadingVaultList : false
- }
+ return toV2Result(result)
}
diff --git a/src/components/shared/hooks/useV3VaultFilter.ts b/src/components/shared/hooks/useV3VaultFilter.ts
index 047d24640..5196179ed 100644
--- a/src/components/shared/hooks/useV3VaultFilter.ts
+++ b/src/components/shared/hooks/useV3VaultFilter.ts
@@ -1,45 +1,7 @@
-import { useAppSettings } from '@pages/vaults/contexts/useAppSettings'
-import { DEFAULT_MIN_TVL } from '@pages/vaults/utils/constants'
-import {
- deriveAssetCategory,
- deriveListKind,
- deriveV3Aggressiveness,
- expandUnderlyingAssetSelection,
- isAllocatorVaultOverride,
- normalizeUnderlyingAssetSymbol,
- type TVaultAggressiveness
-} from '@pages/vaults/utils/vaultListFacets'
-import { useDeepCompareMemo } from '@react-hookz/web'
-import { useWallet } from '@shared/contexts/useWallet'
-import { useYearn } from '@shared/contexts/useYearn'
+import type { TVaultAggressiveness } from '@pages/vaults/utils/vaultListFacets'
import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
-import { useMemo } from 'react'
-import {
- createCheckHasAvailableBalance,
- createCheckHasHoldings,
- getVaultKey,
- isV3Vault,
- type TVaultFlags
-} from './useVaultFilterUtils'
-
-type TVaultIndexEntry = {
- key: string
- vault: TYDaemonVault
- searchableText: string
- kind: ReturnType
- category: string
- aggressiveness: TVaultAggressiveness | null
- isHidden: boolean
- isFeatured: boolean
- isActive: boolean
- isMigratable: boolean
- isRetired: boolean
-}
-
-type TVaultWalletFlags = {
- hasHoldings: boolean
- hasAvailableBalance: boolean
-}
+import { useVaultFilter } from './useVaultFilter'
+import type { TVaultFlags } from './useVaultFilterUtils'
type TV3VaultFilterResult = {
filteredVaults: TYDaemonVault[]
@@ -67,275 +29,16 @@ export function useV3VaultFilter(
showHiddenVaults?: boolean,
enabled?: boolean
): TV3VaultFilterResult {
- const { vaults, getPrice, isLoadingVaultList } = useYearn()
- const { getBalance } = useWallet()
- const { shouldHideDust } = useAppSettings()
- const isEnabled = enabled ?? true
- const searchValue = search ?? ''
- const minTvlValue = Number.isFinite(minTvl) ? Math.max(0, minTvl || 0) : DEFAULT_MIN_TVL
- const isSearchEnabled = isEnabled && searchValue !== ''
- const searchRegex = useMemo(() => {
- if (!isSearchEnabled) {
- return null
- }
- try {
- const escapedSearch = searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
- return new RegExp(escapedSearch, 'i')
- } catch {
- return null
- }
- }, [isSearchEnabled, searchValue])
- const lowercaseSearch = useMemo(
- () => (isSearchEnabled ? searchValue.toLowerCase() : ''),
- [isSearchEnabled, searchValue]
- )
- const normalizedUnderlyingAssets = useMemo(() => {
- if (!underlyingAssets || underlyingAssets.length === 0) {
- return new Set()
- }
- const normalized = underlyingAssets.map((asset) => normalizeUnderlyingAssetSymbol(asset)).filter(Boolean)
- return new Set(normalized)
- }, [underlyingAssets])
- const expandedUnderlyingAssets = useMemo(
- () => expandUnderlyingAssetSelection(normalizedUnderlyingAssets),
- [normalizedUnderlyingAssets]
- )
-
- const checkHasHoldings = useMemo(
- () => createCheckHasHoldings(getBalance, getPrice, shouldHideDust),
- [getBalance, getPrice, shouldHideDust]
- )
-
- const checkHasAvailableBalance = useMemo(() => createCheckHasAvailableBalance(getBalance), [getBalance])
-
- const vaultIndex = useDeepCompareMemo(() => {
- if (!isEnabled) {
- return new Map()
- }
- const vaultMap = new Map()
-
- const shouldIncludeVault = (vault: TYDaemonVault): boolean => isV3Vault(vault, isAllocatorVaultOverride(vault))
-
- const upsertVault = (
- vault: TYDaemonVault,
- updates: Partial>
- ): void => {
- const key = getVaultKey(vault)
- const existing = vaultMap.get(key)
- if (existing) {
- vaultMap.set(key, { ...existing, ...updates })
- return
- }
-
- const kind = deriveListKind(vault)
- vaultMap.set(key, {
- key,
- vault,
- searchableText:
- `${vault.name} ${vault.symbol} ${vault.token.name} ${vault.token.symbol} ${vault.address} ${vault.token.address}`.toLowerCase(),
- kind,
- category: deriveAssetCategory(vault),
- aggressiveness: deriveV3Aggressiveness(vault),
- isHidden: Boolean(vault.info?.isHidden),
- isFeatured: Boolean(vault.info?.isHighlighted),
- isActive: Boolean(updates.isActive),
- isMigratable: Boolean(updates.isMigratable),
- isRetired: Boolean(updates.isRetired)
- })
- }
-
- Object.values(vaults).forEach((vault) => {
- if (!shouldIncludeVault(vault)) {
- return
- }
- const isRetired = Boolean(vault.info?.isRetired)
- upsertVault(vault, { isActive: !isRetired, isRetired, isMigratable: Boolean(vault.migration?.available) })
- })
-
- return vaultMap
- }, [isEnabled, isEnabled ? vaults : null])
-
- const walletFlags = useMemo(() => {
- const flags = new Map()
- vaultIndex.forEach((entry, key) => {
- flags.set(key, {
- hasHoldings: checkHasHoldings(entry.vault),
- hasAvailableBalance: checkHasAvailableBalance(entry.vault)
- })
- })
- return flags
- }, [vaultIndex, checkHasHoldings, checkHasAvailableBalance])
-
- const holdingsVaults = useMemo(() => {
- return Array.from(vaultIndex.values())
- .filter(({ key }) => walletFlags.get(key)?.hasHoldings)
- .map(({ vault }) => vault)
- }, [vaultIndex, walletFlags])
-
- const availableVaults = useMemo(() => {
- return Array.from(vaultIndex.values())
- .filter(({ key, isActive }) => {
- const flags = walletFlags.get(key)
- return Boolean(flags?.hasAvailableBalance && (isActive || flags?.hasHoldings))
- })
- .map(({ vault }) => vault)
- }, [vaultIndex, walletFlags])
-
- const filteredResults = useMemo(() => {
- const filteredVaults: TYDaemonVault[] = []
- const vaultFlags: Record = {}
-
- let totalMatchingVaults = 0
- let totalHoldingsMatching = 0
- let totalAvailableMatching = 0
- let totalMigratableMatching = 0
- let totalRetiredMatching = 0
- const availableUnderlyingAssets = new Set()
- const underlyingAssetVaults: Record = {}
- const hasChainFilter = Boolean(chains?.length)
- const hasCategoryFilter = Boolean(categories?.length)
- const hasAggressivenessFilter = Boolean(aggressiveness?.length)
- const hasTypeFilter = Boolean(types?.length)
- const hasUnderlyingAssetFilter = normalizedUnderlyingAssets.size > 0
-
- const matchesSearch = (searchableText: string): boolean => {
- if (!isSearchEnabled) {
- return true
- }
- if (searchRegex) {
- return searchRegex.test(searchableText)
- }
- return searchableText.includes(lowercaseSearch)
- }
-
- vaultIndex.forEach((entry) => {
- const {
- key,
- vault,
- searchableText,
- kind,
- category,
- aggressiveness: aggressivenessScore,
- isHidden,
- isFeatured,
- isActive,
- isMigratable,
- isRetired
- } = entry
- const walletFlag = walletFlags.get(key)
- const hasHoldings = Boolean(walletFlag?.hasHoldings)
- const hasAvailableBalance = Boolean(walletFlag?.hasAvailableBalance)
-
- if (!isActive && !hasHoldings) {
- return
- }
- if (!showHiddenVaults && isHidden) {
- return
- }
- if (!matchesSearch(searchableText)) {
- return
- }
-
- if (hasChainFilter && !chains?.includes(vault.chainID)) {
- return
- }
-
- const vaultTvl = vault.tvl?.tvl || 0
- if (vaultTvl < minTvlValue) {
- return
- }
-
- const isMigratableVault = Boolean(isMigratable && hasHoldings)
- const isRetiredVault = Boolean(isRetired && hasHoldings)
- const hasUserHoldings = hasHoldings || isMigratableVault || isRetiredVault
-
- vaultFlags[key] = {
- hasHoldings: hasUserHoldings,
- isMigratable: isMigratableVault,
- isRetired: isRetiredVault,
- isHidden
- }
-
- totalMatchingVaults++
- if (hasUserHoldings) {
- totalHoldingsMatching++
- }
- if (hasAvailableBalance) {
- totalAvailableMatching++
- }
- if (isMigratableVault) {
- totalMigratableMatching++
- }
- if (isRetiredVault) {
- totalRetiredMatching++
- }
-
- const shouldIncludeByCategory = !hasCategoryFilter || Boolean(categories?.includes(category))
- const isPinnedByUserContext = hasUserHoldings || isMigratableVault || isRetiredVault
- const isStrategy = kind === 'strategy'
- const shouldIncludeByFeaturedGate = showHiddenVaults || isStrategy || isFeatured || isPinnedByUserContext
- const shouldIncludeByKind =
- !hasTypeFilter ||
- (Boolean(types?.includes('multi')) && kind === 'allocator') ||
- (Boolean(types?.includes('single')) && kind === 'strategy')
- const shouldIncludeByAggressiveness =
- !hasAggressivenessFilter ||
- (aggressivenessScore !== null && Boolean(aggressiveness?.includes(aggressivenessScore)))
-
- if (
- shouldIncludeByCategory &&
- shouldIncludeByFeaturedGate &&
- shouldIncludeByKind &&
- shouldIncludeByAggressiveness
- ) {
- const assetKey = normalizeUnderlyingAssetSymbol(vault.token?.symbol)
- if (assetKey && !underlyingAssetVaults[assetKey]) {
- availableUnderlyingAssets.add(assetKey)
- underlyingAssetVaults[assetKey] = vault
- } else if (assetKey) {
- availableUnderlyingAssets.add(assetKey)
- }
-
- const matchesUnderlyingAsset = !hasUnderlyingAssetFilter || (assetKey && expandedUnderlyingAssets.has(assetKey))
-
- if (matchesUnderlyingAsset) {
- filteredVaults.push(vault)
- }
- }
- })
-
- return {
- filteredVaults,
- holdingsVaults,
- vaultFlags,
- availableUnderlyingAssets: Array.from(availableUnderlyingAssets),
- underlyingAssetVaults,
- totalMatchingVaults,
- totalHoldingsMatching,
- totalAvailableMatching,
- totalMigratableMatching,
- totalRetiredMatching
- }
- }, [
- vaultIndex,
- walletFlags,
+ return useVaultFilter({
+ version: 'v3',
types,
chains,
+ search,
categories,
aggressiveness,
- normalizedUnderlyingAssets,
- expandedUnderlyingAssets,
- minTvlValue,
- holdingsVaults,
+ underlyingAssets,
+ minTvl,
showHiddenVaults,
- searchRegex,
- lowercaseSearch,
- isSearchEnabled
- ])
-
- return {
- ...filteredResults,
- availableVaults,
- isLoading: isEnabled ? isLoadingVaultList : false
- }
+ enabled
+ })
}
diff --git a/src/components/shared/hooks/useVaultFilter.ts b/src/components/shared/hooks/useVaultFilter.ts
new file mode 100644
index 000000000..be848f795
--- /dev/null
+++ b/src/components/shared/hooks/useVaultFilter.ts
@@ -0,0 +1,371 @@
+import { useAppSettings } from '@pages/vaults/contexts/useAppSettings'
+import { DEFAULT_MIN_TVL } from '@pages/vaults/utils/constants'
+import {
+ deriveAssetCategory,
+ deriveListKind,
+ deriveV3Aggressiveness,
+ expandUnderlyingAssetSelection,
+ isAllocatorVaultOverride,
+ normalizeUnderlyingAssetSymbol,
+ type TVaultAggressiveness
+} from '@pages/vaults/utils/vaultListFacets'
+import { useDeepCompareMemo } from '@react-hookz/web'
+import { useWallet } from '@shared/contexts/useWallet'
+import { useYearn } from '@shared/contexts/useYearn'
+import type { TYDaemonVault } from '@shared/utils/schemas/yDaemonVaultsSchemas'
+import { useMemo } from 'react'
+import {
+ createCheckHasAvailableBalance,
+ createCheckHasHoldings,
+ getVaultKey,
+ isV3Vault,
+ type TVaultFlags
+} from './useVaultFilterUtils'
+
+export type TVaultVersion = 'v2' | 'v3' | 'all'
+
+type TVaultIndexEntry = {
+ key: string
+ vault: TYDaemonVault
+ searchableText: string
+ kind: ReturnType
+ category: string
+ aggressiveness: TVaultAggressiveness | null
+ isHidden: boolean
+ isFeatured: boolean
+ isActive: boolean
+ isMigratable: boolean
+ isRetired: boolean
+}
+
+type TVaultWalletFlags = {
+ hasHoldings: boolean
+ hasAvailableBalance: boolean
+}
+
+export type TVaultFilterResult = {
+ filteredVaults: TYDaemonVault[]
+ holdingsVaults: TYDaemonVault[]
+ availableVaults: TYDaemonVault[]
+ vaultFlags: Record
+ availableUnderlyingAssets: string[]
+ underlyingAssetVaults: Record
+ totalMatchingVaults: number
+ totalHoldingsMatching: number
+ totalAvailableMatching: number
+ totalMigratableMatching: number
+ totalRetiredMatching: number
+ isLoading: boolean
+}
+
+export type TVaultFilterParams = {
+ version: TVaultVersion
+ types: string[] | null
+ chains: number[] | null
+ search?: string
+ categories?: string[] | null
+ aggressiveness?: TVaultAggressiveness[] | null
+ underlyingAssets?: string[] | null
+ minTvl?: number
+ showHiddenVaults?: boolean
+ enabled?: boolean
+}
+
+function shouldIncludeVaultByVersion(
+ vault: TYDaemonVault,
+ version: TVaultVersion,
+ isAllocatorOverride: boolean
+): boolean {
+ const isV3 = isV3Vault(vault, isAllocatorOverride)
+ if (version === 'v2') return !isAllocatorOverride && !isV3
+ if (version === 'v3') return isV3
+ return true
+}
+
+export function useVaultFilter(params: TVaultFilterParams): TVaultFilterResult {
+ const {
+ version,
+ types,
+ chains,
+ search,
+ categories,
+ aggressiveness,
+ underlyingAssets,
+ minTvl,
+ showHiddenVaults,
+ enabled
+ } = params
+
+ const { vaults, getPrice, isLoadingVaultList } = useYearn()
+ const { getBalance } = useWallet()
+ const { shouldHideDust } = useAppSettings()
+ const isEnabled = enabled ?? true
+ const searchValue = search ?? ''
+ const minTvlValue = Number.isFinite(minTvl) ? Math.max(0, minTvl || 0) : DEFAULT_MIN_TVL
+ const isSearchEnabled = isEnabled && searchValue !== ''
+ const searchRegex = useMemo(() => {
+ if (!isSearchEnabled || searchValue === '') return null
+ try {
+ const escapedSearch = searchValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+ return new RegExp(escapedSearch, 'i')
+ } catch {
+ return null
+ }
+ }, [searchValue, isSearchEnabled])
+ const lowercaseSearch = useMemo(
+ () => (isSearchEnabled ? searchValue.toLowerCase() : ''),
+ [isSearchEnabled, searchValue]
+ )
+ const normalizedUnderlyingAssets = useMemo(() => {
+ if (!underlyingAssets || underlyingAssets.length === 0) {
+ return new Set()
+ }
+ const normalized = underlyingAssets.map((asset) => normalizeUnderlyingAssetSymbol(asset)).filter(Boolean)
+ return new Set(normalized)
+ }, [underlyingAssets])
+ const expandedUnderlyingAssets = useMemo(
+ () => expandUnderlyingAssetSelection(normalizedUnderlyingAssets),
+ [normalizedUnderlyingAssets]
+ )
+
+ const checkHasHoldings = useMemo(
+ () => createCheckHasHoldings(getBalance, getPrice, shouldHideDust),
+ [getBalance, getPrice, shouldHideDust]
+ )
+
+ const checkHasAvailableBalance = useMemo(() => createCheckHasAvailableBalance(getBalance), [getBalance])
+
+ const vaultIndex = useDeepCompareMemo(() => {
+ if (!isEnabled) {
+ return new Map()
+ }
+ const vaultMap = new Map()
+
+ const upsertVault = (
+ vault: TYDaemonVault,
+ updates: Partial>
+ ): void => {
+ const key = getVaultKey(vault)
+ const existing = vaultMap.get(key)
+ if (existing) {
+ vaultMap.set(key, { ...existing, ...updates })
+ return
+ }
+
+ const kind = deriveListKind(vault)
+ vaultMap.set(key, {
+ key,
+ vault,
+ searchableText:
+ `${vault.name} ${vault.symbol} ${vault.token.name} ${vault.token.symbol} ${vault.address} ${vault.token.address}`.toLowerCase(),
+ kind,
+ category: deriveAssetCategory(vault),
+ aggressiveness: deriveV3Aggressiveness(vault),
+ isHidden: Boolean(vault.info?.isHidden),
+ isFeatured: Boolean(vault.info?.isHighlighted),
+ isActive: Boolean(updates.isActive),
+ isMigratable: Boolean(updates.isMigratable),
+ isRetired: Boolean(updates.isRetired)
+ })
+ }
+
+ Object.values(vaults).forEach((vault) => {
+ const isAllocatorOverride = isAllocatorVaultOverride(vault)
+ if (!shouldIncludeVaultByVersion(vault, version, isAllocatorOverride)) {
+ return
+ }
+ const isRetired = Boolean(vault.info?.isRetired)
+ upsertVault(vault, { isActive: !isRetired, isRetired, isMigratable: Boolean(vault.migration?.available) })
+ })
+
+ return vaultMap
+ }, [isEnabled, version, isEnabled ? vaults : null])
+
+ const walletFlags = useMemo(() => {
+ const flags = new Map()
+ vaultIndex.forEach((entry, key) => {
+ flags.set(key, {
+ hasHoldings: checkHasHoldings(entry.vault),
+ hasAvailableBalance: checkHasAvailableBalance(entry.vault)
+ })
+ })
+ return flags
+ }, [vaultIndex, checkHasHoldings, checkHasAvailableBalance])
+
+ const holdingsVaults = useMemo(() => {
+ return Array.from(vaultIndex.values())
+ .filter(({ key }) => walletFlags.get(key)?.hasHoldings)
+ .map(({ vault }) => vault)
+ }, [vaultIndex, walletFlags])
+
+ const availableVaults = useMemo(() => {
+ return Array.from(vaultIndex.values())
+ .filter(({ key, isActive }) => {
+ const flags = walletFlags.get(key)
+ return Boolean(flags?.hasAvailableBalance && (isActive || flags?.hasHoldings))
+ })
+ .map(({ vault }) => vault)
+ }, [vaultIndex, walletFlags])
+
+ const filteredResults = useMemo(() => {
+ const filteredVaults: TYDaemonVault[] = []
+ const vaultFlags: Record = {}
+
+ let totalMatchingVaults = 0
+ let totalHoldingsMatching = 0
+ let totalAvailableMatching = 0
+ let totalMigratableMatching = 0
+ let totalRetiredMatching = 0
+ const availableUnderlyingAssets = new Set()
+ const underlyingAssetVaults: Record = {}
+ const shouldShowHidden = Boolean(showHiddenVaults)
+ const hasChainFilter = Boolean(chains?.length)
+ const hasTypeFilter = Boolean(types?.length)
+ const hasCategoryFilter = Boolean(categories?.length)
+ const hasAggressivenessFilter = Boolean(aggressiveness?.length)
+ const hasUnderlyingAssetFilter = normalizedUnderlyingAssets.size > 0
+
+ const matchesSearch = (searchableText: string): boolean => {
+ if (!isSearchEnabled) {
+ return true
+ }
+ if (searchRegex) {
+ return searchRegex.test(searchableText)
+ }
+ return searchableText.includes(lowercaseSearch)
+ }
+
+ vaultIndex.forEach((entry) => {
+ const {
+ key,
+ vault,
+ searchableText,
+ kind,
+ category,
+ aggressiveness: aggressivenessScore,
+ isHidden,
+ isFeatured,
+ isActive,
+ isMigratable,
+ isRetired
+ } = entry
+ const walletFlag = walletFlags.get(key)
+ const hasHoldings = Boolean(walletFlag?.hasHoldings)
+ const hasAvailableBalance = Boolean(walletFlag?.hasAvailableBalance)
+
+ if (!isActive && !hasHoldings) {
+ return
+ }
+ if (!shouldShowHidden && isHidden) {
+ return
+ }
+
+ if (!matchesSearch(searchableText)) {
+ return
+ }
+
+ if (hasChainFilter && !chains?.includes(vault.chainID)) {
+ return
+ }
+
+ const vaultTvl = vault.tvl?.tvl || 0
+ if (vaultTvl < minTvlValue) {
+ return
+ }
+
+ const isMigratableVault = Boolean(isMigratable && hasHoldings)
+ const isRetiredVault = Boolean(isRetired && hasHoldings)
+ const hasUserHoldings = hasHoldings || isMigratableVault || isRetiredVault
+
+ vaultFlags[key] = {
+ hasHoldings: hasUserHoldings,
+ isMigratable: isMigratableVault,
+ isRetired: isRetiredVault,
+ isHidden
+ }
+
+ totalMatchingVaults++
+ if (hasUserHoldings) {
+ totalHoldingsMatching++
+ }
+ if (hasAvailableBalance) {
+ totalAvailableMatching++
+ }
+ if (isMigratableVault) {
+ totalMigratableMatching++
+ }
+ if (isRetiredVault) {
+ totalRetiredMatching++
+ }
+
+ const matchesKind = !hasTypeFilter || Boolean(types?.includes(kind))
+ const matchesCategory = !hasCategoryFilter || Boolean(categories?.includes(category))
+ const matchesAggressiveness =
+ !hasAggressivenessFilter ||
+ (aggressivenessScore !== null && Boolean(aggressiveness?.includes(aggressivenessScore)))
+
+ const isPinnedByUserContext = hasUserHoldings || isMigratableVault || isRetiredVault
+ const isStrategy = kind === 'strategy'
+ const shouldIncludeByFeaturedGate =
+ version !== 'v3' || shouldShowHidden || isStrategy || isFeatured || isPinnedByUserContext
+
+ const shouldIncludeByKind =
+ version !== 'v3'
+ ? matchesKind
+ : !hasTypeFilter ||
+ (Boolean(types?.includes('multi')) && kind === 'allocator') ||
+ (Boolean(types?.includes('single')) && kind === 'strategy')
+
+ if (shouldIncludeByFeaturedGate && shouldIncludeByKind && matchesCategory && matchesAggressiveness) {
+ const assetKey = normalizeUnderlyingAssetSymbol(vault.token?.symbol)
+ if (assetKey && !underlyingAssetVaults[assetKey]) {
+ availableUnderlyingAssets.add(assetKey)
+ underlyingAssetVaults[assetKey] = vault
+ } else if (assetKey) {
+ availableUnderlyingAssets.add(assetKey)
+ }
+
+ const matchesUnderlyingAsset = !hasUnderlyingAssetFilter || (assetKey && expandedUnderlyingAssets.has(assetKey))
+ if (!matchesUnderlyingAsset) {
+ return
+ }
+
+ filteredVaults.push(vault)
+ }
+ })
+
+ return {
+ filteredVaults,
+ vaultFlags,
+ availableUnderlyingAssets: Array.from(availableUnderlyingAssets),
+ underlyingAssetVaults,
+ totalMatchingVaults,
+ totalHoldingsMatching,
+ totalAvailableMatching,
+ totalMigratableMatching,
+ totalRetiredMatching
+ }
+ }, [
+ vaultIndex,
+ walletFlags,
+ types,
+ chains,
+ categories,
+ aggressiveness,
+ normalizedUnderlyingAssets,
+ expandedUnderlyingAssets,
+ minTvlValue,
+ searchRegex,
+ lowercaseSearch,
+ isSearchEnabled,
+ showHiddenVaults,
+ version
+ ])
+
+ return {
+ ...filteredResults,
+ holdingsVaults,
+ availableVaults,
+ isLoading: isEnabled ? isLoadingVaultList : false
+ }
+}
diff --git a/src/components/shared/hooks/useYearnBalance.ts b/src/components/shared/hooks/useYearnBalance.ts
deleted file mode 100644
index 0bdf39d87..000000000
--- a/src/components/shared/hooks/useYearnBalance.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import type { TAddress, TDict, TNormalizedBN } from '@shared/types'
-import { toAddress } from '@shared/utils'
-import { useWallet } from '../contexts/useWallet'
-
-/******************************************************************************
- ** The useYearnBalance hook is used to retrieve the balance of a token from
- ** the useYearn context.
- *****************************************************************************/
-export function useYearnBalance({
- address,
- chainID
-}: {
- address: string | TAddress
- chainID: number
- source?: TDict
-}): TNormalizedBN {
- const { getBalance } = useWallet()
-
- return getBalance({ address: toAddress(address), chainID: chainID })
-}
diff --git a/src/components/shared/hooks/useYearnToken.ts b/src/components/shared/hooks/useYearnToken.ts
deleted file mode 100644
index 7fc4b0876..000000000
--- a/src/components/shared/hooks/useYearnToken.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { TAddress, TToken } from '@shared/types'
-import { toAddress } from '@shared/utils'
-import { useMemo } from 'react'
-import { useWallet } from '../contexts/useWallet'
-
-/******************************************************************************
- ** The useYearnToken hook is used to retrieve the token from the useWallet
- ** context. The token is returned as a TToken.
- *****************************************************************************/
-export function useYearnToken({ address, chainID }: { address: string | TAddress; chainID: number }): TToken {
- const { getToken } = useWallet()
-
- const balance = useMemo((): TToken => {
- return getToken({ address: toAddress(address), chainID: chainID })
- }, [getToken, address, chainID])
-
- return balance
-}
diff --git a/src/components/shared/types/optionalRenderProps.ts b/src/components/shared/types/optionalRenderProps.ts
deleted file mode 100644
index aa9ab0781..000000000
--- a/src/components/shared/types/optionalRenderProps.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { ReactNode } from 'react'
-
-export type TOptionalRenderProps = TChildren | ((renderProps: TProps) => TChildren)
-
-export const optionalRenderProps = (children: TOptionalRenderProps, renderProps: TProps): ReactNode =>
- typeof children === 'function' ? children(renderProps) : children
diff --git a/src/components/shared/utils/animations.ts b/src/components/shared/utils/animations.ts
deleted file mode 100644
index 9493544fe..000000000
--- a/src/components/shared/utils/animations.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Transition, Variants } from 'framer-motion'
-
-export const transition: Transition = { duration: 0.1, ease: 'easeInOut' }
-
-export const variants: Variants = {
- initial: { y: 0, opacity: 0, transition },
- enter: { y: 0, opacity: 1, transition },
- exit: { y: 0, opacity: 0, transition }
-}
-
-export const TABS_VARIANTS: Variants = {
- initial: { y: 0, opacity: 0, transition },
- enter: { y: 0, opacity: 1, transition },
- exit: { y: 0, opacity: 0, transition }
-}
diff --git a/src/components/shared/utils/calculations.ts b/src/components/shared/utils/calculations.ts
deleted file mode 100644
index 2ae76e25e..000000000
--- a/src/components/shared/utils/calculations.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/************************************************************************************************
- * Calculate boost based on veYFI amount, total deposits, and current deposit amount
- * Handles bigint values properly by converting to numbers for ratio calculation
- ************************************************************************************************/
-export function calculateBoostFromVeYFI(
- veYFIAmount: number,
- veYFITotalSupply: number,
- totalDeposited: number,
- depositAmount: number
-): number {
- const veRatio = veYFITotalSupply ? veYFIAmount / veYFITotalSupply : 0
- const boost = depositAmount ? 1 + veRatio * 9 + (totalDeposited * veRatio * 9) / depositAmount : 1
- return Math.min(boost, 10)
-}
diff --git a/src/components/shared/utils/opacity.ts b/src/components/shared/utils/opacity.ts
deleted file mode 100644
index 4e69a8cee..000000000
--- a/src/components/shared/utils/opacity.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * Converts a number between 0 and 1 to a hex string representing the opacity.
- *
- * @param opacity - A number between 0 and 1 representing the opacity.
- * @returns A string representing the opacity in hex format.
- */
-export const opacityToHex = (opacity: number): string => {
- const alpha = Math.round(opacity * 255)
- return alpha.toString(16).padStart(2, '0').toUpperCase()
-}
diff --git a/src/components/shared/utils/schemas/coinGeckoSchemas.ts b/src/components/shared/utils/schemas/coinGeckoSchemas.ts
deleted file mode 100644
index 1d5dfb169..000000000
--- a/src/components/shared/utils/schemas/coinGeckoSchemas.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as z from 'zod'
-
-export const coinGeckoPricesSchema = z.record(z.string(), z.object({ usd: z.number() }))
-
-export type TCoinGeckoPrices = z.infer
diff --git a/src/components/shared/utils/schemas/curveSchemas.ts b/src/components/shared/utils/schemas/curveSchemas.ts
deleted file mode 100644
index 28457ce6c..000000000
--- a/src/components/shared/utils/schemas/curveSchemas.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import * as z from 'zod'
-
-import { toAddress } from '../'
-
-export const curveWeeklyFeesSchema = z.object({
- success: z.boolean().optional(),
- data: z.object({
- weeklyFeesTable: z
- .object({
- date: z.string(),
- ts: z.number(),
- rawFees: z.number()
- })
- .array()
- .optional()
- .nullable(),
- totalFees: z.object({
- fees: z.number()
- })
- }),
- generatedTimeMs: z.number().optional()
-})
-
-const curveGaugeSchema = z.object({
- poolUrls: z
- .object({
- swap: z.string().array().optional().nullable(),
- deposit: z.string().array().optional().nullable(),
- withdraw: z.string().array().optional().nullable()
- })
- .optional(),
- swap: z.string().optional().transform(toAddress),
- swap_token: z.string().optional().transform(toAddress),
- name: z.string(),
- shortName: z.string().optional(),
- gauge: z.string().optional().transform(toAddress),
- swap_data: z.object({ virtual_price: z.string().or(z.number().optional()) }).optional(),
- gauge_data: z
- .object({
- inflation_rate: z.number().or(z.string()).optional().default('0'),
- working_supply: z.string().optional()
- })
- .optional(),
- gauge_controller: z
- .object({
- gauge_relative_weight: z.string().optional(),
- get_gauge_weight: z.string().optional(),
- inflation_rate: z.number().or(z.string()).optional().default('0')
- })
- .optional(),
- factory: z.boolean(),
- side_chain: z.boolean().optional(),
- is_killed: z.boolean().optional(),
- hasNoCrv: z.boolean().optional(),
- type: z.string().optional(),
- lpTokenPrice: z.number().nullable().optional(),
- rewardPerGauge: z.string().array().optional()
-})
-
-export const curveAllGaugesSchema = z.object({
- success: z.boolean().optional(),
- data: z.record(z.string(), curveGaugeSchema),
- generatedTimeMs: z.number().optional()
-})
-
-export const curveGaugeFromYearnSchema = z.object({
- gauge_name: z.string(),
- gauge_address: z.string().optional().transform(toAddress),
- pool_address: z.string().optional().transform(toAddress),
- pool_coins: z
- .object({
- name: z.string().optional(),
- address: z.string().transform(toAddress),
- error: z.string().optional()
- })
- .array()
- .optional(),
- lp_token: z.string().optional().transform(toAddress),
- weight: z.string().optional().default('0'),
- inflation_rate: z.string().or(z.number()).optional().default('0'),
- working_supply: z.string().default('0'),
- apy: z.object({
- type: z.string(),
- gross_apr: z.number().default(0),
- net_apy: z.number().default(0)
- })
-})
-
-export const curveGaugesFromYearnSchema = curveGaugeFromYearnSchema.array()
-
-export type TCurveWeeklyFees = z.infer
-export type TCurveGauge = z.infer
-export type TCurveAllGauges = z.infer
-export type TCurveGaugeFromYearn = z.infer
-export type TCurveGaugesFromYearn = z.infer
diff --git a/src/components/shared/utils/schemas/yDaemonGaugeRewardsFeedSchema.ts b/src/components/shared/utils/schemas/yDaemonGaugeRewardsFeedSchema.ts
deleted file mode 100644
index d4e691fc4..000000000
--- a/src/components/shared/utils/schemas/yDaemonGaugeRewardsFeedSchema.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as z from 'zod'
-
-import { addressSchema } from '../../types'
-
-export const yDaemonGaugeRewardSchema = z.object({
- amount: z.string(),
- briber: addressSchema,
- gauge: addressSchema,
- rewardToken: addressSchema,
- txHash: z.string(),
- timestamp: z.number(),
- blockNumber: z.number()
-})
-
-export const yDaemonGaugeRewardsFeedSchema = z.array(yDaemonGaugeRewardSchema)
-
-export type TYDaemonGaugeReward = z.infer
-
-export type TYDaemonGaugeRewardsFeed = z.infer
diff --git a/src/components/shared/utils/schemas/yDaemonTokensSchema.ts b/src/components/shared/utils/schemas/yDaemonTokensSchema.ts
deleted file mode 100644
index 6f0170f7b..000000000
--- a/src/components/shared/utils/schemas/yDaemonTokensSchema.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import * as z from 'zod'
-
-import { addressSchema } from '../../types'
-
-export const yDaemonTokenSchema = z.object({
- address: addressSchema,
- name: z.string(),
- symbol: z.string(),
- decimals: z.number(),
- isVault: z.boolean(),
- underlyingTokens: z.array(addressSchema).optional(),
- chainID: z.number().optional()
-})
-
-export const yDaemonTokensSchema = z.record(addressSchema, yDaemonTokenSchema)
-export const yDaemonTokensChainSchema = z.record(z.string(), yDaemonTokensSchema)
-
-export type TYDaemonToken = z.infer
-export type TYDaemonTokens = z.infer
-export type TYDaemonTokensChain = z.infer
diff --git a/src/components/shared/utils/tools.identifier.ts b/src/components/shared/utils/tools.identifier.ts
deleted file mode 100644
index a206a94cf..000000000
--- a/src/components/shared/utils/tools.identifier.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import XXH from 'xxhashjs'
-
-export function createUniqueID(msg: string): string {
- const hash = XXH.h32(0x536d6f6c).update(msg).digest().toString(16)
- return hash
-}
diff --git a/src/components/shared/utils/wagmi/ethersAdapter.ts b/src/components/shared/utils/wagmi/ethersAdapter.ts
deleted file mode 100644
index d820d0ed9..000000000
--- a/src/components/shared/utils/wagmi/ethersAdapter.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { providers } from 'ethers'
-import { useMemo } from 'react'
-import type { Account, Chain, Client, Transport } from 'viem'
-import { type Config, useConnectorClient } from 'wagmi'
-import { getClient, getConnectorClient } from 'wagmi/actions'
-
-export function clientToProvider(
- client: Client
-): providers.JsonRpcProvider | providers.FallbackProvider {
- const { chain, transport } = client
- const network = {
- chainId: chain.id,
- name: chain.name,
- ensAddress: chain.contracts?.ensRegistry?.address
- }
- if (transport.type === 'fallback') {
- return new providers.FallbackProvider(
- (transport.transports as ReturnType[]).map(
- ({ value }) => new providers.JsonRpcProvider(value?.url, network)
- )
- )
- }
- return new providers.JsonRpcProvider(transport.url, network)
-}
-
-/** Action to convert a viem Public Client to an ethers.js Provider. */
-export function getEthersProvider(
- config: Config,
- { chainId }: { chainId?: number } = {}
-): providers.JsonRpcProvider | providers.FallbackProvider {
- const client = getClient(config, { chainId })
- return clientToProvider(client as Client)
-}
-
-export function clientToSigner(client: Client): providers.JsonRpcSigner {
- const { account, chain, transport } = client
- const network = {
- chainId: chain.id,
- name: chain.name,
- ensAddress: chain.contracts?.ensRegistry?.address
- }
- const provider = new providers.Web3Provider(transport, network)
- const signer = provider.getSigner(account.address)
- return signer
-}
-
-export async function getEthersSigner(
- config: Config,
- { chainId }: { chainId?: number } = {}
-): Promise {
- const client = await getConnectorClient(config, { chainId })
- return clientToSigner(client)
-}
-
-/** Hook to convert a Viem Client to an ethers.js Signer. */
-export async function useEthersSigner({
- chainId
-}: {
- chainId?: number
-} = {}): Promise {
- const { data: client } = useConnectorClient({ chainId })
- return useMemo(() => (client ? clientToSigner(client) : undefined), [client])
-}
diff --git a/src/hooks/useScrollDirection.ts b/src/hooks/useScrollDirection.ts
deleted file mode 100644
index 844d3de9e..000000000
--- a/src/hooks/useScrollDirection.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import { useEffect, useRef, useState } from 'react'
-
-export type TScrollDirection = 'up' | 'down' | null
-
-type UseScrollDirectionOptions = {
- threshold?: number
- topThreshold?: number
-}
-
-export function useScrollDirection(options: UseScrollDirectionOptions = {}): TScrollDirection {
- const { threshold = 10, topThreshold = 50 } = options
- const [direction, setDirection] = useState(null)
- const lastScrollY = useRef(0)
- const accumulatedDelta = useRef(0)
-
- useEffect(() => {
- if (typeof window === 'undefined') return
-
- let rafId = 0
-
- const updateDirection = (): void => {
- const scrollY = window.scrollY
-
- // Always show buttons when at top of page
- if (scrollY <= topThreshold) {
- setDirection(null)
- lastScrollY.current = scrollY
- accumulatedDelta.current = 0
- return
- }
-
- const delta = scrollY - lastScrollY.current
-
- // Accumulate scroll delta in the same direction
- if ((delta > 0 && accumulatedDelta.current >= 0) || (delta < 0 && accumulatedDelta.current <= 0)) {
- accumulatedDelta.current += delta
- } else {
- // Direction changed, reset accumulator
- accumulatedDelta.current = delta
- }
-
- // Only change direction when threshold is exceeded
- if (accumulatedDelta.current > threshold) {
- setDirection('down')
- accumulatedDelta.current = 0
- } else if (accumulatedDelta.current < -threshold) {
- setDirection('up')
- accumulatedDelta.current = 0
- }
-
- lastScrollY.current = scrollY
- }
-
- const onScroll = (): void => {
- cancelAnimationFrame(rafId)
- rafId = window.requestAnimationFrame(updateDirection)
- }
-
- lastScrollY.current = window.scrollY
- window.addEventListener('scroll', onScroll, { passive: true })
-
- return (): void => {
- cancelAnimationFrame(rafId)
- window.removeEventListener('scroll', onScroll)
- }
- }, [threshold, topThreshold])
-
- return direction
-}
diff --git a/src/types/router.ts b/src/types/router.ts
deleted file mode 100644
index 86d0aa286..000000000
--- a/src/types/router.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export interface RouterType {
- pathname: string
- asPath: string
- query: Record
- replace: (url: any, as?: string, options?: any) => Promise
- push: (url: any, as?: string, options?: any) => Promise
- back: () => void
-}
diff --git a/vite.config.ts b/vite.config.ts
index 2c2ce399e..8ec33d3b6 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -82,9 +82,7 @@ export default defineConfig({
'@pages': path.resolve(__dirname, './src/components/pages'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
- '@safe-global/safe-apps-sdk': path.resolve(__dirname, 'node_modules/@safe-global/safe-apps-sdk/dist/esm'),
- // Polyfill node-fetch for browser
- 'node-fetch': 'cross-fetch'
+ '@safe-global/safe-apps-sdk': path.resolve(__dirname, 'node_modules/@safe-global/safe-apps-sdk/dist/esm')
}
},
define: {
@@ -130,9 +128,7 @@ export default defineConfig({
'@tanstack/react-query',
'recharts',
'framer-motion',
- '@react-hookz/web',
- '@cowprotocol/cow-sdk',
- 'cross-fetch'
+ '@react-hookz/web'
],
esbuildOptions: {
define: {
From 223ff7efcaae396b5f50c231fbe93559e4fa91f4 Mon Sep 17 00:00:00 2001
From: rossgalloway <58150151+rossgalloway@users.noreply.github.com>
Date: Tue, 10 Feb 2026 11:25:33 -0500
Subject: [PATCH 03/11] feat: add automatic deposit pop-up (#1061)
* Fix: incorrect route error on factory vault deposit (#1055)
* fix error with factory vault showing unavailable route on deposit
* fix issue in review
---------
Co-authored-by: Ross
* add automatic deposit pop-up
---------
Co-authored-by: Ross
---
.../pages/vaults/[chainID]/[address].tsx | 12 ++++-
.../components/widget/deposit/index.tsx | 3 ++
.../widget/deposit/useDepositError.ts | 6 ++-
.../components/widget/migrate/index.tsx | 2 +
.../widget/shared/TransactionOverlay.tsx | 45 ++++++++++++++++---
.../components/widget/withdraw/index.tsx | 2 +
6 files changed, 62 insertions(+), 8 deletions(-)
diff --git a/src/components/pages/vaults/[chainID]/[address].tsx b/src/components/pages/vaults/[chainID]/[address].tsx
index de37c405c..d7fb351c7 100644
--- a/src/components/pages/vaults/[chainID]/[address].tsx
+++ b/src/components/pages/vaults/[chainID]/[address].tsx
@@ -266,9 +266,19 @@ function Index(): ReactElement | null {
address: params.address
})
const isSnapshotNotFound = (snapshotError as any)?.response?.status === 404
- const shouldDisableStakingForDeposit = Boolean(snapshotVault?.meta?.shouldDisableStaking)
const baseMergedVault = useMemo(() => mergeVaultSnapshot(baseVault, snapshotVault), [baseVault, snapshotVault])
+ const isFactoryVault = useMemo(() => {
+ if (!baseMergedVault) return false
+ return deriveListKind(baseMergedVault) === 'factory'
+ }, [baseMergedVault])
+ const snapshotShouldDisableStaking = snapshotVault?.meta?.shouldDisableStaking
+ const shouldDisableStakingForDeposit = useMemo(() => {
+ if (isFactoryVault) {
+ return true
+ }
+ return snapshotShouldDisableStaking === true
+ }, [snapshotShouldDisableStaking, isFactoryVault])
const isYBold = useMemo(() => {
if (!baseMergedVault?.address && !params.address) return false
diff --git a/src/components/pages/vaults/components/widget/deposit/index.tsx b/src/components/pages/vaults/components/widget/deposit/index.tsx
index ada63d6ec..eea114e22 100644
--- a/src/components/pages/vaults/components/widget/deposit/index.tsx
+++ b/src/components/pages/vaults/components/widget/deposit/index.tsx
@@ -183,6 +183,7 @@ export const WidgetDeposit: FC = ({
account,
isLoadingRoute: activeFlow.periphery.isLoadingRoute,
flowError: activeFlow.periphery.error,
+ routeType,
selectedToken,
vaultAddress,
isAutoStakingEnabled
@@ -558,6 +559,8 @@ export const WidgetDeposit: FC = ({
onClose={() => setShowTransactionOverlay(false)}
step={currentStep}
isLastStep={!needsApproval}
+ autoContinueToNextStep
+ autoContinueStepLabels={['Approve', 'Sign Permit']}
onAllComplete={handleDepositSuccess}
/>
diff --git a/src/components/pages/vaults/components/widget/deposit/useDepositError.ts b/src/components/pages/vaults/components/widget/deposit/useDepositError.ts
index cfcb360f9..7b23fcd03 100644
--- a/src/components/pages/vaults/components/widget/deposit/useDepositError.ts
+++ b/src/components/pages/vaults/components/widget/deposit/useDepositError.ts
@@ -1,5 +1,6 @@
import { useMemo } from 'react'
import type { Address } from 'viem'
+import type { DepositRouteType } from './types'
interface UseDepositErrorProps {
// Amount state
@@ -13,6 +14,7 @@ interface UseDepositErrorProps {
// Flow state
isLoadingRoute: boolean
flowError?: unknown
+ routeType: DepositRouteType
// Settings
selectedToken?: Address
vaultAddress: Address
@@ -27,6 +29,7 @@ export const useDepositError = ({
account,
isLoadingRoute,
flowError,
+ routeType,
selectedToken,
vaultAddress,
isAutoStakingEnabled
@@ -43,7 +46,7 @@ export const useDepositError = ({
}
// Route-dependent validation - wait for debounce and route fetch
- if (flowError && !isLoadingRoute && debouncedAmount > 0n && !isDebouncing) {
+ if (routeType === 'ENSO' && flowError && !isLoadingRoute && debouncedAmount > 0n && !isDebouncing) {
return 'Unable to find route'
}
@@ -56,6 +59,7 @@ export const useDepositError = ({
account,
isLoadingRoute,
flowError,
+ routeType,
selectedToken,
vaultAddress,
isAutoStakingEnabled
diff --git a/src/components/pages/vaults/components/widget/migrate/index.tsx b/src/components/pages/vaults/components/widget/migrate/index.tsx
index 94f98eb3e..a7d99f8d4 100644
--- a/src/components/pages/vaults/components/widget/migrate/index.tsx
+++ b/src/components/pages/vaults/components/widget/migrate/index.tsx
@@ -507,6 +507,8 @@ export const WidgetMigrate: FC = ({
onClose={handleOverlayClose}
step={currentStep}
isLastStep={isLastStep}
+ autoContinueToNextStep
+ autoContinueStepLabels={['Approve', 'Sign Permit']}
onAllComplete={handleMigrateSuccess}
/>
diff --git a/src/components/pages/vaults/components/widget/shared/TransactionOverlay.tsx b/src/components/pages/vaults/components/widget/shared/TransactionOverlay.tsx
index f800ac5b9..157adddfe 100644
--- a/src/components/pages/vaults/components/widget/shared/TransactionOverlay.tsx
+++ b/src/components/pages/vaults/components/widget/shared/TransactionOverlay.tsx
@@ -85,6 +85,8 @@ type TransactionOverlayProps = {
onAllComplete?: () => void
topOffset?: string
contentAlign?: 'center' | 'start'
+ autoContinueToNextStep?: boolean
+ autoContinueStepLabels?: string[]
}
export const TransactionOverlay: FC = ({
@@ -93,7 +95,9 @@ export const TransactionOverlay: FC = ({
step,
isLastStep = true,
onAllComplete,
- contentAlign = 'center'
+ contentAlign = 'center',
+ autoContinueToNextStep = false,
+ autoContinueStepLabels = []
}) => {
const [overlayState, setOverlayState] = useState('success')
const [errorMessage, setErrorMessage] = useState('')
@@ -141,6 +145,7 @@ export const TransactionOverlay: FC = ({
// Track if we've started execution to prevent re-triggering
const hasStartedRef = useRef(false)
+ const hasAutoContinuedFromStepRef = useRef(null)
// Reset state when overlay closes
useEffect(() => {
@@ -149,6 +154,7 @@ export const TransactionOverlay: FC = ({
setErrorMessage('')
setEnsoTxHash(undefined)
hasStartedRef.current = false
+ hasAutoContinuedFromStepRef.current = null
executedStepRef.current = null
wasLastStepRef.current = false
setNotificationId(undefined)
@@ -195,6 +201,7 @@ export const TransactionOverlay: FC = ({
},
[notificationId, updateNotification]
)
+
const executeStep = useCallback(async () => {
if (!step) {
console.warn('[TransactionOverlay] Execute called without step')
@@ -375,6 +382,13 @@ export const TransactionOverlay: FC = ({
onAllComplete
])
+ const advanceToNextStep = useCallback(() => {
+ // Reset for next step - parent will provide the new step
+ writeContract.reset()
+ setEnsoTxHash(undefined)
+ executeStep()
+ }, [writeContract, executeStep])
+
useEffect(() => {
if (step?.prepare.isError) {
console.error('[TransactionOverlay] Prepare failed', getStepDebugInfo(step))
@@ -385,12 +399,9 @@ export const TransactionOverlay: FC = ({
if (wasLastStepRef.current) {
onClose()
} else {
- // Reset for next step - parent will provide the new step
- writeContract.reset()
- setEnsoTxHash(undefined)
- executeStep()
+ advanceToNextStep()
}
- }, [onClose, writeContract, executeStep])
+ }, [onClose, advanceToNextStep])
const handleRetry = useCallback(() => {
writeContract.reset()
@@ -402,6 +413,28 @@ export const TransactionOverlay: FC = ({
onClose()
}, [onClose])
+ useEffect(() => {
+ if (!isOpen || overlayState !== 'success') return
+ if (!autoContinueToNextStep || wasLastStepRef.current || !isStepReady) return
+
+ const executedStepLabel = executedStepRef.current?.label
+ if (!executedStepLabel) return
+ if (!step?.label || step.label === executedStepLabel) return
+ if (autoContinueStepLabels.length > 0 && !autoContinueStepLabels.includes(executedStepLabel)) return
+ if (hasAutoContinuedFromStepRef.current === executedStepLabel) return
+
+ hasAutoContinuedFromStepRef.current = executedStepLabel
+ advanceToNextStep()
+ }, [
+ isOpen,
+ overlayState,
+ autoContinueToNextStep,
+ autoContinueStepLabels,
+ isStepReady,
+ step?.label,
+ advanceToNextStep
+ ])
+
// Start step when overlay opens
useEffect(() => {
if (isOpen && overlayState === 'idle' && step && !hasStartedRef.current) {
diff --git a/src/components/pages/vaults/components/widget/withdraw/index.tsx b/src/components/pages/vaults/components/widget/withdraw/index.tsx
index 7470c3fb0..c3984111e 100644
--- a/src/components/pages/vaults/components/widget/withdraw/index.tsx
+++ b/src/components/pages/vaults/components/widget/withdraw/index.tsx
@@ -594,6 +594,8 @@ export const WidgetWithdraw: FC<
onClose={() => setShowTransactionOverlay(false)}
step={currentStep}
isLastStep={!needsApproval}
+ autoContinueToNextStep
+ autoContinueStepLabels={['Approve', 'Sign Permit']}
onAllComplete={handleWithdrawSuccess}
/>
From 2cdc7cc1b973a65c3542ccb222933f0a156f0c7b Mon Sep 17 00:00:00 2001
From: Ross
Date: Tue, 10 Feb 2026 17:36:40 -0500
Subject: [PATCH 04/11] migrate yearnx pages
---
bun.lock | 1 +
public/partner-aerodrome.png | Bin 0 -> 168853 bytes
public/partner-curve.png | Bin 0 -> 151626 bytes
public/partner-katana.png | Bin 0 -> 283229 bytes
public/partner-morpho.png | Bin 0 -> 189565 bytes
public/partner-pooltogether.png | Bin 0 -> 148833 bytes
public/partner-velodrome.png | Bin 0 -> 218974 bytes
src/App.tsx | 14 +-
src/components/pages/aerodrome/index.tsx | 6 +
src/components/pages/curve/index.tsx | 6 +
src/components/pages/katana/index.tsx | 6 +
.../landing/components/sections/Partners.tsx | 19 +-
src/components/pages/morpho/index.tsx | 6 +
src/components/pages/partners/index.tsx | 109 +++++++++
src/components/pages/pooltogether/index.tsx | 6 +
.../components/filters/VaultsFiltersBar.tsx | 32 ++-
.../pages/vaults/hooks/useVaultsListModel.ts | 12 +-
.../pages/vaults/hooks/useVaultsPageModel.ts | 208 +++++++++++++-----
src/components/pages/vaults/index.tsx | 125 +++++++++--
src/components/pages/velodrome/index.tsx | 6 +
.../shared/components/AccountDropdown.tsx | 2 +-
.../shared/components/HeaderNavMenu.tsx | 5 +-
src/components/shared/components/Meta.tsx | 2 +
.../shared/components/MobileNavMenu.tsx | 5 +-
src/components/shared/contexts/useYearn.tsx | 12 +-
src/components/shared/hooks/useCurrentApp.tsx | 24 ++
.../shared/hooks/useFetchYearnVaults.ts | 14 +-
.../shared/partners/configs/aerodrome.ts | 24 ++
.../shared/partners/configs/curve.ts | 24 ++
.../shared/partners/configs/katana.ts | 24 ++
.../shared/partners/configs/morpho.ts | 24 ++
.../shared/partners/configs/pooltogether.ts | 24 ++
.../shared/partners/configs/velodrome.ts | 24 ++
.../partners/isAerodromeVaultListItem.ts | 5 +
.../shared/partners/isCurveVaultListItem.ts | 5 +
.../partners/isKatanaVaultListItem.test.ts | 20 ++
.../shared/partners/isKatanaVaultListItem.ts | 21 ++
.../shared/partners/isMorphoVaultListItem.ts | 5 +
.../partners/isPoolTogetherVaultListItem.ts | 5 +
.../partners/isVelodromeVaultListItem.ts | 5 +
.../shared/partners/partnerFilterUtils.ts | 28 +++
.../partners/partnerVaultFilters.test.ts | 40 ++++
src/components/shared/partners/registry.ts | 33 +++
.../partners/resolvePartnerFromPath.test.ts | 23 ++
.../shared/partners/resolvePartnerFromPath.ts | 12 +
src/components/shared/partners/types.ts | 26 +++
src/routes.tsx | 18 ++
src/styles/partners.css | 85 +++++++
style.css | 2 +
49 files changed, 988 insertions(+), 109 deletions(-)
create mode 100644 public/partner-aerodrome.png
create mode 100644 public/partner-curve.png
create mode 100644 public/partner-katana.png
create mode 100644 public/partner-morpho.png
create mode 100644 public/partner-pooltogether.png
create mode 100644 public/partner-velodrome.png
create mode 100644 src/components/pages/aerodrome/index.tsx
create mode 100644 src/components/pages/curve/index.tsx
create mode 100644 src/components/pages/katana/index.tsx
create mode 100644 src/components/pages/morpho/index.tsx
create mode 100644 src/components/pages/partners/index.tsx
create mode 100644 src/components/pages/pooltogether/index.tsx
create mode 100644 src/components/pages/velodrome/index.tsx
create mode 100644 src/components/shared/partners/configs/aerodrome.ts
create mode 100644 src/components/shared/partners/configs/curve.ts
create mode 100644 src/components/shared/partners/configs/katana.ts
create mode 100644 src/components/shared/partners/configs/morpho.ts
create mode 100644 src/components/shared/partners/configs/pooltogether.ts
create mode 100644 src/components/shared/partners/configs/velodrome.ts
create mode 100644 src/components/shared/partners/isAerodromeVaultListItem.ts
create mode 100644 src/components/shared/partners/isCurveVaultListItem.ts
create mode 100644 src/components/shared/partners/isKatanaVaultListItem.test.ts
create mode 100644 src/components/shared/partners/isKatanaVaultListItem.ts
create mode 100644 src/components/shared/partners/isMorphoVaultListItem.ts
create mode 100644 src/components/shared/partners/isPoolTogetherVaultListItem.ts
create mode 100644 src/components/shared/partners/isVelodromeVaultListItem.ts
create mode 100644 src/components/shared/partners/partnerFilterUtils.ts
create mode 100644 src/components/shared/partners/partnerVaultFilters.test.ts
create mode 100644 src/components/shared/partners/registry.ts
create mode 100644 src/components/shared/partners/resolvePartnerFromPath.test.ts
create mode 100644 src/components/shared/partners/resolvePartnerFromPath.ts
create mode 100644 src/components/shared/partners/types.ts
create mode 100644 src/styles/partners.css
diff --git a/bun.lock b/bun.lock
index ea04d2b20..f54abeec6 100644
--- a/bun.lock
+++ b/bun.lock
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
+ "configVersion": 0,
"workspaces": {
"": {
"name": "yearnfi",
diff --git a/public/partner-aerodrome.png b/public/partner-aerodrome.png
new file mode 100644
index 0000000000000000000000000000000000000000..a33798aaf41417184712c2598de27effce1af0e9
GIT binary patch
literal 168853
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