From c58138cd2cfab844e26e49d6226c1fbe8a7ad3bb Mon Sep 17 00:00:00 2001 From: Chid Gilovitz Date: Wed, 11 Dec 2024 13:49:26 +0800 Subject: [PATCH 01/11] fix: potential memory leak (#1739) --- apps/extension/src/ui/api/api.ts | 2 +- apps/extension/src/ui/api/types.ts | 2 +- .../Settings/ChangePasswordPage/index.tsx | 29 ++++++++++++------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/apps/extension/src/ui/api/api.ts b/apps/extension/src/ui/api/api.ts index 69ab527796..9b43d51860 100644 --- a/apps/extension/src/ui/api/api.ts +++ b/apps/extension/src/ui/api/api.ts @@ -19,7 +19,7 @@ export const api: MessageTypes = { changePassword: (currentPw, newPw, newPwConfirm) => messageService.sendMessage("pri(app.changePassword)", { currentPw, newPw, newPwConfirm }), changePasswordSubscribe: (currentPw, newPw, newPwConfirm, cb) => - messageService.sendMessage( + messageService.subscribe( "pri(app.changePassword.subscribe)", { currentPw, newPw, newPwConfirm }, cb, diff --git a/apps/extension/src/ui/api/types.ts b/apps/extension/src/ui/api/types.ts index 0270240bf4..b35d35cced 100644 --- a/apps/extension/src/ui/api/types.ts +++ b/apps/extension/src/ui/api/types.ts @@ -83,7 +83,7 @@ export default interface MessageTypes { newPw: string, newPwConfirm: string, cb: (val: ChangePasswordStatusUpdate) => void, - ) => Promise + ) => UnsubscribeFn checkPassword: (password: string) => Promise authStatus: () => Promise authStatusSubscribe: (cb: (val: LoggedinType) => void) => UnsubscribeFn diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/ChangePasswordPage/index.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/ChangePasswordPage/index.tsx index b62ad36cae..114e6dd312 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/ChangePasswordPage/index.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/ChangePasswordPage/index.tsx @@ -92,17 +92,24 @@ const Content = () => { const subscribeChangePassword = useCallback( async ({ currentPw, newPw, newPwConfirm }: FormData) => { // sets up a custom promise, resolving when the password change is done or there is an error - return await new Promise((resolve, reject) => - api.changePasswordSubscribe(currentPw, newPw, newPwConfirm, ({ status, message }) => { - setProgress(status) - if (status === ChangePasswordStatusUpdateStatus.ERROR) { - reject(new Error(message)) - } - if (status === ChangePasswordStatusUpdateStatus.DONE) { - resolve() - } - }), - ).catch((err) => { + return await new Promise((resolve, reject) => { + const unsub = api.changePasswordSubscribe( + currentPw, + newPw, + newPwConfirm, + ({ status, message }) => { + setProgress(status) + if (status === ChangePasswordStatusUpdateStatus.ERROR) { + unsub() + reject(new Error(message)) + } + if (status === ChangePasswordStatusUpdateStatus.DONE) { + unsub() + resolve() + } + }, + ) + }).catch((err) => { switch (err.message) { case "Incorrect password": setError("currentPw", { message: err.message }) From 799ca1051e79d28ea89e7401e4aac1a6de90c3be Mon Sep 17 00:00:00 2001 From: Alec WM Date: Wed, 11 Dec 2024 17:09:59 +1100 Subject: [PATCH 02/11] fix: rename (Substrate) to (Polkadot) in network details (#1737) --- apps/extension/src/ui/domains/SendFunds/useNetworkDetails.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/extension/src/ui/domains/SendFunds/useNetworkDetails.ts b/apps/extension/src/ui/domains/SendFunds/useNetworkDetails.ts index 48cfb933db..a30effee7a 100644 --- a/apps/extension/src/ui/domains/SendFunds/useNetworkDetails.ts +++ b/apps/extension/src/ui/domains/SendFunds/useNetworkDetails.ts @@ -9,7 +9,7 @@ import { useSendFunds } from "./useSendFunds" * @returns A function that formats a network name for display. * @description * For networks which have both a Substrate and Ethereum chain, the network name will be formatted as: - * Network Name (Substrate) or Network Name (Ethereum) + * Network Name (Polkadot) or Network Name (Ethereum) * * For networks which have only a Substrate or Ethereum chain, the network name will be formatted as: * Network Name @@ -20,7 +20,7 @@ export const useFormatNetworkName = () => { return useCallback( (chain?: Chain | CustomChain | null, evmNetwork?: EvmNetwork | CustomEvmNetwork | null) => chain?.name - ? `${chain.name}${chain.evmNetworks?.length > 0 ? ` (${t("Substrate")})` : ""}` + ? `${chain.name}${chain.evmNetworks?.length > 0 ? ` (${t("Polkadot")})` : ""}` : evmNetwork ? `${evmNetwork?.name}${evmNetwork?.substrateChain ? ` (${t("Ethereum")})` : ""}` : `${t("Chain")} ${(chain ?? evmNetwork)?.id}`, From 32167b2cae96d5ec55c88a692134b9a819925efb Mon Sep 17 00:00:00 2001 From: Kheops <26880866+0xKheops@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:33:05 +0900 Subject: [PATCH 03/11] fix: use scale api only for bittensor balance rows (#1740) * fix: use scale api only for bittensor balance rows * refactor: move check for bittensor chain inside hook logic * chore: amend last * chore: amend last --------- Co-authored-by: Chid Gilovitz --- apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts | 5 +---- .../Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts | 3 ++- apps/extension/src/ui/hooks/sapi/useScaleApi.ts | 5 +++++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts b/apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts index 22a8410809..e69de55c5b 100644 --- a/apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts +++ b/apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts @@ -38,10 +38,7 @@ export const useBondButton = ({ const address = sorted[0]?.address - const { data: hotkeys } = useGetBittensorStakeHotkeys({ - chainId: token?.chain?.id, - address, - }) + const { data: hotkeys } = useGetBittensorStakeHotkeys({ chainId: token?.chain?.id, address }) const [openArgs, isNomPoolStaking] = useMemo<[Parameters[0] | null, boolean]>(() => { if (!balances || !tokenId || !token?.chain || token?.type !== "substrate-native") diff --git a/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts b/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts index daee5a3443..de49d7036f 100644 --- a/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts +++ b/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts @@ -16,7 +16,8 @@ export const useGetBittensorStakeHotkeys = ({ address, totalStaked, }: GetBittensorStakeHotkeys) => { - const { data: sapi } = useScaleApi(chainId) + // this calls useScaleApi which downloads metadata from chain, we only want this to be done for bittensor + const { data: sapi } = useScaleApi(chainId === "bittensor" ? "bittensor" : null) return useQuery({ queryKey: ["getBittensorStakeHotkeys", sapi?.id, address, totalStaked], diff --git a/apps/extension/src/ui/hooks/sapi/useScaleApi.ts b/apps/extension/src/ui/hooks/sapi/useScaleApi.ts index 972c34611b..e69900fb1a 100644 --- a/apps/extension/src/ui/hooks/sapi/useScaleApi.ts +++ b/apps/extension/src/ui/hooks/sapi/useScaleApi.ts @@ -9,6 +9,11 @@ import { api } from "@ui/api" import { useChain, useChainByGenesisHash, useToken } from "@ui/state" import { getScaleApi, ScaleApi } from "@ui/util/scaleApi" +/** + * useScaleApi instantiates a ScaleApi object for a given chainIdOrHash, specVersion, and blockHash. + * Calling this hook will download the metadata for the given chainIdOrHash, which can cause performance issues. + * It is recommended to use this hook only when necessary and not in a loop where it may be called many times for many chains. + */ export const useScaleApi = ( chainIdOrHash: ChainId | HexString | null | undefined, specVersion?: number, From 4c49a1333ce3ab84318bc320c3fd0bb43f18d913 Mon Sep 17 00:00:00 2001 From: Kheops <26880866+0xKheops@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:33:39 +0900 Subject: [PATCH 04/11] feat: ignore certain messages when logging backend messages (#1742) --- packages/extension-core/src/handlers/index.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/extension-core/src/handlers/index.ts b/packages/extension-core/src/handlers/index.ts index 5ac7b722cb..c6a269cf2b 100644 --- a/packages/extension-core/src/handlers/index.ts +++ b/packages/extension-core/src/handlers/index.ts @@ -30,6 +30,13 @@ const OBFUSCATE_LOG_MESSAGES: MessageTypes[] = [ ] const OBFUSCATED_PAYLOAD = "#OBFUSCATED#" +// ignore the ones that generate too much spam, making it hard to debug other things +const IGNORED_LOG_MESSAGES: MessageTypes[] = [ + "pri(keepalive)", + "pri(keepunlocked)", + "pri(app.analyticsCapture)", +] + const formatFrom = (source: string) => { if (["extension", ""].includes(source)) return source if (!source) return source @@ -60,8 +67,8 @@ const talismanHandler = ( }` const shouldLog = !OBFUSCATE_LOG_MESSAGES.includes(message) - // eslint-disable-next-line no-console - log.debug(`[${port.name} REQ] ${source}`, { request: shouldLog ? request : OBFUSCATED_PAYLOAD }) + if (!IGNORED_LOG_MESSAGES.includes(message)) + log.debug(`[${port.name} REQ] ${source}`, { request: shouldLog ? request : OBFUSCATED_PAYLOAD }) const safePostMessage = (port: chrome.runtime.Port | undefined, message: unknown): void => { // only send message back to port if it's still connected, unfortunately this check is not reliable in all browsers @@ -87,10 +94,11 @@ const talismanHandler = ( // resolve the promise and send back the response promise .then((response): void => { - log.debug(`[${port.name} RES] ${source}`, { - request: shouldLog ? request : OBFUSCATED_PAYLOAD, - response: shouldLog ? response : OBFUSCATED_PAYLOAD, - }) + if (!IGNORED_LOG_MESSAGES.includes(message)) + log.debug(`[${port.name} RES] ${source}`, { + request: shouldLog ? request : OBFUSCATED_PAYLOAD, + response: shouldLog ? response : OBFUSCATED_PAYLOAD, + }) // between the start and the end of the promise, the user may have closed // the tab, in which case port will be undefined From d66ed78be8c4cdddb4e4f9c68da4a9c6975b39c6 Mon Sep 17 00:00:00 2001 From: Chid Gilovitz Date: Wed, 11 Dec 2024 15:33:54 +0800 Subject: [PATCH 05/11] Minor audit issues (#1741) * chore: clarify isSafeImageUrl tests * fix: use TALISMAN_WEB_APP_DOMAIN in paraverse protector instead of hard coded domain --- .../app/protector/ParaverseProtector.ts | 7 +++++-- .../ethereum/__tests__/ethereum.helpers.ts | 18 +++++++++--------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/extension-core/src/domains/app/protector/ParaverseProtector.ts b/packages/extension-core/src/domains/app/protector/ParaverseProtector.ts index fe168c5828..ae618c41a8 100644 --- a/packages/extension-core/src/domains/app/protector/ParaverseProtector.ts +++ b/packages/extension-core/src/domains/app/protector/ParaverseProtector.ts @@ -2,7 +2,7 @@ import { checkHost } from "@polkadot/phishing" import { Dexie } from "dexie" import metamaskInitialData from "eth-phishing-detect/src/config.json" import MetamaskDetector from "eth-phishing-detect/src/detector" -import { log } from "extension-shared" +import { log, TALISMAN_WEB_APP_DOMAIN } from "extension-shared" import { decompressFromUTF16 } from "lz-string" import { sentry } from "../../../config/sentry" @@ -20,7 +20,10 @@ const COMMIT_PATH = "/commits/master" const REFRESH_INTERVAL_MIN = 20 -const DEFAULT_ALLOW = ["talisman.xyz", "app.talisman.xyz"] +const DEFAULT_ALLOW = [ + TALISMAN_WEB_APP_DOMAIN, // app.talisman.xyz + TALISMAN_WEB_APP_DOMAIN.split(".").slice(1).join("."), // talisman.xyz +] type HostList = { allow: string[]; deny: string[] } diff --git a/packages/extension-core/src/domains/ethereum/__tests__/ethereum.helpers.ts b/packages/extension-core/src/domains/ethereum/__tests__/ethereum.helpers.ts index 145859e746..50f9f974c6 100644 --- a/packages/extension-core/src/domains/ethereum/__tests__/ethereum.helpers.ts +++ b/packages/extension-core/src/domains/ethereum/__tests__/ethereum.helpers.ts @@ -92,14 +92,14 @@ describe("Test ethereum helpers", () => { }) test("isSafeImageUrl", () => { - expect(isSafeImageUrl("https://localhost/evilsvgfile_(1).svg")).toEqual(false) - expect(isSafeImageUrl("https://127.0.0.1/evilsvgfile_(1).svg")).toEqual(false) - expect(isSafeImageUrl("https://192.168.0.1/evilsvgfile_(1).svg")).toEqual(false) - expect(isSafeImageUrl("https://172.19.0.1/evilsvgfile_(1).svg")).toEqual(false) - expect(isSafeImageUrl("https://10.0.0.1/evilsvgfile_(1).svg")).toEqual(false) - expect(isSafeImageUrl("https://legit-domain:666/evilsvgfile_(1).svg")).toEqual(false) - expect(isSafeImageUrl("http://legit-domain/evilsvgfile_(1).svg")).toEqual(false) - expect(isSafeImageUrl("https://legit-domain/evilsvgfile_(1).js")).toEqual(false) - expect(isSafeImageUrl("https://legit-domain/chadsvgfile_(1).svg")).toEqual(true) + expect(isSafeImageUrl("https://localhost/anysvgfile_(1).svg")).toEqual(false) + expect(isSafeImageUrl("https://127.0.0.1/anysvgfile_(1).svg")).toEqual(false) + expect(isSafeImageUrl("https://192.168.0.1/anysvgfile_(1).svg")).toEqual(false) + expect(isSafeImageUrl("https://172.19.0.1/anysvgfile_(1).svg")).toEqual(false) + expect(isSafeImageUrl("https://10.0.0.1/anysvgfile_(1).svg")).toEqual(false) + expect(isSafeImageUrl("https://legit-domain:666/anysvgfile_(1).svg")).toEqual(false) + expect(isSafeImageUrl("http://legit-domain/anysvgfile_(1).svg")).toEqual(false) // uses http + expect(isSafeImageUrl("https://legit-domain/anysvgfile_(1).js")).toEqual(false) + expect(isSafeImageUrl("https://legit-domain/anysvgfile_(1).svg")).toEqual(true) }) }) From af14a0986ac18992747c9233affc2425bcb50597 Mon Sep 17 00:00:00 2001 From: Kheops <26880866+0xKheops@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:50:43 +0900 Subject: [PATCH 06/11] fix: no sentry captures for scans and tx decoding (#1736) * fix: throttle reads on asset discovery store * fix: remove useless shareReplay * fix: remove "failed to scan" sentry capture * fix: dont use sentry's error boundary for tx decoding --- .../components/FallbackErrorBoundary.tsx | 43 +++++++++++++++++++ .../ui/domains/Sign/Ethereum/EthSignBody.tsx | 8 ++-- .../SubSignDecodedCallButtonContent.tsx | 6 +-- .../decode/SubSignDecodedCallContent.tsx | 6 +-- .../decode/SubSignDecodedCallSummaryBlock.tsx | 6 +-- apps/extension/src/ui/state/assetDiscovery.ts | 7 ++- .../src/domains/assetDiscovery/scanner.ts | 2 - 7 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 apps/extension/src/@talisman/components/FallbackErrorBoundary.tsx diff --git a/apps/extension/src/@talisman/components/FallbackErrorBoundary.tsx b/apps/extension/src/@talisman/components/FallbackErrorBoundary.tsx new file mode 100644 index 0000000000..a4f1c8502e --- /dev/null +++ b/apps/extension/src/@talisman/components/FallbackErrorBoundary.tsx @@ -0,0 +1,43 @@ +import { log } from "extension-shared" +import { Component, ErrorInfo, ReactNode } from "react" + +interface FallbackErrorBoundaryProps { + children: ReactNode + fallback: ReactNode +} + +interface FallbackErrorBoundaryState { + hasError: boolean +} + +/** + * Error boundary that catches errors in its children and renders a fallback UI. + * Use this if you don't want to use the Sentry error boundary. + */ +export class FallbackErrorBoundary extends Component< + FallbackErrorBoundaryProps, + FallbackErrorBoundaryState +> { + constructor(props: FallbackErrorBoundaryProps) { + super(props) + this.state = { hasError: false } + } + + static getDerivedStateFromError(_: Error): FallbackErrorBoundaryState { + // Update state so the next render will show the fallback UI. + return { hasError: true } + } + + componentDidCatch(error: Error, info: ErrorInfo): void { + log.warn("FallbackErrorBoundary caught an error", { error, info }) + } + + render() { + if (this.state.hasError) { + // Render the provided fallback UI + return this.props.fallback + } + + return this.props.children + } +} diff --git a/apps/extension/src/ui/domains/Sign/Ethereum/EthSignBody.tsx b/apps/extension/src/ui/domains/Sign/Ethereum/EthSignBody.tsx index 143a46e70e..896ba9bf07 100644 --- a/apps/extension/src/ui/domains/Sign/Ethereum/EthSignBody.tsx +++ b/apps/extension/src/ui/domains/Sign/Ethereum/EthSignBody.tsx @@ -1,6 +1,6 @@ -import { ErrorBoundary, FallbackRender } from "@sentry/react" import { FC } from "react" +import { FallbackErrorBoundary } from "@talisman/components/FallbackErrorBoundary" import { DecodedEvmTransaction } from "@ui/domains/Ethereum/util/decodeEvmTransaction" import { SignViewBodyShimmer } from "../Views/SignViewBodyShimmer" @@ -71,8 +71,6 @@ const getComponentFromKnownContractCall = (decodedTx: DecodedEvmTransaction) => } } -const Fallback: FallbackRender = () => - export const EthSignBody: FC = ({ decodedTx, isReady }) => { if (!isReady || !decodedTx) return @@ -80,9 +78,9 @@ export const EthSignBody: FC = ({ decodedTx, isReady }) => { if (Component) return ( - + }> - + ) return diff --git a/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallButtonContent.tsx b/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallButtonContent.tsx index bf241b9430..074cd51f20 100644 --- a/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallButtonContent.tsx +++ b/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallButtonContent.tsx @@ -1,6 +1,6 @@ -import { ErrorBoundary } from "@sentry/react" import { FC } from "react" +import { FallbackErrorBoundary } from "@talisman/components/FallbackErrorBoundary" import { DecodedCall } from "@ui/util/scaleApi" import { SUMMARY_COMPONENTS } from "../summary/calls" @@ -22,8 +22,8 @@ export const SubSignDecodedCallButtonContent: DecodedCallComponent< if (!Component) return return ( - }> + }> - + ) } diff --git a/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallContent.tsx b/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallContent.tsx index 7688ee1930..cca7afc124 100644 --- a/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallContent.tsx +++ b/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallContent.tsx @@ -1,4 +1,3 @@ -import { ErrorBoundary } from "@sentry/react" import { LoaderIcon } from "@talismn/icons" import { classNames, encodeAnyAddress } from "@talismn/util" import DOMPurify from "dompurify" @@ -12,6 +11,7 @@ import { FC, Suspense, useMemo } from "react" import { useTranslation } from "react-i18next" import { CodeBlock } from "@talisman/components/CodeBlock" +import { FallbackErrorBoundary } from "@talisman/components/FallbackErrorBoundary" import { DecodedCall, ScaleApi } from "@ui/util/scaleApi" import { SubSignDecodedCallSummaryBlock } from "./SubSignDecodedCallSummaryBlock" @@ -21,7 +21,7 @@ export const SubSignDecodedCallContent: FC<{ sapi: ScaleApi payload: SignerPayloadJSON }> = ({ decodedCall, sapi, payload }) => ( - }> + }> }>
{/* Summary can suspense to fetch additional data, and break if a chain uses incompatible types */} @@ -29,7 +29,7 @@ export const SubSignDecodedCallContent: FC<{
-
+ ) const ErrorFallback: FC<{ diff --git a/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallSummaryBlock.tsx b/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallSummaryBlock.tsx index 8df3e39423..501d6d0780 100644 --- a/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallSummaryBlock.tsx +++ b/apps/extension/src/ui/domains/Sign/Substrate/decode/SubSignDecodedCallSummaryBlock.tsx @@ -1,4 +1,4 @@ -import { ErrorBoundary } from "@sentry/react" +import { FallbackErrorBoundary } from "@talisman/components/FallbackErrorBoundary" import { SUMMARY_COMPONENTS } from "../summary/calls" import { DecodedCallComponent } from "../types" @@ -10,8 +10,8 @@ export const SubSignDecodedCallSummaryBlock: DecodedCallComponent = (pr if (!Component) return null return ( - + - + ) } diff --git a/apps/extension/src/ui/state/assetDiscovery.ts b/apps/extension/src/ui/state/assetDiscovery.ts index d7640625a3..d5ce00fa85 100644 --- a/apps/extension/src/ui/state/assetDiscovery.ts +++ b/apps/extension/src/ui/state/assetDiscovery.ts @@ -13,7 +13,11 @@ const assetDiscoveryBalances$ = from(liveQuery(() => db.assetDiscovery.toArray() shareReplay(1), ) -export const [useAssetDiscoveryScan, assetDiscoveryScan$] = bind(assetDiscoveryStore.observable) +export const [useAssetDiscoveryScan, assetDiscoveryScan$] = bind( + assetDiscoveryStore.observable.pipe( + throttleTime(100, undefined, { leading: true, trailing: true }), + ), +) export const [useAssetDiscoveryScanProgress, assetDiscoveryScanProgress$] = bind( combineLatest([ @@ -58,6 +62,5 @@ export const [useAssetDiscoveryScanProgress, assetDiscoveryScanProgress$] = bind tokenIds, } }), - shareReplay(1), ), ) diff --git a/packages/extension-core/src/domains/assetDiscovery/scanner.ts b/packages/extension-core/src/domains/assetDiscovery/scanner.ts index 3f36c2f037..48882bf009 100644 --- a/packages/extension-core/src/domains/assetDiscovery/scanner.ts +++ b/packages/extension-core/src/domains/assetDiscovery/scanner.ts @@ -12,7 +12,6 @@ import sortBy from "lodash/sortBy" import { combineLatest, debounceTime, distinctUntilKeyChanged, skip } from "rxjs" import { PublicClient } from "viem" -import { sentry } from "../../config/sentry" import { db } from "../../db" import { chainConnectorEvm } from "../../rpcs/chain-connector-evm" import { chaindataProvider } from "../../rpcs/chaindata" @@ -549,7 +548,6 @@ const getEvmTokenBalancesWithoutAggregator = async ( throw new Error(`Failed to scan ${token.id} (Timeout)`) } catch (err) { - sentry.captureException(err) log.error(`Failed to scan ${token.id} for ${address}: `, { err }) return "0" } From fd7f10994bf275cd7e98a372c0223b633b737492 Mon Sep 17 00:00:00 2001 From: Chid Gilovitz Date: Wed, 11 Dec 2024 17:01:29 +0800 Subject: [PATCH 07/11] Version bump v2.2.1 (#1743) * chore: version bump v2.2.1 * chore: update init data * chore: changeset --- .changeset/slimy-beers-tell.md | 5 +++++ apps/extension/package.json | 2 +- packages/chaindata-provider/src/init/chains.ts | 8 ++++---- packages/chaindata-provider/src/init/evm-networks.ts | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 .changeset/slimy-beers-tell.md diff --git a/.changeset/slimy-beers-tell.md b/.changeset/slimy-beers-tell.md new file mode 100644 index 0000000000..9255a38389 --- /dev/null +++ b/.changeset/slimy-beers-tell.md @@ -0,0 +1,5 @@ +--- +"@talismn/chaindata-provider": patch +--- + +Update init data diff --git a/apps/extension/package.json b/apps/extension/package.json index 6f2e51f2c6..250d27a49b 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -1,6 +1,6 @@ { "name": "extension", - "version": "2.2.0", + "version": "2.2.1", "private": true, "license": "GPL-3.0-or-later", "dependencies": { diff --git a/packages/chaindata-provider/src/init/chains.ts b/packages/chaindata-provider/src/init/chains.ts index 5c35ce6a58..84949d9c43 100644 --- a/packages/chaindata-provider/src/init/chains.ts +++ b/packages/chaindata-provider/src/init/chains.ts @@ -558,7 +558,7 @@ export const chains = [ id: "kusama-asset-hub", isTestnet: false, isDefault: true, - sortIndex: 521, + sortIndex: 524, genesisHash: "0x48239ef607d7928874027a43a67689209727dfb3d3dc5e5b03a39bdc2eda771a", prefix: 2, name: "Kusama Asset Hub", @@ -664,7 +664,7 @@ export const chains = [ id: "kusama-bridge-hub", isTestnet: false, isDefault: true, - sortIndex: 522, + sortIndex: 525, genesisHash: "0x00dcb981df86429de8bbacf9803401f09485366c44efbf53af9ecfab03adc7e5", prefix: 2, name: "Kusama Bridge Hub", @@ -738,7 +738,7 @@ export const chains = [ id: "polkadot-asset-hub", isTestnet: false, isDefault: true, - sortIndex: 753, + sortIndex: 758, genesisHash: "0x68d56f15f85d3136970ec16946040bc1752654e906147f7e43e9d539d7c3de2f", prefix: 0, name: "Polkadot Asset Hub", @@ -1078,7 +1078,7 @@ export const chains = [ id: "polkadot-bridge-hub", isTestnet: false, isDefault: true, - sortIndex: 754, + sortIndex: 759, genesisHash: "0xdcf691b5a3fbe24adc99ddc959c0561b973e329b1aef4c4b22e7bb2ddecb4464", prefix: 0, name: "Polkadot Bridge Hub", diff --git a/packages/chaindata-provider/src/init/evm-networks.ts b/packages/chaindata-provider/src/init/evm-networks.ts index 519a1dd247..9316920e38 100644 --- a/packages/chaindata-provider/src/init/evm-networks.ts +++ b/packages/chaindata-provider/src/init/evm-networks.ts @@ -2,7 +2,7 @@ export const evmNetworks = [ { id: "1", isTestnet: false, - sortIndex: 324, + sortIndex: 326, name: "Ethereum Mainnet", themeColor: "#62688f", logo: "https://raw.githubusercontent.com/TalismanSociety/chaindata/main/assets/chains/1.svg", From 998e610357d259a4d9fd78fa78b5ec9140558d91 Mon Sep 17 00:00:00 2001 From: Kheops <26880866+0xKheops@users.noreply.github.com> Date: Thu, 12 Dec 2024 18:16:46 +0900 Subject: [PATCH 08/11] fix: dont use sapi for displaying balances (#1744) * feat: subtensor staking hotkeys in balances * feat: read subtensor validator from balance meta * fix: layout shift and positioning of shimmer * chore: changeset * chore: yeet * feat: distinct balance values for each hotkey * fix: unbond buttons read hotkey from meta * feat: change hook to read stake by hotkey from balance instead of chain * fix: isEnabled * fix: isEnabled * feat: read hotkey from balance --- .changeset/thirty-crabs-cross.md | 5 + .../AssetDetails/DashboardAssetDetails.tsx | 11 +- .../AssetDetails/PopupAssetDetails.tsx | 8 +- .../AssetDetails/useChainTokenBalances.ts | 61 +++++-- .../ui/domains/Staking/Bond/useBondButton.ts | 37 ++--- .../bittensor/useCombineBittensorStakeInfo.ts | 127 --------------- .../bittensor/useGetBittensorStakeByHotKey.ts | 78 ++------- .../bittensor/useGetBittensorStakeHotkeys.ts | 49 ++---- .../domains/Staking/shared/useGetStakeInfo.ts | 2 +- .../Staking/shared/useGetUnbondInfo.ts | 3 +- .../modules/SubstrateNativeModule/index.ts | 8 +- .../subscribeSubtensorStaking.ts | 151 ++++++++++++------ .../util/mergeBalances.ts | 5 +- packages/balances/src/types/balancetypes.ts | 3 +- 14 files changed, 219 insertions(+), 329 deletions(-) create mode 100644 .changeset/thirty-crabs-cross.md delete mode 100644 apps/extension/src/ui/domains/Staking/hooks/bittensor/useCombineBittensorStakeInfo.ts diff --git a/.changeset/thirty-crabs-cross.md b/.changeset/thirty-crabs-cross.md new file mode 100644 index 0000000000..d7df16eeea --- /dev/null +++ b/.changeset/thirty-crabs-cross.md @@ -0,0 +1,5 @@ +--- +"@talismn/balances": minor +--- + +subtensor hotkey in balance meta diff --git a/apps/extension/src/ui/domains/Portfolio/AssetDetails/DashboardAssetDetails.tsx b/apps/extension/src/ui/domains/Portfolio/AssetDetails/DashboardAssetDetails.tsx index 2863ac0afe..4c22041eb3 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetDetails/DashboardAssetDetails.tsx +++ b/apps/extension/src/ui/domains/Portfolio/AssetDetails/DashboardAssetDetails.tsx @@ -52,6 +52,9 @@ const AssetState = ({
{title}
{/* show description next to title when address is set */} {description && address &&
{description}
} + {!description && address && isLoading && ( +
+ )}
{address && (
@@ -59,8 +62,8 @@ const AssetState = ({
)} {/* show description below title when address is not set */} - {isLoading && !description && locked && ( -
+ {isLoading && !description && !address && locked && ( +
)} {description && !address && (
{description}
@@ -297,7 +300,7 @@ const LockedExtra: FC<{ tokenId: TokenId address?: string // this is only set when browsing all accounts isLoading: boolean - rowMeta: { poolId?: number; unbonding?: boolean } + rowMeta: { poolId?: number; unbonding?: boolean; hotkey?: string } }> = ({ tokenId, address, rowMeta, isLoading }) => { const { t } = useTranslation() const { data } = useNomPoolStakingStatus(tokenId) @@ -348,7 +351,7 @@ const LockedExtra: FC<{ tokenId={tokenId} address={rowAddress} variant="large" - poolId={rowMeta.poolId} + poolId={rowMeta.poolId ?? rowMeta.hotkey} /> ) : null}
diff --git a/apps/extension/src/ui/domains/Portfolio/AssetDetails/PopupAssetDetails.tsx b/apps/extension/src/ui/domains/Portfolio/AssetDetails/PopupAssetDetails.tsx index 39e34d4004..80e0b7cb09 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetDetails/PopupAssetDetails.tsx +++ b/apps/extension/src/ui/domains/Portfolio/AssetDetails/PopupAssetDetails.tsx @@ -220,8 +220,8 @@ const ChainTokenBalancesDetailRow = ({
)} - {row.isLoading && !row.description && row.locked && ( -
+ {!row.address && row.isLoading && !row.description && row.locked && ( +
)} {!row.address && row.description && (
@@ -258,7 +258,7 @@ const LockedExtra: FC<{ tokenId: TokenId address?: string // this is only set when browsing all accounts isLoading: boolean - rowMeta: { poolId?: number; unbonding?: boolean } + rowMeta: { poolId?: number; unbonding?: boolean; hotkey?: string } }> = ({ tokenId, address, rowMeta, isLoading }) => { const { t } = useTranslation() const { data } = useNomPoolStakingStatus(tokenId) @@ -313,7 +313,7 @@ const LockedExtra: FC<{ tokenId={tokenId} address={rowAddress} variant="small" - poolId={rowMeta.poolId} + poolId={rowMeta.poolId ?? rowMeta.hotkey} /> ) : null} diff --git a/apps/extension/src/ui/domains/Portfolio/AssetDetails/useChainTokenBalances.ts b/apps/extension/src/ui/domains/Portfolio/AssetDetails/useChainTokenBalances.ts index 92b68ce9e0..a6adcb787c 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetDetails/useChainTokenBalances.ts +++ b/apps/extension/src/ui/domains/Portfolio/AssetDetails/useChainTokenBalances.ts @@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next" import { Address, Balances } from "@extension/core" import { sortBigBy } from "@talisman/util/bigHelper" import { cleanupNomPoolName } from "@ui/domains/Staking/helpers" -import { useCombineBittensorStakeInfo } from "@ui/domains/Staking/hooks/bittensor/useCombineBittensorStakeInfo" +import { useGetBittensorValidators } from "@ui/domains/Staking/hooks/bittensor/useGetBittensorValidator" import { useBalancesStatus } from "@ui/hooks/useBalancesStatus" import { useNetworkCategory } from "@ui/hooks/useNetworkCategory" import { useChain, useSelectedCurrency } from "@ui/state" @@ -33,20 +33,14 @@ type ChainTokenBalancesParams = { } export const useChainTokenBalances = ({ chainId, balances }: ChainTokenBalancesParams) => { + const { t } = useTranslation() + const currency = useSelectedCurrency() const chain = useChain(chainId) const { selectedAccount: account } = usePortfolioNavigation() const { summary, tokenBalances, token } = useTokenBalancesSummary(balances) - const { t } = useTranslation() - - const currency = useSelectedCurrency() - const { combinedStakeInfo: subtensor } = useCombineBittensorStakeInfo({ - address: account?.address, - balances: balances, - }) - - const detailRows = useMemo((): DetailRow[] => { + const rawDetailRows = useMemo((): DetailRow[] => { if (!summary) return [] // AVAILABLE @@ -130,10 +124,28 @@ export const useChainTokenBalances = ({ chainId, balances }: ChainTokenBalancesP })), ) + // BITTENSOR + const subtensor = tokenBalances.each.flatMap((b) => + b.subtensor.map((subtensor, index) => ({ + key: `${b.id}-subtensor-${index}`, + title: getLockTitle({ label: "subtensor-staking" }), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + description: (subtensor.meta as any)?.description ?? undefined, + tokens: BigNumber(subtensor.amount.tokens), + fiat: subtensor.amount.fiat(currency), + locked: true, + // only show address when we're viewing balances for all accounts + address: account ? undefined : b.address, + meta: subtensor.meta, + })), + ) + return [...available, ...locked, ...reserved, ...staked, ...crowdloans, ...subtensor] .filter((row) => row && row.tokens.gt(0)) .sort(sortBigBy("tokens", true)) - }, [summary, account, t, tokenBalances.each, subtensor, currency]) + }, [summary, account, t, tokenBalances, currency]) + + const detailRows = useEnhanceDetailRows(rawDetailRows) const { evmNetwork } = balances.sorted[0] const relay = useChain(chain?.relay?.id) @@ -153,3 +165,30 @@ export const useChainTokenBalances = ({ chainId, balances }: ChainTokenBalancesP chainOrNetwork: chain || evmNetwork, } } + +const useEnhanceDetailRows = (detailRows: DetailRow[]) => { + // fetch the validator name for each subtensor staking lock, so we can display it in the description + const hotkeys = useMemo(() => { + return detailRows + .filter((row) => row.meta?.type === "subtensor-staking" && !!row.meta?.hotkey) + .map((row) => row.meta?.hotkey as string) + }, [detailRows]) + + const { data: validators, isLoading: isLoadingValidators } = useGetBittensorValidators({ + hotkeys, + isEnabled: !!hotkeys.length, + }) + + return useMemo(() => { + return detailRows.map((row) => { + if (row.meta?.type === "subtensor-staking") + return { + ...row, + description: validators?.find((v) => v?.hotkey.ss58 === row.meta.hotkey)?.name, + isLoading: isLoadingValidators, + } as DetailRow + + return row + }) + }, [detailRows, isLoadingValidators, validators]) +} diff --git a/apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts b/apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts index e69de55c5b..621898ab94 100644 --- a/apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts +++ b/apps/extension/src/ui/domains/Staking/Bond/useBondButton.ts @@ -6,7 +6,6 @@ import { MouseEventHandler, useCallback, useMemo } from "react" import { useAnalytics } from "@ui/hooks/useAnalytics" import { useAccounts, useRemoteConfig, useToken } from "@ui/state" -import { useGetBittensorStakeHotkeys } from "../hooks/bittensor/useGetBittensorStakeHotkeys" import { useBondModal } from "./useBondModal" export const useBondButton = ({ @@ -38,15 +37,11 @@ export const useBondButton = ({ const address = sorted[0]?.address - const { data: hotkeys } = useGetBittensorStakeHotkeys({ chainId: token?.chain?.id, address }) - const [openArgs, isNomPoolStaking] = useMemo<[Parameters[0] | null, boolean]>(() => { if (!balances || !tokenId || !token?.chain || token?.type !== "substrate-native") return [null, false] try { - let isNomPoolStaking = false - - let poolId = + const poolId = remoteConfig.stakingPools[token.chain.id]?.[0] || remoteConfig.nominationPools[token.chain.id]?.[0] @@ -57,32 +52,32 @@ export const useBondButton = ({ // lookup existing poolId for that account for (const balance of sorted.filter((b) => b.address === address)) { - type Meta = { poolId?: number } - let pool - let meta switch (token.chain.id) { - case "bittensor": - poolId = hotkeys?.[0] ?? poolId + case "bittensor": { + type SubtensorMeta = { hotkeys?: string[] } + const entry = balance.subtensor.find((b) => !!(b.meta as SubtensorMeta).hotkeys?.length) + const meta = entry?.meta as SubtensorMeta | undefined + if (meta?.hotkeys?.[0]) return [{ tokenId, address, poolId: meta?.hotkeys[0] }, false] break - default: - pool = balance.nompools.find((np) => !!(np.meta as Meta).poolId) - meta = pool?.meta as Meta | undefined - if (meta?.poolId) { - poolId = meta.poolId - isNomPoolStaking = true - break - } + } + default: { + // assume nomination pool staking, but there will be more in the future + type NomPoolMeta = { poolId?: number } + const entry = balance.nompools.find((b) => !!(b.meta as NomPoolMeta).poolId) + const meta = entry?.meta as NomPoolMeta | undefined + if (meta?.poolId) return [{ tokenId, address, poolId: meta.poolId }, true] break + } } } - return [{ tokenId, address, poolId }, isNomPoolStaking] + return [{ tokenId, address, poolId }, false] } catch (err) { log.error("Failed to compute staking modal open args", err) } return [null, false] - }, [balances, remoteConfig, tokenId, token?.chain, token?.type, hotkeys, address, sorted]) + }, [balances, remoteConfig, tokenId, token?.chain, token?.type, address, sorted]) const handleClick: MouseEventHandler = useCallback( (e) => { diff --git a/apps/extension/src/ui/domains/Staking/hooks/bittensor/useCombineBittensorStakeInfo.ts b/apps/extension/src/ui/domains/Staking/hooks/bittensor/useCombineBittensorStakeInfo.ts deleted file mode 100644 index 9a7bf7d9aa..0000000000 --- a/apps/extension/src/ui/domains/Staking/hooks/bittensor/useCombineBittensorStakeInfo.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { getLockTitle } from "@talismn/balances" -import { planckToTokens } from "@talismn/util" -import BigNumber from "bignumber.js" -import { useMemo } from "react" - -import { Balances } from "@extension/core" -import { DetailRow } from "@ui/domains/Portfolio/AssetDetails/useChainTokenBalances" -import { useTokenBalancesSummary } from "@ui/domains/Portfolio/useTokenBalancesSummary" -import { useSelectedCurrency, useTokenRates } from "@ui/state" - -import { useGetBittensorStakesByHotKeys } from "./useGetBittensorStakeByHotKey" -import { useGetBittensorStakesHotkeys } from "./useGetBittensorStakeHotkeys" -import { useGetBittensorValidators } from "./useGetBittensorValidator" - -type CombineBittensorStakeInfo = { - address: string | undefined - balances: Balances -} - -export const useCombineBittensorStakeInfo = ({ address, balances }: CombineBittensorStakeInfo) => { - const { token } = useTokenBalancesSummary(balances) - const bittensorTokenId = "bittensor-substrate-native" - const tokenRates = useTokenRates(token?.id) - const selectedCurrency = useSelectedCurrency() - - const totalStaked = useMemo(() => { - if (token?.id !== bittensorTokenId) return 0 - return balances.each.reduce((acc, b) => { - return acc + b.subtensor.reduce((acc, subtensor) => acc + Number(subtensor.amount.tokens), 0) - }, 0) - }, [balances.each, token?.id]) - - const addresses = useMemo( - () => (address ? [address] : balances.each.map((b) => b.address)), - [address, balances.each], - ) - - const { data: hotkeys } = useGetBittensorStakesHotkeys({ - chainId: token?.id === bittensorTokenId ? "bittensor" : "", - addresses: addresses, - totalStaked, - }) - - const flatHotkeys = useMemo(() => hotkeys?.flat(), [hotkeys]) - - const { data: stakes, isLoading: isStakesLoading } = useGetBittensorStakesByHotKeys({ - addresses, - hotkeys: hotkeys, - isEnabled: hotkeys?.length > 0 && totalStaked > 0, - }) - - const { data: validators, isLoading: isBittensorValidatorLoading } = useGetBittensorValidators({ - hotkeys: flatHotkeys ?? [], - isEnabled: flatHotkeys?.length > 0 && totalStaked > 0, - }) - - const combinedStakeInfo: DetailRow[] = useMemo(() => { - if ( - (totalStaked > 0 && flatHotkeys?.length && isBittensorValidatorLoading) || - isStakesLoading - ) { - return [ - { - key: "loading-placeholder", - title: getLockTitle({ label: "subtensor-staking" }), - description: undefined, - tokens: BigNumber(totalStaked), - fiat: null, - locked: true, - address: undefined, - meta: null, - isLoading: true, - }, - ] - } - if (!flatHotkeys?.length) return [] - - let currentIndex = 0 - - const stakesInfo = addresses.map((addr, index) => { - const hotkeysCount = hotkeys?.[index]?.length ?? 0 - const hotkeysForAddress = flatHotkeys.slice(currentIndex, currentIndex + hotkeysCount) - const stakesForAddress = stakes?.slice(currentIndex, currentIndex + hotkeysCount) - const validatorsForAddress = validators?.slice(currentIndex, currentIndex + hotkeysCount) - currentIndex += hotkeysCount - - const stakeInfo = hotkeysForAddress.map((hotkey, index) => { - const formattedStakedAmount = planckToTokens( - stakesForAddress?.[index]?.toString() ?? "0", - token?.decimals ?? 9, - ) - - return { - key: `${hotkey}-subtensor-${index}`, - title: getLockTitle({ label: "subtensor-staking" }), - description: validatorsForAddress?.[index]?.name, - tokens: BigNumber(formattedStakedAmount), - fiat: Number(formattedStakedAmount) * (tokenRates?.[selectedCurrency] ?? 0), - locked: true, - // only show address when we're viewing balances for all accounts - address: address ? undefined : addr, - meta: { poolId: hotkey }, - isLoading: isBittensorValidatorLoading, - } - }) - - return stakeInfo - }) - - return stakesInfo.flat() - }, [ - totalStaked, - flatHotkeys, - isBittensorValidatorLoading, - isStakesLoading, - addresses, - hotkeys, - stakes, - validators, - token?.decimals, - tokenRates, - selectedCurrency, - address, - ]) - - return { combinedStakeInfo } -} diff --git a/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeByHotKey.ts b/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeByHotKey.ts index 0fc64dd06e..7184b7a250 100644 --- a/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeByHotKey.ts +++ b/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeByHotKey.ts @@ -1,6 +1,6 @@ -import { useQueries, useQuery } from "@tanstack/react-query" +import { useMemo } from "react" -import { useScaleApi } from "@ui/hooks/sapi/useScaleApi" +import { useBalance } from "@ui/state" type GetBittensorStakeByHotKey = { address: string | null | undefined @@ -8,76 +8,18 @@ type GetBittensorStakeByHotKey = { isEnabled?: boolean } -type GetBittensorStakeByHotKeys = Omit & { - hotkeys: (string | undefined)[] -} -type GetBittensorStakesByHotKeys = Omit & { - addresses: (string | undefined)[] - hotkeys: (string[] | undefined)[] -} +type Meta = { hotkey?: string } | undefined export const useGetBittensorStakeByHotKey = ({ address, hotkey, - isEnabled = true, + isEnabled, }: GetBittensorStakeByHotKey) => { - const { data: sapi } = useScaleApi("bittensor") - return useQuery({ - queryKey: ["useGetBittensorStakeByHotKey", sapi?.id, address, hotkey], - queryFn: async () => { - return sapi?.getStorage("SubtensorModule", "Stake", [hotkey, address]) - }, - enabled: isEnabled && !!sapi && !!address && !!hotkey, - }) -} - -export const useGetBittensorStakeByHotKeys = ({ - address, - hotkeys, - isEnabled = true, -}: GetBittensorStakeByHotKeys) => { - const { data: sapi } = useScaleApi("bittensor") - return useQueries({ - queries: hotkeys.map((hotkey) => ({ - queryKey: ["useGetBittensorStakeByHotKey", sapi?.id, address, hotkey], - queryFn: () => sapi?.getStorage("SubtensorModule", "Stake", [hotkey, address]), - enabled: isEnabled && !!sapi && !!address && !!hotkey, - })), - combine: (results) => { - return { - data: results.map((result) => result.data), - isPending: results.some((result) => result.isPending), - isLoading: results.some((result) => result.isLoading), - error: results.find((result) => result.isError), - } - }, - }) -} + const balance = useBalance(isEnabled ? address : null, "bittensor-substrate-native") -export const useGetBittensorStakesByHotKeys = ({ - addresses, - hotkeys, - isEnabled = true, -}: GetBittensorStakesByHotKeys) => { - const { data: sapi } = useScaleApi("bittensor") - return useQueries({ - queries: addresses - .map((address, index) => { - const hotkeysForAddress = hotkeys[index] ?? [] - return hotkeysForAddress.map((hotkey) => ({ - queryKey: ["useGetBittensorStakeByHotKey", sapi?.id, address, hotkey], - queryFn: () => sapi?.getStorage("SubtensorModule", "Stake", [hotkey, address]), - enabled: isEnabled && !!sapi && !!address && !!hotkey, - })) - }) - .flat(), - combine: (results) => { - return { - data: results.map((result) => result.data), - isPending: results.some((result) => result.isPending), - isLoading: results.some((result) => result.isLoading), - error: results.find((result) => result.isError), - } - }, - }) + return useMemo(() => { + if (!balance || !hotkey) return undefined + const value = balance?.subtensor.find((b) => (b.meta as Meta)?.hotkey === hotkey) + return value?.amount.planck + }, [balance, hotkey]) } diff --git a/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts b/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts index de49d7036f..286190248e 100644 --- a/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts +++ b/apps/extension/src/ui/domains/Staking/hooks/bittensor/useGetBittensorStakeHotkeys.ts @@ -1,51 +1,20 @@ -import { useQueries, useQuery } from "@tanstack/react-query" import { ChainId } from "extension-core" +import { useMemo } from "react" -import { useScaleApi } from "@ui/hooks/sapi/useScaleApi" +import { useBalance } from "@ui/state" type GetBittensorStakeHotkeys = { chainId: ChainId | null | undefined address: string | null | undefined - totalStaked?: number } -type GetBittensorStakesHotkeys = Omit & { addresses: string[] } +type Meta = { hotkey?: string } | undefined -export const useGetBittensorStakeHotkeys = ({ - chainId, - address, - totalStaked, -}: GetBittensorStakeHotkeys) => { - // this calls useScaleApi which downloads metadata from chain, we only want this to be done for bittensor - const { data: sapi } = useScaleApi(chainId === "bittensor" ? "bittensor" : null) +export const useGetBittensorStakeHotkeys = ({ chainId, address }: GetBittensorStakeHotkeys) => { + const balance = useBalance(chainId === "bittensor" ? address : null, "bittensor-substrate-native") - return useQuery({ - queryKey: ["getBittensorStakeHotkeys", sapi?.id, address, totalStaked], - queryFn: async () => - await sapi?.getStorage("SubtensorModule", "StakingHotkeys", [address]), - enabled: !!sapi && !!address && chainId === "bittensor", - }) -} - -export const useGetBittensorStakesHotkeys = ({ - chainId, - addresses, - totalStaked, -}: GetBittensorStakesHotkeys) => { - const { data: sapi } = useScaleApi(chainId) - return useQueries({ - queries: addresses.map((address) => ({ - queryKey: ["getBittensorStakeHotkeys", sapi?.id, address, totalStaked], - queryFn: () => sapi?.getStorage("SubtensorModule", "StakingHotkeys", [address]), - enabled: !!sapi && !!address && chainId === "bittensor", - })), - combine: (results) => { - return { - data: results.map((result) => result.data), - isPending: results.some((result) => result.isPending), - isLoading: results.some((result) => result.isLoading), - error: results.find((result) => result.isError), - } - }, - }) + return useMemo(() => { + if (!balance) return undefined + return balance.subtensor.map((b) => (b.meta as Meta)?.hotkey).filter((h): h is string => !!h) + }, [balance]) } diff --git a/apps/extension/src/ui/domains/Staking/shared/useGetStakeInfo.ts b/apps/extension/src/ui/domains/Staking/shared/useGetStakeInfo.ts index 394406a63a..530840ffd3 100644 --- a/apps/extension/src/ui/domains/Staking/shared/useGetStakeInfo.ts +++ b/apps/extension/src/ui/domains/Staking/shared/useGetStakeInfo.ts @@ -43,7 +43,7 @@ export const useGetStakeInfo = ({ sapi, address, poolId, plancks, chainId }: Get chainId, }) - const { data: hotkeys } = useGetBittensorStakeHotkeys({ address, chainId }) + const hotkeys = useGetBittensorStakeHotkeys({ address, chainId }) const { data: claimPermission } = useNomPoolsClaimPermission(chainId, address) diff --git a/apps/extension/src/ui/domains/Staking/shared/useGetUnbondInfo.ts b/apps/extension/src/ui/domains/Staking/shared/useGetUnbondInfo.ts index 79f6a3fe01..804fc39aad 100644 --- a/apps/extension/src/ui/domains/Staking/shared/useGetUnbondInfo.ts +++ b/apps/extension/src/ui/domains/Staking/shared/useGetUnbondInfo.ts @@ -34,9 +34,10 @@ export const useGetUnbondInfo = ({ sapi, chainId, address, unstakePoolId }: GetU isEnabled: chainId !== "bittensor", }) - const { data: bittensorPlanks } = useGetBittensorStakeByHotKey({ + const bittensorPlanks = useGetBittensorStakeByHotKey({ address, hotkey: unstakePoolId, + isEnabled: chainId === "bittensor", }) const bittensorUnbondPayload = useGetBittensorUnbondPayload({ diff --git a/packages/balances/src/modules/SubstrateNativeModule/index.ts b/packages/balances/src/modules/SubstrateNativeModule/index.ts index c47188d86a..d3792bee2c 100644 --- a/packages/balances/src/modules/SubstrateNativeModule/index.ts +++ b/packages/balances/src/modules/SubstrateNativeModule/index.ts @@ -148,7 +148,9 @@ export const SubNativeModule: NewBalanceModule< { pallet: "Staking", items: ["Ledger"] }, { pallet: "Crowdloan", items: ["Funds"] }, { pallet: "Paras", items: ["Parachains"] }, - { pallet: "SubtensorModule", items: ["TotalColdkeyStake"] }, + // TotalColdkeyStake is used until v.2.2.1, then it is replaced by StakingHotkeys+Stake + // Need to keep TotalColdkeyStake for a while so chaindata keeps including it in miniMetadatas, so it doesnt break old versions of the wallet + { pallet: "SubtensorModule", items: ["TotalColdkeyStake", "StakingHotkeys", "Stake"] }, ]) const miniMetadata = encodeMetadata(tag === "v15" ? { tag, metadata } : { tag, metadata }) @@ -280,7 +282,7 @@ export const SubNativeModule: NewBalanceModule< .filter((b) => b.values.length > 0) .reduce>((acc, b) => { const bId = getBalanceId(b) - acc[bId] = mergeBalances(acc[bId], b, source) + acc[bId] = mergeBalances(acc[bId], b, source, false) return acc }, {}) @@ -288,7 +290,7 @@ export const SubNativeModule: NewBalanceModule< const mergedBalances: Record = {} Object.entries(accumulatedUpdates).forEach(([bId, b]) => { // merge the values from the new balance into the existing balance, if there is one - mergedBalances[bId] = mergeBalances(currentBalances[bId], b, source) + mergedBalances[bId] = mergeBalances(currentBalances[bId], b, source, true) // update initialisingBalances to remove balances which have been updated const intialisingForToken = initialisingBalances.get(b.tokenId) diff --git a/packages/balances/src/modules/SubstrateNativeModule/subscribeSubtensorStaking.ts b/packages/balances/src/modules/SubstrateNativeModule/subscribeSubtensorStaking.ts index eb35401c46..2b4ad8d5b2 100644 --- a/packages/balances/src/modules/SubstrateNativeModule/subscribeSubtensorStaking.ts +++ b/packages/balances/src/modules/SubstrateNativeModule/subscribeSubtensorStaking.ts @@ -2,7 +2,8 @@ import { ChainConnector } from "@talismn/chain-connector" import { ChaindataProvider } from "@talismn/chaindata-provider" import { decodeScale, encodeStateKey } from "@talismn/scale" import { isEthereumAddress } from "@talismn/util" -import { combineLatest, scan, share } from "rxjs" +import { toPairs } from "lodash" +import { scan, share, switchMap } from "rxjs" import type { SubNativeModule } from "./index" import log from "../../log" @@ -68,7 +69,8 @@ export async function subscribeSubtensorStaking( miniMetadatas, moduleType: "substrate-native", coders: { - totalColdkeyStake: ["SubtensorModule", "TotalColdkeyStake"], + stakingHotkeys: ["SubtensorModule", "StakingHotkeys"], + stake: ["SubtensorModule", "Stake"], }, }) @@ -94,37 +96,36 @@ export async function subscribeSubtensorStaking( continue } - type TotalColdkeyStake = { - tokenId: string + type StakingHotkeys = { address: string - stake?: bigint + hotkeys?: string[] } - const subscribeTotalColdkeyStake = ( + const subscribeStakingHotkeys = ( addresses: string[], - callback: SubscriptionCallback, + callback: SubscriptionCallback, ) => { - const scaleCoder = chainStorageCoders.get(chainId)?.totalColdkeyStake - const queries = addresses.flatMap((address): RpcStateQuery | [] => { + const scaleCoder = chainStorageCoders.get(chainId)?.stakingHotkeys + const queries = addresses.flatMap((address): RpcStateQuery | [] => { const stateKey = encodeStateKey( scaleCoder, - `Invalid address in ${chainId} totalColdkeyStake query ${address}`, + `Invalid address in ${chainId} stakingHotkeys query ${address}`, address, ) if (!stateKey) return [] const decodeResult = (change: string | null) => { /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */ - type DecodedType = bigint + type DecodedType = string[] const decoded = decodeScale( scaleCoder, change, - `Failed to decode totalColdkeyStake on chain ${chainId}`, + `Failed to decode stakingHotkeys on chain ${chainId}`, ) - const stake: bigint | undefined = decoded ?? undefined + const hotkeys: DecodedType | undefined = decoded ?? undefined - return { tokenId, address, stake } + return { address, hotkeys } } return { chainId, stateKey, decodeResult } @@ -134,45 +135,101 @@ export async function subscribeSubtensorStaking( return () => subscription.then((unsubscribe) => unsubscribe()) } - const totalColdkeyStakeByAddress$ = asObservable(subscribeTotalColdkeyStake)(addresses).pipe( + const stakingHotkeysByAddress$ = asObservable(subscribeStakingHotkeys)(addresses).pipe( scan((state, next) => { - for (const totalColdkeyStake of next) { - const { address, stake } = totalColdkeyStake - if (typeof stake === "bigint") state.set(address, stake) - else state.delete(totalColdkeyStake.address) + for (const { address, hotkeys } of next) { + if (hotkeys?.length) state.set(address, hotkeys) + else state.delete(address) } return state - }, new Map()), + }, new Map()), share(), ) - const subscription = combineLatest([totalColdkeyStakeByAddress$]).subscribe({ - next: ([totalColdkeyStakeByAddress]) => { - const balances = Array.from(totalColdkeyStakeByAddress) - .map(([address, stake]) => { - return { - source: "substrate-native", - status: "live", - address, - multiChainId: { subChainId: chainId }, - chainId, - tokenId, - values: [ - { - source: "subtensor-staking", - type: "subtensor", - label: "subtensor-staking", - amount: stake.toString(), - }, - ], - } as SubNativeBalance - }) - .filter(Boolean) as SubNativeBalance[] - - if (balances.length > 0) callback(null, balances) - }, - error: (error) => callback(error), - }) + type HotkeyStakeDef = { address: string; hotkey: string } + type HotkeyStake = { address: string; hotkey: string; stake?: bigint } + + const subscribeStakes = ( + defs: HotkeyStakeDef[], + callback: SubscriptionCallback, + ) => { + const scaleCoder = chainStorageCoders.get(chainId)?.stake + const queries = defs.flatMap(({ address, hotkey }): RpcStateQuery | [] => { + const stateKey = encodeStateKey( + scaleCoder, + `Invalid input in ${chainId} stake query ${address}/${hotkey}`, + hotkey, + address, + ) + if (!stateKey) return [] + + const decodeResult = (change: string | null) => { + /** NOTE: This type is only a hint for typescript, the chain can actually return whatever it wants to */ + type DecodedType = bigint + + const decoded = decodeScale( + scaleCoder, + change, + `Failed to decode stake on chain ${chainId}`, + ) + + const stake: DecodedType | undefined = decoded ?? undefined + + return { address, hotkey, stake } + } + + return { chainId, stateKey, decodeResult } + }) + + const subscription = new RpcStateQueryHelper(chainConnector, queries).subscribe(callback) + return () => subscription.then((unsubscribe) => unsubscribe()) + } + + // subscribe to hotkeys for each address + // then for each address/hotkey pair, subscribe to the staked amount + const subscription = stakingHotkeysByAddress$ + .pipe( + switchMap((hotkeysByAddress) => { + const stakeDefs: HotkeyStakeDef[] = toPairs(hotkeysByAddress).flatMap( + ([address, hotkeys]) => + hotkeys.map((hotkey: string): HotkeyStakeDef => ({ address, hotkey })), + ) + + return asObservable(subscribeStakes)(stakeDefs) + }), + ) + .subscribe({ + next: (stakes) => { + const balances = stakes + .filter(({ stake }) => typeof stake === "bigint") + .map(({ address, hotkey, stake }) => { + return { + source: "substrate-native", + status: "live", + address, + multiChainId: { subChainId: chainId }, + chainId, + tokenId, + values: [ + { + source: "subtensor-staking", + type: "subtensor", + label: "subtensor-staking", + amount: stake!.toString(), + meta: { + type: "subtensor-staking", + hotkey, + }, + }, + ], + } as SubNativeBalance + }) + .filter(Boolean) as SubNativeBalance[] + + if (balances.length > 0) callback(null, balances) + }, + error: (error) => callback(error), + }) resultUnsubscribes.push(() => subscription.unsubscribe()) } diff --git a/packages/balances/src/modules/SubstrateNativeModule/util/mergeBalances.ts b/packages/balances/src/modules/SubstrateNativeModule/util/mergeBalances.ts index 462418a54e..9e80606a5b 100644 --- a/packages/balances/src/modules/SubstrateNativeModule/util/mergeBalances.ts +++ b/packages/balances/src/modules/SubstrateNativeModule/util/mergeBalances.ts @@ -12,12 +12,14 @@ export type { BalanceLockType } from "./balanceLockTypes" * @param balance1 SubNativeBalance * @param balance2 SubNativeBalance * @param source source that this merge is for (will discard previous values from that source) + * @param clear whether to clear the previous values from the source * @returns SubNativeBalance */ export const mergeBalances = ( balance1: SubNativeBalance | undefined, balance2: SubNativeBalance, source: string, + clear: boolean, ) => { if (balance1 === undefined) return balance2 assert( @@ -27,7 +29,7 @@ export const mergeBalances = ( // locks and freezes should completely replace the previous rather than merging together const existingValues = Object.fromEntries( balance1.values - .filter((v) => !v.source || v.source !== source) + .filter((v) => !clear || !v.source || v.source !== source) .map((value) => [getValueId(value), value]), ) const newValues = Object.fromEntries(balance2.values.map((value) => [getValueId(value), value])) @@ -38,5 +40,6 @@ export const mergeBalances = ( status: balance2.status, // only the status field should actually be different apart from the values values: Object.values(mergedValues), } + return merged } diff --git a/packages/balances/src/types/balancetypes.ts b/packages/balances/src/types/balancetypes.ts index b2fd53236a..d116e6c567 100644 --- a/packages/balances/src/types/balancetypes.ts +++ b/packages/balances/src/types/balancetypes.ts @@ -125,10 +125,11 @@ type BaseAmountWithLabel = { export const getValueId = (amount: AmountWithLabel) => { const getMetaId = () => { - const meta = amount.meta as { poolId?: number; paraId?: number } | undefined + const meta = amount.meta as { poolId?: number; paraId?: number; hotkey?: string } | undefined if (!meta) return "" if (amount.type === "crowdloan") return meta.paraId?.toString() ?? "" if (amount.type === "nompool") return meta.poolId?.toString() ?? "" + if (amount.type === "subtensor") return meta.hotkey?.toString() ?? "" return "" } From db4e053ea707a83f0440fd2abfb96dfd2cccf994 Mon Sep 17 00:00:00 2001 From: Kheops <26880866+0xKheops@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:51:23 +0900 Subject: [PATCH 09/11] fix: unnecessary scan starts (#1748) * fix: unnecessary scan starts * chore: cleanup * chore: cleanup --- .../src/domains/assetDiscovery/scanner.ts | 78 +++++++++++-------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/packages/extension-core/src/domains/assetDiscovery/scanner.ts b/packages/extension-core/src/domains/assetDiscovery/scanner.ts index 48882bf009..fbffde1343 100644 --- a/packages/extension-core/src/domains/assetDiscovery/scanner.ts +++ b/packages/extension-core/src/domains/assetDiscovery/scanner.ts @@ -9,7 +9,7 @@ import { isEqual, uniq } from "lodash" import chunk from "lodash/chunk" import groupBy from "lodash/groupBy" import sortBy from "lodash/sortBy" -import { combineLatest, debounceTime, distinctUntilKeyChanged, skip } from "rxjs" +import { combineLatest, debounceTime, distinct, distinctUntilKeyChanged, map, skip } from "rxjs" import { PublicClient } from "viem" import { db } from "../../db" @@ -66,53 +66,69 @@ class AssetDiscoveryScanner { let prevAllAddresses: string[] | null = null // identify newly added accounts and scan those - keyring.accounts.subject.pipe(debounceTime(500)).subscribe(async (accounts) => { - try { - const allAddresses = Object.keys(accounts) + keyring.accounts.subject + .pipe( + debounceTime(500), + map((accounts) => Object.keys(accounts).sort()), + distinct((addresses) => addresses.join("")), + ) + .subscribe(async (allAddresses) => { + try { + if (prevAllAddresses && !this.#preventAutoStart) { + const addresses = allAddresses.filter( + (k) => !(prevAllAddresses as string[]).includes(k), + ) - if (prevAllAddresses && !this.#preventAutoStart) { - const addresses = allAddresses.filter((k) => !(prevAllAddresses as string[]).includes(k)) - const networkIds = await getActiveNetworkIdsToScan() + if (addresses.length) { + const networkIds = await getActiveNetworkIdsToScan() - log.debug("[AssetDiscovery] New accounts detected, starting scan", { - addresses, - networkIds, - }) + log.debug("[AssetDiscovery] New accounts detected, starting scan", { + addresses, + networkIds, + }) - this.startScan({ networkIds, addresses }) - } + this.startScan({ networkIds, addresses }) + } + } - prevAllAddresses = allAddresses // update reference - } catch (err) { - log.error("[AssetDiscovery] Failed to start scan after account creation", { err }) - } - }) + prevAllAddresses = allAddresses // update reference + } catch (err) { + log.error("[AssetDiscovery] Failed to start scan after account creation", { err }) + } + }) } - private watchEnabledNetworks = async () => { + private watchEnabledNetworks = () => { let prevAllActiveNetworkIds: string[] | null = null // identify newly enabled networks and scan those combineLatest([chaindataProvider.evmNetworksByIdObservable, activeEvmNetworksStore.observable]) - .pipe(debounceTime(500)) - .subscribe(([networksById, activeNetworks]) => { + .pipe( + debounceTime(500), + map(([networksById, activeNetworks]) => + Object.keys(activeNetworks) + .filter((k) => !!activeNetworks[k] && networksById[k] && !networksById.isTestnet) + .sort(), + ), + distinct((allActiveNetworkIds) => allActiveNetworkIds.join("")), + ) + .subscribe((allActiveNetworkIds) => { try { - const allActiveNetworkIds = Object.keys(activeNetworks).filter( - (k) => !!activeNetworks[k] && networksById[k] && !networksById.isTestnet, - ) - if (prevAllActiveNetworkIds && !this.#preventAutoStart) { const networkIds = allActiveNetworkIds.filter( (k) => !(prevAllActiveNetworkIds as string[]).includes(k), ) - const addresses = keyring.getAccounts().map((acc) => acc.address) - log.debug("[AssetDiscovery] New enabled networks detected, starting scan", { - addresses, - networkIds, - }) + if (networkIds.length) { + const addresses = keyring.getAccounts().map((acc) => acc.address) - this.startScan({ networkIds, addresses }) + log.debug("[AssetDiscovery] New enabled networks detected, starting scan", { + addresses, + networkIds, + }) + + this.startScan({ networkIds, addresses }) + } } prevAllActiveNetworkIds = allActiveNetworkIds From eb959d49db4a381592138afc6c0e9a51758f0226 Mon Sep 17 00:00:00 2001 From: Kheops <26880866+0xKheops@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:28:54 +0900 Subject: [PATCH 10/11] feat: portfolio performance improvements (#1746) * fix: hook deps * fix: portfolio container performance * feat: minor performance optimizations * feat: virtualized rows on assets table * feat: context for usePortfolioNavigation * feat: no count up on asset details (because of virtualization) * fix: glitch when changing account on portfolio * wip: tanstack virtual * feat: virtualized asset tables * chore: cleanup * feat: virtualize rows in token picker * fix: wrap dashboard tx history in portfolio container * fix: bool checks * fix: virtualise tx history rows * fix: sidebar must be wrapped in PortfolioContainer to access selected account * chore: export style * feat: add countups back --- apps/extension/package.json | 1 + .../@talisman/components/ScrollContainer.tsx | 18 +- .../apps/dashboard/routes/Portfolio/index.tsx | 11 +- .../ui/apps/dashboard/routes/TxHistory.tsx | 23 +- .../shared/PortfolioAssetsHeader.tsx | 2 +- .../src/ui/domains/Asset/TokenPicker.tsx | 196 ++-- .../Portfolio/AssetBalanceCellValue.tsx | 6 +- .../AssetDetails/useChainTokenBalances.ts | 3 +- .../AssetsTable/DashboardAssetRow.tsx | 19 +- .../AssetsTable/DashboardAssetsTable.tsx | 66 +- .../AssetsTable/PopupAssetsTable.tsx | 234 +++-- .../AssetsTable/usePortfolioSymbolBalances.ts | 2 +- .../domains/Portfolio/PortfolioContainer.tsx | 42 +- .../Portfolio/usePortfolioNavigation.ts | 7 +- .../Portfolio/useTokenBalancesSummary.ts | 2 +- .../Transactions/TxHistory/TxHistoryList.tsx | 74 +- .../src/ui/hooks/useSendFundsPopup.ts | 12 +- .../extension/src/ui/state/authorisedSites.ts | 22 +- apps/extension/src/ui/state/balances.ts | 16 +- pnpm-lock.yaml | 920 +++--------------- 20 files changed, 620 insertions(+), 1056 deletions(-) diff --git a/apps/extension/package.json b/apps/extension/package.json index 250d27a49b..beac77566d 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -47,6 +47,7 @@ "@talismn/token-rates": "workspace:*", "@talismn/util": "workspace:*", "@tanstack/react-query": "5.59.16", + "@tanstack/react-virtual": "^3.11.1", "@types/blueimp-md5": "2.18.2", "@types/chrome": "0.0.279", "@types/color": "3.0.6", diff --git a/apps/extension/src/@talisman/components/ScrollContainer.tsx b/apps/extension/src/@talisman/components/ScrollContainer.tsx index 5b63eba53c..031d86621d 100644 --- a/apps/extension/src/@talisman/components/ScrollContainer.tsx +++ b/apps/extension/src/@talisman/components/ScrollContainer.tsx @@ -1,6 +1,8 @@ import { classNames } from "@talismn/util" import { forwardRef, RefObject, useEffect, useMemo, useRef, useState } from "react" +import { provideContext } from "@talisman/util/provideContext" + type ScrollContainerProps = { className?: string children?: React.ReactNode @@ -67,7 +69,7 @@ export const ScrollContainer = forwardRef( innerClassName, )} > - {children} + {children}
( }, ) ScrollContainer.displayName = "ScrollContainer" + +const useScrollContainerProvider = ({ + refContainer, +}: { + refContainer: RefObject +}) => { + return refContainer +} + +const [ScrollContainerProvider, useScrollContainer] = provideContext(useScrollContainerProvider) + +// this hook will provite a way for its children to access the ref of the scrollable element +// mainly useful when using a virtualizer or other scroll related libraries +export { useScrollContainer } diff --git a/apps/extension/src/ui/apps/dashboard/routes/Portfolio/index.tsx b/apps/extension/src/ui/apps/dashboard/routes/Portfolio/index.tsx index 5a4670206d..79dd24e2c0 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Portfolio/index.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Portfolio/index.tsx @@ -31,9 +31,10 @@ const BuyTokensOpener = () => { } export const PortfolioRoutes = () => ( - - - + + + + {/* share layout to prevent tabs flickering */} }> @@ -44,8 +45,8 @@ export const PortfolioRoutes = () => ( } /> - - + + ) const PortfolioToolbar = () => ( diff --git a/apps/extension/src/ui/apps/dashboard/routes/TxHistory.tsx b/apps/extension/src/ui/apps/dashboard/routes/TxHistory.tsx index 6651073d76..e2bc66476c 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/TxHistory.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/TxHistory.tsx @@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next" import { useOpenClose } from "talisman-ui" import { ChainLogo } from "@ui/domains/Asset/ChainLogo" +import { PortfolioContainer } from "@ui/domains/Portfolio/PortfolioContainer" import { usePortfolioNavigation } from "@ui/domains/Portfolio/usePortfolioNavigation" import { TxHistoryList, TxHistoryProvider } from "@ui/domains/Transactions/TxHistory" import { useTxHistory } from "@ui/domains/Transactions/TxHistory/TxHistoryContext" @@ -86,15 +87,17 @@ const TxHistoryAccountFilter = () => { export const TxHistory = () => { return ( - - - -
-
-
- -
-
-
+ + + + +
+
+
+ +
+
+
+
) } diff --git a/apps/extension/src/ui/apps/popup/pages/Portfolio/shared/PortfolioAssetsHeader.tsx b/apps/extension/src/ui/apps/popup/pages/Portfolio/shared/PortfolioAssetsHeader.tsx index 179d469cb5..96185e2fd2 100644 --- a/apps/extension/src/ui/apps/popup/pages/Portfolio/shared/PortfolioAssetsHeader.tsx +++ b/apps/extension/src/ui/apps/popup/pages/Portfolio/shared/PortfolioAssetsHeader.tsx @@ -99,7 +99,7 @@ export const PortfolioAssetsHeader: FC<{ backBtnTo?: string }> = ({ backBtnTo }) balancesByAddress.get(balance.address)?.push(balance) }) return balancesByAddress - }, [allBalances.each]) + }, [allBalances]) const balances = useMemo( () => diff --git a/apps/extension/src/ui/domains/Asset/TokenPicker.tsx b/apps/extension/src/ui/domains/Asset/TokenPicker.tsx index 5667c8a417..9dac3b41c5 100644 --- a/apps/extension/src/ui/domains/Asset/TokenPicker.tsx +++ b/apps/extension/src/ui/domains/Asset/TokenPicker.tsx @@ -3,13 +3,13 @@ import { Balances } from "@talismn/balances" import { Token, TokenId } from "@talismn/chaindata-provider" import { CheckCircleIcon } from "@talismn/icons" import { classNames, planckToTokens } from "@talismn/util" +import { useVirtualizer } from "@tanstack/react-virtual" import sortBy from "lodash/sortBy" import { FC, useCallback, useDeferredValue, useMemo, useRef, useState } from "react" import { useTranslation } from "react-i18next" -import { useIntersection } from "react-use" import { Address } from "@extension/core" -import { ScrollContainer } from "@talisman/components/ScrollContainer" +import { ScrollContainer, useScrollContainer } from "@talisman/components/ScrollContainer" import { SearchInput } from "@talisman/components/SearchInput" import { useAccountByAddress, @@ -67,6 +67,74 @@ const TokenRowSkeleton = () => (
) +type TokenData = { + id: string + token: Token + balances: Balances + chainNameSearch: string | null | undefined + chainName: string + chainLogo: string | null | undefined + hasFiatRate: boolean +} + +const TokenRows: FC<{ + tokens: TokenData[] + selectedTokenId?: TokenId + allowUntransferable?: boolean + onTokenClick: (tokenId: TokenId) => void +}> = ({ tokens, selectedTokenId, allowUntransferable, onTokenClick }) => { + const refContainer = useScrollContainer() + const ref = useRef(null) + + const virtualizer = useVirtualizer({ + count: tokens.length, + estimateSize: () => 58, + overscan: 5, + getScrollElement: () => refContainer.current, + }) + + if (!tokens.length) return null + + return ( +
+
+ {virtualizer.getVirtualItems().map((item) => { + const tokenData = tokens[item.index] + if (!tokenData) return null + + return ( +
+ onTokenClick(tokenData.token.id)} + /> +
+ ) + })} +
+
+ ) +} + const TokenRow: FC = ({ token, selected, @@ -84,23 +152,15 @@ const TokenRow: FC = ({ tokensTotal: planckToTokens(planck.toString(), token.decimals), isLoading: balances.each.find((b) => b.status === "cache"), } - }, [balances.each, token.decimals]) + }, [balances, token.decimals]) const isTransferable = useMemo(() => isTransferableToken(token), [token]) - // there are more than 250 tokens so we should render only visible tokens to prevent performance issues - const refButton = useRef(null) - const intersection = useIntersection(refButton, { - root: null, - rootMargin: "1000px", - }) - const currency = useSelectedCurrency() const isUniswapV2LpToken = token?.type === "evm-uniswapv2" return ( ) } @@ -258,7 +314,7 @@ const TokensList: FC = ({ tokenRatesMap, ]) - const tokensWithBalances = useMemo(() => { + const tokensWithBalances = useMemo(() => { // wait until balances are loaded if (!accountBalances.count) return [] @@ -336,9 +392,9 @@ const TokensList: FC = ({ }) }, [search, tokensWithBalances]) - const handleAccountClick = useCallback( - (address: string) => () => { - onSelect?.(address) + const handleTokenClick = useCallback( + (tokenId: string) => { + onSelect?.(tokenId) }, [onSelect], ) @@ -347,19 +403,13 @@ const TokensList: FC = ({
{accountBalances.count ? ( <> - {tokens?.map(({ token, balances, chainName, chainLogo, hasFiatRate }) => ( - - ))} + + {!tokens?.length && (
{t("No token matches your search")} diff --git a/apps/extension/src/ui/domains/Portfolio/AssetBalanceCellValue.tsx b/apps/extension/src/ui/domains/Portfolio/AssetBalanceCellValue.tsx index c2b8f18470..a232bf82ea 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetBalanceCellValue.tsx +++ b/apps/extension/src/ui/domains/Portfolio/AssetBalanceCellValue.tsx @@ -19,6 +19,7 @@ type Props = { className?: string tooltip?: ReactNode balancesStatus?: BalancesStatus + noCountUp?: boolean } export const AssetBalanceCellValue = ({ @@ -30,6 +31,7 @@ export const AssetBalanceCellValue = ({ className, tooltip, balancesStatus, + noCountUp, }: Props) => { if (!render) return null return ( @@ -47,7 +49,7 @@ export const AssetBalanceCellValue = ({ )} >
- +
{locked ? (
@@ -60,7 +62,7 @@ export const AssetBalanceCellValue = ({
) : null}
-
{fiat === null ? "-" : }
+
{fiat === null ? "-" : }
) diff --git a/apps/extension/src/ui/domains/Portfolio/AssetDetails/useChainTokenBalances.ts b/apps/extension/src/ui/domains/Portfolio/AssetDetails/useChainTokenBalances.ts index a6adcb787c..b08ac072fb 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetDetails/useChainTokenBalances.ts +++ b/apps/extension/src/ui/domains/Portfolio/AssetDetails/useChainTokenBalances.ts @@ -147,7 +147,8 @@ export const useChainTokenBalances = ({ chainId, balances }: ChainTokenBalancesP const detailRows = useEnhanceDetailRows(rawDetailRows) - const { evmNetwork } = balances.sorted[0] + const { evmNetwork } = useMemo(() => balances.sorted[0], [balances]) + const relay = useChain(chain?.relay?.id) const networkType = useNetworkCategory({ chain, evmNetwork, relay }) diff --git a/apps/extension/src/ui/domains/Portfolio/AssetsTable/DashboardAssetRow.tsx b/apps/extension/src/ui/domains/Portfolio/AssetsTable/DashboardAssetRow.tsx index 9c28abab46..704a8d20a4 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetsTable/DashboardAssetRow.tsx +++ b/apps/extension/src/ui/domains/Portfolio/AssetsTable/DashboardAssetRow.tsx @@ -1,6 +1,6 @@ import { ZapFastIcon } from "@talismn/icons" import { classNames } from "@talismn/util" -import { useCallback } from "react" +import { FC, useCallback } from "react" import { useTranslation } from "react-i18next" import { Balances } from "@extension/core" @@ -18,11 +18,10 @@ import { useTokenBalancesSummary } from "../useTokenBalancesSummary" import { NetworksLogoStack } from "./NetworksLogoStack" import { usePortfolioNetworkIds } from "./usePortfolioNetworkIds" -type AssetRowProps = { - balances: Balances -} - -export const AssetRow = ({ balances }: AssetRowProps) => { +export const AssetRow: FC<{ balances: Balances; noCountUp?: boolean }> = ({ + balances, + noCountUp, +}) => { const { t } = useTranslation() const networkIds = usePortfolioNetworkIds(balances) const { genericEvent } = useAnalytics() @@ -45,7 +44,7 @@ export const AssetRow = ({ balances }: AssetRowProps) => { if (!token || !summary) return null return ( -
+
{isUniswapV2LpToken && typeof tvl === "number" && (
- TVL + TVL
)} {!isUniswapV2LpToken && typeof rate === "number" && ( - + )}
@@ -95,6 +94,7 @@ export const AssetRow = ({ balances }: AssetRowProps) => { "noPadRight", status.status === "fetching" && "animate-pulse transition-opacity", )} + noCountUp={noCountUp} />
@@ -122,6 +122,7 @@ export const AssetRow = ({ balances }: AssetRowProps) => { canBondNomPool && "group-hover:hidden", status.status === "fetching" && "animate-pulse transition-opacity", )} + noCountUp={noCountUp} />
diff --git a/apps/extension/src/ui/domains/Portfolio/AssetsTable/DashboardAssetsTable.tsx b/apps/extension/src/ui/domains/Portfolio/AssetsTable/DashboardAssetsTable.tsx index 99128b388f..569018b6dc 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetsTable/DashboardAssetsTable.tsx +++ b/apps/extension/src/ui/domains/Portfolio/AssetsTable/DashboardAssetsTable.tsx @@ -1,6 +1,9 @@ import { classNames } from "@talismn/util" -import { FC, useMemo } from "react" +import { useVirtualizer } from "@tanstack/react-virtual" +import { Balances } from "extension-core" +import { FC, useEffect, useMemo, useRef, useState } from "react" import { useTranslation } from "react-i18next" +import { useLocation } from "react-router-dom" import { usePortfolio, useSelectedCurrency } from "@ui/state" @@ -14,7 +17,7 @@ const AssetRowSkeleton: FC<{ className?: string }> = ({ className }) => { return (
@@ -83,9 +86,10 @@ export const DashboardAssetsTable = () => { const { t } = useTranslation() const { isInitialising } = usePortfolio() const { selectedAccount, selectedFolder } = usePortfolioNavigation() - // group by token (symbol) const { symbolBalances } = usePortfolioSymbolBalancesByFilter("search") + const location = useLocation() + if (!symbolBalances.length && !isInitialising) { return (
@@ -99,13 +103,59 @@ export const DashboardAssetsTable = () => { } return ( -
+
{!!symbolBalances.length && } - - {symbolBalances.map(([symbol, b]) => ( - - ))} + {isInitialising && }
) } + +const VirtualizedRows: FC<{ symbolBalances: [string, Balances][] }> = ({ symbolBalances }) => { + const [noCountUp, setNoCountUp] = useState(false) + const ref = useRef(null) + + useEffect(() => { + const timeout = setTimeout(() => { + // we only want count up on the first rendering of the table + // ex: sorting or filtering rows using search box should not trigger count up + setNoCountUp(true) + }, 500) + + return () => clearTimeout(timeout) + }, []) + + const virtualizer = useVirtualizer({ + count: symbolBalances.length, + overscan: 5, + gap: 8, + estimateSize: () => 66, + getScrollElement: () => document.getElementById("main"), + }) + + return ( +
+
+ {virtualizer.getVirtualItems().map((item) => ( +
+ {!!symbolBalances[item.index] && ( + + )} +
+ ))} +
+
+ ) +} diff --git a/apps/extension/src/ui/domains/Portfolio/AssetsTable/PopupAssetsTable.tsx b/apps/extension/src/ui/domains/Portfolio/AssetsTable/PopupAssetsTable.tsx index bac0c885bd..926535a522 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetsTable/PopupAssetsTable.tsx +++ b/apps/extension/src/ui/domains/Portfolio/AssetsTable/PopupAssetsTable.tsx @@ -1,11 +1,13 @@ import { LockIcon } from "@talismn/icons" import { classNames } from "@talismn/util" -import { ReactNode, useCallback, useMemo } from "react" +import { useVirtualizer } from "@tanstack/react-virtual" +import { FC, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react" import { useTranslation } from "react-i18next" import { Balances } from "@extension/core" import { Accordion, AccordionIcon } from "@talisman/components/Accordion" import { FadeIn } from "@talisman/components/FadeIn" +import { useScrollContainer } from "@talisman/components/ScrollContainer" import { useOpenClose } from "@talisman/hooks/useOpenClose" import { Fiat } from "@ui/domains/Asset/Fiat" import Tokens from "@ui/domains/Asset/Tokens" @@ -26,16 +28,11 @@ import { NetworksLogoStack } from "./NetworksLogoStack" import { usePortfolioNetworkIds } from "./usePortfolioNetworkIds" import { usePortfolioSymbolBalancesByFilter } from "./usePortfolioSymbolBalances" -type AssetRowProps = { - balances: Balances - locked?: boolean -} - const AssetRowSkeleton = ({ className }: { className?: string }) => { return (
@@ -54,7 +51,11 @@ const AssetRowSkeleton = ({ className }: { className?: string }) => { ) } -const AssetRow = ({ balances, locked }: AssetRowProps) => { +const AssetRow: FC<{ + balances: Balances + noCountUp: boolean + locked?: boolean +}> = ({ balances, locked, noCountUp }) => { const networkIds = usePortfolioNetworkIds(balances) const { genericEvent } = useAnalytics() @@ -94,87 +95,86 @@ const AssetRow = ({ balances, locked }: AssetRowProps) => { if (!token || !summary) return null return ( - <> - - +
+ ) } @@ -204,7 +204,7 @@ const BalancesGroup = ({ label, fiatAmount, className, children }: GroupProps) =
-
{children}
+ {children}
) @@ -254,9 +254,7 @@ export const PopupAssetsTable = () => { )} - {available.map(([symbol, b]) => ( - - ))} + {isInitialising && } {!isInitialising && !available.length && (
@@ -279,12 +277,70 @@ export const PopupAssetsTable = () => { } fiatAmount={totalLocked} > - {lockedSymbolBalances.map(([symbol, b]) => ( - - ))} + )}
) } + +const VirtualizedRows: FC<{ rows: [string, Balances][]; locked?: boolean; overscan?: number }> = ({ + rows, + locked, + overscan, +}) => { + const [noCountUp, setNoCountUp] = useState(false) + const refContainer = useScrollContainer() + const ref = useRef(null) + + useEffect(() => { + const timeout = setTimeout(() => { + // we only want count up on the first rendering of the table + // ex: sorting or filtering rows using search box should not trigger count up + setNoCountUp(true) + }, 500) + + return () => clearTimeout(timeout) + }, []) + + const virtualizer = useVirtualizer({ + count: rows.length, + overscan: overscan ?? 5, + gap: 8, + estimateSize: () => 56, + getScrollElement: () => refContainer.current, + }) + + return ( +
+
+ {virtualizer.getVirtualItems().map((item) => ( +
+ {!!rows[item.index] && ( + + )} +
+ ))} +
+
+ ) +} diff --git a/apps/extension/src/ui/domains/Portfolio/AssetsTable/usePortfolioSymbolBalances.ts b/apps/extension/src/ui/domains/Portfolio/AssetsTable/usePortfolioSymbolBalances.ts index 35c0fad340..a37d42f725 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetsTable/usePortfolioSymbolBalances.ts +++ b/apps/extension/src/ui/domains/Portfolio/AssetsTable/usePortfolioSymbolBalances.ts @@ -193,7 +193,7 @@ export const usePortfolioSymbolBalances = (balances: Balances) => { balances.sum.fiat("usd").total >= 1 : () => true, ) - }, [balances.each, currency, hideDust]) + }, [balances, currency, hideDust]) const availableSymbolBalances = useMemo(() => { const available = symbolBalances diff --git a/apps/extension/src/ui/domains/Portfolio/PortfolioContainer.tsx b/apps/extension/src/ui/domains/Portfolio/PortfolioContainer.tsx index b9d2989723..ba25994676 100644 --- a/apps/extension/src/ui/domains/Portfolio/PortfolioContainer.tsx +++ b/apps/extension/src/ui/domains/Portfolio/PortfolioContainer.tsx @@ -1,38 +1,56 @@ import { bind } from "@react-rxjs/core" -import { FC, ReactNode, useEffect } from "react" +import { FC, PropsWithChildren, useEffect } from "react" import { combineLatest } from "rxjs" +import { portfolioAccounts$ } from "@ui/hooks/usePortfolioAccounts" import { - accounts$, - accountsCatalog$, + authorisedSites$, balancesHydrate$, portfolioSelectedAccounts$, remoteConfig$, usePortfolio, } from "@ui/state" -import { usePortfolioNavigation } from "./usePortfolioNavigation" +import { PortfolioNavigationProvider, usePortfolioNavigation } from "./usePortfolioNavigation" const [usePreload] = bind( - combineLatest([balancesHydrate$, accounts$, accountsCatalog$, remoteConfig$]), + combineLatest([balancesHydrate$, remoteConfig$, authorisedSites$, portfolioAccounts$]), ) -export const PortfolioContainer: FC<{ children: ReactNode; renderWhileLoading?: boolean }> = ({ +export const PortfolioContainer: FC> = ({ children, renderWhileLoading, // true in popup, false in dashboard }) => { usePreload() - const { selectedAccounts } = usePortfolioNavigation() + return ( + + + + {children} + + + + ) +} + +const ProvisionedPortfolioGuard: FC> = ({ + children, + renderWhileLoading, +}) => { const { isProvisioned } = usePortfolio() + // on popup home page, portfolio is loading while we display the home page + // but on dashboard, don't render until portfolio is provisioned + return !renderWhileLoading && !isProvisioned ? null : children +} + +const SelectedAccountsGuard: FC = ({ children }) => { + const { selectedAccounts } = usePortfolioNavigation() + useEffect(() => { portfolioSelectedAccounts$.next(selectedAccounts) }, [selectedAccounts]) - // // on popup home page, portfolio is loading while we display the home page - // // but on dashboard, don't render until portfolio is provisioned - if (!renderWhileLoading && !isProvisioned) return null - - return <>{children} + return children } diff --git a/apps/extension/src/ui/domains/Portfolio/usePortfolioNavigation.ts b/apps/extension/src/ui/domains/Portfolio/usePortfolioNavigation.ts index 111acc8556..c64b8f7bb7 100644 --- a/apps/extension/src/ui/domains/Portfolio/usePortfolioNavigation.ts +++ b/apps/extension/src/ui/domains/Portfolio/usePortfolioNavigation.ts @@ -3,9 +3,10 @@ import { AccountJsonAny, Tree, TreeAccount, TreeFolder, TreeItem } from "extensi import { useCallback, useMemo } from "react" import { useSearchParams } from "react-router-dom" +import { provideContext } from "@talisman/util/provideContext" import { usePortfolioAccounts } from "@ui/hooks/usePortfolioAccounts" -export const usePortfolioNavigation = () => { +const usePortfolioNavigationProvider = () => { const { accounts: allAccounts, portfolioAccounts, catalog } = usePortfolioAccounts() const [searchParams, updateSearchParams] = useSearchParams() @@ -94,6 +95,10 @@ export const usePortfolioNavigation = () => { } } +export const [PortfolioNavigationProvider, usePortfolioNavigation] = provideContext( + usePortfolioNavigationProvider, +) + const isAddressInTree = (tree: Tree, address: string): boolean => { try { const addresses = tree diff --git a/apps/extension/src/ui/domains/Portfolio/useTokenBalancesSummary.ts b/apps/extension/src/ui/domains/Portfolio/useTokenBalancesSummary.ts index 7a5fd78896..fb27905db1 100644 --- a/apps/extension/src/ui/domains/Portfolio/useTokenBalancesSummary.ts +++ b/apps/extension/src/ui/domains/Portfolio/useTokenBalancesSummary.ts @@ -119,7 +119,7 @@ export const useTokenBalancesSummary = (balances: Balances) => { ) return summary - }, [currency, tokenBalanceRates, tokenBalances.count, tokenBalances.each]) + }, [currency, tokenBalanceRates, tokenBalances]) return { token, diff --git a/apps/extension/src/ui/domains/Transactions/TxHistory/TxHistoryList.tsx b/apps/extension/src/ui/domains/Transactions/TxHistory/TxHistoryList.tsx index cc63ebc302..54be0d0f51 100644 --- a/apps/extension/src/ui/domains/Transactions/TxHistory/TxHistoryList.tsx +++ b/apps/extension/src/ui/domains/Transactions/TxHistory/TxHistoryList.tsx @@ -1,5 +1,6 @@ import { LoaderIcon, MoreHorizontalIcon, RocketIcon, XOctagonIcon } from "@talismn/icons" import { classNames } from "@talismn/util" +import { useVirtualizer } from "@tanstack/react-virtual" import { formatDistanceToNowStrict } from "date-fns" import { BalanceFormatter, @@ -22,6 +23,7 @@ import { useCallback, useEffect, useMemo, + useRef, useState, } from "react" import { useTranslation } from "react-i18next" @@ -35,6 +37,7 @@ import { } from "talisman-ui" import urlJoin from "url-join" +import { useScrollContainer } from "@talisman/components/ScrollContainer" import { ChainLogo } from "@ui/domains/Asset/ChainLogo" import { Fiat } from "@ui/domains/Asset/Fiat" import { TokenLogo } from "@ui/domains/Asset/TokenLogo" @@ -64,7 +67,7 @@ export const TxHistoryList = () => { const [activeTxHash, setActiveTxHash] = useState() const handleContextMenuOpen = useCallback( - (hash: string) => () => { + (hash: string) => { if (activeTxHash) return setActiveTxHash(hash) }, @@ -72,7 +75,7 @@ export const TxHistoryList = () => { ) const handleContextMenuClose = useCallback( - (hash: string) => () => { + (hash: string) => { if (hash !== activeTxHash) return setActiveTxHash(undefined) }, @@ -80,16 +83,14 @@ export const TxHistoryList = () => { ) return ( -
- {transactions.map((tx) => ( - - ))} +
+ + {!isLoading && !transactions.length && (
{t("No transactions found")} @@ -100,6 +101,55 @@ export const TxHistoryList = () => { ) } +const TransactionRows: FC<{ + transactions: WalletTransaction[] + activeTxHash?: string + onContextMenuOpen: (hash: string) => void + onContextMenuClose: (hash: string) => void +}> = ({ transactions, activeTxHash, onContextMenuOpen, onContextMenuClose }) => { + const refContainer = useScrollContainer() // used/defined in popup only + const ref = useRef(null) + + const virtualizer = useVirtualizer({ + count: transactions.length, + estimateSize: () => (IS_POPUP ? 52 : 58), + overscan: 5, + getScrollElement: () => refContainer.current ?? document.getElementById("main"), // fallback to main, the container for dashboard + gap: 8, + }) + + return ( +
+
+ {virtualizer.getVirtualItems().map((item) => ( +
+ {!!transactions[item.index] && ( + onContextMenuOpen(transactions[item.index].hash)} + onContextMenuClose={() => onContextMenuClose(transactions[item.index].hash)} + /> + )} +
+ ))} +
+
+ ) +} + type TransactionRowProps = { tx: WalletTransaction diff --git a/apps/extension/src/ui/hooks/useSendFundsPopup.ts b/apps/extension/src/ui/hooks/useSendFundsPopup.ts index 164a160692..b5fa8f4d3e 100644 --- a/apps/extension/src/ui/hooks/useSendFundsPopup.ts +++ b/apps/extension/src/ui/hooks/useSendFundsPopup.ts @@ -22,10 +22,10 @@ export const useSendFundsPopup = ( const { t } = useTranslation() const accounts = useAccounts("owned") const balances = useBalances("owned") - const transferableBalances = useMemo( - () => new Balances(balances.each.filter((b) => !tokenId || b.tokenId === tokenId)), - [balances, tokenId], - ) + const transferableBalance = useMemo(() => { + const owned = new Balances(balances.each.filter((b) => !tokenId || b.tokenId === tokenId)) + return owned.sum.planck.transferable + }, [balances, tokenId]) const { canSendFunds, cannotSendFundsReason } = useMemo<{ canSendFunds: boolean @@ -46,7 +46,7 @@ export const useSendFundsPopup = ( canSendFunds: false, cannotSendFundsReason: t(`Please send funds on Signet: ${account.signetUrl}`), } - if (tokenId && transferableBalances.sum.planck.transferable === 0n) + if (tokenId && transferableBalance === 0n) return { canSendFunds: false, cannotSendFundsReason: t("No tokens available to send"), @@ -70,7 +70,7 @@ export const useSendFundsPopup = ( } } return { canSendFunds: true } - }, [account, accounts, t, to, tokenId, transferableBalances.sum.planck.transferable]) + }, [account, accounts, t, to, tokenId, transferableBalance]) const openSendFundsPopup = useCallback(() => { if (!canSendFunds) return diff --git a/apps/extension/src/ui/state/authorisedSites.ts b/apps/extension/src/ui/state/authorisedSites.ts index ba5731420b..da82bdc296 100644 --- a/apps/extension/src/ui/state/authorisedSites.ts +++ b/apps/extension/src/ui/state/authorisedSites.ts @@ -1,17 +1,17 @@ import { bind } from "@react-rxjs/core" import { AuthorizedSites } from "extension-core" -import { Observable, shareReplay } from "rxjs" +import { Observable } from "rxjs" import { api } from "@ui/api" -import { debugObservable } from "./util/debugObservable" +export const [useAuthorisedSites, authorisedSites$] = bind( + new Observable((subscriber) => { + const unsubscribe = api.authorizedSitesSubscribe((sites) => { + subscriber.next(sites) + }) -export const authorisedSites$ = new Observable((subscriber) => { - const unsubscribe = api.authorizedSitesSubscribe((sites) => { - subscriber.next(sites) - }) - - return () => unsubscribe() -}).pipe(debugObservable("authorisedSites$"), shareReplay({ bufferSize: 1, refCount: true })) - -export const [useAuthorisedSites] = bind(authorisedSites$) + return () => { + unsubscribe() + } + }), +) diff --git a/apps/extension/src/ui/state/balances.ts b/apps/extension/src/ui/state/balances.ts index 77bd8198eb..f5bbdfd9fb 100644 --- a/apps/extension/src/ui/state/balances.ts +++ b/apps/extension/src/ui/state/balances.ts @@ -58,14 +58,15 @@ export const [useIsBalanceInitializing, isBalanceInitialising$] = bind( ), ) -const validBalances$ = combineLatest([ +const allBalances$ = combineLatest([ getTokensMap$(BALANCES_CHAINDATA_QUERY), getChainsMap$(BALANCES_CHAINDATA_QUERY), accountsMap$, rawBalances$.pipe(map((balances) => balances.data)), + balancesHydrate$, ]).pipe( - map(([tokens, chains, accounts, balances]) => - balances.filter((b) => { + map(([tokens, chains, accounts, balances, hydrate]) => { + const validBalances = balances.filter((b) => { // ensure there is a matching token if (!tokens[b.tokenId]) return false @@ -77,12 +78,9 @@ const validBalances$ = combineLatest([ return isAccountCompatibleWithChain(chains[b.chainId], account.type, account.genesisHash) if ("evmNetworkId" in b && b.evmNetworkId) return account.type === "ethereum" return false - }), - ), -) - -const allBalances$ = combineLatest([validBalances$, balancesHydrate$]).pipe( - map(([rawBalances, hydrate]) => new Balances(rawBalances, hydrate)), + }) + return new Balances(validBalances, hydrate) + }, shareReplay(1)), ) type BalanceQueryParams = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5f35179c5..e1e621041b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -137,7 +137,7 @@ importers: version: 0.6.8(@ianvs/prettier-plugin-sort-imports@4.3.1(prettier@3.3.3))(prettier-plugin-import-sort@0.0.7(prettier@3.3.3))(prettier@3.3.3) ts-loader: specifier: 9.5.1 - version: 9.5.1(typescript@5.6.3)(webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)) + version: 9.5.1(typescript@5.6.3)(webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))) turbo: specifier: 2.2.3 version: 2.2.3 @@ -358,6 +358,9 @@ importers: '@tanstack/react-query': specifier: 5.59.16 version: 5.59.16(react@18.3.1) + '@tanstack/react-virtual': + specifier: ^3.11.1 + version: 3.11.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/blueimp-md5': specifier: 2.18.2 version: 2.18.2 @@ -805,7 +808,7 @@ importers: version: 2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) wagmi: specifier: ^2.12.25 - version: 2.12.25(@tanstack/query-core@5.59.16)(@tanstack/react-query@5.59.16(react@18.3.1))(@types/react@18.3.12)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)) + version: 2.12.25(@tanstack/query-core@5.59.16)(@tanstack/react-query@5.59.16(react@18.3.1))(@types/react@18.3.12)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)) devDependencies: '@openzeppelin/contracts': specifier: ^5.1.0 @@ -4585,7 +4588,7 @@ packages: resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} engines: {node: '>= 8.0.0'} peerDependencies: - rollup: '>=4.22.4' + rollup: '>=2.79.2' '@rollup/pluginutils@4.2.1': resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} @@ -5354,14 +5357,14 @@ packages: peerDependencies: react: ^18 || ^19 - '@tanstack/react-virtual@3.10.8': - resolution: {integrity: sha512-VbzbVGSsZlQktyLrP5nxE+vE1ZR+U0NFAWPbJLoG2+DKPwd2D7dVICTVIIaYlJqX1ZCEnYDbaOpmMwbsyhBoIA==} + '@tanstack/react-virtual@3.11.1': + resolution: {integrity: sha512-orn2QNe5tF6SqjucHJ6cKTKcRDe3GG7bcYqPNn72Yejj7noECdzgAyRfGt2pGDPemhYim3d1HIR/dgruCnLfUA==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/virtual-core@3.10.8': - resolution: {integrity: sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA==} + '@tanstack/virtual-core@3.10.9': + resolution: {integrity: sha512-kBknKOKzmeR7lN+vSadaKWXaLS0SZZG+oqpQ/k80Q6g9REn6zRHS/ZYdrIzHnpHgy/eWs00SujveUN/GJT2qTw==} '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} @@ -12854,7 +12857,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.25.9 convert-source-map: 2.0.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 7.6.3 @@ -12874,7 +12877,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.26.0 convert-source-map: 2.0.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 7.6.3 @@ -12956,29 +12959,11 @@ snapshots: regexpu-core: 6.1.1 semver: 7.6.3 - '@babel/helper-create-regexp-features-plugin@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - regexpu-core: 6.1.1 - semver: 7.6.3 - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.7 - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 debug: 4.3.7(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 @@ -12995,18 +12980,6 @@ snapshots: resolve: 1.22.8 transitivePeerDependencies: - supports-color - optional: true - - '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.7(supports-color@8.1.1) - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color '@babel/helper-member-expression-to-functions@7.25.9': dependencies: @@ -13066,15 +13039,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-wrap-function': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/helper-replace-supers@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13154,34 +13118,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13191,15 +13137,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13208,14 +13145,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -13228,12 +13157,6 @@ snapshots: dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - optional: true - - '@babel/plugin-proposal-export-default-from@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.26.0)': dependencies: @@ -13254,10 +13177,6 @@ snapshots: dependencies: '@babel/core': 7.25.9 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13267,6 +13186,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.25.9)': dependencies: @@ -13277,6 +13197,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.9)': dependencies: @@ -13287,6 +13208,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.9)': dependencies: @@ -13297,28 +13219,17 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - optional: true - - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-syntax-export-default-from@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - optional: true - - '@babel/plugin-syntax-export-default-from@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-syntax-flow@7.25.9(@babel/core@7.25.9)': dependencies: @@ -13329,7 +13240,6 @@ snapshots: dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - optional: true '@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0)': dependencies: @@ -13341,11 +13251,6 @@ snapshots: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-import-assertions@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-import-attributes@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13355,6 +13260,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.9)': dependencies: @@ -13365,6 +13271,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.9)': dependencies: @@ -13375,6 +13282,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.25.9)': dependencies: @@ -13395,6 +13303,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.9)': dependencies: @@ -13415,6 +13324,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.9)': dependencies: @@ -13425,6 +13335,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.9)': dependencies: @@ -13435,6 +13346,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.9)': dependencies: @@ -13455,6 +13367,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.9)': dependencies: @@ -13465,6 +13378,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + optional: true '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.25.9)': dependencies: @@ -13482,22 +13396,11 @@ snapshots: '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.9) '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-async-generator-functions@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13507,15 +13410,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-generator-functions@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13525,35 +13419,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-block-scoped-functions@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-block-scoped-functions@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13562,14 +13437,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-class-static-block@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13578,14 +13445,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-classes@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13598,84 +13457,39 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) - '@babel/traverse': 7.25.9 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 '@babel/template': 7.25.9 - '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/template': 7.25.9 - '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.9) '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.9) '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-exponentiation-operator@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13684,30 +13498,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-flow-strip-types@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.25.9) - optional: true '@babel/plugin-transform-flow-strip-types@7.25.9(@babel/core@7.26.0)': dependencies: @@ -13723,14 +13523,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-for-of@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13740,55 +13532,26 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-literals@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13797,14 +13560,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-commonjs@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13833,16 +13588,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13851,56 +13596,27 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-transforms': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.9) '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-nullish-coalescing-operator@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-nullish-coalescing-operator@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13908,13 +13624,6 @@ snapshots: '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.25.9) - '@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13923,24 +13632,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13949,24 +13645,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13975,14 +13658,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -13992,25 +13667,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-constant-elements@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -14021,11 +13682,6 @@ snapshots: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-display-name@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx-development@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -14038,21 +13694,11 @@ snapshots: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -14064,17 +13710,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/types': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-react-pure-annotations@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -14087,22 +13722,11 @@ snapshots: '@babel/helper-plugin-utils': 7.25.9 regenerator-transform: 0.15.2 - '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-runtime@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -14114,30 +13738,12 @@ snapshots: semver: 7.6.3 transitivePeerDependencies: - supports-color - optional: true - - '@babel/plugin-transform-runtime@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.26.0) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) - babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.26.0) - semver: 7.6.3 - transitivePeerDependencies: - - supports-color '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-spread@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -14146,42 +13752,19 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-template-literals@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-template-literals@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-typeof-symbol@7.25.9(@babel/core@7.25.9)': dependencies: - '@babel/core': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-typeof-symbol@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-typescript@7.25.9(@babel/core@7.25.9)': @@ -14211,47 +13794,24 @@ snapshots: '@babel/core': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.9) '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.9) '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.25.9) '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/preset-env@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/compat-data': 7.25.9 @@ -14326,80 +13886,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/preset-env@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/compat-data': 7.25.9 - '@babel/core': 7.26.0 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0) - '@babel/plugin-syntax-import-assertions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-import-attributes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoped-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-static-block': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-exponentiation-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-template-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typeof-symbol': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.26.0) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.26.0) - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0) - babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) - babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.0) - core-js-compat: 3.38.1 - semver: 7.6.3 - transitivePeerDependencies: - - supports-color - '@babel/preset-flow@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -14414,13 +13900,6 @@ snapshots: '@babel/types': 7.25.9 esutils: 2.0.3 - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/types': 7.25.9 - esutils: 2.0.3 - '@babel/preset-react@7.25.9(@babel/core@7.25.9)': dependencies: '@babel/core': 7.25.9 @@ -14485,7 +13964,7 @@ snapshots: '@babel/parser': 7.25.9 '@babel/template': 7.25.9 '@babel/types': 7.25.9 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -15093,7 +14572,7 @@ snapshots: '@eslint/config-array@0.18.0': dependencies: '@eslint/object-schema': 2.1.4 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -15117,7 +14596,7 @@ snapshots: '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -15491,7 +14970,7 @@ snapshots: '@floating-ui/react': 0.26.25(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@react-aria/focus': 3.18.4(react@18.3.1) '@react-aria/interactions': 3.22.4(react@18.3.1) - '@tanstack/react-virtual': 3.10.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-virtual': 3.11.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -16084,31 +15563,31 @@ snapshots: - supports-color optional: true - '@metamask/sdk-install-modal-web@0.30.0(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)': + '@metamask/sdk-install-modal-web@0.30.0(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)': dependencies: i18next: 23.11.5 qr-code-styling: 1.8.4 optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4) - optional: true + react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) - '@metamask/sdk-install-modal-web@0.30.0(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)': + '@metamask/sdk-install-modal-web@0.30.0(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)': dependencies: i18next: 23.11.5 qr-code-styling: 1.8.4 optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-native: 0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) + react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4) + optional: true - '@metamask/sdk@0.30.1(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)(utf-8-validate@6.0.4)': + '@metamask/sdk@0.30.1(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(utf-8-validate@5.0.10)': dependencies: '@metamask/onboarding': 1.0.1 '@metamask/providers': 16.1.0 - '@metamask/sdk-communication-layer': 0.30.0(cross-fetch@4.0.0)(eciesjs@0.4.10)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) - '@metamask/sdk-install-modal-web': 0.30.0(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1) + '@metamask/sdk-communication-layer': 0.30.0(cross-fetch@4.0.0)(eciesjs@0.4.10)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + '@metamask/sdk-install-modal-web': 0.30.0(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) bowser: 2.11.0 cross-fetch: 4.0.0 debug: 4.3.7(supports-color@8.1.1) @@ -16120,9 +15599,9 @@ snapshots: obj-multiplex: 1.0.0 pump: 3.0.2 qrcode-terminal-nooctal: 0.12.1 - react-native-webview: 11.26.1(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1) + react-native-webview: 11.26.1(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) readable-stream: 3.6.2 - socket.io-client: 4.8.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + socket.io-client: 4.8.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) util: 0.12.5 uuid: 8.3.2 optionalDependencies: @@ -16134,14 +15613,13 @@ snapshots: - react-native - supports-color - utf-8-validate - optional: true - '@metamask/sdk@0.30.1(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(utf-8-validate@5.0.10)': + '@metamask/sdk@0.30.1(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)(utf-8-validate@6.0.4)': dependencies: '@metamask/onboarding': 1.0.1 '@metamask/providers': 16.1.0 - '@metamask/sdk-communication-layer': 0.30.0(cross-fetch@4.0.0)(eciesjs@0.4.10)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@metamask/sdk-install-modal-web': 0.30.0(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) + '@metamask/sdk-communication-layer': 0.30.0(cross-fetch@4.0.0)(eciesjs@0.4.10)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + '@metamask/sdk-install-modal-web': 0.30.0(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1) bowser: 2.11.0 cross-fetch: 4.0.0 debug: 4.3.7(supports-color@8.1.1) @@ -16153,9 +15631,9 @@ snapshots: obj-multiplex: 1.0.0 pump: 3.0.2 qrcode-terminal-nooctal: 0.12.1 - react-native-webview: 11.26.1(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) + react-native-webview: 11.26.1(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1) readable-stream: 3.6.2 - socket.io-client: 4.8.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + socket.io-client: 4.8.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) util: 0.12.5 uuid: 8.3.2 optionalDependencies: @@ -16167,6 +15645,7 @@ snapshots: - react-native - supports-color - utf-8-validate + optional: true '@metamask/superstruct@3.1.0': {} @@ -17274,14 +16753,6 @@ snapshots: transitivePeerDependencies: - '@babel/preset-env' - supports-color - optional: true - - '@react-native/babel-plugin-codegen@0.76.0(@babel/preset-env@7.25.9(@babel/core@7.26.0))': - dependencies: - '@react-native/codegen': 0.76.0(@babel/preset-env@7.25.9(@babel/core@7.26.0)) - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color '@react-native/babel-preset@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))': dependencies: @@ -17333,58 +16804,6 @@ snapshots: transitivePeerDependencies: - '@babel/preset-env' - supports-color - optional: true - - '@react-native/babel-preset@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))': - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-generator-functions': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) - '@babel/template': 7.25.9 - '@react-native/babel-plugin-codegen': 0.76.0(@babel/preset-env@7.25.9(@babel/core@7.26.0)) - babel-plugin-syntax-hermes-parser: 0.23.1 - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.0) - react-refresh: 0.14.2 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color '@react-native/codegen@0.76.0(@babel/preset-env@7.25.9(@babel/core@7.25.9))': dependencies: @@ -17399,36 +16818,21 @@ snapshots: yargs: 17.7.2 transitivePeerDependencies: - supports-color - optional: true - - '@react-native/codegen@0.76.0(@babel/preset-env@7.25.9(@babel/core@7.26.0))': - dependencies: - '@babel/parser': 7.26.2 - '@babel/preset-env': 7.25.9(@babel/core@7.26.0) - glob: 7.2.3 - hermes-parser: 0.23.1 - invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.25.9(@babel/core@7.26.0)) - mkdirp: 0.5.6 - nullthrows: 1.1.1 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - '@react-native/community-cli-plugin@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(bufferutil@4.0.8)(utf-8-validate@6.0.4)': + '@react-native/community-cli-plugin@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: - '@react-native/dev-middleware': 0.76.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@react-native/dev-middleware': 0.76.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@react-native/metro-babel-transformer': 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9)) chalk: 4.1.2 execa: 5.1.1 invariant: 2.2.4 - metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) - metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) metro-core: 0.81.0 node-fetch: 2.7.0 readline: 1.3.0 optionalDependencies: - '@react-native-community/cli-server-api': 15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@react-native-community/cli-server-api': 15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' @@ -17436,22 +16840,21 @@ snapshots: - encoding - supports-color - utf-8-validate - optional: true - '@react-native/community-cli-plugin@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@react-native/community-cli-plugin@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(bufferutil@4.0.8)(utf-8-validate@6.0.4)': dependencies: - '@react-native/dev-middleware': 0.76.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@react-native/metro-babel-transformer': 0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0)) + '@react-native/dev-middleware': 0.76.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@react-native/metro-babel-transformer': 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9)) chalk: 4.1.2 execa: 5.1.1 invariant: 2.2.4 - metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + metro: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + metro-config: 0.81.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) metro-core: 0.81.0 node-fetch: 2.7.0 readline: 1.3.0 optionalDependencies: - '@react-native-community/cli-server-api': 15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@react-native-community/cli-server-api': 15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' @@ -17459,6 +16862,7 @@ snapshots: - encoding - supports-color - utf-8-validate + optional: true '@react-native/debugger-frontend@0.76.0': {} @@ -17512,38 +16916,27 @@ snapshots: transitivePeerDependencies: - '@babel/preset-env' - supports-color - optional: true - - '@react-native/metro-babel-transformer@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))': - dependencies: - '@babel/core': 7.26.0 - '@react-native/babel-preset': 0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0)) - hermes-parser: 0.23.1 - nullthrows: 1.1.1 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color '@react-native/normalize-colors@0.76.0': {} - '@react-native/virtualized-lists@0.76.0(@types/react@18.3.12)(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)': + '@react-native/virtualized-lists@0.76.0(@types/react@18.3.12)(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4) + react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) optionalDependencies: '@types/react': 18.3.12 - optional: true - '@react-native/virtualized-lists@0.76.0(@types/react@18.3.12)(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)': + '@react-native/virtualized-lists@0.76.0(@types/react@18.3.12)(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) + react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4) optionalDependencies: '@types/react': 18.3.12 + optional: true '@react-rxjs/core@0.10.7(react@18.3.1)(rxjs@7.8.1)': dependencies: @@ -18502,13 +17895,13 @@ snapshots: '@tanstack/query-core': 5.59.16 react: 18.3.1 - '@tanstack/react-virtual@3.10.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-virtual@3.11.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@tanstack/virtual-core': 3.10.8 + '@tanstack/virtual-core': 3.10.9 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@tanstack/virtual-core@3.10.8': {} + '@tanstack/virtual-core@3.10.9': {} '@testing-library/dom@10.4.0': dependencies: @@ -18867,7 +18260,7 @@ snapshots: '@typescript-eslint/types': 8.11.0 '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 8.11.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) eslint: 9.13.0(jiti@2.3.3) optionalDependencies: typescript: 5.6.3 @@ -18900,7 +18293,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) '@typescript-eslint/utils': 8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3) - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 @@ -18930,7 +18323,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.11.0 '@typescript-eslint/visitor-keys': 8.11.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -19021,10 +18414,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@wagmi/connectors@5.3.3(@types/react@18.3.12)(@wagmi/core@2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10))': + '@wagmi/connectors@5.3.3(@types/react@18.3.12)(@wagmi/core@2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10))': dependencies: '@coinbase/wallet-sdk': 4.1.0 - '@metamask/sdk': 0.30.1(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(utf-8-validate@5.0.10) + '@metamask/sdk': 0.30.1(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(utf-8-validate@5.0.10) '@safe-global/safe-apps-provider': 0.18.3(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) '@wagmi/core': 2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)) @@ -19731,10 +19124,6 @@ snapshots: dependencies: acorn: 8.13.0 - acorn-import-attributes@1.9.5(acorn@8.14.0): - dependencies: - acorn: 8.14.0 - acorn-jsx@5.3.2(acorn@8.13.0): dependencies: acorn: 8.13.0 @@ -20084,6 +19473,7 @@ snapshots: slash: 3.0.0 transitivePeerDependencies: - supports-color + optional: true babel-plugin-istanbul@6.1.1: dependencies: @@ -20120,15 +19510,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.26.0): - dependencies: - '@babel/compat-data': 7.25.9 - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) - semver: 7.6.3 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.25.9): dependencies: '@babel/compat-data': 7.26.2 @@ -20137,16 +19518,6 @@ snapshots: semver: 7.6.3 transitivePeerDependencies: - supports-color - optional: true - - babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.0): - dependencies: - '@babel/compat-data': 7.26.2 - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) - semver: 7.6.3 - transitivePeerDependencies: - - supports-color babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.25.9): dependencies: @@ -20156,14 +19527,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) - core-js-compat: 3.38.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.25.9): dependencies: '@babel/core': 7.25.9 @@ -20171,27 +19534,12 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.25.9): dependencies: '@babel/core': 7.25.9 '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.25.9) transitivePeerDependencies: - supports-color - optional: true - - babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.26.0): - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color babel-plugin-syntax-hermes-parser@0.23.1: dependencies: @@ -20202,13 +19550,6 @@ snapshots: '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.25.9) transitivePeerDependencies: - '@babel/core' - optional: true - - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.26.0): - dependencies: - '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) - transitivePeerDependencies: - - '@babel/core' babel-preset-current-node-syntax@1.1.0(@babel/core@7.25.9): dependencies: @@ -20247,6 +19588,7 @@ snapshots: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) + optional: true babel-preset-jest@29.6.3(@babel/core@7.25.9): dependencies: @@ -20259,6 +19601,7 @@ snapshots: '@babel/core': 7.26.0 babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + optional: true balanced-match@1.0.2: {} @@ -21177,10 +20520,6 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.7: - dependencies: - ms: 2.1.3 - debug@4.3.7(supports-color@8.1.1): dependencies: ms: 2.1.3 @@ -21985,7 +21324,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -24015,32 +23354,6 @@ snapshots: write-file-atomic: 2.4.3 transitivePeerDependencies: - supports-color - optional: true - - jscodeshift@0.14.0(@babel/preset-env@7.25.9(@babel/core@7.26.0)): - dependencies: - '@babel/core': 7.26.0 - '@babel/parser': 7.26.2 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/preset-env': 7.25.9(@babel/core@7.26.0) - '@babel/preset-flow': 7.25.9(@babel/core@7.26.0) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) - '@babel/register': 7.25.9(@babel/core@7.26.0) - babel-core: 7.0.0-bridge.0(@babel/core@7.26.0) - chalk: 4.1.2 - flow-parser: 0.255.0 - graceful-fs: 4.2.11 - micromatch: 4.0.8 - neo-async: 2.6.2 - node-dir: 0.1.17 - recast: 0.21.5 - temp: 0.8.4 - write-file-atomic: 2.4.3 - transitivePeerDependencies: - - supports-color jsdom@20.0.3(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: @@ -24194,7 +23507,7 @@ snapshots: dependencies: chalk: 5.3.0 commander: 12.1.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) execa: 8.0.1 lilconfig: 3.1.2 listr2: 8.2.5 @@ -25862,31 +25175,31 @@ snapshots: react-is@18.3.1: {} - react-native-webview@11.26.1(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1): + react-native-webview@11.26.1(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1): dependencies: escape-string-regexp: 2.0.0 invariant: 2.2.4 react: 18.3.1 - react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4) - optional: true + react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) - react-native-webview@11.26.1(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1): + react-native-webview@11.26.1(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1): dependencies: escape-string-regexp: 2.0.0 invariant: 2.2.4 react: 18.3.1 - react-native: 0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) + react-native: 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4) + optional: true - react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4): + react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10): dependencies: '@jest/create-cache-key-function': 29.7.0 '@react-native/assets-registry': 0.76.0 '@react-native/codegen': 0.76.0(@babel/preset-env@7.25.9(@babel/core@7.25.9)) - '@react-native/community-cli-plugin': 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@react-native/community-cli-plugin': 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@react-native/gradle-plugin': 0.76.0 '@react-native/js-polyfills': 0.76.0 '@react-native/normalize-colors': 0.76.0 - '@react-native/virtualized-lists': 0.76.0(@types/react@18.3.12)(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1) + '@react-native/virtualized-lists': 0.76.0(@types/react@18.3.12)(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -25909,14 +25222,14 @@ snapshots: pretty-format: 29.7.0 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + react-devtools-core: 5.3.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) react-refresh: 0.14.2 regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 semver: 7.6.3 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) + ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@5.0.10) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.12 @@ -25928,22 +25241,21 @@ snapshots: - encoding - supports-color - utf-8-validate - optional: true - react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10): + react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4): dependencies: '@jest/create-cache-key-function': 29.7.0 '@react-native/assets-registry': 0.76.0 - '@react-native/codegen': 0.76.0(@babel/preset-env@7.25.9(@babel/core@7.26.0)) - '@react-native/community-cli-plugin': 0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@react-native/codegen': 0.76.0(@babel/preset-env@7.25.9(@babel/core@7.25.9)) + '@react-native/community-cli-plugin': 0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@react-native/gradle-plugin': 0.76.0 '@react-native/js-polyfills': 0.76.0 '@react-native/normalize-colors': 0.76.0 - '@react-native/virtualized-lists': 0.76.0(@types/react@18.3.12)(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) + '@react-native/virtualized-lists': 0.76.0(@types/react@18.3.12)(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 - babel-jest: 29.7.0(@babel/core@7.26.0) + babel-jest: 29.7.0(@babel/core@7.25.9) babel-plugin-syntax-hermes-parser: 0.23.1 base64-js: 1.5.1 chalk: 4.1.2 @@ -25962,14 +25274,14 @@ snapshots: pretty-format: 29.7.0 promise: 8.3.0 react: 18.3.1 - react-devtools-core: 5.3.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) + react-devtools-core: 5.3.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) react-refresh: 0.14.2 regenerator-runtime: 0.13.11 scheduler: 0.24.0-canary-efb381bbf-20230505 semver: 7.6.3 stacktrace-parser: 0.1.10 whatwg-fetch: 3.6.20 - ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@5.0.10) + ws: 6.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) yargs: 17.7.2 optionalDependencies: '@types/react': 18.3.12 @@ -25981,6 +25293,7 @@ snapshots: - encoding - supports-color - utf-8-validate + optional: true react-property@2.0.2: {} @@ -27041,29 +26354,28 @@ snapshots: term-size@2.2.1: {} - terser-webpack-plugin@5.3.10(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)): + terser-webpack-plugin@5.3.10(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack@5.95.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.36.0 - webpack: 5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.7.39(@swc/helpers@0.5.13) esbuild: 0.24.0 - terser-webpack-plugin@5.3.10(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack@5.95.0): + terser-webpack-plugin@5.3.10(@swc/core@1.7.39(@swc/helpers@0.5.13))(webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.36.0 - webpack: 5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack-cli@5.1.4) + webpack: 5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13)) optionalDependencies: '@swc/core': 1.7.39(@swc/helpers@0.5.13) - esbuild: 0.24.0 terser@5.36.0: dependencies: @@ -27226,7 +26538,7 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) - ts-loader@9.5.1(typescript@5.6.3)(webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)): + ts-loader@9.5.1(typescript@5.6.3)(webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))): dependencies: chalk: 4.1.2 enhanced-resolve: 5.17.1 @@ -27234,7 +26546,7 @@ snapshots: semver: 7.6.3 source-map: 0.7.4 typescript: 5.6.3 - webpack: 5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13)) ts-loader@9.5.1(typescript@5.6.3)(webpack@5.95.0): dependencies: @@ -27328,7 +26640,7 @@ snapshots: cac: 6.7.14 chokidar: 4.0.1 consola: 3.2.3 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) esbuild: 0.24.0 joycon: 3.1.1 picocolors: 1.1.1 @@ -27764,14 +27076,14 @@ snapshots: dependencies: xml-name-validator: 4.0.0 - wagmi@2.12.25(@tanstack/query-core@5.59.16)(@tanstack/react-query@5.59.16(react@18.3.1))(@types/react@18.3.12)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@6.0.4)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4)): + wagmi@2.12.25(@tanstack/query-core@5.59.16)(@tanstack/react-query@5.59.16(react@18.3.1))(@types/react@18.3.12)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)): dependencies: '@tanstack/react-query': 5.59.16(react@18.3.1) - '@wagmi/connectors': 5.3.3(@types/react@18.3.12)(@wagmi/core@2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@6.0.4)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4)) - '@wagmi/core': 2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4)) + '@wagmi/connectors': 5.3.3(@types/react@18.3.12)(@wagmi/core@2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)) + '@wagmi/core': 2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)) react: 18.3.1 use-sync-external-store: 1.2.0(react@18.3.1) - viem: 2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4) + viem: 2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -27798,16 +27110,15 @@ snapshots: - supports-color - utf-8-validate - zod - optional: true - wagmi@2.12.25(@tanstack/query-core@5.59.16)(@tanstack/react-query@5.59.16(react@18.3.1))(@types/react@18.3.12)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)): + wagmi@2.12.25(@tanstack/query-core@5.59.16)(@tanstack/react-query@5.59.16(react@18.3.1))(@types/react@18.3.12)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@6.0.4)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4)): dependencies: '@tanstack/react-query': 5.59.16(react@18.3.1) - '@wagmi/connectors': 5.3.3(@types/react@18.3.12)(@wagmi/core@2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.25.9(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)) - '@wagmi/core': 2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)) + '@wagmi/connectors': 5.3.3(@types/react@18.3.12)(@wagmi/core@2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.76.0(@babel/core@7.25.9)(@babel/preset-env@7.25.9(@babel/core@7.25.9))(@react-native-community/cli-server-api@15.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(@types/react@18.3.12)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@6.0.4))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@6.0.4)(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4)) + '@wagmi/core': 2.14.1(@tanstack/query-core@5.59.16)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4)) react: 18.3.1 use-sync-external-store: 1.2.0(react@18.3.1) - viem: 2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + viem: 2.21.34(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@6.0.4) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -27834,6 +27145,7 @@ snapshots: - supports-color - utf-8-validate - zod + optional: true walk-sync@2.2.0: dependencies: @@ -27952,14 +27264,14 @@ snapshots: webpack-virtual-modules@0.5.0: {} - webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0): + webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13)): dependencies: '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.14.0 - acorn-import-attributes: 1.9.5(acorn@8.14.0) + acorn: 8.13.0 + acorn-import-attributes: 1.9.5(acorn@8.13.0) browserslist: 4.24.2 chrome-trace-event: 1.0.3 enhanced-resolve: 5.17.1 @@ -27974,7 +27286,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))(esbuild@0.24.0)) + terser-webpack-plugin: 5.3.10(@swc/core@1.7.39(@swc/helpers@0.5.13))(webpack@5.95.0(@swc/core@1.7.39(@swc/helpers@0.5.13))) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: From 0ee3c9cf1cabc398667881b18e55727eeba27a51 Mon Sep 17 00:00:00 2001 From: Kheops <26880866+0xKheops@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:28:50 +0900 Subject: [PATCH 11/11] feat: portfolio header adjustments (#1749) * feat: rename receive to copy, and enable it, for watched accounts * feat: disable swap button for watched accounts --- .../popup/components/TotalFiatBalance.tsx | 2 ++ .../Portfolio/DashboardPortfolioHeader.tsx | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/extension/src/ui/apps/popup/components/TotalFiatBalance.tsx b/apps/extension/src/ui/apps/popup/components/TotalFiatBalance.tsx index 3dae654a44..6142b3c58a 100644 --- a/apps/extension/src/ui/apps/popup/components/TotalFiatBalance.tsx +++ b/apps/extension/src/ui/apps/popup/components/TotalFiatBalance.tsx @@ -204,6 +204,8 @@ const TopActions = ({ disabled }: { disabled?: boolean }) => { label: t("Swap"), icon: RepeatIcon, onClick: () => handleSwapClick(), + disabled: disableActions, + disabledReason, }, canBuy ? { diff --git a/apps/extension/src/ui/domains/Portfolio/DashboardPortfolioHeader.tsx b/apps/extension/src/ui/domains/Portfolio/DashboardPortfolioHeader.tsx index 9ca63fedc9..75aadf57fe 100644 --- a/apps/extension/src/ui/domains/Portfolio/DashboardPortfolioHeader.tsx +++ b/apps/extension/src/ui/domains/Portfolio/DashboardPortfolioHeader.tsx @@ -271,14 +271,13 @@ const TopActions: FC = () => { { analyticsName: "Goto", analyticsAction: "open receive", - label: t("Receive"), + label: !!selectedAccount && !isOwnedAccount(selectedAccount) ? t("Copy") : t("Receive"), icon: ArrowDownIcon, onClick: () => openCopyAddressModal({ address: selectedAddress, }), - disabled: disableActions, - disabledReason, + disabled: !selectedAccounts.length, // always allow, as long as there is at least one account }, { analyticsName: "Goto", @@ -286,6 +285,8 @@ const TopActions: FC = () => { label: t("Swap"), icon: RepeatIcon, onClick: () => window.open(TALISMAN_WEB_APP_SWAP_URL, "_blank"), + disabled: disableActions, + disabledReason, }, canBuy ? { @@ -299,7 +300,17 @@ const TopActions: FC = () => { } : null, ].filter(Boolean) as Array, - [canBuy, disableActions, disabledReason, selectedAddress, openCopyAddressModal, symbol, t], + [ + t, + disableActions, + disabledReason, + selectedAccount, + selectedAccounts.length, + canBuy, + selectedAddress, + symbol, + openCopyAddressModal, + ], ) return (