testnet-onboarding-app/src/context/WalletConnectContext.tsx
neerajvijay1997 3adcdfa39c
UI Improvements (#9)
* Add loading spinners for buttons

* Add navigation to home page

* Add logo inside anchor tag
2024-03-28 09:14:06 +05:30

174 lines
4.4 KiB
TypeScript

import assert from "assert";
import React, {
createContext,
useContext,
ReactNode,
useState,
useEffect,
useCallback,
} from "react";
import { SnackbarProvider, enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router-dom";
import SignClient from "@walletconnect/sign-client";
import { WalletConnectModal } from "@walletconnect/modal";
import { SessionTypes } from "@walletconnect/types";
import { getSdkError } from "@walletconnect/utils";
const PROJECT_ID = process.env.REACT_APP_WALLET_CONNECT_ID;
assert(PROJECT_ID, "Wallet connect project id not provided");
interface ContextValue {
connect: () => Promise<void>;
session: SessionTypes.Struct | null;
signClient: SignClient | undefined;
checkPersistedState: (client: SignClient) => Promise<void>;
disconnect: () => Promise<void>;
}
const walletConnectContext = createContext<ContextValue>({
connect: () => Promise.resolve(),
session: null,
signClient: undefined,
checkPersistedState: () => Promise.resolve(),
disconnect: () => Promise.resolve(),
});
const web3Modal = new WalletConnectModal({
projectId: PROJECT_ID,
chains: ["eip155:1"],
});
export const WalletConnectProvider = ({
children,
}: {
children: ReactNode;
}) => {
const [signClient, setSignClient] = useState<SignClient>();
const [session, setSession] = useState<SessionTypes.Struct | null>(null);
const navigate = useNavigate()
const disconnect = useCallback(async () => {
if (signClient && session) {
await signClient.disconnect({
topic: session.topic,
reason: getSdkError("USER_DISCONNECTED"),
});
}
setSession(null);
}, [signClient, session]);
const checkPersistedState = useCallback(async (client: SignClient) => {
if (client.session.length) {
const lastKeyIndex = client.session.keys.length - 1;
const session = client.session.get(client.session.keys[lastKeyIndex]);
setSession(session);
}
}, []);
const subscribeToEvents = useCallback(
async (client: SignClient) => {
client.on("session_update", ({ topic, params }) => {
const { namespaces } = params;
const currentSession = client.session.get(topic);
const updatedSession = { ...currentSession, namespaces };
setSession(updatedSession);
});
client.on("session_delete", () => {
setSession(null);
navigate("/")
});
},
[navigate]
);
const createClient = useCallback(async () => {
const signClient = await SignClient.init({
projectId: PROJECT_ID,
metadata: {
name: "Urbit onboarding app",
description: "Urbit onboarding app",
url: "localhost:3000",
icons: ["https://avatars.githubusercontent.com/u/5237680?s=200&v=4"],
},
});
setSignClient(signClient);
await subscribeToEvents(signClient);
await checkPersistedState(signClient);
}, [checkPersistedState, subscribeToEvents])
const connect = async () => {
if (!signClient) {
throw Error("SignClient does not exist");
}
const proposalNamespace = {
eip155: {
methods: ["personal_sign"],
chains: ["eip155:1"],
events: [],
},
cosmos: {
methods: ["cosmos_signDirect", "cosmos_signAmino"],
chains: ["cosmos:cosmoshub-4"],
events: [],
},
};
const { uri, approval } = await signClient.connect({
requiredNamespaces: proposalNamespace,
});
if (uri) {
web3Modal.openModal({ uri });
try {
const session = await approval();
setSession(session);
} catch (error) {
enqueueSnackbar("User rejected pairing request", { variant: "error" });
console.log(error);
}
web3Modal.closeModal();
}
};
useEffect(() => {
if (!signClient) {
createClient();
}
}, [signClient, createClient]);
return (
<>
<walletConnectContext.Provider
value={{
connect,
session,
signClient,
checkPersistedState,
disconnect,
}}
>
{children}
</walletConnectContext.Provider>
<SnackbarProvider />
</>
);
};
export const useWalletConnectContext = () => {
const { connect, session, signClient, checkPersistedState, disconnect } =
useContext(walletConnectContext);
return {
connect,
session,
signClient,
checkPersistedState,
disconnect,
};
};