From 2ef425241192549bfe3236b8e95aa833b9726f19 Mon Sep 17 00:00:00 2001 From: Sasha Date: Tue, 23 Jan 2024 23:00:52 +0100 Subject: [PATCH] add MetaMask abstraction, add default start to RLN Instance, expose RLN Contract --- src/create.ts | 9 +++++++++ src/index.ts | 11 ++--------- src/metamask.ts | 15 +++++++++++++++ src/rln.ts | 31 +++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 src/create.ts create mode 100644 src/metamask.ts diff --git a/src/create.ts b/src/create.ts new file mode 100644 index 0000000..9d7f6e0 --- /dev/null +++ b/src/create.ts @@ -0,0 +1,9 @@ +import type { RLNInstance } from "./rln.js"; + +export async function create(): Promise { + // A dependency graph that contains any wasm must all be imported + // asynchronously. This file does the single async import, so + // that no one else needs to worry about it again. + const rlnModule = await import("./rln.js"); + return rlnModule.create(); +} diff --git a/src/index.ts b/src/index.ts index 0d27230..6b53efc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ import { RLN_STORAGE_ABI, SEPOLIA_CONTRACT, } from "./constants.js"; +import { create } from "./create.js"; import { Keystore } from "./keystore/index.js"; import { IdentityCredential, @@ -14,16 +15,8 @@ import { import { RLNContract } from "./rln_contract.js"; import { MerkleRootTracker } from "./root_tracker.js"; -// reexport the create function, dynamically imported from rln.ts -export async function create(): Promise { - // A dependency graph that contains any wasm must all be imported - // asynchronously. This file does the single async import, so - // that no one else needs to worry about it again. - const rlnModule = await import("./rln.js"); - return await rlnModule.create(); -} - export { + create, Keystore, RLNInstance, IdentityCredential, diff --git a/src/metamask.ts b/src/metamask.ts new file mode 100644 index 0000000..69e3084 --- /dev/null +++ b/src/metamask.ts @@ -0,0 +1,15 @@ +import { ethers } from "ethers"; + +export const extractMetaMaskAccount = + async (): Promise => { + const ethereum = (window as any).ethereum; + + if (!ethereum) { + throw Error( + "Missing or invalid Ethereum provider. Please install MetaMask." + ); + } + + await ethereum.request({ method: "eth_requestAccounts" }); + return new ethers.providers.Web3Provider(ethereum, "any"); + }; diff --git a/src/rln.ts b/src/rln.ts index ccab1ac..3a770ab 100644 --- a/src/rln.ts +++ b/src/rln.ts @@ -1,10 +1,14 @@ import type { IRateLimitProof } from "@waku/interfaces"; import init from "@waku/zerokit-rln-wasm"; import * as zerokitRLN from "@waku/zerokit-rln-wasm"; +import { ethers } from "ethers"; import { buildBigIntFromUint8Array, writeUIntLE } from "./byte_utils.js"; +import { SEPOLIA_CONTRACT } from "./constants.js"; import { dateToEpoch, epochIntToBytes } from "./epoch.js"; +import { extractMetaMaskAccount } from "./metamask.js"; import verificationKey from "./resources/verification_key.js"; +import { RLNContract } from "./rln_contract.js"; import * as wc from "./witness_calculator.js"; import { WitnessCalculator } from "./witness_calculator.js"; @@ -158,12 +162,39 @@ export function sha256(input: Uint8Array): Uint8Array { return zerokitRLN.hash(lenPrefixedData); } +type StartRLNOptions = { + /** + * If not set - will extract MetaMask account and get provider from it. + */ + provider?: ethers.providers.Web3Provider; + /** + * If not set - will use default SEPOLIA_CONTRACT address. + */ + registryAddress?: string; +}; + export class RLNInstance { + private _contract: null | RLNContract = null; + constructor( private zkRLN: number, private witnessCalculator: WitnessCalculator ) {} + public get contract(): null | RLNContract { + return this._contract; + } + + public async start(options: StartRLNOptions = {}): Promise { + const provider = options.provider || (await extractMetaMaskAccount()); + const registryAddress = options.registryAddress || SEPOLIA_CONTRACT.address; + + this._contract = await RLNContract.init(this, { + registryAddress, + provider: provider.getSigner(), + }); + } + generateIdentityCredentials(): IdentityCredential { const memKeys = zerokitRLN.generateExtendedMembershipKey(this.zkRLN); // TODO: rename this function in zerokit rln-wasm return IdentityCredential.fromBytes(memKeys);