mirror of
https://github.com/logos-messaging/examples.waku.org.git
synced 2026-01-02 12:53:08 +00:00
add features
This commit is contained in:
parent
690cb1ae59
commit
eecd6a29b9
@ -21,9 +21,7 @@ export const Blockchain: React.FunctionComponent<{}> = () => {
|
||||
|
||||
<Block type={BlockTypes.FlexHorizontal}>
|
||||
<p>Latest membership ID on contract</p>
|
||||
<code>
|
||||
{lastMembershipID === -1 ? "Not loaded yet" : lastMembershipID}
|
||||
</code>
|
||||
<code>{lastMembershipID || "Not loaded yet"}</code>
|
||||
</Block>
|
||||
</Block>
|
||||
);
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import React from "react";
|
||||
import { Block, BlockTypes } from "@/components/Block";
|
||||
import { Button } from "@/components/Button";
|
||||
import { Status } from "@/components/Status";
|
||||
import { Subtitle } from "@/components/Subtitle";
|
||||
import { useStore, useWallet } from "@/hooks";
|
||||
|
||||
export const Keystore: React.FunctionComponent<{}> = () => {
|
||||
const { keystoreStatus, keystoreCredentials } = useStore();
|
||||
const { onGenerateCredentials } = useWallet();
|
||||
const { keystorePassword, setKeystorePassword, keystoreCredentials } =
|
||||
useStore();
|
||||
const { onGenerateCredentials, onRegisterCredentials } = useWallet();
|
||||
|
||||
const credentialsNodes = React.useMemo(
|
||||
() =>
|
||||
@ -19,6 +19,13 @@ export const Keystore: React.FunctionComponent<{}> = () => {
|
||||
[keystoreCredentials]
|
||||
);
|
||||
|
||||
const onPasswordChanged = React.useCallback(
|
||||
(event: React.FormEvent<HTMLInputElement>) => {
|
||||
setKeystorePassword(event.currentTarget.value);
|
||||
},
|
||||
[setKeystorePassword]
|
||||
);
|
||||
|
||||
return (
|
||||
<Block className="mt-10">
|
||||
<Block type={BlockTypes.FlexHorizontal}>
|
||||
@ -29,8 +36,6 @@ export const Keystore: React.FunctionComponent<{}> = () => {
|
||||
</div>
|
||||
</Block>
|
||||
|
||||
<Status text="Keystore status" mark={keystoreStatus} />
|
||||
|
||||
<Block className="mt-4">
|
||||
<label
|
||||
htmlFor="keystore-input"
|
||||
@ -41,6 +46,8 @@ export const Keystore: React.FunctionComponent<{}> = () => {
|
||||
<input
|
||||
type="text"
|
||||
id="keystore-input"
|
||||
value={keystorePassword || ""}
|
||||
onChange={onPasswordChanged}
|
||||
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm w-full rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||
/>
|
||||
</Block>
|
||||
@ -50,7 +57,9 @@ export const Keystore: React.FunctionComponent<{}> = () => {
|
||||
<Button onClick={onGenerateCredentials}>
|
||||
Generate new credentials
|
||||
</Button>
|
||||
<Button className="ml-5">Register credentials</Button>
|
||||
<Button className="ml-5" onClick={onRegisterCredentials}>
|
||||
Register credentials
|
||||
</Button>
|
||||
</Block>
|
||||
|
||||
<Block className="mt-4">
|
||||
|
||||
@ -3,18 +3,18 @@ import { useStore } from "@/hooks";
|
||||
import { bytesToHex } from "@waku/utils/bytes";
|
||||
|
||||
export const KeystoreDetails: React.FunctionComponent<{}> = () => {
|
||||
const { credentials } = useStore();
|
||||
const { credentials, activeCredential, activeMembershipID } = useStore();
|
||||
|
||||
return (
|
||||
<Block className="mt-5">
|
||||
<Block className="mt-3" type={BlockTypes.FlexHorizontal}>
|
||||
<p>Keystore hash</p>
|
||||
<code>none</code>
|
||||
<code>{activeCredential || "none"}</code>
|
||||
</Block>
|
||||
|
||||
<Block className="mt-3" type={BlockTypes.FlexHorizontal}>
|
||||
<p>Membership ID</p>
|
||||
<code>none</code>
|
||||
<code>{activeMembershipID || "none"}</code>
|
||||
</Block>
|
||||
|
||||
<Block className="mt-3" type={BlockTypes.FlexHorizontal}>
|
||||
|
||||
@ -7,9 +7,6 @@ import { KeystoreDetails } from "./components/KeystoreDetails";
|
||||
import { useRLN } from "@/hooks";
|
||||
|
||||
export default function Home() {
|
||||
const { rln } = useRLN();
|
||||
console.log(rln);
|
||||
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col p-24 font-mono max-w-screen-lg m-auto">
|
||||
<Header />
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { rln, RLN, RLNEventsNames } from "@/services/rln";
|
||||
import { useStore } from "./useStore";
|
||||
@ -7,38 +8,39 @@ type RLNResult = {
|
||||
};
|
||||
|
||||
export const useRLN = (): RLNResult => {
|
||||
const { setAppStatus, setKeystoreStatus } = useStore();
|
||||
const { setAppStatus, setKeystoreCredentials } = useStore();
|
||||
const rlnRef = React.useRef<undefined | RLN>(undefined);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (rlnRef.current) {
|
||||
if (rlnRef.current || !rln) {
|
||||
return;
|
||||
}
|
||||
|
||||
let terminate = false;
|
||||
|
||||
const statusListener = (event: CustomEvent) => {
|
||||
setAppStatus(event?.detail);
|
||||
};
|
||||
const keystoreListener = (event: CustomEvent) => {
|
||||
setKeystoreStatus(event?.detail);
|
||||
};
|
||||
|
||||
rln.addEventListener(RLNEventsNames.Status, statusListener);
|
||||
|
||||
const keystoreListener = (event: CustomEvent) => {
|
||||
setKeystoreCredentials(event?.detail || []);
|
||||
};
|
||||
rln.addEventListener(RLNEventsNames.Keystore, keystoreListener);
|
||||
|
||||
const run = async () => {
|
||||
if (terminate) {
|
||||
return;
|
||||
}
|
||||
await rln.init();
|
||||
await rln?.init();
|
||||
rlnRef.current = rln;
|
||||
};
|
||||
|
||||
run();
|
||||
return () => {
|
||||
terminate = true;
|
||||
rln.removeEventListener(RLNEventsNames.Status, statusListener);
|
||||
rln.removeEventListener(RLNEventsNames.Keystore, keystoreListener);
|
||||
rln?.removeEventListener(RLNEventsNames.Status, statusListener);
|
||||
rln?.removeEventListener(RLNEventsNames.Keystore, keystoreListener);
|
||||
};
|
||||
}, [rlnRef, setAppStatus]);
|
||||
|
||||
|
||||
@ -6,19 +6,21 @@ type StoreResult = {
|
||||
setAppStatus: (v: string) => void;
|
||||
ethAccount: string;
|
||||
setEthAccount: (v: string) => void;
|
||||
chainID: number;
|
||||
chainID: undefined | number;
|
||||
setChainID: (v: number) => void;
|
||||
lastMembershipID: number;
|
||||
lastMembershipID: undefined | number;
|
||||
setLastMembershipID: (v: number) => void;
|
||||
credentials: undefined | IdentityCredential;
|
||||
setCredentials: (v: undefined | IdentityCredential) => void;
|
||||
|
||||
keystoreStatus: string;
|
||||
setKeystoreStatus: (v: string) => void;
|
||||
keystorePassword: undefined | string;
|
||||
setKeystorePassword: (v: string) => void;
|
||||
activeCredential: string;
|
||||
keystoreCredentials: string[];
|
||||
setKeystoreCredentials: (v: string[]) => void;
|
||||
setActiveCredential: (v: string) => void;
|
||||
activeMembershipID: undefined | number;
|
||||
setActiveMembershipID: (v: number) => void;
|
||||
|
||||
wakuStatus: string;
|
||||
setWakuStatus: (v: string) => void;
|
||||
@ -33,9 +35,9 @@ export const useStore = create<StoreResult>((set) => {
|
||||
|
||||
ethAccount: "",
|
||||
setEthAccount: (v: string) => set((state) => ({ ...state, ethAccount: v })),
|
||||
chainID: -1,
|
||||
chainID: undefined,
|
||||
setChainID: (v: number) => set((state) => ({ ...state, chainID: v })),
|
||||
lastMembershipID: -1,
|
||||
lastMembershipID: undefined,
|
||||
setLastMembershipID: (v: number) =>
|
||||
set((state) => ({ ...state, lastMembershipID: v })),
|
||||
credentials: undefined,
|
||||
@ -50,15 +52,18 @@ export const useStore = create<StoreResult>((set) => {
|
||||
};
|
||||
|
||||
const keystoreModule = {
|
||||
keystoreStatus: DEFAULT_VALUE,
|
||||
setKeystoreStatus: (v: string) =>
|
||||
set((state) => ({ ...state, keystoreStatus: v })),
|
||||
keystorePassword: undefined,
|
||||
setKeystorePassword: (v: string) =>
|
||||
set((state) => ({ ...state, keystorePassword: v })),
|
||||
activeCredential: DEFAULT_VALUE,
|
||||
keystoreCredentials: [], // ["277026D55D6F3988FB4E4695F1DCA2F59B012581A854FEE6035EE1566F898908", "59FDF2A610545099326E736269EA2E297BCA0B2BA4D68D245130BF10F9FFAC43", "FC98D3EDD1CCB2AA4C25CCDDD18ADADC8C4BBA9BA11B9F652B2E5E9732D531D3"],
|
||||
setActiveCredential: (v: string) =>
|
||||
set((state) => ({ ...state, activeCredential: v })),
|
||||
keystoreCredentials: [],
|
||||
setKeystoreCredentials: (v: string[]) =>
|
||||
set((state) => ({ ...state, keystoreCredentials: v })),
|
||||
activeMembershipID: undefined,
|
||||
setActiveMembershipID: (v: number) =>
|
||||
set((state) => ({ ...state, activeMembershipID: v })),
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@ -3,15 +3,27 @@ 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 { setEthAccount, setChainID, setCredentials } = useStore();
|
||||
const {
|
||||
keystorePassword,
|
||||
credentials,
|
||||
setEthAccount,
|
||||
setChainID,
|
||||
setCredentials,
|
||||
setActiveCredential,
|
||||
setActiveMembershipID,
|
||||
setAppStatus,
|
||||
} = useStore();
|
||||
|
||||
React.useEffect(() => {
|
||||
const ethereum = window.ethereum;
|
||||
@ -69,9 +81,48 @@ 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,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -12,10 +12,10 @@ import { isBrowserProviderValid } from "@/utils/ethereum";
|
||||
|
||||
export enum RLNEventsNames {
|
||||
Status = "status",
|
||||
Keystore = "keystore",
|
||||
Keystore = "keystore-changed",
|
||||
}
|
||||
|
||||
enum StatusEventPayload {
|
||||
export enum StatusEventPayload {
|
||||
WASM_LOADING = "WASM Blob download in progress...",
|
||||
WASM_FAILED = "Failed to download WASM, check console",
|
||||
CONTRACT_LOADING = "Connecting to RLN contract",
|
||||
@ -23,11 +23,15 @@ enum StatusEventPayload {
|
||||
RLN_INITIALIZED = "RLN dependencies initialized",
|
||||
KEYSTORE_LOCAL = "Keystore initialized from localStore",
|
||||
KEYSTORE_NEW = "New Keystore was initialized",
|
||||
CREDENTIALS_REGISTERING = "Registering credentials...",
|
||||
CREDENTIALS_REGISTERED = "Registered credentials",
|
||||
CREDENTIALS_FAILURE = "Failed to register credentials, check console",
|
||||
}
|
||||
|
||||
type EventListener = (event: CustomEvent) => void;
|
||||
|
||||
type IRLN = {
|
||||
saveKeystore: () => void;
|
||||
addEventListener: (name: RLNEventsNames, fn: EventListener) => void;
|
||||
removeEventListener: (name: RLNEventsNames, fn: EventListener) => void;
|
||||
};
|
||||
@ -38,7 +42,7 @@ export class RLN implements IRLN {
|
||||
|
||||
public rlnInstance: undefined | RLNInstance;
|
||||
public rlnContract: undefined | RLNContract;
|
||||
public keystore: undefined | Keystore;
|
||||
public readonly keystore: Keystore;
|
||||
|
||||
private initialized = false;
|
||||
private initializing = false;
|
||||
@ -52,6 +56,7 @@ export class RLN implements IRLN {
|
||||
);
|
||||
}
|
||||
this.ethProvider = new ethers.providers.Web3Provider(ethereum, "any");
|
||||
this.keystore = this.initKeystore();
|
||||
}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
@ -65,7 +70,8 @@ export class RLN implements IRLN {
|
||||
|
||||
this.emitStatusEvent(StatusEventPayload.RLN_INITIALIZED);
|
||||
|
||||
this.initKeystore();
|
||||
// emit keystore keys once app is ready
|
||||
this.emitKeystoreKeys();
|
||||
|
||||
this.initialized = true;
|
||||
this.initializing = false;
|
||||
@ -100,17 +106,11 @@ export class RLN implements IRLN {
|
||||
}
|
||||
}
|
||||
|
||||
private initKeystore(): void {
|
||||
private initKeystore(): Keystore {
|
||||
const localKeystoreString = localStorage.getItem("keystore");
|
||||
const _keystore = Keystore.fromString(localKeystoreString || "");
|
||||
|
||||
if (localKeystoreString) {
|
||||
this.emitKeystoreStatusEvent(StatusEventPayload.KEYSTORE_LOCAL);
|
||||
} else {
|
||||
this.emitKeystoreStatusEvent(StatusEventPayload.KEYSTORE_NEW);
|
||||
}
|
||||
|
||||
this.keystore = _keystore || Keystore.create();
|
||||
return _keystore || Keystore.create();
|
||||
}
|
||||
|
||||
public addEventListener(name: RLNEventsNames, fn: EventListener) {
|
||||
@ -127,11 +127,17 @@ export class RLN implements IRLN {
|
||||
);
|
||||
}
|
||||
|
||||
private emitKeystoreStatusEvent(payload: StatusEventPayload) {
|
||||
private emitKeystoreKeys() {
|
||||
const credentials = Object.keys(this.keystore.toObject().credentials || {});
|
||||
this.emitter.dispatchEvent(
|
||||
new CustomEvent(RLNEventsNames.Keystore, { detail: payload })
|
||||
new CustomEvent(RLNEventsNames.Keystore, { detail: credentials })
|
||||
);
|
||||
}
|
||||
|
||||
public async saveKeystore() {
|
||||
localStorage.setItem("keystore", this.keystore.toString());
|
||||
this.emitKeystoreKeys();
|
||||
}
|
||||
}
|
||||
|
||||
export const rln = new RLN();
|
||||
export const rln = typeof window === "undefined" ? undefined : new RLN();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user