diff --git a/.gitignore b/.gitignore index 27ed070def..430adb7414 100644 --- a/.gitignore +++ b/.gitignore @@ -93,8 +93,6 @@ test-results .github/test-data junit.xml -# Leap extension local storage for e2e tests with playwright -apps/deploy-web/tests/ui/fixture/leapExtensionLocalStorage.*.json # Clinic.js diagnostic artifacts .clinic diff --git a/.npmrc b/.npmrc index dc26c586f1..e69de29bb2 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +0,0 @@ -@leapwallet:registry=https://registry.npmjs.org/ \ No newline at end of file diff --git a/apps/deploy-web/package.json b/apps/deploy-web/package.json index 6f7002ac55..310907b232 100644 --- a/apps/deploy-web/package.json +++ b/apps/deploy-web/package.json @@ -44,7 +44,6 @@ "@cosmos-kit/cosmos-extension-metamask": "0.13.3", "@cosmos-kit/cosmostation-extension": "~2.16.3", "@cosmos-kit/keplr": "~2.15.3", - "@cosmos-kit/leap": "~2.15.3", "@cosmos-kit/react": "^2.20.1", "@emotion/cache": "^11.7.1", "@emotion/css": "^11.7.1", diff --git a/apps/deploy-web/src/components/get-started/GetStartedStepper.spec.tsx b/apps/deploy-web/src/components/get-started/GetStartedStepper.spec.tsx new file mode 100644 index 0000000000..a0499e6e07 --- /dev/null +++ b/apps/deploy-web/src/components/get-started/GetStartedStepper.spec.tsx @@ -0,0 +1,73 @@ +import { describe, expect, it, vi } from "vitest"; + +import { DEPENDENCIES, GetStartedStepper } from "./GetStartedStepper"; + +import { render, screen } from "@testing-library/react"; +import { MockComponents } from "@tests/unit/mocks"; + +describe(GetStartedStepper.name, () => { + it("displays AKT and USDC balance for custodial wallet", () => { + setup({ + isWalletConnected: true, + isManagedWallet: false, + balanceUAKT: 10_000_000, + balanceUUSDC: 5_000_000 + }); + + expect(screen.queryByText("10")).toBeInTheDocument(); + expect(screen.queryByText(/AKT and/)).toBeInTheDocument(); + expect(screen.queryByText(/USDC/)).toBeInTheDocument(); + }); + + it("displays USD balance for managed wallet", () => { + setup({ + isWalletConnected: true, + isManagedWallet: true, + balanceUAKT: 10_000_000, + balanceUUSDC: 5_000_000 + }); + + expect(screen.queryByText(/\$/)).toBeInTheDocument(); + expect(screen.queryByText(/AKT and/)).not.toBeInTheDocument(); + }); + + it("shows billing not set up when wallet is disconnected", () => { + setup({ isWalletConnected: false }); + + expect(screen.queryByText("Billing is not set up")).toBeInTheDocument(); + }); + + function setup(input?: { + isWalletConnected?: boolean; + isManagedWallet?: boolean; + isTrialing?: boolean; + balanceUAKT?: number; + balanceUUSDC?: number; + balanceUACT?: number; + }) { + const deps = MockComponents(DEPENDENCIES, { + useWallet: vi.fn(() => ({ + isWalletConnected: input?.isWalletConnected ?? false, + isManaged: input?.isManagedWallet ?? false, + isTrialing: input?.isTrialing ?? false, + address: "akash1test" + })) as unknown as (typeof DEPENDENCIES)["useWallet"], + useWalletBalance: vi.fn(() => ({ + balance: + input?.balanceUAKT !== undefined || input?.balanceUUSDC !== undefined || input?.balanceUACT !== undefined + ? { + balanceUAKT: input?.balanceUAKT ?? 0, + balanceUUSDC: input?.balanceUUSDC ?? 0, + balanceUACT: input?.balanceUACT ?? 0 + } + : undefined, + refetch: vi.fn() + })) as unknown as (typeof DEPENDENCIES)["useWalletBalance"], + useChainParam: vi.fn(() => ({ + minDeposit: { akt: 5, act: 5 } + })) as unknown as (typeof DEPENDENCIES)["useChainParam"] + }); + + return render(); + } +}); diff --git a/apps/deploy-web/src/components/get-started/GetStartedStepper.tsx b/apps/deploy-web/src/components/get-started/GetStartedStepper.tsx index 4ba9560b83..ade5db3c1e 100644 --- a/apps/deploy-web/src/components/get-started/GetStartedStepper.tsx +++ b/apps/deploy-web/src/components/get-started/GetStartedStepper.tsx @@ -18,16 +18,23 @@ import { RouteStep } from "@src/types/route-steps.type"; import { udenomToDenom } from "@src/utils/mathHelpers"; import { uaktToAKT } from "@src/utils/priceUtils"; import { UrlService } from "@src/utils/urlUtils"; -import LiquidityModal from "../liquidity-modal"; import { ExternalLink } from "../shared/ExternalLink"; import { WalletConnectionButtons } from "../wallet/WalletConnectionButtons"; import { QontoConnector, QontoStepIcon } from "./Stepper"; -export const GetStartedStepper: React.FunctionComponent = () => { +export const DEPENDENCIES = { + useWallet, + useWalletBalance, + useChainParam, + WalletConnectionButtons, + AddFundsLink +}; + +export const GetStartedStepper: React.FunctionComponent<{ dependencies?: typeof DEPENDENCIES }> = ({ dependencies: d = DEPENDENCIES }) => { const [activeStep, setActiveStep] = useState(0); - const { isWalletConnected, address, isManaged: isManagedWallet, isTrialing } = useWallet(); - const { refetch: refetchBalances, balance: walletBalance } = useWalletBalance(); - const { minDeposit } = useChainParam(); + const { isWalletConnected, isManaged: isManagedWallet, isTrialing } = d.useWallet(); + const { balance: walletBalance } = d.useWalletBalance(); + const { minDeposit } = d.useChainParam(); const aktBalance = walletBalance ? uaktToAKT(walletBalance.balanceUAKT) : 0; const usdcBalance = walletBalance ? udenomToDenom(walletBalance.balanceUUSDC) : 0; const actBalance = walletBalance ? udenomToDenom(walletBalance.balanceUACT) : 0; @@ -98,10 +105,10 @@ export const GetStartedStepper: React.FunctionComponent = () => {
{isManagedWallet && (
- + Add Funds - +
)}
@@ -136,7 +143,7 @@ export const GetStartedStepper: React.FunctionComponent = () => { Billing is not set up - + )} @@ -165,7 +172,6 @@ export const GetStartedStepper: React.FunctionComponent = () => { You have {aktBalance} AKT and {usdcBalance} USDC )} - {!isManagedWallet && isWalletConnected && } )} diff --git a/apps/deploy-web/src/components/liquidity-modal/index.tsx b/apps/deploy-web/src/components/liquidity-modal/index.tsx deleted file mode 100644 index d5ca1cac30..0000000000 --- a/apps/deploy-web/src/components/liquidity-modal/index.tsx +++ /dev/null @@ -1,220 +0,0 @@ -"use client"; - -import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { Button, Spinner } from "@akashnetwork/ui/components"; -import { useWallet as useConnectedWallet, useWalletClient } from "@cosmos-kit/react"; -// import * as Elements from "@leapwallet/elements-umd-types"; -import { Modal } from "@mui/material"; - -import { useServices } from "@src/context/ServicesProvider"; -import { useWallet } from "@src/context/WalletProvider"; - -export type NonUndefined = T extends undefined ? never : T; - -const ToggleLiquidityModalButton: React.FC<{ onClick: () => void }> = ({ onClick }) => { - const { analyticsService } = useServices(); - const _onClick = () => { - analyticsService.track("leap_get_more_tokens", { - category: "wallet", - label: "Open Leap liquidity modal" - }); - - onClick(); - }; - - return ( - - ); -}; - -// TODO: Fix the elements types -// const convertWalletType = (walletName: string | undefined): Elements.WalletType | undefined => { -const convertWalletType = (walletName: string | undefined): any => { - if (!window.LeapElements) { - return undefined; - } - const walletType = window.LeapElements.WalletType; - switch (walletName) { - case "leap-extension": - return walletType.LEAP; - case "keplr-extension": - return walletType.KEPLR; - case "cosmostation-extension": - return walletType.COSMOSTATION; - case "keplr-mobile": - return walletType.WC_KEPLR_MOBILE; - default: - return undefined; - } -}; - -// const getTabsConfig = (txnLifecycleHooks: Partial>) => { -const getTabsConfig = (txnLifecycleHooks: any) => { - return { - aggregated: { - enabled: true, - orderIndex: 0, - title: "Swap or Bridge", - allowedDestinationChains: [ - { - chainId: "akashnet-2" - } - ], - defaultValues: { - sourceChainId: "osmosis-1", - sourceAsset: "uosmo", - destinationChainId: "akashnet-2", - destinationAsset: "uakt" - }, - txnLifecycleHooks - }, - swap: { - enabled: false - }, - "fiat-on-ramp": { - enabled: true, - title: "Buy AKT", - orderIndex: 1, - allowedDestinationChains: [ - { - chainId: "akashnet-2" - } - ], - defaultValues: { - currency: "USD", - sourceAmount: "10", - destinationChainId: "akashnet-2", - destinationAsset: "uakt" - }, - onTxnComplete: txnLifecycleHooks.onTxnComplete - }, - transfer: { - enabled: true, - orderIndex: 2, - title: "IBC Transfer", - defaultValues: { - sourceChainId: "osmosis-1", - sourceAsset: { originChainId: "akashnet-2", originDenom: "uakt" } - }, - txnLifecycleHooks - } - }; - // } satisfies Elements.TabsConfig; -}; - -type Props = { address: string; aktBalance: number; refreshBalances: () => void }; - -const LiquidityModal: React.FC = ({ refreshBalances }) => { - const { analyticsService } = useServices(); - const [isOpen, setIsOpen] = useState(false); - const [isElementsReady, setIsElementsReady] = useState(false); - const isElementsMounted = useRef(false); - - const { isWalletConnected } = useWallet(); - const { client: walletClient } = useWalletClient(); - const { mainWallet } = useConnectedWallet(); - - const walletName = isWalletConnected ? mainWallet?.walletName : undefined; - - const handleConnectWallet = useCallback(() => { - if (!isWalletConnected && walletClient) { - if (walletClient.enable) { - return walletClient.enable("akashnet-2"); - } else if (walletClient.connect) { - return walletClient.connect("akashnet-2"); - } - } else { - throw new Error("Wallet is not connected"); - } - }, [isWalletConnected, walletClient]); - - const tabsConfig = useMemo(() => { - // const txnLifecycleHooks: Partial> = { - const txnLifecycleHooks: any = { - onTxnComplete: () => { - refreshBalances(); - analyticsService.track("leap_tx_complete", { - category: "wallet", - label: "Completed a transaction on Leap liquidity modal" - }); - } - }; - - return getTabsConfig(txnLifecycleHooks); - }, [refreshBalances]); - - const connectedWalletType = useMemo(() => (isElementsReady ? convertWalletType(walletName) : undefined), [isElementsReady, walletName]); - - useEffect(() => { - if (isElementsReady && isOpen && !isElementsMounted.current) { - isElementsMounted.current = true; - window.LeapElements?.mountElements?.({ - connectWallet: handleConnectWallet, - connectedWalletType, - element: { - name: "multi-view", - props: { - tabsConfig - } - }, - enableSmartSwap: true, - skipClientId: `akashnet-console-${process.env.NODE_ENV}`, - enableCaching: true, - elementsRoot: "#leap-elements-portal" - }); - } - }, [isOpen, handleConnectWallet, connectedWalletType, tabsConfig, isElementsReady]); - - useEffect(() => { - if (isOpen) { - document.body.style.overflow = "hidden"; - } else { - document.body.style.overflow = "auto"; - } - }, [isOpen]); - - useEffect(() => { - isElementsMounted.current = false; - }, [connectedWalletType]); - - useEffect(() => { - if (!window) { - return; - } - - if (window.LeapElements) { - setIsElementsReady(true); - return; - } - - const cb = () => { - setIsElementsReady(true); - }; - - window.addEventListener("@leapwallet/elements:load", cb); - - return () => { - window.removeEventListener("@leapwallet/elements:load", cb); - }; - }, []); - - return ( - <> - setIsOpen(o => !o)} /> - {walletClient ? ( - setIsOpen(false)} className="flex items-center justify-center"> -
- {!isElementsReady ? : null} -
-
- - ) : null} - - ); -}; - -LiquidityModal.displayName = "LiquidityModal"; - -export default LiquidityModal; diff --git a/apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx b/apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx index 993008843d..53f9c90e55 100644 --- a/apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx +++ b/apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx @@ -9,7 +9,6 @@ import type { ChainContext, WalletModalProps } from "@cosmos-kit/core"; import { wallets as metamask } from "@cosmos-kit/cosmos-extension-metamask"; import { wallets as cosmostation } from "@cosmos-kit/cosmostation-extension"; import { wallets as keplr } from "@cosmos-kit/keplr"; -import { wallets as leap } from "@cosmos-kit/leap"; import { ChainProvider, DefaultModal, useChain } from "@cosmos-kit/react"; import { useAtom } from "jotai"; import { useSnackbar } from "notistack"; @@ -28,7 +27,7 @@ export function CustomChainProvider({ children }: Props) { { - - - - -