From a6e02a8158ff9874815d9b2c902dea0b1c053f7c Mon Sep 17 00:00:00 2001 From: Jose Felix Date: Thu, 30 May 2024 13:54:13 -0400 Subject: [PATCH] feat: Integrate Wagmi (#3280) * feat: add wagmi and start refactoring wallet select * feat: display eth wallets in wallet select and create basic multi wallet network selection arch * feat: add wallet select modal new layout type * feat: display evm wallets in a simpler list * feat: handle evm wallet connection * fix: build * improvement: mark old evm observable wallets as deprecated * fix: build --- packages/stores/src/account/base.ts | 6 +- packages/stores/src/account/types.ts | 6 +- packages/stores/src/tests/test-wallet.ts | 13 +- packages/web/__tests__/test-utils.tsx | 2 +- .../components/bridge/immersive/provider.tsx | 44 +- .../web/components/cards/stake-learn-more.tsx | 6 +- .../components/complex/add-conc-liquidity.tsx | 2 +- .../web/components/complex/portfolio-page.tsx | 6 +- packages/web/components/navbar/index.tsx | 6 +- packages/web/components/swap-tool/index.tsx | 4 +- .../transactions/no-transactions-splash.tsx | 13 +- .../wallet-states/connecting-wallet-state.tsx | 35 + .../wallet-states/error-wallet-state.tsx | 41 + .../web/components/wallet-states/index.ts | 2 + .../components/your-balance/your-balance.tsx | 8 +- .../config/generate-cosmos-kit-wallet-list.ts | 4 +- packages/web/config/index.ts | 2 +- packages/web/config/wagmi.ts | 74 + packages/web/config/wallet-registry.ts | 4 +- packages/web/hooks/evm-wallet.ts | 8 + packages/web/hooks/index.ts | 2 +- .../use-connect-wallet-modal-redirect.tsx | 6 +- .../web/hooks/use-has-installed-wallets.ts | 14 + packages/web/hooks/use-ibc-transfer/index.ts | 24 +- packages/web/hooks/use-swap.tsx | 2 +- ...allet-select.tsx => use-wallet-select.tsx} | 65 +- .../web/integrations/ethereum/metamask.ts | 4 +- .../integrations/ethereum/walletconnect.ts | 4 +- packages/web/jest.config.js | 20 +- packages/web/modals/ibc-transfer.tsx | 17 +- packages/web/modals/wallet-select.tsx | 1200 ----------------- .../__tests__/wallet-select.spec.ts | 139 ++ .../wallet-select/cosmos-wallet-state.tsx | 351 +++++ .../modals/wallet-select/evm-wallet-state.tsx | 88 ++ .../modals/wallet-select/full-wallet-list.tsx | 189 +++ packages/web/modals/wallet-select/index.tsx | 479 +++++++ .../web/modals/wallet-select/qr-code-view.tsx | 187 +++ .../wallet-select/simple-wallet-list.tsx | 97 ++ .../wallet-select/use-selectable-wallets.ts | 113 ++ packages/web/modals/wallet-select/utils.ts | 72 + .../modals/wallet-select/wallet-tutorial.tsx | 69 + packages/web/package.json | 4 +- packages/web/pages/_app.tsx | 56 +- packages/web/pages/earn/index.tsx | 9 +- packages/web/pages/stake.tsx | 6 +- packages/web/public/logos/metamask.svg | 32 + packages/web/public/logos/walletconnect.svg | 15 + yarn.lock | 527 +++++++- 48 files changed, 2728 insertions(+), 1349 deletions(-) create mode 100644 packages/web/components/wallet-states/connecting-wallet-state.tsx create mode 100644 packages/web/components/wallet-states/error-wallet-state.tsx create mode 100644 packages/web/components/wallet-states/index.ts create mode 100644 packages/web/config/wagmi.ts create mode 100644 packages/web/hooks/evm-wallet.ts create mode 100644 packages/web/hooks/use-has-installed-wallets.ts rename packages/web/hooks/{wallet-select.tsx => use-wallet-select.tsx} (68%) delete mode 100644 packages/web/modals/wallet-select.tsx create mode 100644 packages/web/modals/wallet-select/__tests__/wallet-select.spec.ts create mode 100644 packages/web/modals/wallet-select/cosmos-wallet-state.tsx create mode 100644 packages/web/modals/wallet-select/evm-wallet-state.tsx create mode 100644 packages/web/modals/wallet-select/full-wallet-list.tsx create mode 100644 packages/web/modals/wallet-select/index.tsx create mode 100644 packages/web/modals/wallet-select/qr-code-view.tsx create mode 100644 packages/web/modals/wallet-select/simple-wallet-list.tsx create mode 100644 packages/web/modals/wallet-select/use-selectable-wallets.ts create mode 100644 packages/web/modals/wallet-select/utils.ts create mode 100644 packages/web/modals/wallet-select/wallet-tutorial.tsx create mode 100644 packages/web/public/logos/metamask.svg create mode 100644 packages/web/public/logos/walletconnect.svg diff --git a/packages/stores/src/account/base.ts b/packages/stores/src/account/base.ts index f77bebba6b..aa6408fad9 100644 --- a/packages/stores/src/account/base.ts +++ b/packages/stores/src/account/base.ts @@ -88,9 +88,9 @@ import { TxTracer } from "../tx"; import { aminoConverters } from "./amino-converters"; import { AccountStoreWallet, + CosmosRegistryWallet, DeliverTxResponse, OneClickTradingInfo, - RegistryWallet, SignOptions, TxEvent, TxEvents, @@ -374,7 +374,7 @@ export class AccountStore[] = []> { walletWithAccountSet[key] = injectedAccountsForChain[key]; } - const walletInfo = wallet.walletInfo as RegistryWallet; + const walletInfo = wallet.walletInfo as CosmosRegistryWallet; walletWithAccountSet.txTypeInProgress = txInProgress ?? ""; walletWithAccountSet.isReadyToSendTx = @@ -483,7 +483,7 @@ export class AccountStore[] = []> { // If the wallet isn't found, return the error if (!wallet) return new Error(errorMessage); - const walletInfo = wallet.walletInfo as RegistryWallet; + const walletInfo = wallet.walletInfo as CosmosRegistryWallet; // If the wallet has a custom error matcher, use it if (walletInfo?.matchError) { diff --git a/packages/stores/src/account/types.ts b/packages/stores/src/account/types.ts index ae1dd64f0d..c442b0e51b 100644 --- a/packages/stores/src/account/types.ts +++ b/packages/stores/src/account/types.ts @@ -35,7 +35,7 @@ export interface DeliverTxResponse { readonly gasWanted: string; } -export type RegistryWallet = Omit & { +export type CosmosRegistryWallet = Omit & { logo: string; lazyInstall: () => any; stakeUrl?: string; @@ -84,8 +84,8 @@ export type AccountStoreWallet[] = []> = UnionToIntersection & { txTypeInProgress: string; isReadyToSendTx: boolean; - supportsChain: Required["supportsChain"]; - walletInfo: RegistryWallet; + supportsChain: Required["supportsChain"]; + walletInfo: CosmosRegistryWallet; }; export interface TxEvents { diff --git a/packages/stores/src/tests/test-wallet.ts b/packages/stores/src/tests/test-wallet.ts index c68bfc87cd..0ba037a730 100644 --- a/packages/stores/src/tests/test-wallet.ts +++ b/packages/stores/src/tests/test-wallet.ts @@ -173,13 +173,22 @@ export class MockKeplrClient implements WalletClient { signer: string, signDoc: DirectSignDoc, signOptions?: SignOptions - ): ReturnType { - return await this.client.signDirect( + ): ReturnType["signDirect"]> { + const response = await this.client.signDirect( chainId, signer, signDoc as any, signOptions ); + + // Convert Long to bigint + return { + signed: { + ...response.signed, + accountNumber: BigInt(response.signed.accountNumber.toString()), + }, + signature: response.signature, + }; } async sendTx(chainId: string, tx: Uint8Array, mode: BroadcastMode) { diff --git a/packages/web/__tests__/test-utils.tsx b/packages/web/__tests__/test-utils.tsx index a660275bf7..68bc2bf54a 100644 --- a/packages/web/__tests__/test-utils.tsx +++ b/packages/web/__tests__/test-utils.tsx @@ -13,7 +13,7 @@ import { ReactNode } from "react"; import { TestWallet, testWalletInfo } from "~/__tests__/test-wallet"; import { MultiLanguageProvider } from "~/hooks/language/context"; import { AvailableFlags } from "~/hooks/use-feature-flags"; -import { WalletSelectProvider } from "~/hooks/wallet-select"; +import { WalletSelectProvider } from "~/hooks/use-wallet-select"; import { AppRouter } from "~/server/api/root-router"; import { storeContext, StoreProvider } from "~/stores"; import { RootStore } from "~/stores/root"; diff --git a/packages/web/components/bridge/immersive/provider.tsx b/packages/web/components/bridge/immersive/provider.tsx index 01cf48e128..7f9d47d6b9 100644 --- a/packages/web/components/bridge/immersive/provider.tsx +++ b/packages/web/components/bridge/immersive/provider.tsx @@ -3,6 +3,11 @@ import { PropsWithChildren, useState } from "react"; import { StepProgress } from "~/components/stepper/progress-bar"; import { Button } from "~/components/ui/button"; +import { useWalletSelect } from "~/hooks"; +import { + useDisconnectEvmWallet, + useEvmWalletAccount, +} from "~/hooks/evm-wallet"; import { FiatRampKey } from "~/integrations"; import { BridgeFlowProvider } from "../flow"; @@ -12,34 +17,37 @@ export const ImmersiveBridgeFlow = ({ children, }: PropsWithChildren) => { // TODO: state will be encapsulated in a state hook - const [isShowing, setIsShowing] = useState(false); + const [isVisible, setIsVisible] = useState(false); const [step, setStep] = useState<0 | 1 | 2 | 3 | 4>(0); + const { isConnected, address } = useEvmWalletAccount(); + const { onOpenWalletSelect } = useWalletSelect(); + const { disconnect } = useDisconnectEvmWallet(); return ( { - setIsShowing(true); + setIsVisible(true); console.log("startBridge", direction); }, bridgeAsset: (anyDenom: string, direction: "deposit" | "withdraw") => { - setIsShowing(true); + setIsVisible(true); console.log("bridgeAsset", anyDenom, direction); }, fiatRamp: (fiatRampKey: FiatRampKey, assetKey: string) => { - setIsShowing(true); + setIsVisible(true); console.log("fiatRamp", fiatRampKey, assetKey); }, fiatRampSelection: () => { - setIsShowing(true); + setIsVisible(true); console.log("fiatRampSelection"); }, }} > {children}
I will fade in and out
- + + + {isConnected ? ( +
+

Evm Address: {address}

+ +
+ ) : ( + + )}
diff --git a/packages/web/components/cards/stake-learn-more.tsx b/packages/web/components/cards/stake-learn-more.tsx index 9dbe6abfae..37ebf4f30b 100644 --- a/packages/web/components/cards/stake-learn-more.tsx +++ b/packages/web/components/cards/stake-learn-more.tsx @@ -10,7 +10,7 @@ import { } from "~/components/stepper"; import { Button } from "~/components/ui/button"; import { useTranslation } from "~/hooks"; -import { useWalletSelect } from "~/hooks/wallet-select"; +import { useWalletSelect } from "~/hooks/use-wallet-select"; import { useStore } from "~/stores"; const BuildStakeSquadButton: React.FC = ({ @@ -26,7 +26,9 @@ const BuildStakeSquadButton: React.FC = ({ if (isWalletConnected) { setShowValidatorModal(); } else { - onOpenWalletSelect(osmosisChainId); + onOpenWalletSelect({ + walletOptions: [{ walletType: "cosmos", chainId: osmosisChainId }], + }); } }, [ isWalletConnected, diff --git a/packages/web/components/complex/add-conc-liquidity.tsx b/packages/web/components/complex/add-conc-liquidity.tsx index e324a5b585..768f394ecb 100644 --- a/packages/web/components/complex/add-conc-liquidity.tsx +++ b/packages/web/components/complex/add-conc-liquidity.tsx @@ -29,7 +29,7 @@ import { CustomClasses } from "~/components/types"; import { Button } from "~/components/ui/button"; import { ChartButton } from "~/components/ui/button"; import { Checkbox } from "~/components/ui/checkbox"; -import { EventName } from "~/config"; +import { EventName } from "~/config/analytics-events"; import { ObservableAddConcentratedLiquidityConfig, useAmplitudeAnalytics, diff --git a/packages/web/components/complex/portfolio-page.tsx b/packages/web/components/complex/portfolio-page.tsx index 5bf6527710..2f0440a8bb 100644 --- a/packages/web/components/complex/portfolio-page.tsx +++ b/packages/web/components/complex/portfolio-page.tsx @@ -329,7 +329,11 @@ const GetStartedWithOsmosis: FunctionComponent = () => { diff --git a/packages/web/components/wallet-states/connecting-wallet-state.tsx b/packages/web/components/wallet-states/connecting-wallet-state.tsx new file mode 100644 index 0000000000..5bfffab462 --- /dev/null +++ b/packages/web/components/wallet-states/connecting-wallet-state.tsx @@ -0,0 +1,35 @@ +import { isNil } from "@osmosis-labs/utils"; +import React from "react"; + +interface ConnectingWalletStateProps { + walletLogo?: string; + title?: string; + desc?: string; +} + +const ConnectingWalletState = ({ + walletLogo, + title, + desc, +}: ConnectingWalletStateProps) => { + return ( +
+
+ {!!walletLogo && typeof walletLogo === "string" && ( + Wallet logo + )} +
+ +
+ {!isNil(title) && ( +

{title}

+ )} + {!isNil(desc) && ( +

{desc}

+ )} +
+
+ ); +}; + +export default ConnectingWalletState; diff --git a/packages/web/components/wallet-states/error-wallet-state.tsx b/packages/web/components/wallet-states/error-wallet-state.tsx new file mode 100644 index 0000000000..be2df2991c --- /dev/null +++ b/packages/web/components/wallet-states/error-wallet-state.tsx @@ -0,0 +1,41 @@ +import { isNil } from "@osmosis-labs/utils"; +import React, { ReactNode } from "react"; + +interface ErrorWalletStateProps { + walletLogo?: string; + title?: string; + desc?: string; + actions?: ReactNode; +} + +const ErrorWalletState = ({ + walletLogo, + title, + desc, + actions, +}: ErrorWalletStateProps) => { + return ( +
+
+ {!!walletLogo && typeof walletLogo === "string" && ( + Wallet logo + )} +
+ +
+
+ {!isNil(title) && ( +

{title}

+ )} + {!isNil(desc) && ( +

{desc}

+ )} +
+ + {actions} +
+
+ ); +}; + +export default ErrorWalletState; diff --git a/packages/web/components/wallet-states/index.ts b/packages/web/components/wallet-states/index.ts new file mode 100644 index 0000000000..240d5c1900 --- /dev/null +++ b/packages/web/components/wallet-states/index.ts @@ -0,0 +1,2 @@ +export * from "./connecting-wallet-state"; +export * from "./error-wallet-state"; diff --git a/packages/web/components/your-balance/your-balance.tsx b/packages/web/components/your-balance/your-balance.tsx index 58da844d8c..3ba055917c 100644 --- a/packages/web/components/your-balance/your-balance.tsx +++ b/packages/web/components/your-balance/your-balance.tsx @@ -394,7 +394,7 @@ const BalanceStats = observer(({ denom }: YourBalanceProps) => { const { ibcBalances } = assetsStore; const account = accountStore.getWallet(chainStore.osmosis.chainId); const tokenChain = chainStore.getChainFromCurrency(denom); - const chainName = tokenChain?.chainName; + const chainId = tokenChain?.chainId; const { data, isLoading: isCoinDataLoading } = api.edge.assets.getUserMarketAsset.useQuery({ @@ -464,7 +464,11 @@ const BalanceStats = observer(({ denom }: YourBalanceProps) => { ) : ( - )} - - onCreate1CTSession({ - walletRepo: walletRepoProp, - transaction1CTParams, - }) - } - show1CTConnectAWallet={show1CTConnectAWallet} - setShow1CTConnectAWallet={setShow1CTConnectAWallet} - show1CTEditParams={show1CTEditParams} - setShow1CTEditParams={setShow1CTEditParams} - /> - - {/* Hide close button since 1CT edit params will include it */} - {!show1CTEditParams && } - - - - ); -}); - -const LeftModalContent: FunctionComponent< - Pick, "walletRepo"> & { - onConnect: ( - sync: boolean, - wallet?: ChainWalletBase | (typeof WalletRegistry)[number] - ) => void; - isMobile: boolean; - modalView: ModalView; - } -> = observer(({ walletRepo, onConnect, isMobile, modalView }) => { - const { t } = useTranslation(); - - const wallets = useMemo( - () => - [...WalletRegistry] - // If mobile, filter out browser wallets - .reduce((acc, wallet, _index, array) => { - if (isMobile) { - /** - * If an extension wallet is found in mobile, this means that we are inside an app browser. - * Therefore, we should only show that compatible extension wallet. - * */ - if (acc.length > 0 && acc[0].name.endsWith("-extension")) { - return acc; - } - - const _window = window as Record; - const mobileWebModeName = "mobile-web"; - - /** - * If on mobile and `leap` is in `window`, it means that the user enters - * the frontend from Leap's app in app browser. So, there is no need - * to use wallet connect, as it resembles the extension's usage. - */ - if (_window?.leap && _window?.leap?.mode === mobileWebModeName) { - return array - .filter((wallet) => wallet.name === AvailableWallets.Leap) - .map((wallet) => ({ ...wallet, mobileDisabled: false })); - } - - /** - * If on mobile and `keplr` is in `window`, it means that the user enters - * the frontend from Keplr's app in app browser. So, there is no need - * to use wallet connect, as it resembles the extension's usage. - */ - if (_window?.keplr && _window?.keplr?.mode === mobileWebModeName) { - return array - .filter((wallet) => wallet.name === AvailableWallets.Keplr) - .map((wallet) => ({ ...wallet, mobileDisabled: false })); - } - - /** - * If user is in a normal mobile browser, show only wallet connect - */ - return wallet.name.endsWith("mobile") ? [...acc, wallet] : acc; - } - - return [...acc, wallet]; - }, [] as (typeof WalletRegistry)[number][]), - [isMobile] - ); - - /** - * Categorizes wallets into three distinct categories: - * 1. Mobile Wallets: Wallets that use the "wallet-connect" mode. - * 2. Installed Wallets: Wallets that have a defined window property present in the current window. - * 3. Other Wallets: Wallets that do not fall into the above two categories. - * - * Note: The object keys are the translation keys for the category name. - */ - const categories = useMemo( - () => - wallets.reduce( - (acc, wallet) => { - if (wallet.mode === "wallet-connect") { - acc["walletSelect.mobileWallets"].push(wallet); - return acc; - } - - if ( - wallet.windowPropertyName && - wallet.windowPropertyName in window - ) { - acc["walletSelect.installedWallets"].push(wallet); - return acc; - } - - acc["walletSelect.otherWallets"].push(wallet); - return acc; - }, - { - "walletSelect.installedWallets": - [] as (typeof WalletRegistry)[number][], - "walletSelect.mobileWallets": [] as (typeof WalletRegistry)[number][], - "walletSelect.otherWallets": [] as (typeof WalletRegistry)[number][], - } - ), - [wallets] - ); - - return ( -
-

- {t("connectWallet")} -

-
- {Object.entries(categories) - .filter(([_, wallets]) => wallets.length > 0) - .map(([categoryName, wallets]) => { - const isDisabled = modalView === "initializingOneClickTrading"; - return ( -
-

- {t(categoryName)} -

- -
- {wallets.map((wallet) => ( - - ))} -
-
- ); - })} -
-
- ); -}); - -enum WalletSelect1CTScreens { - Introduction = "Introduction", - Settings = "Settings", - WelcomeBack = "WelcomeBack", - ConnectAWallet = "ConnectAWallet", -} - -const RightModalContent: FunctionComponent< - Pick< - ComponentPropsWithoutRef, - "walletRepo" | "onRequestClose" - > & { - transaction1CTParams: OneClickTradingTransactionParams | undefined; - setTransaction1CTParams: Dispatch< - SetStateAction - >; - isLoading1CTParams?: boolean; - modalView: ModalView; - lazyWalletInfo?: (typeof WalletRegistry)[number]; - onConnect: ( - sync: boolean, - wallet?: ChainWalletBase | (typeof WalletRegistry)[number] - ) => void; - onCreate1CTSession: () => void; - show1CTConnectAWallet: boolean; - setShow1CTConnectAWallet: Dispatch>; - show1CTEditParams: boolean; - setShow1CTEditParams: Dispatch>; - } -> = observer( - ({ - walletRepo, - onRequestClose, - modalView, - onConnect, - lazyWalletInfo, - transaction1CTParams, - setTransaction1CTParams, - isLoading1CTParams, - onCreate1CTSession, - show1CTConnectAWallet, - setShow1CTConnectAWallet, - show1CTEditParams, - setShow1CTEditParams, - }) => { - const { t } = useTranslation(); - const { accountStore, chainStore } = useStore(); - const featureFlags = useFeatureFlags(); - const hasInstalledWallets = useHasInstalledWallets(); - const [, setDoNotShow1CTFloatingBanner] = useLocalStorage( - OneClickFloatingBannerDoNotShowKey - ); - - const show1CT = - hasInstalledWallets && - featureFlags.oneClickTrading && - walletRepo?.chainRecord.chain.chain_name === chainStore.osmosis.chainName; - - const currentWallet = walletRepo?.current; - const walletInfo = currentWallet?.walletInfo ?? lazyWalletInfo; - - useEffect(() => { - /** - * If the user has already viewed the 1CT introduction during - * the wallet selection process, then don't display the 1CT - * banner when they connect to their wallet. - */ - if (show1CT && modalView === "list") { - setDoNotShow1CTFloatingBanner(true); - } - }, [modalView, setDoNotShow1CTFloatingBanner, show1CT]); - - if (modalView === "connected") { - onRequestClose(); - } - - if (modalView === "error") { - const error = accountStore.matchError(currentWallet?.message ?? ""); - - let message = error.message; - - if (error instanceof WalletConnectionInProgressError) { - message = t("walletSelect.connectionInProgress"); - } - - return ( -
-
- {!!walletInfo && typeof walletInfo?.logo === "string" && ( - Wallet logo - )} -
- -
-
-

- {t("walletSelect.somethingWentWrong")} -

-

{message}

-
- -
-
- ); - } - - if (modalView === "doesNotExist") { - const downloadInfo = currentWallet?.downloadInfo; - return ( -
-
- Wallet logo -
- -
-

- {t("walletSelect.isNotInstalled", { - walletName: walletInfo?.prettyName ?? "", - })} -

-

- {Boolean(downloadInfo) - ? t("walletSelect.maybeInstalled", { - walletName: walletInfo?.prettyName?.toLowerCase() ?? "", - }) - : t("walletSelect.downloadLinkNotProvided")} -

-
- {Boolean(downloadInfo) && ( - - )} -
- ); - } - - if (modalView === "rejected") { - return ( -
-
- {!!walletInfo && typeof walletInfo?.logo === "string" && ( - Wallet logo - )} -
- -
-
-

- {t("walletSelect.requestRejected")} -

-

- {currentWallet?.rejectMessageTarget ?? - t("walletSelect.connectionDenied")} -

-
- -
-
- ); - } - - if (modalView === "initializeOneClickTradingError") { - const title = t("walletSelect.errorInitializingOneClickTradingSession"); - const desc = t("walletSelect.retryInWalletOrContinue", { - walletName: walletInfo?.prettyName ?? "", - }); - - return ( -
-
- {!!walletInfo && typeof walletInfo?.logo === "string" && ( - Wallet logo - )} -
- -
-
-

{title}

-

{desc}

-
- -
- - -
-
-
- ); - } - - if ( - modalView === "initializingOneClickTrading" || - modalView === "broadcastedOneClickTrading" - ) { - const title = - modalView === "broadcastedOneClickTrading" - ? t("walletSelect.enablingOneClickTrading") - : t("walletSelect.approveOneClickTradingSession", { - walletName: walletInfo?.prettyName ?? "", - }); - - return ( -
-
- {!!walletInfo && typeof walletInfo?.logo === "string" && ( - Wallet logo - )} -
- -
-

{title}

-
-
- ); - } - - if (modalView === "connecting") { - const message = currentWallet?.message; - - let title: string = t("walletSelect.connectingWallet"); - let desc: string = - walletInfo?.mode === "wallet-connect" - ? t("walletSelect.approveWalletConnect", { - walletName: walletInfo?.prettyName ?? "", - }) - : t("walletSelect.openExtension", { - walletName: walletInfo?.prettyName ?? "", - }); - - if (message === "InitClient" || Boolean(lazyWalletInfo)) { - title = t("walletSelect.initializingWallet"); - desc = ""; - } - - return ( -
-
- {!!walletInfo && typeof walletInfo?.logo === "string" && ( - Wallet logo - )} -
- -
-

{title}

-

{desc}

-
-
- ); - } - - if (modalView === "qrCode") { - return ; - } - - let oneClickTradingScreen: WalletSelect1CTScreens; - if (show1CTConnectAWallet) { - oneClickTradingScreen = WalletSelect1CTScreens.ConnectAWallet; - } else if (show1CTEditParams) { - oneClickTradingScreen = WalletSelect1CTScreens.Settings; - } else if (!show1CTEditParams && accountStore.hasUsedOneClickTrading) { - oneClickTradingScreen = WalletSelect1CTScreens.WelcomeBack; - } else { - oneClickTradingScreen = WalletSelect1CTScreens.Introduction; - } - - return ( - <> - {show1CT ? ( - - - { - setShow1CTEditParams(false); - }} - onClose={onRequestClose} - setTransaction1CTParams={setTransaction1CTParams} - transaction1CTParams={transaction1CTParams!} - onStartTrading={() => { - setShow1CTConnectAWallet(true); - setShow1CTEditParams(false); - }} - /> - - - - - -
- { - setShow1CTEditParams(true); - }} - isLoading={isLoading1CTParams} - isDisabled={!transaction1CTParams} - /> -
-
- -
- { - setShow1CTConnectAWallet(true); - - setTransaction1CTParams((prev) => { - if (!prev) - throw new Error("transaction1CTParams is undefined"); - return { ...prev, isOneClickEnabled: true }; - }); - }} - onClickEditParams={() => { - setShow1CTEditParams(true); - }} - isLoading={isLoading1CTParams} - isDisabled={!transaction1CTParams} - /> -
-
-
- ) : ( -
-

- {t("walletSelect.gettingStarted")} -

- - - - {OnboardingSteps(t).map(({ title, content }) => ( - -
-
- Wallet showcase -
-
-

{title}

-

{content}

-
-
-
- ))} - - -
-
- )} - - ); - } -); - -const QRCodeLoader = () => ( -
- -
-
-
- -
-); - -type QRCodeStatus = "pending" | "done" | "error" | "expired" | undefined; -const QRCodeView: FunctionComponent<{ wallet?: ChainWalletBase }> = ({ - wallet, -}) => { - const { t } = useTranslation(); - - const qrUrl = wallet?.qrUrl; - - const [errorTitle, errorDesc, status] = useMemo(() => { - const isExpired = qrUrl?.message === ExpiredError.message; - - const errorDesc = isExpired - ? t("walletSelect.clickToRefresh") - : qrUrl?.message; - const errorTitle = isExpired - ? t("walletSelect.qrCodeExpired") - : t("walletSelect.qrCodeError"); - - const statusDict: Record = { - [State.Pending]: "pending" as const, - [State.Done]: "done" as const, - [State.Error]: isExpired ? ("expired" as const) : ("error" as const), - [State.Init]: undefined, - }; - - return [errorTitle, errorDesc, statusDict[qrUrl?.state ?? State.Init]]; - }, [qrUrl?.message, qrUrl?.state, t]); - - const downloadLink = wallet?.walletInfo.downloads?.find( - ({ os }) => !os - )?.link; - - return ( - - {({ open: isDownloadQROpen }) => ( -
-

- {t("walletSelect.connectWith")} {wallet?.walletPrettyName} -

- -
-

- {t("walletSelect.tapThe")} - scan icon - {t("walletSelect.button")} -

- -

- {t("walletSelect.topRightButton", { - wallet: wallet?.walletPrettyName ?? "", - })} -

-
- - {(status === "error" || status === "expired") && ( - <> -
-
- -
- -
-
-
-

{errorTitle}

-

- {errorDesc} -

-
- - )} - {status === "pending" && } - {status === "done" && ( -
-
- {Boolean(qrUrl?.data) && ( - }> -
- -
-
- )} -
- -
-

- {t("walletSelect.dontHaveThisWallet")} -

- -
- - {t("walletSelect.get")} {wallet?.walletPrettyName} - - - -

- {t("walletSelect.scanThis")} {wallet?.walletPrettyName} -

- {typeof downloadLink === "string" && - downloadLink !== "" && ( - }> -
- -
-
- )} -
-
-
-
- )} -
- )} - - ); -}; diff --git a/packages/web/modals/wallet-select/__tests__/wallet-select.spec.ts b/packages/web/modals/wallet-select/__tests__/wallet-select.spec.ts new file mode 100644 index 0000000000..51831aaadd --- /dev/null +++ b/packages/web/modals/wallet-select/__tests__/wallet-select.spec.ts @@ -0,0 +1,139 @@ +import { State, WalletStatus } from "@cosmos-kit/core"; + +import { getModalView } from "../utils"; + +describe("getModalView", () => { + it('should return "connecting" when walletStatus is Connecting and qrState is Init', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Connecting, + }); + expect(result).toBe("connecting"); + }); + + it('should return "qrCode" when walletStatus is Connecting and qrState is not Init', () => { + const result = getModalView({ + // @ts-expect-error + qrState: "other", // Assuming other is a valid state + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Connecting, + }); + expect(result).toBe("qrCode"); + }); + + it('should return "initializeOneClickTradingError" when walletStatus is Connected and hasOneClickTradingError is true', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: false, + hasOneClickTradingError: true, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Connected, + }); + expect(result).toBe("initializeOneClickTradingError"); + }); + + it('should return "initializingOneClickTrading" when walletStatus is Connected, isInitializingOneClickTrading is true, and hasBroadcastedTx is false', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: true, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Connected, + }); + expect(result).toBe("initializingOneClickTrading"); + }); + + it('should return "broadcastedOneClickTrading" when walletStatus is Connected, isInitializingOneClickTrading is true, and hasBroadcastedTx is true', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: true, + hasOneClickTradingError: false, + hasBroadcastedTx: true, + walletStatus: WalletStatus.Connected, + }); + expect(result).toBe("broadcastedOneClickTrading"); + }); + + it('should return "connected" when walletStatus is Connected and no other conditions are met', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Connected, + }); + expect(result).toBe("connected"); + }); + + it('should return "error" when walletStatus is Error and qrState is Init', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Error, + }); + expect(result).toBe("error"); + }); + + it('should return "qrCode" when walletStatus is Error and qrState is not Init', () => { + const result = getModalView({ + // @ts-expect-error + qrState: "other", // Assuming "other" is a valid state + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Error, + }); + expect(result).toBe("qrCode"); + }); + + it('should return "rejected" when walletStatus is Rejected', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Rejected, + }); + expect(result).toBe("rejected"); + }); + + it('should return "doesNotExist" when walletStatus is NotExist', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.NotExist, + }); + expect(result).toBe("doesNotExist"); + }); + + it('should return "list" when walletStatus is Disconnected', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: WalletStatus.Disconnected, + }); + expect(result).toBe("list"); + }); + + it('should return "list" when walletStatus is undefined', () => { + const result = getModalView({ + qrState: State.Init, + isInitializingOneClickTrading: false, + hasOneClickTradingError: false, + hasBroadcastedTx: false, + walletStatus: undefined, + }); + expect(result).toBe("list"); + }); +}); diff --git a/packages/web/modals/wallet-select/cosmos-wallet-state.tsx b/packages/web/modals/wallet-select/cosmos-wallet-state.tsx new file mode 100644 index 0000000000..6e901028a8 --- /dev/null +++ b/packages/web/modals/wallet-select/cosmos-wallet-state.tsx @@ -0,0 +1,351 @@ +import { WalletRepo } from "@cosmos-kit/core"; +import { WalletConnectionInProgressError } from "@osmosis-labs/stores"; +import { OneClickTradingTransactionParams } from "@osmosis-labs/types"; +import { observer } from "mobx-react-lite"; +import React, { + Dispatch, + FunctionComponent, + SetStateAction, + useEffect, +} from "react"; +import { useLocalStorage } from "react-use"; + +import { IntroducingOneClick } from "~/components/one-click-trading/introducing-one-click-trading"; +import { OneClickFloatingBannerDoNotShowKey } from "~/components/one-click-trading/one-click-floating-banner"; +import OneClickTradingConnectToContinue from "~/components/one-click-trading/one-click-trading-connect-to-continue"; +import OneClickTradingSettings from "~/components/one-click-trading/one-click-trading-settings"; +import OneClickTradingWelcomeBack from "~/components/one-click-trading/one-click-trading-welcome-back"; +import { Screen, ScreenManager } from "~/components/screen-manager"; +import { Button } from "~/components/ui/button"; +import ConnectingWalletState from "~/components/wallet-states/connecting-wallet-state"; +import ErrorWalletState from "~/components/wallet-states/error-wallet-state"; +import { CosmosWalletRegistry } from "~/config"; +import { useFeatureFlags, useTranslation, WalletSelectOption } from "~/hooks"; +import { useHasInstalledCosmosWallets } from "~/hooks/use-has-installed-wallets"; +import { WalletSelectModalProps } from "~/modals/wallet-select"; +import { ModalView, OnConnectWallet } from "~/modals/wallet-select/utils"; +import { useStore } from "~/stores"; + +import QRCodeView from "./qr-code-view"; +import WalletTutorial from "./wallet-tutorial"; + +enum WalletSelect1CTScreens { + Introduction = "Introduction", + Settings = "Settings", + WelcomeBack = "WelcomeBack", + ConnectAWallet = "ConnectAWallet", +} + +export const CosmosWalletState: FunctionComponent< + Pick & { + walletRepo: WalletRepo | undefined; + transaction1CTParams: OneClickTradingTransactionParams | undefined; + setTransaction1CTParams: Dispatch< + SetStateAction + >; + isLoading1CTParams?: boolean; + modalView: ModalView; + lazyWalletInfo?: (typeof CosmosWalletRegistry)[number]; + onConnect: OnConnectWallet; + onCreate1CTSession: () => void; + show1CTConnectAWallet: boolean; + setShow1CTConnectAWallet: Dispatch>; + show1CTEditParams: boolean; + setShow1CTEditParams: Dispatch>; + walletOptions: WalletSelectOption[]; + } +> = observer( + ({ + walletRepo, + onRequestClose, + modalView, + onConnect, + lazyWalletInfo, + transaction1CTParams, + setTransaction1CTParams, + isLoading1CTParams, + onCreate1CTSession, + show1CTConnectAWallet, + setShow1CTConnectAWallet, + show1CTEditParams, + setShow1CTEditParams, + }) => { + const { t } = useTranslation(); + const { accountStore, chainStore } = useStore(); + const featureFlags = useFeatureFlags(); + const hasInstalledWallets = useHasInstalledCosmosWallets(); + const [, setDoNotShow1CTFloatingBanner] = useLocalStorage( + OneClickFloatingBannerDoNotShowKey + ); + + const show1CT = + hasInstalledWallets && + featureFlags.oneClickTrading && + walletRepo?.chainRecord.chain.chain_name === chainStore.osmosis.chainName; + + const currentWallet = walletRepo?.current; + const walletInfo = currentWallet?.walletInfo ?? lazyWalletInfo; + + useEffect(() => { + /** + * If the user has already viewed the 1CT introduction during + * the wallet selection process, then don't display the 1CT + * banner when they connect to their wallet. + */ + if (show1CT && modalView === "list") { + setDoNotShow1CTFloatingBanner(true); + } + }, [modalView, setDoNotShow1CTFloatingBanner, show1CT]); + + if (modalView === "connected") { + onRequestClose(); + } + + if (modalView === "error") { + const error = accountStore.matchError(currentWallet?.message ?? ""); + + let message = error.message; + + if (error instanceof WalletConnectionInProgressError) { + message = t("walletSelect.connectionInProgress"); + } + + return ( + + onConnect({ wallet: currentWallet, walletType: "cosmos" }) + } + > + {t("walletSelect.reconnect")} + + } + /> + ); + } + + if (modalView === "doesNotExist") { + const downloadInfo = currentWallet?.downloadInfo; + return ( + { + window.open(currentWallet?.downloadInfo?.link, "_blank"); + }} + > + {t("walletSelect.installWallet", { + walletName: walletInfo?.prettyName ?? "", + })} + + ) + } + /> + ); + } + + if (modalView === "rejected") { + return ( + + onConnect({ wallet: currentWallet, walletType: "cosmos" }) + } + > + {t("walletSelect.reconnect")} + + } + /> + ); + } + + if (modalView === "initializeOneClickTradingError") { + const title = t("walletSelect.errorInitializingOneClickTradingSession"); + const desc = t("walletSelect.retryInWalletOrContinue", { + walletName: walletInfo?.prettyName ?? "", + }); + + return ( + + + +
+ } + /> + ); + } + + if ( + modalView === "initializingOneClickTrading" || + modalView === "broadcastedOneClickTrading" + ) { + const title = + modalView === "broadcastedOneClickTrading" + ? t("walletSelect.enablingOneClickTrading") + : t("walletSelect.approveOneClickTradingSession", { + walletName: walletInfo?.prettyName ?? "", + }); + + return ( + + ); + } + + if (modalView === "connecting") { + const message = currentWallet?.message; + + let title: string = t("walletSelect.connectingWallet"); + let desc: string = + walletInfo?.mode === "wallet-connect" + ? t("walletSelect.approveWalletConnect", { + walletName: walletInfo?.prettyName ?? "", + }) + : t("walletSelect.openExtension", { + walletName: walletInfo?.prettyName ?? "", + }); + + if (message === "InitClient" || Boolean(lazyWalletInfo)) { + title = t("walletSelect.initializingWallet"); + desc = ""; + } + + return ( + + ); + } + + if (modalView === "qrCode") { + return ; + } + + let oneClickTradingScreen: WalletSelect1CTScreens; + if (show1CTConnectAWallet) { + oneClickTradingScreen = WalletSelect1CTScreens.ConnectAWallet; + } else if (show1CTEditParams) { + oneClickTradingScreen = WalletSelect1CTScreens.Settings; + } else if (!show1CTEditParams && accountStore.hasUsedOneClickTrading) { + oneClickTradingScreen = WalletSelect1CTScreens.WelcomeBack; + } else { + oneClickTradingScreen = WalletSelect1CTScreens.Introduction; + } + + return ( + <> + {show1CT ? ( + + + { + setShow1CTEditParams(false); + }} + onClose={onRequestClose} + setTransaction1CTParams={setTransaction1CTParams} + transaction1CTParams={transaction1CTParams!} + onStartTrading={() => { + setShow1CTConnectAWallet(true); + setShow1CTEditParams(false); + }} + /> + + + + + +
+ { + setShow1CTEditParams(true); + }} + isLoading={isLoading1CTParams} + isDisabled={!transaction1CTParams} + /> +
+
+ +
+ { + setShow1CTConnectAWallet(true); + + setTransaction1CTParams((prev) => { + if (!prev) + throw new Error("transaction1CTParams is undefined"); + return { ...prev, isOneClickEnabled: true }; + }); + }} + onClickEditParams={() => { + setShow1CTEditParams(true); + }} + isLoading={isLoading1CTParams} + isDisabled={!transaction1CTParams} + /> +
+
+
+ ) : ( + + )} + + ); + } +); diff --git a/packages/web/modals/wallet-select/evm-wallet-state.tsx b/packages/web/modals/wallet-select/evm-wallet-state.tsx new file mode 100644 index 0000000000..e0d13f0f34 --- /dev/null +++ b/packages/web/modals/wallet-select/evm-wallet-state.tsx @@ -0,0 +1,88 @@ +import { observer } from "mobx-react-lite"; +import React, { FunctionComponent } from "react"; + +import { Button } from "~/components/ui/button"; +import ConnectingWalletState from "~/components/wallet-states/connecting-wallet-state"; +import ErrorWalletState from "~/components/wallet-states/error-wallet-state"; +import { useTranslation } from "~/hooks"; +import { ConnectEvmWalletReturn } from "~/hooks/evm-wallet"; +import { WalletSelectModalProps } from "~/modals/wallet-select"; +import { OnConnectWallet } from "~/modals/wallet-select/utils"; + +export const EvmWalletState: FunctionComponent< + Pick & { + onConnect: OnConnectWallet; + connector: ConnectEvmWalletReturn["connectors"][number]; + status: ConnectEvmWalletReturn["status"]; + error: ConnectEvmWalletReturn["error"]; + } +> = observer(({ onRequestClose, onConnect, connector, status, error }) => { + const { t } = useTranslation(); + + if (status === "success") { + onRequestClose(); + } + + if (status === "error" && error?.name !== "UserRejectedRequestError") { + let message = error?.message; + + if (error?.name === "ConnectorAlreadyConnectedError") { + message = t("walletSelect.connectionInProgress"); + } + + return ( + onConnect({ wallet: connector, walletType: "evm" })} + > + {t("walletSelect.reconnect")} + + } + /> + ); + } + + if (status === "error" && error?.name === "UserRejectedRequestError") { + return ( + onConnect({ wallet: connector, walletType: "evm" })} + > + {t("walletSelect.reconnect")} + + } + /> + ); + } + + if (status === "loading") { + let title = t("walletSelect.connectingWallet"); + let desc = t("walletSelect.openExtension", { + walletName: connector?.name ?? "", + }); + + return ( + + ); + } + + return <>; +}); diff --git a/packages/web/modals/wallet-select/full-wallet-list.tsx b/packages/web/modals/wallet-select/full-wallet-list.tsx new file mode 100644 index 0000000000..070611c85f --- /dev/null +++ b/packages/web/modals/wallet-select/full-wallet-list.tsx @@ -0,0 +1,189 @@ +import { WalletRepo } from "@cosmos-kit/core"; +import classNames from "classnames"; +import { observer } from "mobx-react-lite"; +import React, { FunctionComponent, useMemo } from "react"; + +import { useTranslation, WalletSelectOption } from "~/hooks"; +import { useSelectableWallets } from "~/modals/wallet-select/use-selectable-wallets"; +import { ModalView, OnConnectWallet } from "~/modals/wallet-select/utils"; + +export const FullWalletList: FunctionComponent<{ + walletRepo: WalletRepo | undefined; + onConnect: OnConnectWallet; + isMobile: boolean; + modalView: ModalView; + walletOptions: WalletSelectOption[]; +}> = observer( + ({ walletRepo, onConnect, isMobile, modalView, walletOptions }) => { + const { t } = useTranslation(); + const { cosmosWallets, evmWallets } = useSelectableWallets({ + includedWallets: walletOptions.map((option) => option.walletType), + isMobile, + }); + + const evmOption = useMemo( + () => + walletOptions.find( + ( + option + ): option is Extract => + option.walletType === "evm" + ), + [walletOptions] + ); + + /** + * Categorizes wallets into three distinct categories: + * 1. Mobile Wallets: Wallets that use the "wallet-connect" mode. + * 2. Installed Wallets: Wallets that have a defined window property present in the current window. + * 3. Other Wallets: Wallets that do not fall into the above two categories. + * + * Note: The object keys are the translation keys for the category name. + */ + const categories = useMemo( + () => + [...cosmosWallets, ...evmWallets].reduce( + (acc, wallet) => { + if (wallet.walletType === "evm") { + acc["walletSelect.installedWallets"].push(wallet); + return acc; + } + + if (wallet.walletType === "cosmos") { + if (wallet.mode === "wallet-connect") { + acc["walletSelect.mobileWallets"].push(wallet); + return acc; + } + + if ( + wallet.windowPropertyName && + wallet.windowPropertyName in window + ) { + acc["walletSelect.installedWallets"].push(wallet); + return acc; + } + + acc["walletSelect.otherWallets"].push(wallet); + return acc; + } + + return acc; + }, + { + "walletSelect.installedWallets": [] as ( + | typeof cosmosWallets + | typeof evmWallets + )[number][], + "walletSelect.mobileWallets": [] as ( + | typeof cosmosWallets + | typeof evmWallets + )[number][], + "walletSelect.otherWallets": [] as ( + | typeof cosmosWallets + | typeof evmWallets + )[number][], + } + ), + [cosmosWallets, evmWallets] + ); + + if (evmWallets.length > 0) { + throw new Error( + "Evm wallets are not supported in 'full' view layout yet." + ); + } + + return ( +
+

+ {t("connectWallet")} +

+
+ {Object.entries(categories) + .filter(([_, wallets]) => wallets.length > 0) + .map(([categoryName, wallets]) => { + const isDisabled = modalView === "initializingOneClickTrading"; + return ( +
+

+ {t(categoryName)} +

+ +
+ {wallets.map((wallet) => { + if (wallet.walletType === "evm") { + return ( + + ); + } + + return ( + + ); + })} +
+
+ ); + })} +
+
+ ); + } +); diff --git a/packages/web/modals/wallet-select/index.tsx b/packages/web/modals/wallet-select/index.tsx new file mode 100644 index 0000000000..93174ba26e --- /dev/null +++ b/packages/web/modals/wallet-select/index.tsx @@ -0,0 +1,479 @@ +import { + ChainWalletBase, + State, + WalletRepo, + WalletStatus, +} from "@cosmos-kit/core"; +import { + CosmosKitAccountsLocalStorageKey, + CosmosKitWalletLocalStorageKey, + CosmosRegistryWallet, +} from "@osmosis-labs/stores"; +import { OneClickTradingTransactionParams } from "@osmosis-labs/types"; +import { isNil, noop } from "@osmosis-labs/utils"; +import classNames from "classnames"; +import { observer } from "mobx-react-lite"; +import React, { FunctionComponent, useEffect, useState } from "react"; +import { useUpdateEffect } from "react-use"; +import { Connector } from "wagmi"; + +import { Icon } from "~/components/assets"; +import ClientOnly from "~/components/client-only"; +import { Button } from "~/components/ui/button"; +import { CosmosWalletRegistry } from "~/config"; +import { EthereumChainIds } from "~/config/wagmi"; +import { + useFeatureFlags, + WalletSelectOption, + WalletSelectParams, +} from "~/hooks"; +import { useWindowSize } from "~/hooks"; +import { useConnectEvmWallet } from "~/hooks/evm-wallet"; +import { + CreateOneClickSessionError, + useCreateOneClickTradingSession, +} from "~/hooks/mutations/one-click-trading"; +import { useOneClickTradingParams } from "~/hooks/one-click-trading/use-one-click-trading-params"; +import { useHasInstalledCosmosWallets } from "~/hooks/use-has-installed-wallets"; +import { ModalBase, ModalBaseProps, ModalCloseButton } from "~/modals/base"; +import { CosmosWalletState } from "~/modals/wallet-select/cosmos-wallet-state"; +import { EvmWalletState } from "~/modals/wallet-select/evm-wallet-state"; +import { FullWalletList } from "~/modals/wallet-select/full-wallet-list"; +import { SimpleWalletList } from "~/modals/wallet-select/simple-wallet-list"; +import { WagmiWalletConnectType } from "~/modals/wallet-select/use-selectable-wallets"; +import { + getModalView, + ModalView, + OnConnectWallet, +} from "~/modals/wallet-select/utils"; +import { useStore } from "~/stores"; + +export interface WalletSelectModalProps extends ModalBaseProps { + /** + * Defines what wallets to show in the modal. + */ + walletOptions: WalletSelectParams["walletOptions"]; + layout?: WalletSelectParams["layout"]; + onConnect?: (params: { walletType: "evm" | "cosmos" }) => void; +} + +export const WalletSelectModal: FunctionComponent = + observer((props) => { + const { + isOpen, + onRequestClose, + walletOptions, + onConnect: onConnectProp, + layout = "full", + } = props; + const { isMobile } = useWindowSize(); + const { accountStore, chainStore } = useStore(); + const featureFlags = useFeatureFlags(); + const hasInstalledWallets = useHasInstalledCosmosWallets(); + const [show1CTEditParams, setShow1CTEditParams] = useState(false); + const [hasBroadcastedTx, setHasBroadcastedTx] = useState(false); + const { + connectAsync: connectEvmWallet, + variables, + status, + error, + reset, + } = useConnectEvmWallet(); + + const create1CTSession = useCreateOneClickTradingSession({ + onBroadcasted: () => { + setHasBroadcastedTx(true); + }, + queryOptions: { + onSuccess: () => { + onRequestClose(); + }, + onSettled: () => { + setIsInitializingOneClickTrading(false); + setHasBroadcastedTx(false); + }, + }, + }); + + const [qrState, setQRState] = useState(State.Init); + const [qrMessage, setQRMessage] = useState(""); + const [modalView, setModalView] = useState("list"); + const [isInitializingOneClickTrading, setIsInitializingOneClickTrading] = + useState(false); + const [lazyWalletInfo, setLazyWalletInfo] = + useState<(typeof CosmosWalletRegistry)[number]>(); + const [show1CTConnectAWallet, setShow1CTConnectAWallet] = useState(false); + + const hasOneClickTradingError = !!create1CTSession.error; + + const { + transaction1CTParams, + setTransaction1CTParams, + isLoading: isLoading1CTParams, + spendLimitTokenDecimals, + reset: reset1CTParams, + } = useOneClickTradingParams(); + + const cosmosOption = walletOptions.find( + ( + option + ): option is Extract => + option.walletType === "cosmos" + ); + + const cosmosChainId = cosmosOption?.chainId; + const rootWalletRepo = cosmosChainId + ? accountStore.getWalletRepo(cosmosChainId) + : undefined; + const current = rootWalletRepo?.current; + const cosmosWalletStatus = current?.walletStatus; + const cosmosChainName = rootWalletRepo?.chainRecord.chain?.chain_name!; + + useEffect(() => { + if (isOpen) { + setModalView( + getModalView({ + qrState, + walletStatus: cosmosWalletStatus, + isInitializingOneClickTrading, + hasOneClickTradingError, + hasBroadcastedTx, + }) + ); + } + }, [ + qrState, + cosmosWalletStatus, + isOpen, + qrMessage, + isInitializingOneClickTrading, + hasOneClickTradingError, + hasBroadcastedTx, + ]); + + useUpdateEffect(() => { + if (!isOpen) { + setIsInitializingOneClickTrading(false); + } + }, [isOpen]); + + (current?.client as any)?.setActions?.({ + qrUrl: { + state: setQRState, + /** + * We need this function to avoid crashing the Cosmoskit library. + * A PR is open with a fix for this issue. + * @see https://github.com/cosmology-tech/cosmos-kit/pull/176 + * */ + message: setQRMessage, + }, + }); + + const onClose = () => { + onRequestClose(); + if ( + cosmosWalletStatus === WalletStatus.Connecting || + cosmosWalletStatus === WalletStatus.Rejected || + cosmosWalletStatus === WalletStatus.Error + ) { + rootWalletRepo?.disconnect(); + } + }; + + const onCreate1CTSession = async ({ + walletRepo, + transaction1CTParams, + }: { + walletRepo: WalletRepo; + transaction1CTParams: OneClickTradingTransactionParams | undefined; + }) => { + create1CTSession.reset(); + setIsInitializingOneClickTrading(true); + return create1CTSession.mutate({ + walletRepo, + transaction1CTParams, + spendLimitTokenDecimals: spendLimitTokenDecimals, + }); + }; + + const onConnectCosmosWallet = async ({ + wallet, + walletRepo: walletRepoParam, + }: { + wallet: CosmosRegistryWallet | ChainWalletBase; + walletRepo: WalletRepo; + }) => { + if (current) { + await current?.disconnect(true); + } + + const handleConnectError = (e: Error) => { + console.error("Error while connecting to wallet. Details: ", e); + localStorage.removeItem(CosmosKitWalletLocalStorageKey); + localStorage.removeItem(CosmosKitAccountsLocalStorageKey); + }; + + if (!("lazyInstall" in wallet)) { + wallet + .connect(false) + .then(() => { + onConnectProp?.({ walletType: "cosmos" }); + }) + .catch(handleConnectError); + return; + } + + const isWalletInstalled = rootWalletRepo?.wallets.some( + ({ walletName }) => walletName === wallet.name + ); + + let walletRepo: WalletRepo; + + // if wallet is not installed, install it + if (!isWalletInstalled && "lazyInstall" in wallet) { + setLazyWalletInfo(wallet); + setModalView("connecting"); + + // wallet is now walletInfo + const walletInfo = wallet; + const WalletClass = await wallet.lazyInstall(); + + const walletManager = await accountStore.addWallet( + new WalletClass(walletInfo) + ); + await walletManager.onMounted().catch(handleConnectError); + setLazyWalletInfo(undefined); + + walletRepo = walletManager.getWalletRepo(cosmosChainName!); + } else { + walletRepo = walletRepoParam; + } + + const isOsmosisConnection = + chainStore.osmosis.chainName === cosmosChainName!; + const osmosisWalletRepo = accountStore.getWalletRepo( + chainStore.osmosis.chainName + ); + + if ( + !isOsmosisConnection && + osmosisWalletRepo.walletStatus !== WalletStatus.Connected + ) { + await osmosisWalletRepo + .connect(wallet.name, false) + .catch(handleConnectError); + } + + return walletRepo + .connect(wallet.name, false) + .then(async () => { + onConnectProp?.({ walletType: "cosmos" }); + + if (transaction1CTParams?.isOneClickEnabled) { + try { + await onCreate1CTSession({ walletRepo, transaction1CTParams }); + } catch (e) { + const error = e as CreateOneClickSessionError | Error; + + if (error instanceof Error) { + throw new CreateOneClickSessionError(error.message); + } + + throw e; + } + } + }) + .catch((e: Error | unknown) => { + if (e instanceof CreateOneClickSessionError) throw e; + handleConnectError( + e instanceof Error ? e : new Error("Unknown error.") + ); + }); + }; + + const onConnectWagmiWallet = async ({ + wallet, + chainId, + }: { + wallet: Connector; + chainId: EthereumChainIds | undefined; + }) => { + // Close modal to show WalletConnect QR code modal + if (wallet.type === WagmiWalletConnectType) { + onRequestClose(); + } + + return connectEvmWallet( + { connector: wallet, chainId: chainId }, + { + onSuccess: () => { + onConnectProp?.({ walletType: "evm" }); + }, + onError: (e) => { + console.error("Error while connecting to wallet. Details: ", e); + }, + } + ); + }; + + const onConnect: OnConnectWallet = async (param) => { + if (!param.wallet) return; + + if (param.walletType === "cosmos" && rootWalletRepo) { + return onConnectCosmosWallet({ + wallet: param.wallet, + walletRepo: rootWalletRepo, + }); + } + + if (param.walletType === "evm") { + return onConnectWagmiWallet({ + wallet: param.wallet, + chainId: param.chainId, + }).catch(noop); + } + }; + + const onRequestBack = + modalView !== "list" + ? () => { + if ( + cosmosWalletStatus === WalletStatus.Connecting || + cosmosWalletStatus === WalletStatus.Rejected || + cosmosWalletStatus === WalletStatus.Error || + cosmosWalletStatus === WalletStatus.Connected + ) { + rootWalletRepo?.disconnect(); + rootWalletRepo?.activate(); + } + + if ( + modalView === "initializeOneClickTradingError" || + modalView === "initializingOneClickTrading" + ) { + reset1CTParams(); + // Clear the errors and loading states + create1CTSession.reset(); + setIsInitializingOneClickTrading(false); + setShow1CTConnectAWallet(false); + } + + setModalView("list"); + } + : undefined; + + return ( + + {layout === "list" && ( +
+ + + {!isNil(variables?.connector) && ( +
+ +
+ )} + +
+ )} + + {layout === "full" && ( + <> +
+ + + +
+ {onRequestBack && ( + + )} + + onCreate1CTSession({ + walletRepo: rootWalletRepo!, + transaction1CTParams, + }) + } + show1CTConnectAWallet={show1CTConnectAWallet} + setShow1CTConnectAWallet={setShow1CTConnectAWallet} + show1CTEditParams={show1CTEditParams} + setShow1CTEditParams={setShow1CTEditParams} + walletOptions={walletOptions} + /> + + {/* Hide close button since 1CT edit params will include it */} + {!show1CTEditParams && } +
+
+ + )} +
+ ); + }); diff --git a/packages/web/modals/wallet-select/qr-code-view.tsx b/packages/web/modals/wallet-select/qr-code-view.tsx new file mode 100644 index 0000000000..6b92b9eb73 --- /dev/null +++ b/packages/web/modals/wallet-select/qr-code-view.tsx @@ -0,0 +1,187 @@ +import { ChainWalletBase, ExpiredError, State } from "@cosmos-kit/core"; +import { Popover } from "@headlessui/react"; +import classNames from "classnames"; +import Image from "next/image"; +import React, { Fragment, FunctionComponent, Suspense, useMemo } from "react"; + +import SkeletonLoader from "~/components/loaders/skeleton-loader"; +import { Button } from "~/components/ui/button"; +import { useTranslation } from "~/hooks"; + +const QRCode = React.lazy(() => import("~/components/qrcode")); + +const QRCodeLoader = () => ( +
+ +
+
+
+ +
+); + +type QRCodeStatus = "pending" | "done" | "error" | "expired" | undefined; +const QRCodeView: FunctionComponent<{ wallet?: ChainWalletBase }> = ({ + wallet, +}) => { + const { t } = useTranslation(); + + const qrUrl = wallet?.qrUrl; + + const [errorTitle, errorDesc, status] = useMemo(() => { + const isExpired = qrUrl?.message === ExpiredError.message; + + const errorDesc = isExpired + ? t("walletSelect.clickToRefresh") + : qrUrl?.message; + const errorTitle = isExpired + ? t("walletSelect.qrCodeExpired") + : t("walletSelect.qrCodeError"); + + const statusDict: Record = { + [State.Pending]: "pending" as const, + [State.Done]: "done" as const, + [State.Error]: isExpired ? ("expired" as const) : ("error" as const), + [State.Init]: undefined, + }; + + return [errorTitle, errorDesc, statusDict[qrUrl?.state ?? State.Init]]; + }, [qrUrl?.message, qrUrl?.state, t]); + + const downloadLink = wallet?.walletInfo.downloads?.find( + ({ os }) => !os + )?.link; + + return ( + + {({ open: isDownloadQROpen }) => ( +
+

+ {t("walletSelect.connectWith")} {wallet?.walletPrettyName} +

+ +
+

+ {t("walletSelect.tapThe")} + scan icon + {t("walletSelect.button")} +

+ +

+ {t("walletSelect.topRightButton", { + wallet: wallet?.walletPrettyName ?? "", + })} +

+
+ + {(status === "error" || status === "expired") && ( + <> +
+
+ +
+ +
+
+
+

{errorTitle}

+

+ {errorDesc} +

+
+ + )} + {status === "pending" && } + {status === "done" && ( +
+
+ {Boolean(qrUrl?.data) && ( + }> +
+ +
+
+ )} +
+ +
+

+ {t("walletSelect.dontHaveThisWallet")} +

+ +
+ + {t("walletSelect.get")} {wallet?.walletPrettyName} + + + +

+ {t("walletSelect.scanThis")} {wallet?.walletPrettyName} +

+ {typeof downloadLink === "string" && + downloadLink !== "" && ( + }> +
+ +
+
+ )} +
+
+
+
+ )} +
+ )} + + ); +}; + +export default QRCodeView; diff --git a/packages/web/modals/wallet-select/simple-wallet-list.tsx b/packages/web/modals/wallet-select/simple-wallet-list.tsx new file mode 100644 index 0000000000..5b8790e1ca --- /dev/null +++ b/packages/web/modals/wallet-select/simple-wallet-list.tsx @@ -0,0 +1,97 @@ +import classNames from "classnames"; +import { observer } from "mobx-react-lite"; +import React, { FunctionComponent, useMemo, useState } from "react"; + +import { SearchBox } from "~/components/input"; +import { useTranslation, WalletSelectOption } from "~/hooks"; +import { useSelectableWallets } from "~/modals/wallet-select/use-selectable-wallets"; +import { OnConnectWallet } from "~/modals/wallet-select/utils"; + +export const SimpleWalletList: FunctionComponent<{ + onConnect: OnConnectWallet; + isMobile: boolean; + walletOptions: WalletSelectOption[]; +}> = observer(({ onConnect, isMobile, walletOptions }) => { + const [search, setSearch] = useState(""); + + const { t } = useTranslation(); + const { cosmosWallets, evmWallets } = useSelectableWallets({ + includedWallets: walletOptions.map((option) => option.walletType), + isMobile, + }); + + const evmOption = useMemo( + () => + walletOptions.find( + ( + option + ): option is Extract => + option.walletType === "evm" + ), + [walletOptions] + ); + + if (cosmosWallets.length > 0) { + throw new Error( + "Cosmos wallets are not supported in 'simple' view layout yet." + ); + } + + return ( +
+

+ {t("connectWallet")} +

+ +
+ { + setSearch(nextValue); + }} + currentValue={search} + /> + +
+ {evmWallets + .filter((wallet) => { + if (!search) return true; + return wallet.name.toLowerCase().includes(search.toLowerCase()); + }) + .map((wallet) => { + return ( + + ); + })} +
+
+
+ ); +}); diff --git a/packages/web/modals/wallet-select/use-selectable-wallets.ts b/packages/web/modals/wallet-select/use-selectable-wallets.ts new file mode 100644 index 0000000000..e748669008 --- /dev/null +++ b/packages/web/modals/wallet-select/use-selectable-wallets.ts @@ -0,0 +1,113 @@ +import { useMemo } from "react"; +import { Connector } from "wagmi"; + +import { AvailableCosmosWallets } from "~/config/generated/cosmos-kit-wallet-list"; +import { CosmosWalletRegistry } from "~/config/wallet-registry"; +import { useConnectEvmWallet } from "~/hooks/evm-wallet"; + +export const WagmiWalletConnectType = "walletConnect"; +export const WagmiMetamaskSdkType = "metaMask"; + +export const useSelectableWallets = ({ + isMobile, + includedWallets, +}: { + isMobile: boolean; + includedWallets: ("cosmos" | "evm")[]; +}) => { + const { connectors } = useConnectEvmWallet(); + + const evmWallets = useMemo(() => { + if (!includedWallets.includes("evm")) return []; + + return ( + connectors + .reduce((acc, wallet) => { + const walletToAdd = { ...wallet, walletType: "evm" as const }; + + if (wallet.name === "MetaMask") { + walletToAdd.icon = "/logos/metamask.svg"; + } + + if (wallet.type === WagmiMetamaskSdkType) { + walletToAdd.name = walletToAdd.name + " (Mobile)"; + } + + if (wallet.name === "WalletConnect") { + walletToAdd.icon = "/logos/walletconnect.svg"; + } + + if (wallet.name === "Coinbase Wallet") { + walletToAdd.icon = "/logos/coinbase.svg"; + } + + return [...acc, walletToAdd]; + }, [] as (Connector & { walletType: "evm" })[]) + // type === "injected" should come first + .sort((a, b) => { + if (a.type === "injected" && b.type !== "injected") return -1; + if (a.type !== "injected" && b.type === "injected") return 1; + return 0; + }) + ); + }, [connectors, includedWallets]); + + const cosmosWallets = useMemo(() => { + if (!includedWallets.includes("cosmos")) return []; + return ( + CosmosWalletRegistry + // If mobile, filter out browser wallets + .reduce((acc, wallet, _index, array) => { + if (isMobile) { + /** + * If an extension wallet is found in mobile, this means that we are inside an app browser. + * Therefore, we should only show that compatible extension wallet. + * */ + if (acc.length > 0 && acc[0].name.endsWith("-extension")) { + return acc; + } + + const _window = window as Record; + const mobileWebModeName = "mobile-web"; + + /** + * If on mobile and `leap` is in `window`, it means that the user enters + * the frontend from Leap's app in app browser. So, there is no need + * to use wallet connect, as it resembles the extension's usage. + */ + if (_window?.leap && _window?.leap?.mode === mobileWebModeName) { + return array + .filter((wallet) => wallet.name === AvailableCosmosWallets.Leap) + .map((wallet) => ({ ...wallet, mobileDisabled: false })); + } + + /** + * If on mobile and `keplr` is in `window`, it means that the user enters + * the frontend from Keplr's app in app browser. So, there is no need + * to use wallet connect, as it resembles the extension's usage. + */ + if (_window?.keplr && _window?.keplr?.mode === mobileWebModeName) { + return array + .filter( + (wallet) => wallet.name === AvailableCosmosWallets.Keplr + ) + .map((wallet) => ({ ...wallet, mobileDisabled: false })); + } + + /** + * If user is in a normal mobile browser, show only wallet connect + */ + return wallet.name.endsWith("mobile") ? [...acc, wallet] : acc; + } + + return [...acc, wallet]; + }, [] as (typeof CosmosWalletRegistry)[number][]) + .map((wallet) => ({ + ...wallet, + walletType: "cosmos" as const, + })) + ); + }, [includedWallets, isMobile]); + + return { evmWallets, cosmosWallets }; +}; diff --git a/packages/web/modals/wallet-select/utils.ts b/packages/web/modals/wallet-select/utils.ts new file mode 100644 index 0000000000..a619ee547f --- /dev/null +++ b/packages/web/modals/wallet-select/utils.ts @@ -0,0 +1,72 @@ +import { ChainWalletBase, State, WalletStatus } from "@cosmos-kit/core"; +import { CosmosRegistryWallet } from "@osmosis-labs/stores"; +import { Connector } from "wagmi"; + +import { EthereumChainIds } from "~/config/wagmi"; + +export type ModalView = + | "list" + | "qrCode" + | "connecting" + | "connected" + | "error" + | "doesNotExist" + | "rejected" + | "initializingOneClickTrading" + | "broadcastedOneClickTrading" + | "initializeOneClickTradingError"; + +export function getModalView({ + qrState, + isInitializingOneClickTrading, + hasOneClickTradingError, + hasBroadcastedTx, + walletStatus, +}: { + qrState: State; + isInitializingOneClickTrading: boolean; + hasOneClickTradingError: boolean; + hasBroadcastedTx: boolean; + walletStatus?: WalletStatus; +}): ModalView { + if (walletStatus === WalletStatus.Connecting) { + return qrState === State.Init ? "connecting" : "qrCode"; + } + + if (walletStatus === WalletStatus.Connected) { + if (hasOneClickTradingError) return "initializeOneClickTradingError"; + if (isInitializingOneClickTrading) { + return hasBroadcastedTx + ? "broadcastedOneClickTrading" + : "initializingOneClickTrading"; + } + return "connected"; + } + + if (walletStatus === WalletStatus.Error) { + return qrState === State.Init ? "error" : "qrCode"; + } + + if (walletStatus === WalletStatus.Rejected) { + return "rejected"; + } + + if (walletStatus === WalletStatus.NotExist) { + return "doesNotExist"; + } + + return "list"; +} + +export type OnConnectWallet = ( + params: + | { + walletType: "cosmos"; + wallet: CosmosRegistryWallet | ChainWalletBase | undefined; + } + | { + walletType: "evm"; + wallet: Connector; + chainId?: EthereumChainIds; + } +) => void; diff --git a/packages/web/modals/wallet-select/wallet-tutorial.tsx b/packages/web/modals/wallet-select/wallet-tutorial.tsx new file mode 100644 index 0000000000..ad9aceb205 --- /dev/null +++ b/packages/web/modals/wallet-select/wallet-tutorial.tsx @@ -0,0 +1,69 @@ +import Image from "next/image"; +import React from "react"; + +import { + Step, + Stepper, + StepperLeftChevronNavigation, + StepperRightChevronNavigation, + StepsIndicator, +} from "~/components/stepper"; +import { MultiLanguageT, useTranslation } from "~/hooks"; + +const OnboardingSteps = (t: MultiLanguageT) => [ + { + title: t("walletSelect.step1Title"), + content: t("walletSelect.step1Content"), + }, + { + title: t("walletSelect.step2Title"), + content: t("walletSelect.step2Content"), + }, + { + title: t("walletSelect.step3Title"), + content: t("walletSelect.step3Content"), + }, + { + title: t("walletSelect.step4Title"), + content: t("walletSelect.step4Content"), + }, +]; + +const WalletTutorial = () => { + const { t } = useTranslation(); + return ( +
+

+ {t("walletSelect.gettingStarted")} +

+ + + {OnboardingSteps(t).map(({ title, content }) => ( + +
+
+ Wallet showcase +
+
+

{title}

+

{content}

+
+
+
+ ))} + + +
+
+ ); +}; + +export default WalletTutorial; diff --git a/packages/web/package.json b/packages/web/package.json index 11609551c8..e4fe6a1908 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -50,9 +50,9 @@ "@next/bundle-analyzer": "^12.1.6", "@notifi-network/notifi-frontend-client": "0.87.0", "@notifi-network/notifi-react-card": "0.87.0", + "@osmosis-labs/bridge": "^1.0.0", "@osmosis-labs/keplr-hooks": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/keplr-stores": "0.10.24-ibc.go.v7.hot.fix", - "@osmosis-labs/bridge": "^1.0.0", "@osmosis-labs/math": "^5.1.0", "@osmosis-labs/pools": "^5.1.0", "@osmosis-labs/server": "^1.0.0", @@ -132,6 +132,8 @@ "sharp": "^0.30.4", "tailwindcss-animate": "^1.0.7", "utility-types": "^3.10.0", + "viem": "2.12.0", + "wagmi": "^2.9.6", "web3-utils": "^1.7.4", "zod": "^3.22.4" }, diff --git a/packages/web/pages/_app.tsx b/packages/web/pages/_app.tsx index 4f06fbbf9c..6ac7f71fef 100644 --- a/packages/web/pages/_app.tsx +++ b/packages/web/pages/_app.tsx @@ -20,6 +20,7 @@ import { FunctionComponent } from "react"; import { ReactNode } from "react"; import { useEffect } from "react"; import { Bounce, ToastContainer } from "react-toastify"; +import { WagmiProvider } from "wagmi"; import { Icon } from "~/components/assets"; import ErrorBoundary from "~/components/error/error-boundary"; @@ -29,6 +30,7 @@ import { MainLayout } from "~/components/layouts"; import { MainLayoutMenu } from "~/components/main-menu"; import { OneClickFloatingBanner } from "~/components/one-click-trading/one-click-floating-banner"; import { AmplitudeEvent, EventName } from "~/config"; +import { wagmiConfig } from "~/config/wagmi"; import { MultiLanguageProvider, useDisclosure, @@ -39,7 +41,7 @@ import { BridgeProvider } from "~/hooks/bridge"; import { useAmplitudeAnalytics } from "~/hooks/use-amplitude-analytics"; import { useFeatureFlags } from "~/hooks/use-feature-flags"; import { useNewApps } from "~/hooks/use-new-apps"; -import { WalletSelectProvider } from "~/hooks/wallet-select"; +import { WalletSelectProvider } from "~/hooks/use-wallet-select"; import { ExternalLinkModal, handleExternalLink } from "~/modals"; import OneClickTradingIntroModal from "~/modals/one-click-trading-intro-modal"; import DefaultSeo from "~/next-seo.config"; @@ -68,31 +70,33 @@ function MyApp({ Component, pageProps }: AppProps) { useAmplitudeAnalytics({ init: true }); return ( - - - - - - - - - }> - {Component && } - - - - - - + + + + + + + + + + }> + {Component && } + + + + + + + ); } diff --git a/packages/web/pages/earn/index.tsx b/packages/web/pages/earn/index.tsx index 8af020adc3..4e81f390c8 100644 --- a/packages/web/pages/earn/index.tsx +++ b/packages/web/pages/earn/index.tsx @@ -152,7 +152,14 @@ function Earn() { mode={"primary"} className="max-h-11 max-w-[260px] xl:max-w-none" onClick={() => - onOpenWalletSelect(accountStore.osmosisChainId) + onOpenWalletSelect({ + walletOptions: [ + { + walletType: "cosmos", + chainId: accountStore.osmosisChainId, + }, + ], + }) } > {t("connectWallet")} diff --git a/packages/web/pages/stake.tsx b/packages/web/pages/stake.tsx index c20e8c7ecb..5d1cb37129 100644 --- a/packages/web/pages/stake.tsx +++ b/packages/web/pages/stake.tsx @@ -18,7 +18,7 @@ import { AmountDefault, EventName } from "~/config"; import { useAmountConfig, useFakeFeeConfig } from "~/hooks"; import { useAmplitudeAnalytics, useGetApr, useTranslation } from "~/hooks"; import { useStakedAmountConfig } from "~/hooks/ui-config/use-staked-amount-config"; -import { useWalletSelect } from "~/hooks/wallet-select"; +import { useWalletSelect } from "~/hooks/use-wallet-select"; import { StakeLearnMoreModal } from "~/modals/stake-learn-more-modal"; import { ValidatorNextStepModal } from "~/modals/validator-next-step"; import { ValidatorSquadModal } from "~/modals/validator-squad-modal"; @@ -253,7 +253,9 @@ export const Staking: React.FC = observer(() => { const onStakeButtonClick = useCallback(() => { if (!isWalletConnected) { - onOpenWalletSelect(osmosisChainId); + onOpenWalletSelect({ + walletOptions: [{ walletType: "cosmos", chainId: osmosisChainId }], + }); return; } diff --git a/packages/web/public/logos/metamask.svg b/packages/web/public/logos/metamask.svg new file mode 100644 index 0000000000..017dbb898a --- /dev/null +++ b/packages/web/public/logos/metamask.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/web/public/logos/walletconnect.svg b/packages/web/public/logos/walletconnect.svg new file mode 100644 index 0000000000..e711e05183 --- /dev/null +++ b/packages/web/public/logos/walletconnect.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/yarn.lock b/yarn.lock index fbb2b036d2..5054d0db40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2090,6 +2090,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.19.4", "@babel/runtime@^7.8.4": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" + integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.20.7": version "7.23.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d" @@ -2097,13 +2104,6 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/runtime@^7.8.4": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" - integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== - dependencies: - regenerator-runtime "^0.14.0" - "@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": version "7.20.7" resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz" @@ -2356,6 +2356,18 @@ long "^4.0.0" protobufjs "~6.11.2" +"@coinbase/wallet-sdk@4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-4.0.2.tgz#403b2194ecc9bcf8b8fd217ec5cd6529013b58f4" + integrity sha512-WMUeFbtS0rn8zavjAmNhFWq1r3TV7E5KuSij1Sar0/XuOC+nhj96uqSlIApAHdhuScoKZBq39VYsAQCHzOC6/w== + dependencies: + buffer "^6.0.3" + clsx "^1.2.1" + eventemitter3 "^5.0.1" + keccak "^3.0.3" + preact "^10.16.0" + sha.js "^2.4.11" + "@coinbase/wallet-sdk@^3.6.6": version "3.7.2" resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-3.7.2.tgz#7a89bd9e3a06a1f26d4480d8642af33fb0c7e3aa" @@ -5994,6 +6006,15 @@ resolved "https://registry.yarnpkg.com/@metamask/detect-provider/-/detect-provider-2.0.0.tgz#4bc2795e5e6f7d8b84b2e845058d2f222c99917d" integrity sha512-sFpN+TX13E9fdBDh9lvQeZdJn4qYoRb/6QF2oZZK/Pn559IhCFacPMU1rMuqyXoFQF3JSJfii2l98B87QDPeCQ== +"@metamask/eth-json-rpc-provider@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@metamask/eth-json-rpc-provider/-/eth-json-rpc-provider-1.0.1.tgz#3fd5316c767847f4ca107518b611b15396a5a32c" + integrity sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA== + dependencies: + "@metamask/json-rpc-engine" "^7.0.0" + "@metamask/safe-event-emitter" "^3.0.0" + "@metamask/utils" "^5.0.1" + "@metamask/eth-sig-util@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" @@ -6005,7 +6026,7 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" -"@metamask/json-rpc-engine@^7.3.2": +"@metamask/json-rpc-engine@^7.0.0", "@metamask/json-rpc-engine@^7.3.2": version "7.3.3" resolved "https://registry.yarnpkg.com/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.3.tgz#f2b30a2164558014bfcca45db10f5af291d989af" integrity sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg== @@ -6109,6 +6130,52 @@ resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-3.0.0.tgz#8c2b9073fe0722d48693143b0dc8448840daa3bd" integrity sha512-j6Z47VOmVyGMlnKXZmL0fyvWfEYtKWCA9yGZkU3FCsGZUT5lHGmvaV9JA5F2Y+010y7+ROtR3WMXIkvl/nVzqQ== +"@metamask/sdk-communication-layer@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.20.2.tgz#7f7fd334b2d26abd1a5a1ec1ffadf823a9589344" + integrity sha512-TN+whYbCClFSkx52Ild1RcjoRyz8YZgwNvZeooIcZIvCfBM6U9W5273KGiY7WLc/oO4KKmFk17d7vMO4gNvhhw== + dependencies: + bufferutil "^4.0.8" + date-fns "^2.29.3" + debug "^4.3.4" + utf-8-validate "^6.0.3" + uuid "^8.3.2" + +"@metamask/sdk-install-modal-web@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.20.2.tgz#1cf0eb3c26291de7598190878fa9a893c4eb2d66" + integrity sha512-0QiaZhV15AGdN1zU2jfTI32eC3YkwEpzDfR9+oiZ9bd2G72c6lYBhTsmDGUd01aP6A+bqJR5PjI8Wh2AWtoLeA== + dependencies: + qr-code-styling "^1.6.0-rc.1" + +"@metamask/sdk@0.20.3": + version "0.20.3" + resolved "https://registry.yarnpkg.com/@metamask/sdk/-/sdk-0.20.3.tgz#73851d68ffe5d45c1872c024182922530b187b7a" + integrity sha512-HZ9NwA+LxiXzuy0YWbWsuD4xejQtp85bhcCAf8UgpA/0dOyF3RS4dKDdBBXSyRgk3RWPjeJgHxioaH4CmBmiRA== + dependencies: + "@metamask/onboarding" "^1.0.1" + "@metamask/providers" "^15.0.0" + "@metamask/sdk-communication-layer" "0.20.2" + "@metamask/sdk-install-modal-web" "0.20.2" + "@types/dom-screen-wake-lock" "^1.0.0" + bowser "^2.9.0" + cross-fetch "^4.0.0" + debug "^4.3.4" + eciesjs "^0.3.15" + eth-rpc-errors "^4.0.3" + eventemitter2 "^6.4.7" + i18next "22.5.1" + i18next-browser-languagedetector "7.1.0" + obj-multiplex "^1.0.0" + pump "^3.0.0" + qrcode-terminal-nooctal "^0.12.1" + react-native-webview "^11.26.0" + readable-stream "^3.6.2" + rollup-plugin-visualizer "^5.9.2" + socket.io-client "^4.5.1" + util "^0.12.4" + uuid "^8.3.2" + "@metamask/utils@^3.0.1": version "3.6.0" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-3.6.0.tgz#b218b969a05ca7a8093b5d1670f6625061de707d" @@ -6119,7 +6186,7 @@ semver "^7.3.8" superstruct "^1.0.3" -"@metamask/utils@^5.0.0": +"@metamask/utils@^5.0.0", "@metamask/utils@^5.0.1": version "5.0.2" resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-5.0.2.tgz#140ba5061d90d9dac0280c19cab101bc18c8857c" integrity sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g== @@ -7812,6 +7879,14 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz#5f1b518ec5fa54437c0b7c4a821546c64fed6922" integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA== +"@safe-global/safe-apps-provider@0.18.1": + version "0.18.1" + resolved "https://registry.yarnpkg.com/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.1.tgz#287b5a1e2ef3be630dacde54279409df3ced8202" + integrity sha512-V4a05A3EgJcriqtDoJklDz1BOinWhC6P0hjUSxshA4KOZM7rGPCTto/usXs09zr1vvL28evl/NldSTv97j2bmg== + dependencies: + "@safe-global/safe-apps-sdk" "^8.1.0" + events "^3.3.0" + "@safe-global/safe-apps-provider@^0.18.1": version "0.18.2" resolved "https://registry.yarnpkg.com/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.2.tgz#336f3f4bb6ebbad9354e6551687491efc73991bc" @@ -7820,7 +7895,7 @@ "@safe-global/safe-apps-sdk" "^9.0.0" events "^3.3.0" -"@safe-global/safe-apps-sdk@^8.1.0": +"@safe-global/safe-apps-sdk@8.1.0", "@safe-global/safe-apps-sdk@^8.1.0": version "8.1.0" resolved "https://registry.yarnpkg.com/@safe-global/safe-apps-sdk/-/safe-apps-sdk-8.1.0.tgz#d1d0c69cd2bf4eef8a79c5d677d16971926aa64a" integrity sha512-XJbEPuaVc7b9n23MqlF6c+ToYIS3f7P2Sel8f3cSBQ9WORE4xrSuvhMpK9fDSFqJ7by/brc+rmJR/5HViRr0/w== @@ -8837,7 +8912,7 @@ "@stablelib/constant-time" "^1.0.1" "@stablelib/wipe" "^1.0.1" -"@stablelib/random@^1.0.1", "@stablelib/random@^1.0.2": +"@stablelib/random@1.0.2", "@stablelib/random@^1.0.1", "@stablelib/random@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz" integrity sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w== @@ -8868,7 +8943,7 @@ resolved "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz" integrity sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg== -"@stablelib/x25519@^1.0.3": +"@stablelib/x25519@1.0.3", "@stablelib/x25519@^1.0.3": version "1.0.3" resolved "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz" integrity sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw== @@ -9604,6 +9679,11 @@ dependencies: "@types/ms" "*" +"@types/dom-screen-wake-lock@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/dom-screen-wake-lock/-/dom-screen-wake-lock-1.0.3.tgz#c3588a5f6f40fae957f9ce5be9bc4927a61bb9a0" + integrity sha512-3Iten7X3Zgwvk6kh6/NRdwN7WbZ760YgFCsF5AxDifltUQzW1RaW+WRmcVtgwFzLjaNu64H+0MPJ13yRa8g3Dw== + "@types/dompurify@^3.0.4": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-3.0.5.tgz#02069a2fcb89a163bacf1a788f73cb415dd75cb7" @@ -9958,6 +10038,13 @@ dependencies: "@types/node" "*" +"@types/secp256k1@^4.0.4": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.6.tgz#d60ba2349a51c2cbc5e816dcd831a42029d376bf" + integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== + dependencies: + "@types/node" "*" + "@types/semver@^7.5.0": version "7.5.8" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" @@ -10440,6 +10527,28 @@ abitype "0.8.7" eventemitter3 "^4.0.7" +"@wagmi/connectors@5.0.5": + version "5.0.5" + resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-5.0.5.tgz#040a4e2e6858d9d6dcf0c0f36d20cc07f8b49da1" + integrity sha512-EjMsmPeu4iYDSSfpvsCbpIwhns+E2FrMqujpcgqTboWkAeSoUEbhoAsSwmivMts+5XojOX8NTs6/KP4zQriolg== + dependencies: + "@coinbase/wallet-sdk" "4.0.2" + "@metamask/sdk" "0.20.3" + "@safe-global/safe-apps-provider" "0.18.1" + "@safe-global/safe-apps-sdk" "8.1.0" + "@walletconnect/ethereum-provider" "2.13.0" + "@walletconnect/modal" "2.6.2" + cbw-sdk "npm:@coinbase/wallet-sdk@3.9.3" + +"@wagmi/core@2.10.3": + version "2.10.3" + resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-2.10.3.tgz#5184c94e2368b984d9ff8911bb83a3c9a92dc7d5" + integrity sha512-Sx5tWFzbLnwJk/aYPsaG8o4SQ8pVs5ucV5AVyPzA9Ibg3+J1P7qxOcfwPDXSNk67vmCGyZWlmBF/IwQChOJYbQ== + dependencies: + eventemitter3 "5.0.1" + mipd "0.0.5" + zustand "4.4.1" + "@wagmi/core@^1.4.13": version "1.4.13" resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-1.4.13.tgz#8a29bb0370141d48232e3d0b60011dbd8f91a37d" @@ -10564,6 +10673,29 @@ lodash.isequal "4.5.0" uint8arrays "^3.1.0" +"@walletconnect/core@2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.13.0.tgz#6b79b039930643e8ee85a0f512b143a35fdb8b52" + integrity sha512-blDuZxQenjeXcVJvHxPznTNl6c/2DO4VNrFnus+qHmO6OtT5lZRowdMtlCaCNb1q0OxzgrmBDcTOCbFcCpio/g== + dependencies: + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/jsonrpc-ws-connection" "1.0.14" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + "@walletconnect/relay-api" "1.0.10" + "@walletconnect/relay-auth" "1.0.4" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.13.0" + "@walletconnect/utils" "2.13.0" + events "3.3.0" + isomorphic-unfetch "3.1.0" + lodash.isequal "4.5.0" + uint8arrays "3.1.0" + "@walletconnect/core@2.9.2": version "2.9.2" resolved "https://registry.npmjs.org/@walletconnect/core/-/core-2.9.2.tgz" @@ -10663,7 +10795,23 @@ "@walletconnect/utils" "2.11.0" events "^3.3.0" -"@walletconnect/events@^1.0.1": +"@walletconnect/ethereum-provider@2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.13.0.tgz#5148851983e0d55fa1c18737b2db22802c82434c" + integrity sha512-dnpW8mmLpWl1AZUYGYZpaAfGw1HFkL0WSlhk5xekx3IJJKn4pLacX2QeIOo0iNkzNQxZfux1AK4Grl1DvtzZEA== + dependencies: + "@walletconnect/jsonrpc-http-connection" "1.0.8" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/modal" "2.6.2" + "@walletconnect/sign-client" "2.13.0" + "@walletconnect/types" "2.13.0" + "@walletconnect/universal-provider" "2.13.0" + "@walletconnect/utils" "2.13.0" + events "3.3.0" + +"@walletconnect/events@1.0.1", "@walletconnect/events@^1.0.1": version "1.0.1" resolved "https://registry.npmjs.org/@walletconnect/events/-/events-1.0.1.tgz" integrity sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ== @@ -10680,6 +10828,15 @@ "@walletconnect/time" "^1.0.2" tslib "1.14.1" +"@walletconnect/heartbeat@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz#e8dc5179db7769950c6f9cf59b23516d9b95227d" + integrity sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw== + dependencies: + "@walletconnect/events" "^1.0.1" + "@walletconnect/time" "^1.0.2" + events "^3.3.0" + "@walletconnect/iso-crypto@^1.8.0": version "1.8.0" resolved "https://registry.npmjs.org/@walletconnect/iso-crypto/-/iso-crypto-1.8.0.tgz" @@ -10689,6 +10846,16 @@ "@walletconnect/types" "^1.8.0" "@walletconnect/utils" "^1.8.0" +"@walletconnect/jsonrpc-http-connection@1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz#2f4c3948f074960a3edd07909560f3be13e2c7ae" + integrity sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw== + dependencies: + "@walletconnect/jsonrpc-utils" "^1.0.6" + "@walletconnect/safe-json" "^1.0.1" + cross-fetch "^3.1.4" + events "^3.3.0" + "@walletconnect/jsonrpc-http-connection@^1.0.4", "@walletconnect/jsonrpc-http-connection@^1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.7.tgz#a6973569b8854c22da707a759d241e4f5c2d5a98" @@ -10708,6 +10875,15 @@ "@walletconnect/safe-json" "^1.0.2" tslib "1.14.1" +"@walletconnect/jsonrpc-provider@1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz#696f3e3b6d728b361f2e8b853cfc6afbdf2e4e3e" + integrity sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow== + dependencies: + "@walletconnect/jsonrpc-utils" "^1.0.8" + "@walletconnect/safe-json" "^1.0.2" + events "^3.3.0" + "@walletconnect/jsonrpc-types@1.0.3", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": version "1.0.3" resolved "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.3.tgz" @@ -10716,6 +10892,14 @@ keyvaluestorage-interface "^1.0.0" tslib "1.14.1" +"@walletconnect/jsonrpc-types@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz#ce1a667d79eadf2a2d9d002c152ceb68739c230c" + integrity sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ== + dependencies: + events "^3.3.0" + keyvaluestorage-interface "^1.0.0" + "@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.3", "@walletconnect/jsonrpc-utils@^1.0.4", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.7", "@walletconnect/jsonrpc-utils@^1.0.8": version "1.0.8" resolved "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz" @@ -10746,15 +10930,7 @@ events "^3.3.0" ws "^7.5.1" -"@walletconnect/keyvaluestorage@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.0.2.tgz" - integrity sha512-U/nNG+VLWoPFdwwKx0oliT4ziKQCEoQ27L5Hhw8YOFGA2Po9A9pULUYNWhDgHkrb0gYDNt//X7wABcEWWBd3FQ== - dependencies: - safe-json-utils "^1.1.1" - tslib "1.14.1" - -"@walletconnect/keyvaluestorage@^1.1.1": +"@walletconnect/keyvaluestorage@1.1.1", "@walletconnect/keyvaluestorage@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz#dd2caddabfbaf80f6b8993a0704d8b83115a1842" integrity sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA== @@ -10763,6 +10939,14 @@ idb-keyval "^6.2.1" unstorage "^1.9.0" +"@walletconnect/keyvaluestorage@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.0.2.tgz" + integrity sha512-U/nNG+VLWoPFdwwKx0oliT4ziKQCEoQ27L5Hhw8YOFGA2Po9A9pULUYNWhDgHkrb0gYDNt//X7wABcEWWBd3FQ== + dependencies: + safe-json-utils "^1.1.1" + tslib "1.14.1" + "@walletconnect/legacy-client@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@walletconnect/legacy-client/-/legacy-client-2.0.0.tgz#9f2c09694789fd4b6c5d68d6423b44bac55aed30" @@ -10823,6 +11007,14 @@ detect-browser "^5.3.0" query-string "^6.13.5" +"@walletconnect/logger@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@walletconnect/logger/-/logger-2.1.2.tgz#813c9af61b96323a99f16c10089bfeb525e2a272" + integrity sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw== + dependencies: + "@walletconnect/safe-json" "^1.0.2" + pino "7.11.0" + "@walletconnect/logger@^2.0.1": version "2.0.1" resolved "https://registry.npmjs.org/@walletconnect/logger/-/logger-2.0.1.tgz" @@ -10892,6 +11084,13 @@ randombytes "^2.1.0" tslib "1.14.1" +"@walletconnect/relay-api@1.0.10": + version "1.0.10" + resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.10.tgz#5aef3cd07c21582b968136179aa75849dcc65499" + integrity sha512-tqrdd4zU9VBNqUaXXQASaexklv6A54yEyQQEXYOCr+Jz8Ket0dmPBDyg19LVSNUN2cipAghQc45/KVmfFJ0cYw== + dependencies: + "@walletconnect/jsonrpc-types" "^1.0.2" + "@walletconnect/relay-api@^1.0.9": version "1.0.9" resolved "https://registry.npmjs.org/@walletconnect/relay-api/-/relay-api-1.0.9.tgz" @@ -10900,7 +11099,7 @@ "@walletconnect/jsonrpc-types" "^1.0.2" tslib "1.14.1" -"@walletconnect/relay-auth@^1.0.4": +"@walletconnect/relay-auth@1.0.4", "@walletconnect/relay-auth@^1.0.4": version "1.0.4" resolved "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.0.4.tgz" integrity sha512-kKJcS6+WxYq5kshpPaxGHdwf5y98ZwbfuS4EE/NkQzqrDFm5Cj+dP8LofzWvjrrLkZq7Afy7WrQMXdLy8Sx7HQ== @@ -10917,7 +11116,7 @@ resolved "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.0.tgz" integrity sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg== -"@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": +"@walletconnect/safe-json@1.0.2", "@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.2.tgz" integrity sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA== @@ -10954,6 +11153,21 @@ "@walletconnect/utils" "2.11.3" events "^3.3.0" +"@walletconnect/sign-client@2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.13.0.tgz#f59993f082aec1ca5498b9519027e764c1e6d28b" + integrity sha512-En7KSvNUlQFx20IsYGsFgkNJ2lpvDvRsSFOT5PTdGskwCkUfOpB33SQJ6nCrN19gyoKPNvWg80Cy6MJI0TjNYA== + dependencies: + "@walletconnect/core" "2.13.0" + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/logger" "2.1.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.13.0" + "@walletconnect/utils" "2.13.0" + events "3.3.0" + "@walletconnect/sign-client@^2.9.0": version "2.9.2" resolved "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.9.2.tgz" @@ -10978,7 +11192,7 @@ "@walletconnect/utils" "^1.8.0" ws "7.5.3" -"@walletconnect/time@^1.0.2": +"@walletconnect/time@1.0.2", "@walletconnect/time@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@walletconnect/time/-/time-1.0.2.tgz" integrity sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g== @@ -11021,6 +11235,18 @@ "@walletconnect/logger" "^2.0.1" events "^3.3.0" +"@walletconnect/types@2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.13.0.tgz#cdac083651f5897084fe9ed62779f11810335ac6" + integrity sha512-MWaVT0FkZwzYbD3tvk8F+2qpPlz1LUSWHuqbINUtMXnSzJtXN49Y99fR7FuBhNFtDalfuWsEK17GrNA+KnAsPQ== + dependencies: + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + events "3.3.0" + "@walletconnect/types@2.7.2": version "2.7.2" resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.7.2.tgz#508d1755110864dee294f955e09b7da3f8ee0064" @@ -11065,6 +11291,21 @@ "@walletconnect/utils" "2.11.0" events "^3.3.0" +"@walletconnect/universal-provider@2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.13.0.tgz#f2b597001245e4d4a06d96dd1bce8d3a8a4dcbbf" + integrity sha512-B5QvO8pnk5Bqn4aIt0OukGEQn2Auk9VbHfhQb9cGwgmSCd1GlprX/Qblu4gyT5+TjHMb1Gz5UssUaZWTWbDhBg== + dependencies: + "@walletconnect/jsonrpc-http-connection" "1.0.8" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/logger" "2.1.2" + "@walletconnect/sign-client" "2.13.0" + "@walletconnect/types" "2.13.0" + "@walletconnect/utils" "2.13.0" + events "3.3.0" + "@walletconnect/utils@2.11.0": version "2.11.0" resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.11.0.tgz#31c95151c823022077883dda61800cdea71879b7" @@ -11105,6 +11346,26 @@ query-string "7.1.3" uint8arrays "^3.1.0" +"@walletconnect/utils@2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.13.0.tgz#1fc1fbff0d26db0830e65d1ba8cfe1a13a0616ad" + integrity sha512-q1eDCsRHj5iLe7fF8RroGoPZpdo2CYMZzQSrw1iqL+2+GOeqapxxuJ1vaJkmDUkwgklfB22ufqG6KQnz78sD4w== + dependencies: + "@stablelib/chacha20poly1305" "1.0.1" + "@stablelib/hkdf" "1.0.1" + "@stablelib/random" "1.0.2" + "@stablelib/sha256" "1.0.1" + "@stablelib/x25519" "1.0.3" + "@walletconnect/relay-api" "1.0.10" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.13.0" + "@walletconnect/window-getters" "1.0.1" + "@walletconnect/window-metadata" "1.0.1" + detect-browser "5.3.0" + query-string "7.1.3" + uint8arrays "3.1.0" + "@walletconnect/utils@2.9.2", "@walletconnect/utils@^2.9.0": version "2.9.2" resolved "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.9.2.tgz" @@ -11143,7 +11404,7 @@ resolved "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.0.tgz" integrity sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA== -"@walletconnect/window-getters@^1.0.1": +"@walletconnect/window-getters@1.0.1", "@walletconnect/window-getters@^1.0.1": version "1.0.1" resolved "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.1.tgz" integrity sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q== @@ -11157,7 +11418,7 @@ dependencies: "@walletconnect/window-getters" "^1.0.0" -"@walletconnect/window-metadata@^1.0.1": +"@walletconnect/window-metadata@1.0.1", "@walletconnect/window-metadata@^1.0.1": version "1.0.1" resolved "https://registry.npmjs.org/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz" integrity sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA== @@ -11451,6 +11712,11 @@ abitype@0.9.8: resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.8.tgz#1f120b6b717459deafd213dfbf3a3dd1bf10ae8c" integrity sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ== +abitype@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" + integrity sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -12709,7 +12975,7 @@ buffer@~5.4.3: base64-js "^1.0.2" ieee754 "^1.1.4" -bufferutil@^4.0.1: +bufferutil@^4.0.1, bufferutil@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea" integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== @@ -12920,6 +13186,21 @@ cbor-sync@^1.0.4: resolved "https://registry.yarnpkg.com/cbor-sync/-/cbor-sync-1.0.4.tgz#5a11a1ab75c2a14d1af1b237fd84aa8c1593662f" integrity sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA== +"cbw-sdk@npm:@coinbase/wallet-sdk@3.9.3": + version "3.9.3" + resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-3.9.3.tgz#daf10cb0c85d0363315b7270cb3f02bedc408aab" + integrity sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw== + dependencies: + bn.js "^5.2.1" + buffer "^6.0.3" + clsx "^1.2.1" + eth-block-tracker "^7.1.0" + eth-json-rpc-filters "^6.0.0" + eventemitter3 "^5.0.1" + keccak "^3.0.3" + preact "^10.16.0" + sha.js "^2.4.11" + chain-registry@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/chain-registry/-/chain-registry-1.20.0.tgz#1442a1d715a7ebf57781aeb185e3cbaa7b08196c" @@ -14527,6 +14808,15 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" +eciesjs@^0.3.15: + version "0.3.18" + resolved "https://registry.yarnpkg.com/eciesjs/-/eciesjs-0.3.18.tgz#67b5d73a8466e40a45bbc2f2a3177e71e9c0643d" + integrity sha512-RQhegEtLSyIiGJmFTZfvCTHER/fymipXFVx6OwSRYD6hOuy+6Kjpk0dGvIfP9kxn/smBpxQy71uxpGO406ITCw== + dependencies: + "@types/secp256k1" "^4.0.4" + futoin-hkdf "^1.5.3" + secp256k1 "^5.0.0" + eip1193-provider@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/eip1193-provider/-/eip1193-provider-1.0.1.tgz#420d29cf4f6c443e3f32e718fb16fafb250637c3" @@ -14614,7 +14904,7 @@ encoding@^0.1.13: dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: +end-of-stream@^1.1.0, end-of-stream@^1.4.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: version "1.4.4" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -14929,16 +15219,16 @@ escalade@^3.1.1, escalade@^3.1.2: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" @@ -15232,6 +15522,17 @@ eth-block-tracker@6.1.0: json-rpc-random-id "^1.0.1" pify "^3.0.0" +eth-block-tracker@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz#dfc16085c6817cc30caabba381deb8d204c1c766" + integrity sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg== + dependencies: + "@metamask/eth-json-rpc-provider" "^1.0.0" + "@metamask/safe-event-emitter" "^3.0.0" + "@metamask/utils" "^5.0.1" + json-rpc-random-id "^1.0.1" + pify "^3.0.0" + eth-crypto@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/eth-crypto/-/eth-crypto-2.6.0.tgz#b777f367ae8c70e5917b3b7d52adab6b34841e29" @@ -15256,6 +15557,17 @@ eth-json-rpc-filters@5.1.0: json-rpc-engine "^6.1.0" pify "^5.0.0" +eth-json-rpc-filters@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-6.0.1.tgz#0b3e370f017f5c6f58d3e7bd0756d8099ed85c56" + integrity sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig== + dependencies: + "@metamask/safe-event-emitter" "^3.0.0" + async-mutex "^0.2.6" + eth-query "^2.1.2" + json-rpc-engine "^6.1.0" + pify "^5.0.0" + eth-query@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" @@ -15444,6 +15756,16 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +eventemitter2@^6.4.7: + version "6.4.9" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.9.tgz#41f2750781b4230ed58827bc119d293471ecb125" + integrity sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg== + +eventemitter3@5.0.1, eventemitter3@^5.0.0, eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + eventemitter3@^3.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" @@ -15454,11 +15776,6 @@ eventemitter3@^4.0.4, eventemitter3@^4.0.7: resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -eventemitter3@^5.0.0, eventemitter3@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" - integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== - events@3.3.0, events@^3.1.0, events@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" @@ -15990,6 +16307,11 @@ fuse.js@^6.5.3: resolved "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz" integrity sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA== +futoin-hkdf@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/futoin-hkdf/-/futoin-hkdf-1.5.3.tgz#6c8024f2e1429da086d4e18289ef2239ad33ee35" + integrity sha512-SewY5KdMpaoCeh7jachEWFsh1nNlaDjNHZXWqL5IGwtpEYHTgkr2+AMCgNwKWkcc0wpSYrZfR7he4WdmHFtDxQ== + fuzzy@0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz" @@ -16795,6 +17117,20 @@ hyphenate-style-name@^1.0.3: resolved "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz" integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== +i18next-browser-languagedetector@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.1.0.tgz#01876fac51f86b78975e79b48ccb62e2313a2d7d" + integrity sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA== + dependencies: + "@babel/runtime" "^7.19.4" + +i18next@22.5.1: + version "22.5.1" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.5.1.tgz#99df0b318741a506000c243429a7352e5f44d424" + integrity sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA== + dependencies: + "@babel/runtime" "^7.20.6" + iconv-lite@0.6.3, iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" @@ -17053,6 +17389,13 @@ interpret@^1.0.0: resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== +invariant@2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + ip-address@^9.0.5: version "9.0.5" resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" @@ -17575,6 +17918,11 @@ isows@1.0.3: resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.3.tgz#93c1cf0575daf56e7120bab5c8c448b0809d0d74" integrity sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg== +isows@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.4.tgz#810cd0d90cc4995c26395d2aa4cfa4037ebdf061" + integrity sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" @@ -19944,6 +20292,13 @@ minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" +mipd@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mipd/-/mipd-0.0.5.tgz#367ee796531c23f0631f129038700b1406663aec" + integrity sha512-gbKA784D2WKb5H/GtqEv+Ofd1S9Zj+Z/PGDIl1u1QAbswkxD28BQ5bSXQxkeBzPBABg1iDSbiwGG1XqlOxRspA== + dependencies: + viem "^1.1.4" + miscreant@0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/miscreant/-/miscreant-0.3.2.tgz" @@ -20691,6 +21046,15 @@ oauth-sign@~0.9.0: resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +obj-multiplex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/obj-multiplex/-/obj-multiplex-1.0.0.tgz#2f2ae6bfd4ae11befe742ea9ea5b36636eabffc1" + integrity sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA== + dependencies: + end-of-stream "^1.4.0" + once "^1.4.0" + readable-stream "^2.3.3" + object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" @@ -21481,6 +21845,11 @@ preact@^10.12.0, preact@^10.5.9: resolved "https://registry.yarnpkg.com/preact/-/preact-10.20.1.tgz#1bc598ab630d8612978f7533da45809a8298542b" integrity sha512-JIFjgFg9B2qnOoGiYMVBtrcFxHqn+dNXbq76bVmcaHYJFYR4lW67AOcXgAYQQTDYXDOg/kTZrKPNCdRgJ2UJmw== +preact@^10.16.0: + version "10.22.0" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.22.0.tgz#a50f38006ae438d255e2631cbdaf7488e6dd4e16" + integrity sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw== + prebuild-install@^7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz" @@ -21781,6 +22150,11 @@ qrcode-generator@^1.4.3: resolved "https://registry.yarnpkg.com/qrcode-generator/-/qrcode-generator-1.4.4.tgz#63f771224854759329a99048806a53ed278740e7" integrity sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw== +qrcode-terminal-nooctal@^0.12.1: + version "0.12.1" + resolved "https://registry.yarnpkg.com/qrcode-terminal-nooctal/-/qrcode-terminal-nooctal-0.12.1.tgz#45016aca0d82b2818de7af0a06d072ad671fbe2e" + integrity sha512-jy/kkD0iIMDjTucB+5T6KBsnirlhegDH47vHgrj5MejchSQmi/EAMM0xMFeePgV9CJkkAapNakpVUWYgHvtdKg== + qrcode.react@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-1.0.1.tgz#2834bb50e5e275ffe5af6906eff15391fe9e38a5" @@ -21990,6 +22364,14 @@ react-modal@^3.12.1, react-modal@^3.16.1: react-lifecycles-compat "^3.0.0" warning "^4.0.3" +react-native-webview@^11.26.0: + version "11.26.1" + resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-11.26.1.tgz#658c09ed5162dc170b361e48c2dd26c9712879da" + integrity sha512-hC7BkxOpf+z0UKhxFSFTPAM4shQzYmZHoELa6/8a/MspcjEP7ukYKpuSUTLDywQditT8yI9idfcKvfZDKQExGw== + dependencies: + escape-string-regexp "2.0.0" + invariant "2.2.4" + react-qr-reader@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/react-qr-reader/-/react-qr-reader-2.2.1.tgz#dc89046d1c1a1da837a683dd970de5926817d55b" @@ -22737,6 +23119,16 @@ rlp@^2.2.3, rlp@^2.2.4: dependencies: bn.js "^5.2.0" +rollup-plugin-visualizer@^5.9.2: + version "5.12.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz#661542191ce78ee4f378995297260d0c1efb1302" + integrity sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ== + dependencies: + open "^8.4.0" + picomatch "^2.3.1" + source-map "^0.7.4" + yargs "^17.5.1" + rollup@2.78.0: version "2.78.0" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.78.0.tgz#00995deae70c0f712ea79ad904d5f6b033209d9e" @@ -22940,7 +23332,7 @@ secp256k1@3.7.1: nan "^2.14.0" safe-buffer "^5.1.2" -secp256k1@5.0.0: +secp256k1@5.0.0, secp256k1@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.0.tgz#be6f0c8c7722e2481e9773336d351de8cddd12f7" integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA== @@ -23347,7 +23739,7 @@ snakecase-keys@^5.1.2, snakecase-keys@^5.4.1: snake-case "^3.0.4" type-fest "^3.12.0" -socket.io-client@^4.6.1: +socket.io-client@^4.5.1, socket.io-client@^4.6.1: version "4.7.5" resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.5.tgz#919be76916989758bdc20eec63f7ee0ae45c05b7" integrity sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ== @@ -23473,6 +23865,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + sourcemap-codec@^1.4.8: version "1.4.8" resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz" @@ -24776,6 +25173,13 @@ uglify-js@^3.1.4: resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.5.tgz" integrity sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ== +uint8arrays@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.0.tgz#8186b8eafce68f28bd29bd29d683a311778901e2" + integrity sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog== + dependencies: + multiformats "^9.4.2" + uint8arrays@^3.0.0, uint8arrays@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz" @@ -25064,6 +25468,13 @@ utf-8-validate@^5.0.2, utf-8-validate@^5.0.5: dependencies: node-gyp-build "^4.3.0" +utf-8-validate@^6.0.3: + version "6.0.4" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-6.0.4.tgz#1305a1bfd94cecb5a866e6fc74fd07f3ed7292e5" + integrity sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ== + dependencies: + node-gyp-build "^4.3.0" + utf8@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz" @@ -25231,7 +25642,21 @@ vfile@^5.0.0: unist-util-stringify-position "^3.0.0" vfile-message "^3.0.0" -viem@^1.0.0, viem@^1.20.3, viem@^1.6.0: +viem@2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.12.0.tgz#699ba326a1ce0df81042dc8b6f22fa751f9cefce" + integrity sha512-XBvORspE4x2/gfy7idH6IVFwkJiXirygFCU3lxUH6fttsj8zufLtgiokfvZF/LAZUEDvdxSgL08whSYgffM2fw== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "1.0.0" + isows "1.0.4" + ws "8.13.0" + +viem@^1.0.0, viem@^1.1.4, viem@^1.20.3, viem@^1.6.0: version "1.21.4" resolved "https://registry.yarnpkg.com/viem/-/viem-1.21.4.tgz#883760e9222540a5a7e0339809202b45fe6a842d" integrity sha512-BNVYdSaUjeS2zKQgPs+49e5JKocfo60Ib2yiXOWBT6LuVxY1I/6fFX3waEtpXvL1Xn4qu+BVitVtMh9lyThyhQ== @@ -25257,6 +25682,15 @@ w3c-xmlserializer@^4.0.0: dependencies: xml-name-validator "^4.0.0" +wagmi@^2.9.6: + version "2.9.6" + resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-2.9.6.tgz#301557a7a6546f79fd14b8c40e878fa4242fa679" + integrity sha512-cRZJrI/N8XoPs5DwWP1JPaXPQnUKOr4q3w8xbbKSw2hv++4VXngyUn+clo5vqa/23AZTWwRo4vcJYJoHtHP9Hw== + dependencies: + "@wagmi/connectors" "5.0.5" + "@wagmi/core" "2.10.3" + use-sync-external-store "1.2.0" + walker@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" @@ -25771,7 +26205,7 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.3: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@17.7.2, yargs@^17.6.2, yargs@^17.7.2: +yargs@17.7.2, yargs@^17.5.1, yargs@^17.6.2, yargs@^17.7.2: version "17.7.2" resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== @@ -25865,6 +26299,13 @@ zod@^3.22.4: resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== +zustand@4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.1.tgz#0cd3a3e4756f21811bd956418fdc686877e8b3b0" + integrity sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw== + dependencies: + use-sync-external-store "1.2.0" + zustand@^4.3.1: version "4.5.2" resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.2.tgz#fddbe7cac1e71d45413b3682cdb47b48034c3848"