diff --git a/examples/rln-identity/index.html b/examples/rln-identity/index.html index fc1b937..cfa9376 100644 --- a/examples/rln-identity/index.html +++ b/examples/rln-identity/index.html @@ -1,206 +1,223 @@ - - - - RLN Credential management - - - - - - -
-
-

- Status: - Starting... -

-
+ .mb-2 { + margin-bottom: 2rem; + } -
-

Wallet

- -
+ .mb-3 { + margin-bottom: 3rem; + } -
-

Keystore

-
- - - -
-
+ .mt-1 { + margin-top: 1rem; + } -
+ .block { + display: flex; + justify-content: space-between; + align-items: center; + } -

Existing credentials

+ .hidden { + display: none; + } + + -
- -
- - -
-
+ +
+
+

+ Status: + Starting... +

+
-
-

Create new (will use the password)

- -
+
+

Wallet

+ +
-
-
-

Keystore hash

- none -
- -
-

Membership ID

- none -
- -
-

Secret Hash

- none -
- -
-

Commitment

- none -
- -
-

Nullifier

- none -
- -
-

Trapdoor

- none -
+
+

Keystore

+
+ + +
- - - +
+ +

Existing credentials

+ +
+ +
+ + +
+
+ +
+

Create new (will use the password)

+ +
+ +
+
+

Keystore hash

+ none +
+ +
+

Membership ID

+ none +
+ +
+

Secret Hash

+ none +
+ +
+

Commitment

+ none +
+ +
+

Nullifier

+ none +
+ +
+

Trapdoor

+ none +
+
+
+ +
+

Chat

+
    + +
    + + + + +
    +
    + + + + \ No newline at end of file diff --git a/examples/rln-identity/package.json b/examples/rln-identity/package.json index f99c32f..10413ff 100644 --- a/examples/rln-identity/package.json +++ b/examples/rln-identity/package.json @@ -7,7 +7,7 @@ "start": "webpack-dev-server" }, "dependencies": { - "@waku/rln": "0.1.1-77ba0a6", + "@waku/rln": "0.1.2", "@waku/sdk": "^0.0.22", "@waku/utils": "^0.0.14", "ethers": "^5.7.2", diff --git a/examples/rln-identity/src/index.js b/examples/rln-identity/src/index.js index 810e0b2..af0d035 100644 --- a/examples/rln-identity/src/index.js +++ b/examples/rln-identity/src/index.js @@ -10,6 +10,8 @@ async function run() { readCredential, saveLocalKeystore, importLocalKeystore, + createEncoderDecoder, + onSend } = await initRLN({ onStatusChange, }); @@ -21,6 +23,8 @@ async function run() { readCredential, saveLocalKeystore, importLocalKeystore, + createEncoderDecoder, + onSend }); } diff --git a/examples/rln-identity/src/rln.js b/examples/rln-identity/src/rln.js index 8197294..33fb452 100644 --- a/examples/rln-identity/src/rln.js +++ b/examples/rln-identity/src/rln.js @@ -1,11 +1,23 @@ import { createRLN, Keystore, extractMetaMaskSigner } from "@waku/rln"; +import { createLightNode, waitForRemotePeer } from "@waku/sdk"; import { randomNumber } from "./utils"; import { SIGNATURE_MESSAGE } from "./const"; +import protobuf from "protobufjs"; + +export const CONTENT_TOPIC = "/toy-chat/2/luzhou/proto"; +export const ProtoChatMessage = new protobuf.Type("ChatMessage") + .add(new protobuf.Field("timestamp", 1, "uint64")) + .add(new protobuf.Field("nick", 2, "string")) + .add(new protobuf.Field("text", 3, "string")); + export async function initRLN({ onStatusChange }) { onStatusChange("Initializing RLN..."); let rln; + let encoder; + let decoder; + let node; try { rln = await createRLN(); } catch (err) { @@ -13,24 +25,34 @@ export async function initRLN({ onStatusChange }) { throw Error(err); } - onStatusChange("RLN initialized", "success"); + onStatusChange("RLN initialized. Initializing Waku..."); + node = await createLightNode({ + defaultBootstrap: true, + }); + onStatusChange("Waiting for peers"); + await node.start(); + await waitForRemotePeer(node); + onStatusChange("RLN initialized. Waku peer connected.", "success"); const connectWallet = async () => { let signer; try { onStatusChange("Connecting to wallet..."); signer = await extractMetaMaskSigner(); + console.log("connected metamask") } catch (err) { onStatusChange(`Failed to access MetaMask: ${err}`, "error"); throw Error(err); } - + console.log("reading local keystore") try { onStatusChange("Connecting to Ethereum..."); const localKeystore = readLocalKeystore(); + console.log("got local keystore") + console.log(localKeystore) rln.keystore = Keystore.fromString(localKeystore); - await rln.start({ signer }); + await rln.start({ signer, fetchMembersFromService: true }); } catch (err) { onStatusChange(`Failed to connect to Ethereum: ${err}`, "error"); throw Error(err); @@ -50,13 +72,32 @@ export async function initRLN({ onStatusChange }) { ); const credential = await rln.registerMembership({ signature }); + if (!rln.keystore) { + rln.keystore = Keystore.create(); + } + const credStr = JSON.stringify({ + treeIndex: credential.membership.treeIndex, + identityCredential: { + idCommitment: credential.identity.IDCommitment, + idNullifier: credential.identity.IDNullifier, + idSecretHash: credential.identity.IDSecretHash, + idTrapdoor: credential.identity.IDTrapdoor + }, + membershipContract: { + chainId: credential.membership.chainId, + address: credential.membership.address + } + }); + console.log(credential) + console.log(credStr) const hash = await rln.keystore.addCredential(credential, password); + console.log(rln.keystore) return { hash, credential }; }; const readKeystoreOptions = () => { - return rln.keystore.keys(); + return rln.keystore?.keys(); }; const readCredential = async (hash, password) => { @@ -73,6 +114,32 @@ export async function initRLN({ onStatusChange }) { rln.keystore = Keystore.fromString(keystoreStr) || Keystore.create(); }; + const createEncoderDecoder = async (credentials) => { + encoder = await rln.createEncoder({ + ephemeral: false, + contentTopic: CONTENT_TOPIC, + credentials, + fetchMembersFromService: true + }); + decoder = rln.createDecoder(CONTENT_TOPIC); + + return { encoder, decoder } + } + + const onSend = async (nick, text) => { + const timestamp = new Date(); + const msg = ProtoChatMessage.create({ + text, + nick, + timestamp: Math.floor(timestamp.valueOf() / 1000), + }); + const payload = ProtoChatMessage.encode(msg).finish(); + console.log("Sending message with proof..."); + + const res = await node.lightPush.send(encoder, { payload, timestamp }); + console.log("Message sent:", res); + }; + return { rln, connectWallet, @@ -81,6 +148,8 @@ export async function initRLN({ onStatusChange }) { readCredential, saveLocalKeystore, importLocalKeystore, + createEncoderDecoder, + onSend }; } diff --git a/examples/rln-identity/src/ui.js b/examples/rln-identity/src/ui.js index 157986d..39c7dfb 100644 --- a/examples/rln-identity/src/ui.js +++ b/examples/rln-identity/src/ui.js @@ -1,5 +1,6 @@ import { renderBytes } from "./utils"; +// Identity const status = document.getElementById("status"); const connectWalletButton = document.getElementById("connect"); const importKeystoreButton = document.getElementById("import"); @@ -10,6 +11,16 @@ const keystorePassword = document.getElementById("password"); const readCredentialButton = document.getElementById("read-credential"); const registerNewCredentialButton = document.getElementById("register-new"); const currentCredentials = document.getElementById("current-credentials"); +const createEncoderDecoderButton = document.getElementById("create-coders-button"); + +// Chat +const chat = document.getElementById("chat-area"); +const messages = document.getElementById("messages"); + +const nickInput = document.getElementById("nick"); +const textInput = document.getElementById("text"); +const sendButton = document.getElementById("send"); + export function initUI() { const _renderCredential = (hash, credential) => { @@ -59,11 +70,15 @@ export function initUI() { readCredential, saveLocalKeystore, importLocalKeystore, + createEncoderDecoder, + onSend }) => { connectWalletButton.addEventListener("click", async () => { await connectWallet(); const keystoreKeys = readKeystoreOptions(); - _renderKeystoreOptions(keystoreKeys); + if (keystoreKeys) { + _renderKeystoreOptions(keystoreKeys); + } }); registerNewCredentialButton.addEventListener("click", async () => { @@ -104,6 +119,7 @@ export function initUI() { } const credential = await readCredential(currentHash, password); + console.log(credential) _renderCredential(currentHash, credential); }); @@ -137,6 +153,27 @@ export function initUI() { link.download = filename; link.click(); }); + + createEncoderDecoderButton.addEventListener("click", async () => { + const currentHash = keystoreOptions.value; + const password = keystorePassword.value; + const credential = await readCredential(currentHash, password); + const { encoder, decoder } = await createEncoderDecoder(credential) + console.log('Encoder and Decoder created:', encoder, decoder); + }); + + sendButton.addEventListener("click", async () => { + const nick = nickInput.value; + const text = textInput.value; + + if (!nick || !text) { + console.log("Not sending message: missing nick or text."); + return; + } + + await onSend(nick, text); + textInput.value = ""; + }); }; return { diff --git a/package-lock.json b/package-lock.json index 581e9aa..e489db1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "waku-lab", + "name": "lab.waku.org", "lockfileVersion": 2, "requires": true, "packages": {