diff --git a/explorer/src/components/ConnectKeplrWallet.tsx b/explorer/src/components/ConnectKeplrWallet.tsx
deleted file mode 100644
index 428c725eb2..0000000000
--- a/explorer/src/components/ConnectKeplrWallet.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useChain } from '@cosmos-kit/react';
-import { Box, Button, Typography, IconButton, Stack } from '@mui/material';
-import CloseIcon from '@mui/icons-material/Close';
-import { TokenSVG } from '../icons/TokenSVG';
-import { ElipsSVG } from '../icons/ElipsSVG';
-import { trimAddress } from '../utils';
-import { unymToNym } from '../utils/currency';
-import { useIsMobile } from '../hooks/useIsMobile';
-
-export const ConnectKeplrWallet = () => {
- const { connect, disconnect, wallet, address, getCosmWasmClient, isWalletConnected, isWalletConnecting } =
- useChain('nyx');
- const isMobile = useIsMobile(1200);
-
- const [balance, setBalance] = useState<{
- status: 'loading' | 'success';
- data?: string;
- }>({ status: 'loading', data: undefined });
-
- useEffect(() => {
- const getBalance = async (walletAddress: string) => {
- setBalance({ status: 'loading', data: undefined });
-
- const account = await getCosmWasmClient();
- const uNYMBalance = await account.getBalance(walletAddress, 'unym');
- const NYMBalance = unymToNym(uNYMBalance.amount);
-
- setBalance({ status: 'success', data: NYMBalance });
- };
-
- if (address) {
- getBalance(address);
- }
- }, [address, getCosmWasmClient]);
-
- const getGlobalbutton = () => {
- if (isWalletConnecting) {
- return ;
- }
- if (isWalletConnected) {
- return (
-
- {!isMobile && (
-
-
-
- {balance.data} NYM
-
-
- )}{' '}
-
-
-
- {trimAddress(address, 7)}
-
-
- {
- await disconnect();
- }}
- >
-
-
-
- );
- }
-
- return (
-
- );
- };
-
- return {getGlobalbutton()};
-};
diff --git a/explorer/src/components/Wallet/ConnectKeplrWallet.tsx b/explorer/src/components/Wallet/ConnectKeplrWallet.tsx
new file mode 100644
index 0000000000..ff5d2691c6
--- /dev/null
+++ b/explorer/src/components/Wallet/ConnectKeplrWallet.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { Button, IconButton, Stack, CircularProgress } from '@mui/material';
+import CloseIcon from '@mui/icons-material/Close';
+import { useIsMobile } from '@src/hooks/useIsMobile';
+import { useWalletContext } from '@src/context/wallet';
+import { WalletAddress, WalletBalance } from '@src/components/Wallet';
+
+export const ConnectKeplrWallet = () => {
+ const { connectWallet, disconnectWallet, isWalletConnected, isWalletConnecting } = useWalletContext();
+ const isMobile = useIsMobile(1200);
+
+ if (!connectWallet || !disconnectWallet) {
+ return null;
+ }
+
+ if (isWalletConnected) {
+ return (
+
+
+
+ {
+ await disconnectWallet();
+ }}
+ >
+
+
+
+ );
+ }
+
+ return (
+
+ );
+};
diff --git a/explorer/src/components/Wallet/WalletAddress.tsx b/explorer/src/components/Wallet/WalletAddress.tsx
new file mode 100644
index 0000000000..8be6c9f291
--- /dev/null
+++ b/explorer/src/components/Wallet/WalletAddress.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { Box, Typography } from '@mui/material';
+import { ElipsSVG } from '@src/icons/ElipsSVG';
+import { trimAddress } from '@src/utils';
+import { useWalletContext } from '@src/context/wallet';
+
+export const WalletAddress = () => {
+ const { address } = useWalletContext();
+
+ const displayAddress = trimAddress(address, 7);
+
+ return (
+
+
+
+ {displayAddress}
+
+
+ );
+};
diff --git a/explorer/src/components/Wallet/WalletBalance.tsx b/explorer/src/components/Wallet/WalletBalance.tsx
new file mode 100644
index 0000000000..f94935ac23
--- /dev/null
+++ b/explorer/src/components/Wallet/WalletBalance.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { Box, Typography } from '@mui/material';
+import { useWalletContext } from '@src/context/wallet';
+import { useIsMobile } from '@src/hooks';
+import { TokenSVG } from '@src/icons/TokenSVG';
+
+export const WalletBalance = () => {
+ const { balance } = useWalletContext();
+ const isMobile = useIsMobile(1200);
+
+ const showBalance = !isMobile && balance.status === 'success';
+
+ if (!showBalance) {
+ return null;
+ }
+
+ return (
+
+
+
+ {balance.data} NYM
+
+
+ );
+};
diff --git a/explorer/src/context/cosmos-kit.tsx b/explorer/src/context/cosmos-kit.tsx
index e696106e1a..163332bf19 100644
--- a/explorer/src/context/cosmos-kit.tsx
+++ b/explorer/src/context/cosmos-kit.tsx
@@ -2,10 +2,11 @@ import React from 'react';
import { ChainProvider } from '@cosmos-kit/react';
import { wallets as keplr } from '@cosmos-kit/keplr';
import { wallets as ledger } from '@cosmos-kit/ledger';
+import { wallets as cosmosstation } from '@cosmos-kit/cosmostation';
import { assets, chains } from 'chain-registry';
const CosmosKitProvider = ({ children }: { children: React.ReactNode }) => (
-
+
{children}
);
diff --git a/explorer/src/context/wallet.tsx b/explorer/src/context/wallet.tsx
new file mode 100644
index 0000000000..bb8432f284
--- /dev/null
+++ b/explorer/src/context/wallet.tsx
@@ -0,0 +1,90 @@
+import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
+import { useChain } from '@cosmos-kit/react';
+import { Wallet } from '@cosmos-kit/core';
+
+import { unymToNym } from '@src/utils/currency';
+import { useNymClient } from '@src/hooks';
+import { MixnetClient, MixnetQueryClient } from '@nymproject/contract-clients/Mixnet.client';
+
+interface WalletState {
+ balance: { status: 'loading' | 'success'; data?: string };
+ address?: string;
+ isWalletConnected: boolean;
+ isWalletConnecting: boolean;
+ wallet?: Wallet;
+ nymClient?: MixnetClient;
+ nymQueryClient?: MixnetQueryClient;
+ connectWallet: () => Promise;
+ disconnectWallet: () => Promise;
+}
+
+export const WalletContext = createContext({
+ address: undefined,
+ balance: { status: 'loading', data: undefined },
+ isWalletConnected: false,
+ isWalletConnecting: false,
+ nymClient: undefined,
+ nymQueryClient: undefined,
+ connectWallet: async () => {
+ throw new Error('Please connect your wallet');
+ },
+ disconnectWallet: async () => {
+ throw new Error('Please connect your wallet');
+ },
+});
+
+export const WalletProvider = ({ children }: { children: React.ReactNode }) => {
+ const [balance, setBalance] = useState({ status: 'loading', data: undefined });
+
+ const { connect, disconnect, wallet, address, isWalletConnected, isWalletConnecting, getCosmWasmClient } =
+ useChain('nyx');
+
+ const { nymClient, nymQueryClient } = useNymClient(address);
+
+ const getBalance = async (walletAddress: string) => {
+ const account = await getCosmWasmClient();
+ const uNYMBalance = await account.getBalance(walletAddress, 'unym');
+ const NYMBalance = unymToNym(uNYMBalance.amount);
+
+ return NYMBalance;
+ };
+
+ const init = async (walletAddress: string) => {
+ const walletBalance = await getBalance(walletAddress);
+ setBalance({ status: 'success', data: walletBalance });
+ };
+
+ useEffect(() => {
+ if (isWalletConnected && address) {
+ init(address);
+ }
+ }, [address, isWalletConnected]);
+
+ const handleConnectWallet = async () => {
+ await connect();
+ };
+
+ const handleDisconnectWallet = async () => {
+ await disconnect();
+ setBalance({ status: 'loading', data: undefined });
+ };
+
+ const contextValue: WalletState = useMemo(
+ () => ({
+ address,
+ balance,
+ wallet,
+ isWalletConnected,
+ isWalletConnecting,
+ nymClient,
+ nymQueryClient,
+ connectWallet: handleConnectWallet,
+ disconnectWallet: handleDisconnectWallet,
+ }),
+ [address, balance, wallet, isWalletConnected, isWalletConnecting, nymClient, nymQueryClient],
+ );
+
+ return {children};
+};
+
+export const useWalletContext = () => useContext(WalletContext);
diff --git a/explorer/src/hooks/useNymClient.tsx b/explorer/src/hooks/useNymClient.tsx
new file mode 100644
index 0000000000..b9c5d92b67
--- /dev/null
+++ b/explorer/src/hooks/useNymClient.tsx
@@ -0,0 +1,31 @@
+import { useEffect, useState } from 'react';
+import { useChain } from '@cosmos-kit/react';
+import { contracts } from '@nymproject/contract-clients';
+import { MixnetClient, MixnetQueryClient } from '@nymproject/contract-clients/Mixnet.client';
+import { NYM_MIXNET_CONTRACT } from '@src/api/constants';
+
+export const useNymClient = (address?: string) => {
+ const [nymClient, setNymClient] = useState();
+ const [nymQueryClient, setNymQueryClient] = useState();
+
+ const { getCosmWasmClient, getSigningCosmWasmClient } = useChain('nyx');
+
+ useEffect(() => {
+ if (address) {
+ const init = async () => {
+ const cosmWasmSigningClient = await getSigningCosmWasmClient();
+ const cosmWasmClient = await getCosmWasmClient();
+
+ const client = new contracts.Mixnet.MixnetClient(cosmWasmSigningClient as any, address, NYM_MIXNET_CONTRACT);
+ const queryClient = new contracts.Mixnet.MixnetQueryClient(cosmWasmClient as any, NYM_MIXNET_CONTRACT);
+
+ setNymClient(client);
+ setNymQueryClient(queryClient);
+ };
+
+ init();
+ }
+ }, [address, getCosmWasmClient, getSigningCosmWasmClient]);
+
+ return { nymClient, nymQueryClient };
+};