Skip to content

Commit

Permalink
feat(network): stick to a certain network for managed wallets
Browse files Browse the repository at this point in the history
Also refactor network store, so it can serve both inside and outside react context as a single source of truth.

refs #247
  • Loading branch information
ygrishajev committed Aug 12, 2024
1 parent fa9de2f commit 27999fe
Show file tree
Hide file tree
Showing 18 changed files with 115 additions and 88 deletions.
12 changes: 10 additions & 2 deletions apps/deploy-web/env.config.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
const { z } = require("zod");

const networkId = z.enum(["mainnet", "sandbox", "testnet"]);

const envSchema = z.object({
NEXT_PUBLIC_MASTER_WALLET_ADDRESS: z.string().optional(),
NEXT_PUBLIC_BILLING_ENABLED: z
.enum(["true", "false"])
.transform(val => val === "true")
.optional()
.default("false")
.default("false"),
NEXT_PUBLIC_MANAGED_WALLET_NETWORK_ID: networkId.optional().default("mainnet"),
NEXT_PUBLIC_DEFAULT_NETWORK_ID: networkId.optional().default("mainnet"),
DEFAULT_NETWORK_ID: networkId.optional().default("mainnet")
});

module.exports.envSchema = envSchema;
module.exports.envConfig = envSchema.parse({
NEXT_PUBLIC_MASTER_WALLET_ADDRESS: process.env.NEXT_PUBLIC_MASTER_WALLET_ADDRESS,
NEXT_PUBLIC_BILLING_ENABLED: process.env.NEXT_PUBLIC_BILLING_ENABLED
NEXT_PUBLIC_BILLING_ENABLED: process.env.NEXT_PUBLIC_BILLING_ENABLED,
NEXT_PUBLIC_MANAGED_WALLET_NETWORK_ID: process.env.NEXT_PUBLIC_MANAGED_WALLET_NETWORK_ID,
NEXT_PUBLIC_DEFAULT_NETWORK_ID: process.env.NEXT_PUBLIC_DEFAULT_NETWORK_ID,
DEFAULT_NETWORK_ID: process.env.DEFAULT_NETWORK_ID
});
4 changes: 2 additions & 2 deletions apps/deploy-web/src/components/layout/NodeStatusBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import { Button } from "@akashnetwork/ui/components";
import { useRouter } from "next/navigation";

import { useSelectedNetwork } from "@src/hooks/useSelectedNetwork";
import { getSplitText } from "@src/hooks/useShortText";
import networkStore from "@src/store/networkStore";
import { UrlService } from "@src/utils/urlUtils";
import { useSettings } from "../../context/SettingsProvider";
import { LinearLoadingSkeleton } from "../shared/LinearLoadingSkeleton";
Expand All @@ -14,7 +14,7 @@ export const NodeStatusBar = () => {
const { selectedNode, isCustomNode, customNode } = settings;
const router = useRouter();
const shownNode = isCustomNode ? customNode : selectedNode;
const selectedNetwork = useSelectedNetwork();
const selectedNetwork = networkStore.useSelectedNetwork();

return (
<div className="mb-4">
Expand Down
4 changes: 2 additions & 2 deletions apps/deploy-web/src/components/providers/ProviderList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import { useRouter, useSearchParams } from "next/navigation";
import { useLocalNotes } from "@src/context/LocalNoteProvider";
import { useSettings } from "@src/context/SettingsProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useSelectedNetwork } from "@src/hooks/useSelectedNetwork";
import { useAllLeases } from "@src/queries/useLeaseQuery";
import { useNetworkCapacity, useProviderList } from "@src/queries/useProvidersQuery";
import networkStore from "@src/store/networkStore";
import { ClientProviderList } from "@src/types/provider";
import { domainName, UrlService } from "@src/utils/urlUtils";
import Layout from "../layout/Layout";
Expand Down Expand Up @@ -66,7 +66,7 @@ export const ProviderList: React.FunctionComponent = () => {
const end = start + pageSize;
const currentPageProviders = filteredProviders.slice(start, end);
const pageCount = Math.ceil(filteredProviders.length / pageSize);
const selectedNetwork = useSelectedNetwork();
const selectedNetwork = networkStore.useSelectedNetwork();
const router = useRouter();
const searchParams = useSearchParams();
const sortQuery = searchParams?.get("sort");
Expand Down
36 changes: 14 additions & 22 deletions apps/deploy-web/src/components/settings/SelectNetworkModal.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,22 @@
"use client";
import { useState } from "react";
import { Alert, AlertDescription, AlertTitle, Badge, buttonVariants, Popup, RadioGroup, RadioGroupItem } from "@akashnetwork/ui/components";
import { useAtom } from "jotai/index";

import { useSettings } from "@src/context/SettingsProvider";
import { networks } from "@src/store/networkStore";
import networkStore, { networks } from "@src/store/networkStore";
import { mainnetId } from "@src/utils/constants";
import { cn } from "@src/utils/styleUtils";

export const SelectNetworkModal = ({ onClose }) => {
const { selectedNetworkId } = useSettings();
const [localSelectedNetworkId, setLocalSelectedNetworkId] = useState(selectedNetworkId);
const [selectedNetworkId, setSelectedNetworkId] = useAtom(networkStore.selectedNetworkId);
const [formSelectedNetworkId, setFormSelectedNetworkId] = useState(selectedNetworkId);

const handleSelectNetwork = network => {
setLocalSelectedNetworkId(network.id);
};

const handleSaveChanges = () => {
if (selectedNetworkId !== localSelectedNetworkId) {
// Set in the settings and local storage
localStorage.setItem("selectedNetworkId", localSelectedNetworkId);
// Reset the ui to reload the settings for the currently selected network

location.reload();
} else {
onClose();
const save = () => {
if (selectedNetworkId !== formSelectedNetworkId) {
setSelectedNetworkId(formSelectedNetworkId);
}

onClose();
};

return (
Expand All @@ -44,7 +36,7 @@ export const SelectNetworkModal = ({ onClose }) => {
label: "Save",
variant: "default",
side: "right",
onClick: handleSaveChanges
onClick: save
}
]}
onClose={onClose}
Expand All @@ -57,15 +49,15 @@ export const SelectNetworkModal = ({ onClose }) => {
return (
<li
key={network.id}
onClick={() => handleSelectNetwork(network)}
onClick={() => setFormSelectedNetworkId(network.id)}
className={cn(
buttonVariants({ variant: "text" }),
{ ["pointer-events-none text-muted-foreground"]: !network.enabled },
"flex h-auto cursor-pointer items-center justify-start"
)}
>
<div className="basis-[40px]">
<RadioGroupItem value={network.id} id={network.id} checked={localSelectedNetworkId === network.id} disabled={!network.enabled} />
<RadioGroupItem value={network.id} id={network.id} checked={formSelectedNetworkId === network.id} disabled={!network.enabled} />
</div>
<div>
<div className="flex items-center justify-between text-lg">
Expand All @@ -86,11 +78,11 @@ export const SelectNetworkModal = ({ onClose }) => {
</ul>
</RadioGroup>

{localSelectedNetworkId !== mainnetId && (
{formSelectedNetworkId !== mainnetId && (
<Alert variant="warning" className="mb-2 mt-4">
<AlertTitle className="font-bold">Warning</AlertTitle>

<AlertDescription>Some features are experimental and may not work as intented on the testnet or sandbox.</AlertDescription>
<AlertDescription>Some features are experimental and may not work as intended on the testnet or sandbox.</AlertDescription>
</Alert>
)}
</Popup>
Expand Down
4 changes: 2 additions & 2 deletions apps/deploy-web/src/components/settings/SettingsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { NextSeo } from "next-seo";
import { LocalDataManager } from "@src/components/settings/LocalDataManager";
import { Fieldset } from "@src/components/shared/Fieldset";
import { LabelValue } from "@src/components/shared/LabelValue";
import { useSelectedNetwork } from "@src/hooks/useSelectedNetwork";
import networkStore from "@src/store/networkStore";
import Layout from "../layout/Layout";
import { CertificateList } from "./CertificateList";
import CloudmosImportPanel from "./CloudmosImportPanel";
Expand All @@ -18,7 +18,7 @@ import { SettingsLayout, SettingsTabs } from "./SettingsLayout";

export const SettingsContainer: React.FunctionComponent = () => {
const [isSelectingNetwork, setIsSelectingNetwork] = useState(false);
const selectedNetwork = useSelectedNetwork();
const selectedNetwork = networkStore.useSelectedNetwork();

const onSelectNetworkModalClose = () => {
setIsSelectingNetwork(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ChainProvider } from "@cosmos-kit/react";
import { useChain } from "@cosmos-kit/react";

import { akash, akashSandbox, akashTestnet, assetLists } from "@src/chains";
import { useSelectedNetwork } from "@src/hooks/useSelectedNetwork";
import networkStore from "@src/store/networkStore";
import { customRegistry } from "@src/utils/customRegistry";

type Props = {
Expand Down Expand Up @@ -58,6 +58,6 @@ export function CustomChainProvider({ children }: Props) {
}

export function useSelectedChain() {
const { chainRegistryName } = useSelectedNetwork();
const { chainRegistryName } = networkStore.useSelectedNetwork();
return useChain(chainRegistryName);
}
10 changes: 4 additions & 6 deletions apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ import { event } from "nextjs-google-analytics";
import { SnackbarKey, useSnackbar } from "notistack";

import { LoadingState, TransactionModal } from "@src/components/layout/TransactionModal";
import { useAnonymousUser } from "@src/context/AnonymousUserProvider/AnonymousUserProvider";
import { useAllowance } from "@src/hooks/useAllowance";
import { useCustomUser } from "@src/hooks/useCustomUser";
import { useUsdcDenom } from "@src/hooks/useDenom";
import { useManagedWallet } from "@src/hooks/useManagedWallet";
import { getSelectedNetwork, useSelectedNetwork } from "@src/hooks/useSelectedNetwork";
import { useUser } from "@src/hooks/useUser";
import { useWhen } from "@src/hooks/useWhen";
import { txHttpService } from "@src/services/http/http.service";
import networkStore from "@src/store/networkStore";
import { AnalyticsEvents } from "@src/utils/analytics";
import { STATS_APP_URL, uAktDenom } from "@src/utils/constants";
import { customRegistry } from "@src/utils/customRegistry";
Expand Down Expand Up @@ -110,7 +108,7 @@ export const WalletProvider = ({ children }) => {
}, [settings?.rpcEndpoint, userWallet.isWalletConnected]);

async function createStargateClient() {
const selectedNetwork = getSelectedNetwork();
const selectedNetwork = networkStore.getSelectedNetwork();

const offlineSigner = userWallet.getOfflineSigner();
let rpc = settings?.rpcEndpoint ? settings?.rpcEndpoint : (selectedNetwork.rpcEndpoint as string);
Expand Down Expand Up @@ -165,7 +163,7 @@ export const WalletProvider = ({ children }) => {
useWhen(walletAddress, loadWallet);

async function loadWallet(): Promise<void> {
const selectedNetwork = getSelectedNetwork();
const selectedNetwork = networkStore.getSelectedNetwork();
const storageWallets = JSON.parse(localStorage.getItem(`${selectedNetwork.id}/wallets`) || "[]") as LocalWalletDataType[];

let currentWallets = storageWallets ?? [];
Expand Down Expand Up @@ -368,7 +366,7 @@ export function useWallet() {
}

const TransactionSnackbarContent = ({ snackMessage, transactionHash }) => {
const selectedNetwork = useSelectedNetwork();
const selectedNetwork = networkStore.useSelectedNetwork();
const txUrl = transactionHash && `${STATS_APP_URL}/transactions/${transactionHash}?network=${selectedNetwork.id}`;

return (
Expand Down
6 changes: 3 additions & 3 deletions apps/deploy-web/src/hooks/useDenom.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import networkStore from "@src/store/networkStore";
import { usdcIbcDenoms } from "@src/utils/constants";
import { getSelectedNetwork, useSelectedNetwork } from "./useSelectedNetwork";

export const useUsdcDenom = () => {
const selectedNetwork = useSelectedNetwork();
const selectedNetwork = networkStore.useSelectedNetwork();
return usdcIbcDenoms[selectedNetwork.id];
};

export const getUsdcDenom = () => {
const selectedNetwork = getSelectedNetwork();
const selectedNetwork = networkStore.getSelectedNetwork();
return usdcIbcDenoms[selectedNetwork.id];
};

Expand Down
9 changes: 9 additions & 0 deletions apps/deploy-web/src/hooks/useManagedWallet.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useEffect, useMemo } from "react";
import { useAtom } from "jotai/index";

import { envConfig } from "@src/config/env.config";
import { useUser } from "@src/hooks/useUser";
import { useWhen } from "@src/hooks/useWhen";
import { useCreateManagedWalletMutation, useManagedWalletQuery } from "@src/queries/useManagedWalletQuery";
import networkStore from "@src/store/networkStore";
import { deleteManagedWalletFromStorage, updateStorageManagedWallet } from "@src/utils/walletUtils";

const isBillingEnabled = envConfig.NEXT_PUBLIC_BILLING_ENABLED;
const { NEXT_PUBLIC_MANAGED_WALLET_NETWORK_ID } = envConfig;

export const useManagedWallet = () => {
const user = useUser();
Expand All @@ -14,6 +18,7 @@ export const useManagedWallet = () => {
const { mutate: create, data: created, isLoading: isCreating, isSuccess: isCreated } = useCreateManagedWalletMutation();
const wallet = useMemo(() => queried || created, [queried, created]);
const isLoading = isFetching || isCreating;
const [selectedNetworkId, setSelectedNetworkId] = useAtom(networkStore.selectedNetworkId);

useEffect(() => {
if (!isBillingEnabled) {
Expand All @@ -27,6 +32,10 @@ export const useManagedWallet = () => {
}
}, [isFetched, isCreated, wallet]);

useWhen(created && NEXT_PUBLIC_MANAGED_WALLET_NETWORK_ID && selectedNetworkId !== NEXT_PUBLIC_MANAGED_WALLET_NETWORK_ID, () => {
setSelectedNetworkId(NEXT_PUBLIC_MANAGED_WALLET_NETWORK_ID);
});

return useMemo(() => {
const isConfigured = !!wallet;
return {
Expand Down
24 changes: 0 additions & 24 deletions apps/deploy-web/src/hooks/useSelectedNetwork.ts

This file was deleted.

7 changes: 4 additions & 3 deletions apps/deploy-web/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { TooltipProvider } from "@akashnetwork/ui/components";
import { CustomSnackbarProvider, PopupProvider } from "@akashnetwork/ui/context";
import { AppCacheProvider } from "@mui/material-nextjs/v14-pagesRouter";
import { GeistSans } from "geist/font/sans";
import { Provider } from "jotai";
import { Provider as JotaiProvider } from "jotai";
import { AppProps } from "next/app";
import Router from "next/router";
import { ThemeProvider } from "next-themes";
Expand All @@ -31,6 +31,7 @@ import { SettingsProvider } from "@src/context/SettingsProvider";
import { TemplatesProvider } from "@src/context/TemplatesProvider";
import { WalletProvider } from "@src/context/WalletProvider";
import { queryClient } from "@src/queries";
import { store } from "@src/store/global-store";
import { cn } from "@src/utils/styleUtils";

interface Props extends AppProps {}
Expand All @@ -53,7 +54,7 @@ const App: React.FunctionComponent<Props> = props => {
<AppCacheProvider {...props}>
<CustomIntlProvider>
<QueryClientProvider client={queryClient}>
<Provider>
<JotaiProvider store={store}>
<ThemeProvider attribute="class" defaultTheme="system" storageKey="theme" enableSystem disableTransitionOnChange>
<ColorModeProvider>
<CustomSnackbarProvider>
Expand Down Expand Up @@ -89,7 +90,7 @@ const App: React.FunctionComponent<Props> = props => {
</CustomSnackbarProvider>
</ColorModeProvider>
</ThemeProvider>
</Provider>
</JotaiProvider>
</QueryClientProvider>
</CustomIntlProvider>
</AppCacheProvider>
Expand Down
3 changes: 3 additions & 0 deletions apps/deploy-web/src/store/global-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { createStore } from "jotai";

export const store = createStore();
Loading

0 comments on commit 27999fe

Please sign in to comment.