diff --git a/src/components/masa-interface/pages/create-identity/create-identity.tsx b/src/components/masa-interface/pages/create-identity/create-identity.tsx
index 1aaebca8..972c5f02 100644
--- a/src/components/masa-interface/pages/create-identity/create-identity.tsx
+++ b/src/components/masa-interface/pages/create-identity/create-identity.tsx
@@ -3,13 +3,13 @@ import { useMasa } from '../../../../provider';
import { MasaLoading } from '../../../masa-loading';
export const InterfaceCreateIdentity = (): JSX.Element => {
- const { handlePurchaseIdentity, handleLogout, loading } = useMasa();
+ const { handlePurchaseIdentity, handleLogout, isLoading } = useMasa();
const createIdentity = useCallback(async () => {
await handlePurchaseIdentity?.();
}, [handlePurchaseIdentity]);
- if (loading) return
diff --git a/src/components/masa-interface/pages/switch-chain/switch-chain.tsx b/src/components/masa-interface/pages/switch-chain/switch-chain.tsx
index aae27087..1e695106 100644
--- a/src/components/masa-interface/pages/switch-chain/switch-chain.tsx
+++ b/src/components/masa-interface/pages/switch-chain/switch-chain.tsx
@@ -4,7 +4,8 @@ import { MasaLoading } from '../../../masa-loading';
import { Network } from '../../../../helpers';
export const InterfaceSwitchChain = (): JSX.Element => {
- const { networkName, loading, switchNetwork, SupportedNetworks } = useMasa();
+ const { networkName, isLoading, switchNetwork, SupportedNetworks } =
+ useMasa();
const currentNetwork: Network | null = useMemo(() => {
if (SupportedNetworks && networkName)
@@ -27,7 +28,7 @@ export const InterfaceSwitchChain = (): JSX.Element => {
}
}, [switchNetwork, currentNetwork]);
- if (loading) return
;
+ if (isLoading) return
;
return (
diff --git a/src/helpers/masa.ts b/src/helpers/masa.ts
index 1deb8ada..e59603e1 100644
--- a/src/helpers/masa.ts
+++ b/src/helpers/masa.ts
@@ -1,20 +1,13 @@
-import { Environment, environments, Masa } from '@masa-finance/masa-sdk';
-import { ethers, Wallet } from 'ethers';
+import {
+ createRandomWallet,
+ Environment,
+ environments,
+ Masa,
+} from '@masa-finance/masa-sdk';
+import { ethers } from 'ethers';
import { ArweaveConfig, getWeb3Provider } from '../provider';
import { getNetworkNameByChainId } from './networks';
-export const createRandomWallet = (): Wallet | null => {
- console.info('Creating random wallet!');
- const wallet = ethers.Wallet.createRandom();
- const provider = getWeb3Provider();
-
- if (provider) {
- return wallet.connect(provider);
- }
-
- return null;
-};
-
export const createNewMasa = async ({
signer,
environmentName,
@@ -25,20 +18,19 @@ export const createNewMasa = async ({
environmentName: string;
arweaveConfig?: ArweaveConfig;
verbose: boolean;
-}): Promise
=> {
+}): Promise => {
const newSigner: ethers.Signer | null = signer
? signer
- : createRandomWallet();
+ : createRandomWallet(getWeb3Provider());
- if (!newSigner) return null;
+ if (!newSigner) return;
const environment = environments.find(
(environment: Environment) => environment.name === environmentName
);
- if (!environment) return null;
+ if (!environment) return;
const chainId: number = await newSigner.getChainId();
- console.log({ NETWORK: chainId });
return new Masa({
wallet: newSigner,
diff --git a/src/provider/masa-context-provider.tsx b/src/provider/masa-context-provider.tsx
index abec4497..fc04496c 100644
--- a/src/provider/masa-context-provider.tsx
+++ b/src/provider/masa-context-provider.tsx
@@ -1,16 +1,20 @@
import { EnvironmentName, Masa, NetworkName } from '@masa-finance/masa-sdk';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import { createNewMasa, Network, SupportedNetworks } from '../helpers';
+import { createNewMasa, SupportedNetworks } from '../helpers';
import {
useCreditScores,
useGreen,
useIdentity,
+ useModal,
+ useNetwork,
+ useProvider,
useSession,
useSoulnames,
useWallet,
} from './modules';
-import { providers, Signer, utils, Wallet } from 'ethers';
-import { MASA_CONTEXT, MasaShape } from './masa-context';
+import { Signer, Wallet } from 'ethers';
+import { MASA_CONTEXT } from './masa-context';
+import { MasaShape } from './masa-shape';
export interface ArweaveConfig {
port?: string;
@@ -37,86 +41,93 @@ export const MasaContextProvider = ({
company,
environmentName = 'dev' as EnvironmentNameEx,
verbose = false,
- signer: externalSigner,
+ signer,
noWallet,
arweaveConfig,
networkName,
}: MasaContextProviderProps): JSX.Element => {
- const [masaInstance, setMasaInstance] = useState(null);
+ // masa
+ const [masaInstance, setMasaInstance] = useState();
+ // scope
+ const [scope, setScope] = useState([]);
- const [provider, setProvider] = useState(null);
- const [missingProvider, setMissingProvider] = useState();
+ // provider
+ const { provider, setProvider, isProviderMissing, setIsProviderMissing } =
+ useProvider(signer);
- const [isModalOpen, setModalOpen] = useState(false);
- const [modalCallback, setModalCallback] = useState<(() => void) | null>(null);
+ // wallet
+ const { walletAddress, isWalletLoading, isConnected } = useWallet(
+ masaInstance,
+ provider
+ );
+ // session
+ const { isLoggedIn, handleLogin, handleLogout, isSessionLoading } =
+ useSession(masaInstance, walletAddress);
- const [scope, setScope] = useState([]);
+ // network
+ const { switchNetwork, network } = useNetwork(provider);
- // Modules
- const {
- walletAddress,
- isLoading: walletLoading,
- network,
- }: {
- walletAddress: string | undefined;
- isLoading: boolean;
- network: providers.Network | null;
- } = useWallet(masaInstance, provider);
+ // modal
+ const { isModalOpen, setModalOpen, setModalCallback, closeModal } = useModal(
+ networkName,
+ isLoggedIn,
+ isConnected,
+ network
+ );
+ // identity
const {
identity,
handlePurchaseIdentity,
- isLoading: identityLoading,
+ isIdentityLoading,
+ reloadIdentity,
} = useIdentity(masaInstance, walletAddress);
- const { soulnames } = useSoulnames(masaInstance, walletAddress, identity);
+ // soul names
+ const { soulnames, isSoulnamesLoading, reloadSoulnames } = useSoulnames(
+ masaInstance,
+ walletAddress,
+ identity
+ );
+ // credit scores
const {
creditScores,
- isLoading: creditScoreLoading,
+ isCreditScoresLoading,
handleCreateCreditScore,
+ reloadCreditScores,
} = useCreditScores(masaInstance, walletAddress, identity);
+ // greens
const {
greens,
- isLoading: greenLoading,
+ isGreensLoading,
handleGenerateGreen,
handleCreateGreen,
+ reloadGreens,
} = useGreen(masaInstance, walletAddress);
- const {
- loggedIn,
- login: handleLogin,
- logout: handleLogout,
- isLoading: sessionLoading,
- } = useSession(masaInstance, walletAddress);
-
- // Logic
-
- const loading = useMemo(() => {
+ // global loading flag
+ const isLoading = useMemo(() => {
return (
!masaInstance ||
- sessionLoading ||
- creditScoreLoading ||
- identityLoading ||
- walletLoading ||
- greenLoading
+ isWalletLoading ||
+ isSessionLoading ||
+ isIdentityLoading ||
+ isSoulnamesLoading ||
+ isCreditScoresLoading ||
+ isGreensLoading
);
}, [
- sessionLoading,
- creditScoreLoading,
- identityLoading,
- walletLoading,
- greenLoading,
masaInstance,
+ isWalletLoading,
+ isSessionLoading,
+ isIdentityLoading,
+ isSoulnamesLoading,
+ isCreditScoresLoading,
+ isGreensLoading,
]);
- useEffect(() => {
- if (externalSigner) {
- setProvider(externalSigner);
- }
- }, [externalSigner]);
-
const connect = useCallback(
(options?: { scope?: string[]; callback?: () => void }) => {
setModalOpen(true);
@@ -128,40 +139,18 @@ export const MasaContextProvider = ({
[setModalOpen, setModalCallback]
);
- const isConnected = useMemo(() => {
- return !!walletAddress;
- }, [walletAddress]);
-
- const closeModal = useCallback(() => {
- setModalOpen(false);
- if (
- modalCallback &&
- loggedIn &&
- isConnected &&
- (networkName ? !network?.name.includes(networkName) : true)
- ) {
- modalCallback();
- }
- }, [
- modalCallback,
- setModalOpen,
- loggedIn,
- isConnected,
- network,
- networkName,
- ]);
-
useEffect(() => {
const loadMasa = async (): Promise => {
if (!provider) return;
- const masa: Masa | null = await createNewMasa({
+
+ const masa: Masa | undefined = await createNewMasa({
signer: provider,
environmentName,
arweaveConfig,
verbose,
});
- void setMasaInstance(masa);
+ setMasaInstance(masa);
};
void loadMasa();
@@ -175,78 +164,70 @@ export const MasaContextProvider = ({
network,
]);
- const addNetwork = useCallback(async (networkDetails: Network) => {
- try {
- if (typeof window !== 'undefined' && networkDetails) {
- await window?.ethereum?.request({
- method: 'wallet_addEthereumChain',
- params: [
- {
- ...networkDetails,
- chainId: utils.hexValue(networkDetails.chainId),
- },
- ],
- });
- }
- } catch (error) {
- console.error(
- `error ocuured while adding new chain with chainId:${networkDetails?.chainId}`
- );
- }
- }, []);
-
- const switchNetwork = useCallback(
- async (chainId: number) => {
- try {
- if (typeof window !== 'undefined') {
- await window?.ethereum?.request({
- method: 'wallet_switchEthereumChain',
- params: [{ chainId: utils.hexValue(chainId) }],
- });
- console.log(`switched to chainId: ${chainId} successfully`);
- }
- } catch (err) {
- const error = err as { code: number };
- if (error.code === 4902) {
- void addNetwork(SupportedNetworks[chainId]);
- }
- }
- },
- [addNetwork]
- );
-
const context: MasaShape = {
- setProvider,
+ // masa instance
+ masa: masaInstance as Masa,
+ // global loading
+ isLoading,
+
+ // masa-react global connect
+ connect,
+
+ // general config
+ scope,
+ company,
+
+ // provider handling
provider,
+ setProvider,
+ isProviderMissing,
+ setIsProviderMissing,
+
+ // modal
isModalOpen,
setModalOpen,
- masa: masaInstance as Masa,
- isConnected,
- loading,
+ closeModal,
+
+ // wallet
walletAddress,
+ isWalletLoading,
+ isConnected,
+
+ // identity
identity,
- loggedIn,
+ isIdentityLoading,
+ handlePurchaseIdentity,
+ reloadIdentity,
+
+ // session
+ isLoggedIn,
+ isSessionLoading,
handleLogin,
handleLogout,
- handlePurchaseIdentity,
- connect,
- closeModal,
- scope,
- company,
- handleCreateCreditScore,
+
+ // credit scores
creditScores,
+ isCreditScoresLoading,
+ handleCreateCreditScore,
+ reloadCreditScores,
+
+ // soul names
soulnames,
- logginLoading: sessionLoading,
- missingProvider,
- setMissingProvider,
+ isSoulnamesLoading,
+ reloadSoulnames,
+
+ // greens
greens,
- greenLoading,
+ isGreensLoading,
handleGenerateGreen,
handleCreateGreen,
+ reloadGreens,
+
+ // network
+ networkName,
network,
- switchNetwork,
SupportedNetworks,
- networkName,
+ switchNetwork,
};
return (
diff --git a/src/provider/masa-context.tsx b/src/provider/masa-context.tsx
index a1528425..cb4cf946 100644
--- a/src/provider/masa-context.tsx
+++ b/src/provider/masa-context.tsx
@@ -1,71 +1,4 @@
-import React, { createContext } from 'react';
-import {
- GenerateGreenResult,
- ICreditScore,
- IGreen,
- Masa,
- NetworkName,
- SoulNameDetails,
- VerifyGreenResult,
-} from '@masa-finance/masa-sdk';
-import { BigNumber, ethers } from 'ethers';
-import { Network } from '../helpers';
+import { createContext } from 'react';
+import { MasaShape } from './masa-shape';
export const MASA_CONTEXT = createContext({});
-
-export interface MasaShape {
- children?: React.ReactNode;
- setProvider?: (provider: ethers.Wallet | ethers.Signer | null) => void;
- provider?: ethers.Wallet | ethers.Signer | null;
- isModalOpen?: boolean;
- setModalOpen?: (val: boolean) => void;
- masa?: Masa;
- isConnected?: boolean;
- loading?: boolean;
- walletAddress?: string | undefined;
- identity?: {
- identityId?: BigNumber | undefined;
- address?: string | undefined;
- };
- loggedIn?: boolean;
- handleLogin?: () => void;
- handleLogout?: (callback?: () => void) => void;
- handlePurchaseIdentity?: () => void;
- connect?: (options?: { scope?: string[]; callback?: () => void }) => void;
- closeModal?: () => void;
- scope?: string[];
- company?: string;
- handleCreateCreditScore?: () => void;
- creditScores?:
- | {
- tokenId: BigNumber;
- tokenUri: string;
- metadata?: ICreditScore | undefined;
- }[]
- | null;
- loadCreditScores?: () => void;
- soulnames?: SoulNameDetails[] | null;
- loadSoulnames?: () => void;
- logginLoading?: boolean;
- missingProvider?: boolean;
- setMissingProvider?: (value: boolean) => void;
- greens?:
- | {
- tokenId: BigNumber;
- tokenUri: string;
- metadata?: IGreen | undefined;
- }[]
- | undefined;
- greenLoading?: boolean;
- handleCreateGreen?: (
- phoneNumber: string,
- code: string
- ) => Promise;
- handleGenerateGreen?: (
- phoneNumber: string
- ) => Promise;
- network?: ethers.providers.Network | null;
- switchNetwork?: (chainId: number) => void;
- SupportedNetworks?: Partial<{ [index in NetworkName]: Network }>;
- networkName?: NetworkName;
-}
diff --git a/src/provider/masa-provider.tsx b/src/provider/masa-provider.tsx
index fe58e116..33a6d195 100644
--- a/src/provider/masa-provider.tsx
+++ b/src/provider/masa-provider.tsx
@@ -5,7 +5,6 @@ import {
import React from 'react';
import { QueryClientProvider } from 'react-query';
-import { useMetamask } from './use-metamask';
import { queryClient } from './masa-query-client';
import '../../styles.scss';
@@ -15,12 +14,10 @@ export const MasaProvider = ({
children,
...args
}: MasaContextProviderProps): JSX.Element => {
- useMetamask({ disable: args.noWallet });
-
return (
-
+
{children}
diff --git a/src/provider/masa-query-client.tsx b/src/provider/masa-query-client.tsx
index 0fd037d3..6fc1d9a6 100644
--- a/src/provider/masa-query-client.tsx
+++ b/src/provider/masa-query-client.tsx
@@ -1,3 +1,9 @@
import { QueryClient } from 'react-query';
-export const queryClient = new QueryClient();
+export const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ refetchOnWindowFocus: false, // default: true
+ },
+ },
+});
diff --git a/src/provider/masa-shape.ts b/src/provider/masa-shape.ts
new file mode 100644
index 00000000..5e6fd675
--- /dev/null
+++ b/src/provider/masa-shape.ts
@@ -0,0 +1,99 @@
+import React from 'react';
+import {
+ GenerateGreenResult,
+ ICreditScore,
+ IGreen,
+ Masa,
+ NetworkName,
+ SoulNameDetails,
+ VerifyGreenResult,
+} from '@masa-finance/masa-sdk';
+import { BigNumber, ethers } from 'ethers';
+import { Network } from '../helpers';
+
+export interface MasaShape {
+ children?: React.ReactNode;
+
+ // masa
+ masa?: Masa;
+ // global loading
+ isLoading?: boolean;
+
+ // global connect
+ connect?: (options?: { scope?: string[]; callback?: () => void }) => void;
+
+ // general config
+ scope?: string[];
+ company?: string;
+
+ // provider
+ provider?: ethers.Wallet | ethers.Signer;
+ setProvider?: (provider?: ethers.Wallet | ethers.Signer) => void;
+ isProviderMissing?: boolean;
+ setIsProviderMissing?: (value: boolean) => void;
+
+ // modal
+ isModalOpen?: boolean;
+ setModalOpen?: (val: boolean) => void;
+ closeModal?: () => void;
+
+ // wallet
+ walletAddress?: string;
+ isWalletLoading?: boolean;
+ isConnected?: boolean;
+
+ // identity
+ identity?: {
+ identityId?: BigNumber;
+ address?: string;
+ };
+ isIdentityLoading?: boolean;
+ handlePurchaseIdentity?: () => void;
+ reloadIdentity?: () => void;
+
+ // session
+ isLoggedIn?: boolean;
+ isSessionLoading?: boolean;
+ handleLogin?: () => void;
+ handleLogout?: (logoutCallback?: () => void) => void;
+
+ // credit scores
+ creditScores?:
+ | {
+ tokenId: BigNumber;
+ tokenUri: string;
+ metadata?: ICreditScore | undefined;
+ }[];
+ isCreditScoresLoading?: boolean;
+ handleCreateCreditScore?: () => void;
+ reloadCreditScores?: () => void;
+
+ // soul names
+ soulnames?: SoulNameDetails[];
+ isSoulnamesLoading?: boolean;
+ reloadSoulnames?: () => void;
+
+ // greens
+ greens?:
+ | {
+ tokenId: BigNumber;
+ tokenUri: string;
+ metadata?: IGreen;
+ }[]
+ | undefined;
+ isGreensLoading?: boolean;
+ handleGenerateGreen?: (
+ phoneNumber: string
+ ) => Promise;
+ handleCreateGreen?: (
+ phoneNumber: string,
+ code: string
+ ) => Promise;
+ reloadGreens?: () => void;
+
+ // network
+ networkName?: NetworkName;
+ network?: ethers.providers.Network;
+ SupportedNetworks?: Partial<{ [index in NetworkName]: Network }>;
+ switchNetwork?: (chainId: number) => void;
+}
diff --git a/src/provider/modules/credit-scores/credit-scores.ts b/src/provider/modules/credit-scores/credit-scores.ts
index c4871e7e..90c45ee9 100644
--- a/src/provider/modules/credit-scores/credit-scores.ts
+++ b/src/provider/modules/credit-scores/credit-scores.ts
@@ -5,14 +5,12 @@ import { ICreditScore, Masa } from '@masa-finance/masa-sdk';
import { BigNumber } from 'ethers';
export const useCreditScores = (
- masa: Masa | null,
- walletAddress: string | undefined,
- identity:
- | {
- identityId?: BigNumber | undefined;
- address?: string | undefined;
- }
- | undefined
+ masa?: Masa,
+ walletAddress?: string,
+ identity?: {
+ identityId?: BigNumber | undefined;
+ address?: string | undefined;
+ }
): {
creditScores:
| {
@@ -23,7 +21,8 @@ export const useCreditScores = (
| undefined;
handleCreateCreditScore: () => void;
status: string;
- isLoading: boolean;
+ isCreditScoresLoading: boolean;
+ reloadCreditScores: () => void;
error: unknown;
} => {
const queryKey: (string | undefined)[] = useMemo(() => {
@@ -34,31 +33,46 @@ export const useCreditScores = (
data: creditScores,
status,
isLoading,
+ isFetching,
+ refetch: reloadCreditScores,
error,
- } = useQuery(queryKey, () => masa?.creditScore.list(), {
- enabled:
- !!masa &&
- masa.config.network !== 'unknown' &&
- !!walletAddress &&
- !!identity?.identityId,
+ } = useQuery<
+ | {
+ tokenId: BigNumber;
+ tokenUri: string;
+ metadata?: ICreditScore;
+ }[]
+ | undefined
+ >(queryKey, () => masa?.creditScore.list(), {
+ enabled: !!masa && !!walletAddress && !!identity?.identityId,
retry: false,
+ onSuccess: (
+ creditScores?: {
+ tokenId: BigNumber;
+ tokenUri: string;
+ metadata?: ICreditScore;
+ }[]
+ ) => {
+ if (masa?.config.verbose) {
+ console.log({ creditScores, network: masa?.config.network });
+ }
+ },
});
const handleCreateCreditScore = useCallback(async (): Promise<
boolean | undefined
> => {
const response = await masa?.creditScore.create();
-
await queryClient.invalidateQueries(queryKey);
-
return response?.success;
}, [masa, queryKey]);
return {
creditScores,
+ isCreditScoresLoading: isLoading || isFetching,
handleCreateCreditScore,
+ reloadCreditScores,
status,
- isLoading,
error,
};
};
diff --git a/src/provider/modules/green/green.ts b/src/provider/modules/green/green.ts
index b99f6e13..81bdc46d 100644
--- a/src/provider/modules/green/green.ts
+++ b/src/provider/modules/green/green.ts
@@ -10,8 +10,8 @@ import {
import { BigNumber } from 'ethers';
export const useGreen = (
- masa: Masa | null,
- walletAddress: string | undefined
+ masa?: Masa,
+ walletAddress?: string
): {
greens:
| {
@@ -28,23 +28,33 @@ export const useGreen = (
code: string
) => Promise;
status: string;
- isLoading: boolean;
+ isGreensLoading: boolean;
+ reloadGreens: () => void;
error: unknown;
} => {
const queryKey: (string | undefined)[] = useMemo(() => {
return ['green', walletAddress, masa?.config.network];
- }, [walletAddress, masa]);
+ }, [masa, walletAddress]);
const {
data: greens,
status,
isLoading,
+ isFetching,
+ refetch: reloadGreens,
error,
- } = useQuery(queryKey, () => masa?.green.list(), {
- enabled: !!masa && masa.config.network !== 'unknown' && !!walletAddress,
+ } = useQuery<
+ | {
+ tokenId: BigNumber;
+ tokenUri: string;
+ metadata?: IGreen | undefined;
+ }[]
+ | undefined
+ >(queryKey, () => masa?.green.list(), {
+ enabled: !!masa && !!walletAddress,
retry: false,
onSuccess: (
- greens: {
+ greens?: {
tokenId: BigNumber;
tokenUri: string;
metadata?: IGreen | undefined;
@@ -62,9 +72,7 @@ export const useGreen = (
code: string
): Promise => {
const response = await masa?.green.create(phoneNumber, code);
-
await queryClient.invalidateQueries(queryKey);
-
return response;
},
[masa, queryKey]
@@ -84,10 +92,11 @@ export const useGreen = (
return {
greens,
+ isGreensLoading: isLoading || isFetching,
handleGenerateGreen,
handleCreateGreen,
+ reloadGreens,
status,
- isLoading,
error,
};
};
diff --git a/src/provider/modules/identity/identity.ts b/src/provider/modules/identity/identity.ts
index 6d296cb0..b59b7730 100644
--- a/src/provider/modules/identity/identity.ts
+++ b/src/provider/modules/identity/identity.ts
@@ -5,8 +5,8 @@ import { Masa } from '@masa-finance/masa-sdk';
import { BigNumber } from 'ethers';
export const useIdentity = (
- masa: Masa | null,
- walletAddress: string | undefined
+ masa?: Masa,
+ walletAddress?: string
): {
identity:
| {
@@ -16,7 +16,8 @@ export const useIdentity = (
| undefined;
handlePurchaseIdentity: () => void;
status: string;
- isLoading: boolean;
+ isIdentityLoading: boolean;
+ reloadIdentity: () => void;
error: unknown;
} => {
const queryKey: (string | undefined)[] = useMemo(() => {
@@ -27,19 +28,34 @@ export const useIdentity = (
data: identity,
status,
isLoading,
+ isFetching,
+ refetch: reloadIdentity,
error,
- } = useQuery(queryKey, () => masa?.identity.load(walletAddress), {
- enabled: !!masa && masa.config.network !== 'unknown' && !!walletAddress,
- retry: false,
- onSuccess: (identity: { identityId?: BigNumber; address?: string }) => {
- console.log({ identity });
- },
- });
+ } = useQuery<{ identityId?: BigNumber; address?: string } | undefined>(
+ queryKey,
+ () => masa?.identity.load(walletAddress),
+ {
+ enabled: !!masa && !!walletAddress,
+ retry: false,
+ onSuccess: (identity?: { identityId?: BigNumber; address?: string }) => {
+ if (masa?.config.verbose) {
+ console.log({ identity, network: masa?.config.network });
+ }
+ },
+ }
+ );
const handlePurchaseIdentity = useCallback(async () => {
await masa?.identity.create();
await queryClient.invalidateQueries(queryKey);
}, [masa, queryKey]);
- return { identity, handlePurchaseIdentity, status, isLoading, error };
+ return {
+ identity,
+ isIdentityLoading: isLoading || isFetching,
+ handlePurchaseIdentity,
+ reloadIdentity,
+ status,
+ error,
+ };
};
diff --git a/src/provider/modules/index.ts b/src/provider/modules/index.ts
index da27f85e..d1dba02d 100644
--- a/src/provider/modules/index.ts
+++ b/src/provider/modules/index.ts
@@ -1,6 +1,9 @@
export * from './credit-scores';
export * from './green';
export * from './identity';
+export * from './network';
export * from './session';
export * from './soulnames';
export * from './wallet';
+export * from './modal';
+export * from './provider';
diff --git a/src/provider/modules/modal/index.ts b/src/provider/modules/modal/index.ts
new file mode 100644
index 00000000..133aa742
--- /dev/null
+++ b/src/provider/modules/modal/index.ts
@@ -0,0 +1 @@
+export * from './modal';
diff --git a/src/provider/modules/modal/modal.ts b/src/provider/modules/modal/modal.ts
new file mode 100644
index 00000000..619d003c
--- /dev/null
+++ b/src/provider/modules/modal/modal.ts
@@ -0,0 +1,44 @@
+import { useCallback, useState } from 'react';
+import { NetworkName } from '@masa-finance/masa-sdk';
+import { providers } from 'ethers';
+
+export const useModal = (
+ networkName?: NetworkName,
+ isLoggedIn?: boolean,
+ isConnected?: boolean,
+ network?: providers.Network
+): {
+ isModalOpen: boolean;
+ closeModal: () => void;
+ setModalOpen: (modalOpen: boolean) => void;
+ setModalCallback: (callback: () => void) => void;
+} => {
+ const [isModalOpen, setModalOpen] = useState(false);
+ const [modalCallback, setModalCallback] = useState<(() => void) | null>(null);
+
+ const closeModal = useCallback(() => {
+ setModalOpen(false);
+ if (
+ modalCallback &&
+ isLoggedIn &&
+ isConnected &&
+ (networkName ? !network?.name.includes(networkName) : true)
+ ) {
+ modalCallback();
+ }
+ }, [
+ modalCallback,
+ setModalOpen,
+ isLoggedIn,
+ isConnected,
+ network,
+ networkName,
+ ]);
+
+ return {
+ isModalOpen,
+ closeModal,
+ setModalOpen,
+ setModalCallback,
+ };
+};
diff --git a/src/provider/modules/network/index.ts b/src/provider/modules/network/index.ts
new file mode 100644
index 00000000..a31b9ed5
--- /dev/null
+++ b/src/provider/modules/network/index.ts
@@ -0,0 +1 @@
+export * from './network';
diff --git a/src/provider/modules/network/network.ts b/src/provider/modules/network/network.ts
new file mode 100644
index 00000000..f6f17c1b
--- /dev/null
+++ b/src/provider/modules/network/network.ts
@@ -0,0 +1,72 @@
+import { providers, Signer, utils, Wallet } from 'ethers';
+import { useCallback, useEffect, useState } from 'react';
+import { Network, SupportedNetworks } from '../../../helpers';
+
+export const useNetwork = (
+ provider?: Wallet | Signer
+): {
+ addNetwork: (networkDetails: Network) => void;
+ switchNetwork: (chainId: number) => void;
+ network?: providers.Network;
+} => {
+ const [network, setNetwork] = useState();
+
+ const addNetwork = useCallback(async (networkDetails: Network) => {
+ try {
+ if (typeof window !== 'undefined' && networkDetails) {
+ await window?.ethereum?.request({
+ method: 'wallet_addEthereumChain',
+ params: [
+ {
+ ...networkDetails,
+ chainId: utils.hexValue(networkDetails.chainId),
+ },
+ ],
+ });
+ }
+ } catch (error) {
+ console.error(
+ `error occurred while adding new chain with chainId:${networkDetails?.chainId}`
+ );
+ }
+ }, []);
+
+ const loadNetwork = useCallback(async (): Promise => {
+ if (!provider) return;
+
+ const newNetwork = await provider.provider?.getNetwork();
+ setNetwork(newNetwork ?? undefined);
+ }, [provider]);
+
+ const switchNetwork = useCallback(
+ async (chainId: number) => {
+ try {
+ if (typeof window !== 'undefined') {
+ await window?.ethereum?.request({
+ method: 'wallet_switchEthereumChain',
+ params: [{ chainId: utils.hexValue(chainId) }],
+ });
+ console.log(`switched to chainId: ${chainId} successfully`);
+ }
+ } catch (err) {
+ const error = err as { code: number };
+ if (error.code === 4902) {
+ await addNetwork(SupportedNetworks[chainId]);
+ }
+ }
+
+ await loadNetwork();
+ },
+ [addNetwork, loadNetwork]
+ );
+
+ useEffect(() => {
+ void loadNetwork();
+ }, [loadNetwork]);
+
+ return {
+ addNetwork,
+ switchNetwork,
+ network,
+ };
+};
diff --git a/src/provider/modules/provider/index.ts b/src/provider/modules/provider/index.ts
new file mode 100644
index 00000000..03be03e5
--- /dev/null
+++ b/src/provider/modules/provider/index.ts
@@ -0,0 +1 @@
+export * from './provider';
diff --git a/src/provider/modules/provider/provider.ts b/src/provider/modules/provider/provider.ts
new file mode 100644
index 00000000..2c8fa276
--- /dev/null
+++ b/src/provider/modules/provider/provider.ts
@@ -0,0 +1,21 @@
+import { useState } from 'react';
+import { Signer, Wallet } from 'ethers';
+
+export const useProvider = (
+ signer?: Wallet | Signer
+): {
+ provider: Wallet | Signer | undefined;
+ setProvider: (provider: Wallet | Signer | undefined) => void;
+ isProviderMissing?: boolean;
+ setIsProviderMissing: (providerMissing: boolean) => void;
+} => {
+ const [provider, setProvider] = useState(signer);
+ const [isProviderMissing, setIsProviderMissing] = useState();
+
+ return {
+ provider,
+ setProvider,
+ isProviderMissing,
+ setIsProviderMissing,
+ };
+};
diff --git a/src/provider/modules/session/session.ts b/src/provider/modules/session/session.ts
index d0193cfe..3c0d570b 100644
--- a/src/provider/modules/session/session.ts
+++ b/src/provider/modules/session/session.ts
@@ -4,21 +4,25 @@ import { queryClient } from '../../masa-query-client';
import { ISession, Masa } from '@masa-finance/masa-sdk';
export const useSession = (
- masa: Masa | null,
- walletAddress: string | undefined
+ masa?: Masa,
+ walletAddress?: string
): {
- loggedIn?: boolean;
- login: () => void;
- logout: () => void;
+ isLoggedIn?: boolean;
+ isSessionLoading: boolean;
+ handleLogin: () => void;
+ handleLogout: (logoutCallback?: () => void) => void;
status: string;
- isLoading: boolean;
error: unknown;
} => {
const queryKeySessionData: (string | undefined)[] = useMemo(() => {
- return ['session-data', walletAddress];
+ return ['session', 'data', walletAddress];
}, [walletAddress]);
- const { data: sessionData } = useQuery(
+ const {
+ data: sessionData,
+ isLoading: isSessionDataLoading,
+ isFetching: isSessionDataFetching,
+ } = useQuery(
queryKeySessionData,
() => masa?.session.getSession(),
{
@@ -32,9 +36,10 @@ export const useSession = (
}, [walletAddress]);
const {
- data: loggedIn,
+ data: isLoggedIn,
status,
- isLoading,
+ isLoading: isSessionCheckLoading,
+ isFetching: isSessionCheckFetching,
error,
} = useQuery(
queryKeySession,
@@ -45,41 +50,45 @@ export const useSession = (
}
);
- const doLogout = useCallback(async (): Promise => {
- await masa?.session.logout();
- await queryClient.invalidateQueries(queryKeySession);
- await queryClient.refetchQueries();
- }, [masa, queryKeySession]);
+ const clearSession = useCallback(async () => {
+ await queryClient.invalidateQueries(['wallet']);
+ await queryClient.invalidateQueries(['session']);
+ }, []);
- useEffect(() => {
- if (sessionData && sessionData.user.address !== walletAddress) {
- void doLogout();
- }
- }, [sessionData, walletAddress, masa, queryKeySession, doLogout]);
+ const handleLogout = useCallback(
+ async (logoutCallback?: () => void): Promise => {
+ await masa?.session.logout();
+ await clearSession();
- useEffect(() => {
- if (loggedIn && !walletAddress) {
- void queryClient.invalidateQueries(queryKeySession);
- }
- }, [walletAddress, loggedIn, queryKeySession]);
+ logoutCallback?.();
+ },
+ [masa, clearSession]
+ );
- const login = useCallback(async () => {
+ const handleLogin = useCallback(async (): Promise => {
const isLoggedIn = await masa?.session.login();
if (isLoggedIn) {
- await queryClient.invalidateQueries(queryKeySession);
- await queryClient.invalidateQueries(queryKeySessionData);
- await queryClient.refetchQueries();
+ await clearSession();
}
- }, [masa, queryKeySession, queryKeySessionData]);
+ }, [masa, clearSession]);
- const logout = useCallback(
- async (callback?: () => void) => {
- await doLogout();
- callback?.();
- },
- [doLogout]
- );
+ useEffect(() => {
+ if (sessionData && sessionData.user.address !== walletAddress) {
+ void handleLogout();
+ }
+ }, [sessionData, walletAddress, handleLogout]);
- return { loggedIn, login, logout, status, isLoading, error };
+ return {
+ isLoggedIn,
+ isSessionLoading:
+ isSessionCheckLoading ||
+ isSessionCheckFetching ||
+ isSessionDataLoading ||
+ isSessionDataFetching,
+ handleLogin,
+ handleLogout,
+ status,
+ error,
+ };
};
diff --git a/src/provider/modules/soulnames/soulnames.ts b/src/provider/modules/soulnames/soulnames.ts
index fe2ebc5b..edce4845 100644
--- a/src/provider/modules/soulnames/soulnames.ts
+++ b/src/provider/modules/soulnames/soulnames.ts
@@ -4,39 +4,49 @@ import { BigNumber } from 'ethers';
import { useMemo } from 'react';
export const useSoulnames = (
- masa: Masa | null,
- walletAddress: string | undefined,
- identity:
- | {
- identityId?: BigNumber | undefined;
- address?: string | undefined;
- }
- | undefined
+ masa?: Masa,
+ walletAddress?: string,
+ identity?: {
+ identityId?: BigNumber | undefined;
+ address?: string | undefined;
+ }
): {
soulnames: SoulNameDetails[] | undefined;
status: string;
- isLoading: boolean;
+ isSoulnamesLoading: boolean;
+ reloadSoulnames: () => void;
error: unknown;
} => {
const queryKey: (string | undefined)[] = useMemo(() => {
return ['soulnames', walletAddress, masa?.config.network];
}, [walletAddress, masa]);
- console.log(queryKey);
-
const {
data: soulnames,
status,
isLoading,
+ isFetching,
+ refetch: reloadSoulnames,
error,
- } = useQuery(queryKey, () => masa?.soulName.list(), {
- enabled:
- !!masa &&
- masa.config.network !== 'unknown' &&
- !!walletAddress &&
- !!identity?.identityId,
- retry: false,
- });
+ } = useQuery(
+ queryKey,
+ () => masa?.soulName.list(),
+ {
+ enabled: !!masa && !!walletAddress && !!identity?.identityId,
+ retry: false,
+ onSuccess: (soulNames?: SoulNameDetails[]) => {
+ if (masa?.config.verbose) {
+ console.log({ soulNames, network: masa?.config.network });
+ }
+ },
+ }
+ );
- return { soulnames, status, isLoading, error };
+ return {
+ soulnames,
+ isSoulnamesLoading: isLoading || isFetching,
+ reloadSoulnames,
+ status,
+ error,
+ };
};
diff --git a/src/provider/modules/wallet/wallet.ts b/src/provider/modules/wallet/wallet.ts
index 291d27f5..2fb5eddb 100644
--- a/src/provider/modules/wallet/wallet.ts
+++ b/src/provider/modules/wallet/wallet.ts
@@ -1,50 +1,46 @@
import { useQuery } from 'react-query';
import { Masa } from '@masa-finance/masa-sdk';
-import { providers, Signer, Wallet } from 'ethers';
-import { useCallback, useEffect, useMemo, useState } from 'react';
+import { Signer, Wallet } from 'ethers';
+import { useMemo } from 'react';
export const useWallet = (
- masa: Masa | null,
- provider: Wallet | Signer | null
+ masa?: Masa,
+ provider?: Wallet | Signer
): {
walletAddress: string | undefined;
+ isWalletLoading: boolean;
+ isConnected: boolean;
status: string;
- isLoading: boolean;
error: unknown;
- network: providers.Network | null;
} => {
- const queryKey: (string | boolean)[] = useMemo(() => {
- return ['wallet', !!provider];
- }, [provider]);
+ const queryKey: (string | undefined)[] = useMemo(() => {
+ return ['wallet', masa?.config.network];
+ }, [masa]);
const {
data: walletAddress,
status,
isLoading,
+ isFetching,
error,
- } = useQuery(queryKey, () => masa?.config.wallet.getAddress(), {
- enabled: !!masa && !!provider,
- retry: false,
- });
-
- const [network, setNetwork] = useState(null);
-
- const loadNetwork = useCallback(async (): Promise => {
- if (provider) {
- const newNetwork = await provider.provider?.getNetwork();
- setNetwork(newNetwork ?? null);
+ } = useQuery(
+ queryKey,
+ () => masa?.config.wallet.getAddress(),
+ {
+ enabled: !!masa && !!provider,
+ retry: false,
}
- }, [provider]);
+ );
- useEffect(() => {
- void loadNetwork();
- }, [loadNetwork]);
+ const isConnected = useMemo(() => {
+ return !!walletAddress;
+ }, [walletAddress]);
return {
walletAddress: !provider ? undefined : walletAddress,
+ isWalletLoading: isLoading || isFetching,
+ isConnected,
status,
- isLoading,
error,
- network,
};
};
diff --git a/src/provider/use-masa.tsx b/src/provider/use-masa.tsx
index 6d215575..5b28f8c5 100644
--- a/src/provider/use-masa.tsx
+++ b/src/provider/use-masa.tsx
@@ -1,5 +1,6 @@
import { useContext } from 'react';
-import { MASA_CONTEXT, MasaShape } from './masa-context';
+import { MASA_CONTEXT } from './masa-context';
+import { MasaShape } from './masa-shape';
export const useMasa = (): MasaShape => {
return useContext(MASA_CONTEXT);
diff --git a/src/provider/use-metamask.ts b/src/provider/use-metamask.ts
index 9ce3059c..a6bc0024 100644
--- a/src/provider/use-metamask.ts
+++ b/src/provider/use-metamask.ts
@@ -1,98 +1,102 @@
-import { ethers } from 'ethers';
+import { providers } from 'ethers';
import { useCallback, useEffect, useMemo, useState } from 'react';
-import { queryClient } from './masa-query-client';
import { useMasa } from './use-masa';
-export const getWeb3Provider = (): ethers.providers.Web3Provider | null => {
+export const getWeb3Provider = (): providers.Web3Provider | undefined => {
if (
typeof window !== 'undefined' &&
typeof window?.ethereum !== 'undefined'
) {
- return new ethers.providers.Web3Provider(
- window?.ethereum as unknown as ethers.providers.ExternalProvider
+ return new providers.Web3Provider(
+ window?.ethereum as unknown as providers.ExternalProvider
);
}
- return null;
+ return;
};
export const useMetamask = ({
- disable,
+ disabled,
}: {
- disable?: boolean;
+ disabled?: boolean;
}): { connect: () => void } => {
- const [walletsConnected, setWalletsConnected] = useState([]);
- const { setProvider, setMissingProvider, handleLogout } = useMasa();
+ const [connectedAccounts, setConnectedAccounts] = useState([]);
+ const {
+ setProvider,
+ setIsProviderMissing,
+ handleLogout,
+ isConnected,
+ walletAddress,
+ } = useMasa();
+
+ // use metamask can only be used inside the scope of masa-react
+ // otherwise everything from useMasa is undefined
+ if (Object.keys(useMasa()).length < 1) {
+ throw new Error('useMetamask must be used inside the masa provider scope');
+ }
- const provider = useMemo((): ethers.providers.Web3Provider | null => {
+ const provider = useMemo((): providers.Web3Provider | undefined => {
return getWeb3Provider();
}, []);
useEffect(() => {
- if (setMissingProvider) {
- if (provider) {
- setMissingProvider(false);
- } else {
- setMissingProvider(true);
+ setIsProviderMissing?.(!provider);
+ }, [provider, setIsProviderMissing]);
+
+ const loadSignerFromProvider = useCallback(
+ async (provider: providers.Web3Provider) => {
+ await provider.send('eth_requestAccounts', []);
+
+ const signer = provider.getSigner();
+ if (signer) {
+ setProvider?.(signer);
}
- }
- }, [provider, setMissingProvider]);
+ },
+ [setProvider]
+ );
const connect = useCallback(async () => {
- console.log('DISABLE', disable);
- if (!disable) {
- if (provider && window?.ethereum) {
- await provider.send('eth_requestAccounts', []);
-
- const signer = provider.getSigner();
- if (signer && setProvider) {
- setProvider(signer);
- onConnect();
- }
- }
+ console.log({ disabled });
+
+ if (!disabled && provider && window?.ethereum) {
+ await loadSignerFromProvider(provider);
}
- }, [setProvider, provider, disable]);
+ }, [provider, disabled, loadSignerFromProvider]);
useEffect(() => {
const connectWalletOnPageLoad = async (): Promise => {
- if (localStorage.getItem('isWalletConnected') === 'true') {
- try {
- await connect();
- } catch (error) {
- console.error('Connect failed!', error);
+ if (isConnected) return;
+
+ try {
+ await connect();
+ } catch (error) {
+ if (error instanceof Error) {
+ console.error('Connect failed!', error.message);
}
}
};
void connectWalletOnPageLoad();
- }, [connect]);
-
- const onConnect = (): void => {
- localStorage.setItem('isWalletConnected', 'true');
- };
+ }, [isConnected, connect]);
- const disconnect = useCallback(async () => {
- await handleLogout?.();
- localStorage.setItem('isWalletConnected', 'false');
-
- setProvider?.(null);
-
- await queryClient.invalidateQueries(['wallet']);
- await queryClient.invalidateQueries(['session']);
- }, [handleLogout, setProvider]);
-
- const detectWalletChange = useCallback(async () => {
- const deduplicatedWallets = new Set(walletsConnected);
- console.log({ deduplicatedWallets });
-
- if (deduplicatedWallets.size > 1) {
- console.log('DISCONNECTING, MORE THAN ONE WALLET');
- await disconnect();
+ const disconnect = useCallback(async (): Promise => {
+ if (isConnected) {
+ await handleLogout?.();
}
- }, [walletsConnected, disconnect]);
+ }, [isConnected, handleLogout]);
useEffect(() => {
+ const detectWalletChange = async (): Promise => {
+ if (
+ walletAddress &&
+ connectedAccounts.length > 0 &&
+ !connectedAccounts.includes(walletAddress)
+ ) {
+ await disconnect();
+ }
+ };
+
void detectWalletChange();
- }, [detectWalletChange]);
+ }, [connectedAccounts, disconnect, walletAddress]);
useEffect(() => {
if (typeof window !== 'undefined') {
@@ -100,31 +104,18 @@ export const useMetamask = ({
'accountsChanged',
async (accounts: unknown): Promise => {
const accountsArray = accounts as string[];
- if (accountsArray.length === 0) {
- await disconnect();
- setWalletsConnected([]);
- } else {
- setWalletsConnected([...walletsConnected, ...accountsArray]);
- }
+ setConnectedAccounts(accountsArray);
}
);
window?.ethereum?.on('networkChanged', async () => {
const newProvider = getWeb3Provider();
if (newProvider) {
- await newProvider.send('eth_requestAccounts', []);
-
- const signer = newProvider.getSigner();
- if (signer && setProvider) {
- setProvider(signer);
- onConnect();
-
- await queryClient.invalidateQueries(['wallet']);
- }
+ await loadSignerFromProvider(newProvider);
}
});
}
- }, [handleLogout, disconnect, setProvider, walletsConnected]);
+ }, [loadSignerFromProvider, setConnectedAccounts]);
return { connect };
};
diff --git a/stories/masa.stories.tsx b/stories/masa.stories.tsx
index fbe7b517..c7f56a1c 100644
--- a/stories/masa.stories.tsx
+++ b/stories/masa.stories.tsx
@@ -33,7 +33,7 @@ const Component = (): JSX.Element => {
}, [connect]);
const loadCR = async (): Promise => {
- await queryClient.invalidateQueries('wallet');
+ await queryClient.invalidateQueries(['wallet']);
};
const mintGreen = async (): Promise => {