diff --git a/examples/rln-js/src/app/home/components/Keystore.tsx b/examples/rln-js/src/app/home/components/Keystore.tsx index a82dc65..270de4e 100644 --- a/examples/rln-js/src/app/home/components/Keystore.tsx +++ b/examples/rln-js/src/app/home/components/Keystore.tsx @@ -3,11 +3,15 @@ import { Block, BlockTypes } from "@/components/Block"; import { Button } from "@/components/Button"; import { Subtitle } from "@/components/Subtitle"; import { useStore, useWallet } from "@/hooks"; +import { useKeystore } from "@/hooks/useKeystore"; export const Keystore: React.FunctionComponent<{}> = () => { - const { keystorePassword, setKeystorePassword, keystoreCredentials } = - useStore(); - const { onGenerateCredentials, onRegisterCredentials } = useWallet(); + const { keystoreCredentials } = useStore(); + const { onGenerateCredentials } = useWallet(); + const { onReadCredentials, onRegisterCredentials } = useKeystore(); + + const { password, onPasswordChanged } = usePassword(); + const { selectedKeystore, onKeystoreChanged } = useSelectedKeystore(); const credentialsNodes = React.useMemo( () => @@ -19,13 +23,6 @@ export const Keystore: React.FunctionComponent<{}> = () => { [keystoreCredentials] ); - const onPasswordChanged = React.useCallback( - (event: React.FormEvent) => { - setKeystorePassword(event.currentTarget.value); - }, - [setKeystorePassword] - ); - return ( @@ -45,8 +42,8 @@ export const Keystore: React.FunctionComponent<{}> = () => { @@ -57,7 +54,10 @@ export const Keystore: React.FunctionComponent<{}> = () => { - @@ -65,12 +65,43 @@ export const Keystore: React.FunctionComponent<{}> = () => {

Read from Keystore

- {credentialsNodes} - +
); }; + +function usePassword() { + const [password, setPassword] = React.useState(""); + const onPasswordChanged = (event: React.FormEvent) => { + setPassword(event.currentTarget.value); + }; + + return { + password, + onPasswordChanged, + }; +} + +function useSelectedKeystore() { + const [selectedKeystore, setKeystore] = React.useState(""); + + const onKeystoreChanged = (event: React.FormEvent) => { + setKeystore(event.currentTarget.value || ""); + }; + + return { + selectedKeystore, + onKeystoreChanged, + }; +} diff --git a/examples/rln-js/src/hooks/useKeystore.ts b/examples/rln-js/src/hooks/useKeystore.ts new file mode 100644 index 0000000..ed22d0b --- /dev/null +++ b/examples/rln-js/src/hooks/useKeystore.ts @@ -0,0 +1,83 @@ +import React from "react"; +import { useStore } from "./useStore"; +import { useRLN } from "./useRLN"; +import { SEPOLIA_CONTRACT } from "@waku/rln"; +import { StatusEventPayload } from "@/services/rln"; + +type UseKeystoreResult = { + onReadCredentials: (hash: string, password: string) => void; + onRegisterCredentials: (password: string) => void; +}; + +export const useKeystore = (): UseKeystoreResult => { + const { rln } = useRLN(); + const { + credentials, + setActiveCredential, + setActiveMembershipID, + setAppStatus, + setCredentials, + } = useStore(); + + const onRegisterCredentials = React.useCallback( + async (password: string) => { + if (!credentials || !rln?.rlnContract || !password) { + return; + } + + try { + setAppStatus(StatusEventPayload.CREDENTIALS_REGISTERING); + const membershipInfo = await rln.rlnContract.registerWithKey( + credentials + ); + const membershipID = membershipInfo!.index.toNumber(); + const keystoreHash = await rln.keystore.addCredential( + { + membership: { + treeIndex: membershipID, + chainId: SEPOLIA_CONTRACT.chainId, + address: SEPOLIA_CONTRACT.address, + }, + identity: credentials, + }, + password + ); + setActiveCredential(keystoreHash); + setActiveMembershipID(membershipID); + rln.saveKeystore(); + setAppStatus(StatusEventPayload.CREDENTIALS_REGISTERED); + } catch (error) { + setAppStatus(StatusEventPayload.CREDENTIALS_FAILURE); + console.error("Failed to register to RLN Contract: ", error); + return; + } + }, + [credentials, rln, setActiveCredential, setActiveMembershipID, setAppStatus] + ); + + const onReadCredentials = React.useCallback( + async (hash: string, password: string) => { + if (!rln || !hash || !password) { + return; + } + + try { + const record = await rln.keystore.readCredential(hash, password); + if (record) { + setCredentials(record.identity); + setActiveCredential(hash); + setActiveMembershipID(record.membership.treeIndex); + } + } catch (error) { + console.error("Failed to read credentials from Keystore."); + return; + } + }, + [rln, setActiveCredential, setActiveMembershipID, setCredentials] + ); + + return { + onRegisterCredentials, + onReadCredentials, + }; +}; diff --git a/examples/rln-js/src/hooks/useStore.ts b/examples/rln-js/src/hooks/useStore.ts index 98e59bd..c0b1c89 100644 --- a/examples/rln-js/src/hooks/useStore.ts +++ b/examples/rln-js/src/hooks/useStore.ts @@ -13,8 +13,6 @@ type StoreResult = { credentials: undefined | IdentityCredential; setCredentials: (v: undefined | IdentityCredential) => void; - keystorePassword: undefined | string; - setKeystorePassword: (v: string) => void; activeCredential: string; keystoreCredentials: string[]; setKeystoreCredentials: (v: string[]) => void; @@ -52,9 +50,6 @@ export const useStore = create((set) => { }; const keystoreModule = { - keystorePassword: undefined, - setKeystorePassword: (v: string) => - set((state) => ({ ...state, keystorePassword: v })), activeCredential: DEFAULT_VALUE, setActiveCredential: (v: string) => set((state) => ({ ...state, activeCredential: v })), diff --git a/examples/rln-js/src/hooks/useWallet.ts b/examples/rln-js/src/hooks/useWallet.ts index 656b9cb..c90aa59 100644 --- a/examples/rln-js/src/hooks/useWallet.ts +++ b/examples/rln-js/src/hooks/useWallet.ts @@ -3,27 +3,15 @@ import { useStore } from "./useStore"; import { isEthereumEvenEmitterValid } from "@/utils/ethereum"; import { useRLN } from "./useRLN"; import { SIGNATURE_MESSAGE } from "@/constants"; -import { SEPOLIA_CONTRACT } from "@waku/rln"; -import { StatusEventPayload } from "@/services/rln"; type UseWalletResult = { onConnectWallet: () => void; onGenerateCredentials: () => void; - onRegisterCredentials: () => void; }; export const useWallet = (): UseWalletResult => { const { rln } = useRLN(); - const { - keystorePassword, - credentials, - setEthAccount, - setChainID, - setCredentials, - setActiveCredential, - setActiveMembershipID, - setAppStatus, - } = useStore(); + const { setEthAccount, setChainID, setCredentials } = useStore(); React.useEffect(() => { const ethereum = window.ethereum; @@ -81,48 +69,9 @@ export const useWallet = (): UseWalletResult => { setCredentials(credentials); }, [rln, setCredentials]); - const onRegisterCredentials = React.useCallback(async () => { - if (!credentials || !rln?.rlnContract || !keystorePassword) { - return; - } - - try { - setAppStatus(StatusEventPayload.CREDENTIALS_REGISTERING); - const membershipInfo = await rln.rlnContract.registerWithKey(credentials); - const membershipID = membershipInfo!.index.toNumber(); - const keystoreHash = await rln.keystore.addCredential( - { - membership: { - treeIndex: membershipID, - chainId: SEPOLIA_CONTRACT.chainId, - address: SEPOLIA_CONTRACT.address, - }, - identity: credentials, - }, - keystorePassword - ); - setActiveCredential(keystoreHash); - setActiveMembershipID(membershipID); - rln.saveKeystore(); - setAppStatus(StatusEventPayload.CREDENTIALS_REGISTERED); - } catch (error) { - setAppStatus(StatusEventPayload.CREDENTIALS_FAILURE); - console.error("Failed to register to RLN Contract: ", error); - return; - } - }, [ - credentials, - rln, - keystorePassword, - setActiveCredential, - setActiveMembershipID, - setAppStatus, - ]); - return { onConnectWallet, onGenerateCredentials, - onRegisterCredentials, }; };