UNPKG

@waku/rln

Version:

RLN (Rate Limiting Nullifier) implementation for Waku

118 lines 4.6 kB
import { hexToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; import * as ethers from "ethers"; import sinon from "sinon"; import { DEFAULT_RATE_LIMIT, RLN_CONTRACT } from "./constants.js"; export const mockRateLimits = { minRate: 20, maxRate: 600, maxTotalRate: 1200, currentTotalRate: 500 }; export function createMockProvider() { return { getLogs: () => [], getBlockNumber: () => Promise.resolve(1000), getNetwork: () => Promise.resolve({ chainId: 11155111 }) }; } export function createMockFilters() { return { MembershipRegistered: () => ({ address: RLN_CONTRACT.address }), MembershipErased: () => ({ address: RLN_CONTRACT.address }), MembershipExpired: () => ({ address: RLN_CONTRACT.address }) }; } export function createMockRegistryContract(overrides = {}) { const filters = { MembershipRegistered: () => ({ address: RLN_CONTRACT.address }), MembershipErased: () => ({ address: RLN_CONTRACT.address }), MembershipExpired: () => ({ address: RLN_CONTRACT.address }) }; const baseContract = { minMembershipRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.minRate)), maxMembershipRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxRate)), maxTotalRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxTotalRate)), currentTotalRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.currentTotalRate)), queryFilter: () => [], provider: createMockProvider(), filters, on: () => ({}), removeAllListeners: () => ({}), register: () => ({ wait: () => Promise.resolve({ events: [mockRLNRegisteredEvent()] }) }), estimateGas: { register: () => Promise.resolve(ethers.BigNumber.from(100000)) }, functions: { register: () => Promise.resolve() }, getMemberIndex: () => Promise.resolve(null), interface: { getEvent: (eventName) => ({ name: eventName, format: () => { } }) }, address: RLN_CONTRACT.address }; // Merge overrides while preserving filters const merged = { ...baseContract, ...overrides, filters: { ...filters, ...(overrides.filters || {}) } }; return merged; } export function mockRLNRegisteredEvent(idCommitment) { return { args: { idCommitment: idCommitment || "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT), index: ethers.BigNumber.from(1) }, event: "MembershipRegistered" }; } export function formatIdCommitment(idCommitmentBigInt) { return "0x" + idCommitmentBigInt.toString(16).padStart(64, "0"); } export function createRegisterStub(identity) { return sinon.stub().callsFake(() => ({ wait: () => Promise.resolve({ events: [ { event: "MembershipRegistered", args: { idCommitment: formatIdCommitment(identity.IDCommitmentBigInt), membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT), index: ethers.BigNumber.from(1) } } ] }) })); } export function verifyRegistration(decryptedCredentials, identity, registerStub, insertMemberSpy) { if (!decryptedCredentials) { throw new Error("Decrypted credentials should not be undefined"); } // Verify registration call expect(registerStub.calledWith(sinon.match.same(identity.IDCommitmentBigInt), sinon.match.same(DEFAULT_RATE_LIMIT), sinon.match.array, sinon.match.object)).to.be.true; // Verify credential properties expect(decryptedCredentials).to.have.property("identity"); expect(decryptedCredentials).to.have.property("membership"); expect(decryptedCredentials.membership).to.include({ address: RLN_CONTRACT.address, treeIndex: 1 }); // Verify member insertion const expectedIdCommitment = ethers.utils.zeroPad(hexToBytes(formatIdCommitment(identity.IDCommitmentBigInt)), 32); expect(insertMemberSpy.callCount).to.equal(1); expect(insertMemberSpy.getCall(0).args[0]).to.deep.equal(expectedIdCommitment); } //# sourceMappingURL=test_utils.js.map