UNPKG

@waku/rln

Version:

RLN (Rate Limiting Nullifier) implementation for Waku

107 lines 4.24 kB
import { Logger } from "@waku/utils"; import { hexToBytes } from "@waku/utils/bytes"; import { ethers } from "ethers"; import { MerkleRootTracker } from "../root_tracker.js"; import { BytesUtils } from "../utils/bytes.js"; import { RLNBaseContract } from "./rln_base_contract.js"; const log = new Logger("waku:rln:contract"); export class RLNContract extends RLNBaseContract { instance; merkleRootTracker; /** * Asynchronous initializer for RLNContract. * Allows injecting a mocked contract for testing purposes. */ static async init(rlnInstance, options) { const rlnContract = new RLNContract(rlnInstance, options); return rlnContract; } constructor(rlnInstance, options) { super(options); this.instance = rlnInstance; const initialRoot = rlnInstance.zerokit.getMerkleRoot(); this.merkleRootTracker = new MerkleRootTracker(5, initialRoot); } processEvents(events) { const toRemoveTable = new Map(); const toInsertTable = new Map(); events.forEach((evt) => { if (!evt.args) { return; } if (evt.event === "MembershipErased" || evt.event === "MembershipExpired") { let index = evt.args.index; if (!index) { return; } if (typeof index === "number" || typeof index === "string") { index = ethers.BigNumber.from(index); } else { log.error("Index is not a number or string", { index, event: evt }); return; } const toRemoveVal = toRemoveTable.get(evt.blockNumber); if (toRemoveVal != undefined) { toRemoveVal.push(index.toNumber()); toRemoveTable.set(evt.blockNumber, toRemoveVal); } else { toRemoveTable.set(evt.blockNumber, [index.toNumber()]); } } else if (evt.event === "MembershipRegistered") { let eventsPerBlock = toInsertTable.get(evt.blockNumber); if (eventsPerBlock == undefined) { eventsPerBlock = []; } eventsPerBlock.push(evt); toInsertTable.set(evt.blockNumber, eventsPerBlock); } }); this.removeMembers(this.instance, toRemoveTable); this.insertMembers(this.instance, toInsertTable); } insertMembers(rlnInstance, toInsert) { toInsert.forEach((events, blockNumber) => { events.forEach((evt) => { if (!evt.args) return; const _idCommitment = evt.args.idCommitment; let index = evt.args.index; if (!_idCommitment || !index) { return; } if (typeof index === "number" || typeof index === "string") { index = ethers.BigNumber.from(index); } const idCommitment = BytesUtils.zeroPadLE(hexToBytes(_idCommitment), 32); rlnInstance.zerokit.insertMember(idCommitment); const numericIndex = index.toNumber(); this._members.set(numericIndex, { index, idCommitment: _idCommitment }); }); const currentRoot = rlnInstance.zerokit.getMerkleRoot(); this.merkleRootTracker.pushRoot(blockNumber, currentRoot); }); } removeMembers(rlnInstance, toRemove) { const removeDescending = new Map([...toRemove].reverse()); removeDescending.forEach((indexes, blockNumber) => { indexes.forEach((index) => { if (this._members.has(index)) { this._members.delete(index); rlnInstance.zerokit.deleteMember(index); } }); this.merkleRootTracker.backFill(blockNumber); }); } } //# sourceMappingURL=rln_contract.js.map