@waku/rln 0.0.2-c41b319.0 → 0.0.2-c8128d1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/bundle/index.js +1 -1
  2. package/bundle/packages/interfaces/dist/protocols.js +40 -45
  3. package/bundle/packages/rln/dist/contract/abi.js +648 -0
  4. package/bundle/packages/rln/dist/contract/constants.js +8 -13
  5. package/bundle/packages/rln/dist/contract/rln_contract.js +148 -25
  6. package/bundle/packages/rln/dist/identity.js +0 -24
  7. package/bundle/packages/rln/dist/rln.js +33 -15
  8. package/bundle/packages/rln/dist/zerokit.js +22 -16
  9. package/dist/.tsbuildinfo +1 -1
  10. package/dist/contract/{abi/rlnv2.d.ts → abi.d.ts} +22 -18
  11. package/dist/contract/abi.js +647 -0
  12. package/dist/contract/abi.js.map +1 -0
  13. package/dist/contract/constants.d.ts +22 -23
  14. package/dist/contract/constants.js +7 -12
  15. package/dist/contract/constants.js.map +1 -1
  16. package/dist/contract/rln_contract.d.ts +13 -3
  17. package/dist/contract/rln_contract.js +148 -25
  18. package/dist/contract/rln_contract.js.map +1 -1
  19. package/dist/identity.d.ts +0 -1
  20. package/dist/identity.js +0 -24
  21. package/dist/identity.js.map +1 -1
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +2 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/rln.js +33 -14
  26. package/dist/rln.js.map +1 -1
  27. package/dist/zerokit.d.ts +5 -1
  28. package/dist/zerokit.js +22 -16
  29. package/dist/zerokit.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/contract/abi.ts +646 -0
  32. package/src/contract/constants.ts +8 -14
  33. package/src/contract/rln_contract.ts +227 -27
  34. package/src/identity.ts +0 -42
  35. package/src/index.ts +2 -2
  36. package/src/rln.ts +48 -14
  37. package/src/zerokit.ts +45 -16
  38. package/bundle/node_modules/@iden3/js-crypto/dist/browser/esm/index.js +0 -7
  39. package/bundle/node_modules/@stablelib/binary/lib/binary.js +0 -22
  40. package/bundle/node_modules/@stablelib/chacha/lib/chacha.js +0 -245
  41. package/bundle/node_modules/@stablelib/wipe/lib/wipe.js +0 -26
  42. package/bundle/packages/rln/dist/contract/abi/rlnv2.js +0 -394
  43. package/dist/contract/abi/rlnv2.js +0 -393
  44. package/dist/contract/abi/rlnv2.js.map +0 -1
  45. package/src/contract/abi/rlnv2.ts +0 -392
@@ -5,11 +5,12 @@ import { hexToBytes } from '../../../utils/dist/bytes/index.js';
5
5
  import { Logger } from '../../../utils/dist/logger/index.js';
6
6
  import { MerkleRootTracker } from '../root_tracker.js';
7
7
  import { zeroPadLE } from '../utils/bytes.js';
8
- import { RLN_V2_ABI } from './abi/rlnv2.js';
8
+ import { RLN_ABI } from './abi.js';
9
9
  import { RATE_LIMIT_PARAMS, DEFAULT_RATE_LIMIT } from './constants.js';
10
10
  import { Contract } from '../../../../node_modules/@ethersproject/contracts/lib.esm/index.js';
11
11
  import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
12
12
 
13
+ /* eslint-disable no-console */
13
14
  const log = new Logger("waku:rln:contract");
14
15
  var MembershipState;
15
16
  (function (MembershipState) {
@@ -26,6 +27,7 @@ class RLNContract {
26
27
  _members = new Map();
27
28
  _membersFilter;
28
29
  _membersRemovedFilter;
30
+ _membersExpiredFilter;
29
31
  /**
30
32
  * Asynchronous initializer for RLNContract.
31
33
  * Allows injecting a mocked contract for testing purposes.
@@ -45,12 +47,12 @@ class RLNContract {
45
47
  this.rateLimit = rateLimit;
46
48
  const initialRoot = rlnInstance.zerokit.getMerkleRoot();
47
49
  // Use the injected contract if provided; otherwise, instantiate a new one.
48
- this.contract =
49
- contract || new Contract(address, RLN_V2_ABI, signer);
50
+ this.contract = contract || new Contract(address, RLN_ABI, signer);
50
51
  this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
51
- // Initialize event filters for MembershipRegistered and MembershipRemoved
52
+ // Initialize event filters
52
53
  this._membersFilter = this.contract.filters.MembershipRegistered();
53
- this._membersRemovedFilter = this.contract.filters.MembershipRemoved();
54
+ this._membersRemovedFilter = this.contract.filters.MembershipErased();
55
+ this._membersExpiredFilter = this.contract.filters.MembershipExpired();
54
56
  }
55
57
  /**
56
58
  * Gets the current rate limit for this contract instance
@@ -58,6 +60,18 @@ class RLNContract {
58
60
  getRateLimit() {
59
61
  return this.rateLimit;
60
62
  }
63
+ /**
64
+ * Gets the contract address
65
+ */
66
+ get address() {
67
+ return this.contract.address;
68
+ }
69
+ /**
70
+ * Gets the contract provider
71
+ */
72
+ get provider() {
73
+ return this.contract.provider;
74
+ }
61
75
  /**
62
76
  * Gets the minimum allowed rate limit from the contract
63
77
  * @returns Promise<number> The minimum rate limit in messages per epoch
@@ -120,10 +134,16 @@ class RLNContract {
120
134
  }
121
135
  get membersRemovedFilter() {
122
136
  if (!this._membersRemovedFilter) {
123
- throw Error("MembersRemoved filter was not initialized.");
137
+ throw Error("MembersErased filter was not initialized.");
124
138
  }
125
139
  return this._membersRemovedFilter;
126
140
  }
141
+ get membersExpiredFilter() {
142
+ if (!this._membersExpiredFilter) {
143
+ throw Error("MembersExpired filter was not initialized.");
144
+ }
145
+ return this._membersExpiredFilter;
146
+ }
127
147
  async fetchMembers(rlnInstance, options = {}) {
128
148
  const registeredMemberEvents = await queryFilter(this.contract, {
129
149
  fromBlock: this.deployBlock,
@@ -135,7 +155,16 @@ class RLNContract {
135
155
  ...options,
136
156
  membersFilter: this.membersRemovedFilter
137
157
  });
138
- const events = [...registeredMemberEvents, ...removedMemberEvents];
158
+ const expiredMemberEvents = await queryFilter(this.contract, {
159
+ fromBlock: this.deployBlock,
160
+ ...options,
161
+ membersFilter: this.membersExpiredFilter
162
+ });
163
+ const events = [
164
+ ...registeredMemberEvents,
165
+ ...removedMemberEvents,
166
+ ...expiredMemberEvents
167
+ ];
139
168
  this.processEvents(rlnInstance, events);
140
169
  }
141
170
  processEvents(rlnInstance, events) {
@@ -145,8 +174,17 @@ class RLNContract {
145
174
  if (!evt.args) {
146
175
  return;
147
176
  }
148
- if (evt.event === "MembershipRemoved") {
149
- const index = evt.args.index;
177
+ if (evt.event === "MembershipErased" ||
178
+ evt.event === "MembershipExpired") {
179
+ // Both MembershipErased and MembershipExpired events should remove members
180
+ let index = evt.args.index;
181
+ if (!index) {
182
+ return;
183
+ }
184
+ // Convert index to ethers.BigNumber if it's not already
185
+ if (typeof index === "number" || typeof index === "string") {
186
+ index = BigNumber.from(index);
187
+ }
150
188
  const toRemoveVal = toRemoveTable.get(evt.blockNumber);
151
189
  if (toRemoveVal != undefined) {
152
190
  toRemoveVal.push(index.toNumber());
@@ -174,14 +212,21 @@ class RLNContract {
174
212
  if (!evt.args)
175
213
  return;
176
214
  const _idCommitment = evt.args.idCommitment;
177
- const index = evt.args.index;
215
+ let index = evt.args.index;
216
+ // Ensure index is an ethers.BigNumber
178
217
  if (!_idCommitment || !index) {
179
218
  return;
180
219
  }
220
+ // Convert index to ethers.BigNumber if it's not already
221
+ if (typeof index === "number" || typeof index === "string") {
222
+ index = BigNumber.from(index);
223
+ }
181
224
  const idCommitment = zeroPadLE(hexToBytes(_idCommitment), 32);
182
225
  rlnInstance.zerokit.insertMember(idCommitment);
183
- this._members.set(index.toNumber(), {
184
- index,
226
+ // Always store the numeric index as the key, but the BigNumber as the value
227
+ const numericIndex = index.toNumber();
228
+ this._members.set(numericIndex, {
229
+ index, // This is always a BigNumber
185
230
  idCommitment: _idCommitment
186
231
  });
187
232
  });
@@ -202,34 +247,78 @@ class RLNContract {
202
247
  });
203
248
  }
204
249
  subscribeToMembers(rlnInstance) {
205
- this.contract.on(this.membersFilter, (_idCommitment, _rateLimit, _index, event) => {
250
+ this.contract.on(this.membersFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
206
251
  this.processEvents(rlnInstance, [event]);
207
252
  });
208
- this.contract.on(this.membersRemovedFilter, (_idCommitment, _index, event) => {
253
+ this.contract.on(this.membersRemovedFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
254
+ this.processEvents(rlnInstance, [event]);
255
+ });
256
+ this.contract.on(this.membersExpiredFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
209
257
  this.processEvents(rlnInstance, [event]);
210
258
  });
211
259
  }
212
260
  async registerWithIdentity(identity) {
213
261
  try {
262
+ console.log("registerWithIdentity - starting registration process");
263
+ console.log("registerWithIdentity - identity:", identity);
264
+ console.log("registerWithIdentity - IDCommitmentBigInt:", identity.IDCommitmentBigInt.toString());
265
+ console.log("registerWithIdentity - rate limit:", this.rateLimit);
214
266
  log.info(`Registering identity with rate limit: ${this.rateLimit} messages/epoch`);
267
+ // Check if the ID commitment is already registered
268
+ const existingIndex = await this.getMemberIndex(identity.IDCommitmentBigInt.toString());
269
+ if (existingIndex) {
270
+ console.error(`ID commitment is already registered with index ${existingIndex}`);
271
+ throw new Error(`ID commitment is already registered with index ${existingIndex}`);
272
+ }
273
+ // Check if there's enough remaining rate limit
274
+ const remainingRateLimit = await this.getRemainingTotalRateLimit();
275
+ if (remainingRateLimit < this.rateLimit) {
276
+ console.error(`Not enough remaining rate limit. Requested: ${this.rateLimit}, Available: ${remainingRateLimit}`);
277
+ throw new Error(`Not enough remaining rate limit. Requested: ${this.rateLimit}, Available: ${remainingRateLimit}`);
278
+ }
279
+ console.log("registerWithIdentity - calling contract.register");
215
280
  const txRegisterResponse = await this.contract.register(identity.IDCommitmentBigInt, this.rateLimit, [], { gasLimit: 300000 });
281
+ console.log("registerWithIdentity - txRegisterResponse:", txRegisterResponse);
282
+ console.log("registerWithIdentity - hash:", txRegisterResponse.hash);
283
+ console.log("registerWithIdentity - waiting for transaction confirmation...");
216
284
  const txRegisterReceipt = await txRegisterResponse.wait();
285
+ console.log("registerWithIdentity - txRegisterReceipt:", txRegisterReceipt);
286
+ console.log("registerWithIdentity - transaction status:", txRegisterReceipt.status);
287
+ console.log("registerWithIdentity - block number:", txRegisterReceipt.blockNumber);
288
+ console.log("registerWithIdentity - gas used:", txRegisterReceipt.gasUsed.toString());
289
+ // Check transaction status
290
+ if (txRegisterReceipt.status === 0) {
291
+ console.error("Transaction failed on-chain");
292
+ throw new Error("Transaction failed on-chain");
293
+ }
217
294
  const memberRegistered = txRegisterReceipt.events?.find((event) => event.event === "MembershipRegistered");
295
+ console.log("registerWithIdentity - memberRegistered event:", memberRegistered);
218
296
  if (!memberRegistered || !memberRegistered.args) {
219
- log.error("Failed to register membership: No MembershipRegistered event found");
297
+ console.log("registerWithIdentity - ERROR: no memberRegistered event found");
298
+ console.log("registerWithIdentity - all events:", txRegisterReceipt.events);
299
+ console.error("Failed to register membership: No MembershipRegistered event found");
220
300
  return undefined;
221
301
  }
302
+ console.log("registerWithIdentity - memberRegistered args:", memberRegistered.args);
222
303
  const decodedData = {
223
304
  idCommitment: memberRegistered.args.idCommitment,
224
- rateLimit: memberRegistered.args.rateLimit,
305
+ membershipRateLimit: memberRegistered.args.membershipRateLimit,
225
306
  index: memberRegistered.args.index
226
307
  };
308
+ console.log("registerWithIdentity - decodedData:", decodedData);
309
+ console.log("registerWithIdentity - index:", decodedData.index.toString());
310
+ console.log("registerWithIdentity - membershipRateLimit:", decodedData.membershipRateLimit.toString());
227
311
  log.info(`Successfully registered membership with index ${decodedData.index} ` +
228
- `and rate limit ${decodedData.rateLimit}`);
312
+ `and rate limit ${decodedData.membershipRateLimit}`);
313
+ console.log("registerWithIdentity - getting network information");
229
314
  const network = await this.contract.provider.getNetwork();
315
+ console.log("registerWithIdentity - network:", network);
316
+ console.log("registerWithIdentity - chainId:", network.chainId);
230
317
  const address = this.contract.address;
318
+ console.log("registerWithIdentity - contract address:", address);
231
319
  const membershipId = decodedData.index.toNumber();
232
- return {
320
+ console.log("registerWithIdentity - membershipId:", membershipId);
321
+ const result = {
233
322
  identity,
234
323
  membership: {
235
324
  address,
@@ -237,10 +326,39 @@ class RLNContract {
237
326
  chainId: network.chainId
238
327
  }
239
328
  };
329
+ console.log("registerWithIdentity - returning result:", result);
330
+ return result;
240
331
  }
241
332
  catch (error) {
242
- log.error(`Error in registerWithIdentity: ${error.message}`);
243
- return undefined;
333
+ console.log("registerWithIdentity - ERROR:", error);
334
+ // Improved error handling to decode contract errors
335
+ if (error instanceof Error) {
336
+ const errorMessage = error.message;
337
+ console.log("registerWithIdentity - error message:", errorMessage);
338
+ console.log("registerWithIdentity - error stack:", error.stack);
339
+ // Try to extract more specific error information
340
+ if (errorMessage.includes("CannotExceedMaxTotalRateLimit")) {
341
+ console.error("Registration failed: Cannot exceed maximum total rate limit");
342
+ }
343
+ else if (errorMessage.includes("InvalidIdCommitment")) {
344
+ console.error("Registration failed: Invalid ID commitment");
345
+ }
346
+ else if (errorMessage.includes("InvalidMembershipRateLimit")) {
347
+ console.error("Registration failed: Invalid membership rate limit");
348
+ }
349
+ else if (errorMessage.includes("execution reverted")) {
350
+ // Generic revert
351
+ console.error("Contract execution reverted. Check contract requirements.");
352
+ }
353
+ else {
354
+ console.error(`Error in registerWithIdentity: ${errorMessage}`);
355
+ }
356
+ }
357
+ else {
358
+ console.error("Unknown error in registerWithIdentity");
359
+ }
360
+ // Re-throw the error to allow callers to handle it
361
+ throw error;
244
362
  }
245
363
  }
246
364
  /**
@@ -276,11 +394,11 @@ class RLNContract {
276
394
  }
277
395
  const decodedData = {
278
396
  idCommitment: memberRegistered.args.idCommitment,
279
- rateLimit: memberRegistered.args.rateLimit,
397
+ membershipRateLimit: memberRegistered.args.membershipRateLimit,
280
398
  index: memberRegistered.args.index
281
399
  };
282
400
  log.info(`Successfully registered membership with permit. Index: ${decodedData.index}, ` +
283
- `Rate limit: ${decodedData.rateLimit}, Erased ${idCommitmentsToErase.length} commitments`);
401
+ `Rate limit: ${decodedData.membershipRateLimit}, Erased ${idCommitmentsToErase.length} commitments`);
284
402
  const network = await this.contract.provider.getNetwork();
285
403
  const address = this.contract.address;
286
404
  const membershipId = decodedData.index.toNumber();
@@ -341,17 +459,22 @@ class RLNContract {
341
459
  }
342
460
  }
343
461
  async extendMembership(idCommitment) {
344
- return this.contract.extendMemberships([idCommitment]);
462
+ const tx = await this.contract.extendMemberships([idCommitment]);
463
+ return await tx.wait();
345
464
  }
346
465
  async eraseMembership(idCommitment, eraseFromMembershipSet = true) {
347
- return this.contract.eraseMemberships([idCommitment], eraseFromMembershipSet);
466
+ const tx = await this.contract.eraseMemberships([idCommitment], eraseFromMembershipSet);
467
+ return await tx.wait();
348
468
  }
349
469
  async registerMembership(idCommitment, rateLimit = DEFAULT_RATE_LIMIT) {
350
470
  if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
351
471
  rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
352
472
  throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
353
473
  }
354
- return this.contract.register(idCommitment, rateLimit, []);
474
+ console.log("registering membership", idCommitment, rateLimit);
475
+ const txn = this.contract.register(idCommitment, rateLimit, []);
476
+ console.log("txn", txn);
477
+ return txn;
355
478
  }
356
479
  async getMemberIndex(idCommitment) {
357
480
  try {
@@ -1,7 +1,3 @@
1
- import { arrayify } from '../../../node_modules/@ethersproject/bytes/lib.esm/index.js';
2
- import { keccak256 } from '../../../node_modules/@ethersproject/keccak256/lib.esm/index.js';
3
- import { Poseidon as m } from '../../../node_modules/@iden3/js-crypto/dist/browser/esm/index.js';
4
- import { streamXOR } from '../../../node_modules/@stablelib/chacha/lib/chacha.js';
5
1
  import { buildBigIntFromUint8Array } from './utils/bytes.js';
6
2
  import './utils/epoch.js';
7
3
 
@@ -29,26 +25,6 @@ class IdentityCredential {
29
25
  const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment, 32);
30
26
  return new IdentityCredential(idTrapdoor, idNullifier, idSecretHash, idCommitment, idCommitmentBigInt);
31
27
  }
32
- static generateSeeded(signature) {
33
- // Generate deterministic seed from signature
34
- const seed = arrayify(keccak256(signature));
35
- // Use ChaCha for deterministic randomness (as in Rust code)
36
- const nonce = new Uint8Array(12);
37
- const idSecretHash = new Uint8Array(32);
38
- streamXOR(seed, nonce, idSecretHash, idSecretHash);
39
- // Convert to bigint for Poseidon
40
- const secretBigInt = BigInt("0x" + Buffer.from(idSecretHash).toString("hex"));
41
- // Generate commitment using Poseidon
42
- const idCommitmentBigInt = m.hash([secretBigInt]);
43
- // Convert commitment back to Uint8Array
44
- const idCommitment = arrayify("0x" + idCommitmentBigInt.toString(16).padStart(64, "0"));
45
- // Generate deterministic trapdoor and nullifier from the secret hash
46
- const idTrapdoor = new Uint8Array(32);
47
- const idNullifier = new Uint8Array(32);
48
- streamXOR(idSecretHash, nonce, idTrapdoor, idTrapdoor);
49
- streamXOR(idTrapdoor, nonce, idNullifier, idNullifier);
50
- return new IdentityCredential(idTrapdoor, idNullifier, idSecretHash, idCommitment, idCommitmentBigInt);
51
- }
52
28
  }
53
29
 
54
30
  export { IdentityCredential };
@@ -21,27 +21,43 @@ import { Logger } from '../../utils/dist/logger/index.js';
21
21
  import '../../core/dist/lib/metadata/metadata.js';
22
22
  import __wbg_init, { init_panic_hook, newRLN } from '../../../node_modules/@waku/zerokit-rln-wasm/rln_wasm.js';
23
23
  import { createRLNEncoder, createRLNDecoder } from './codec.js';
24
+ import { DEFAULT_RATE_LIMIT, SEPOLIA_CONTRACT } from './contract/constants.js';
24
25
  import { RLNContract } from './contract/rln_contract.js';
25
- import { SEPOLIA_CONTRACT } from './contract/constants.js';
26
- import { IdentityCredential } from './identity.js';
27
26
  import { Keystore } from './keystore/keystore.js';
28
27
  import verificationKey from './resources/verification_key.js';
29
28
  import { builder } from './resources/witness_calculator.js';
30
29
  import { extractMetaMaskSigner } from './utils/metamask.js';
31
30
  import './utils/epoch.js';
32
31
  import { Zerokit } from './zerokit.js';
33
- import { arrayify } from '../../../node_modules/@ethersproject/bytes/lib.esm/index.js';
34
32
 
35
33
  const log = new Logger("waku:rln");
36
34
  async function loadWitnessCalculator() {
37
- const url = new URL("./resources/rln.wasm", import.meta.url);
38
- const response = await fetch(url);
39
- return await builder(new Uint8Array(await response.arrayBuffer()), false);
35
+ try {
36
+ const url = new URL("./resources/rln.wasm", import.meta.url);
37
+ const response = await fetch(url);
38
+ if (!response.ok) {
39
+ throw new Error(`Failed to fetch witness calculator: ${response.status} ${response.statusText}`);
40
+ }
41
+ return await builder(new Uint8Array(await response.arrayBuffer()), false);
42
+ }
43
+ catch (error) {
44
+ log.error("Error loading witness calculator:", error);
45
+ throw new Error(`Failed to load witness calculator: ${error instanceof Error ? error.message : String(error)}`);
46
+ }
40
47
  }
41
48
  async function loadZkey() {
42
- const url = new URL("./resources/rln_final.zkey", import.meta.url);
43
- const response = await fetch(url);
44
- return new Uint8Array(await response.arrayBuffer());
49
+ try {
50
+ const url = new URL("./resources/rln_final.zkey", import.meta.url);
51
+ const response = await fetch(url);
52
+ if (!response.ok) {
53
+ throw new Error(`Failed to fetch zkey: ${response.status} ${response.statusText}`);
54
+ }
55
+ return new Uint8Array(await response.arrayBuffer());
56
+ }
57
+ catch (error) {
58
+ log.error("Error loading zkey:", error);
59
+ throw new Error(`Failed to load zkey: ${error instanceof Error ? error.message : String(error)}`);
60
+ }
45
61
  }
46
62
  /**
47
63
  * Create an instance of RLN
@@ -58,7 +74,7 @@ async function create() {
58
74
  const vkey = stringEncoder.encode(JSON.stringify(verificationKey));
59
75
  const DEPTH = 20;
60
76
  const zkRLN = newRLN(DEPTH, zkey, vkey);
61
- const zerokit = new Zerokit(zkRLN, witnessCalculator);
77
+ const zerokit = new Zerokit(zkRLN, witnessCalculator, DEFAULT_RATE_LIMIT);
62
78
  return new RLNInstance(zerokit);
63
79
  }
64
80
  catch (error) {
@@ -99,7 +115,7 @@ class RLNInstance {
99
115
  this._contract = await RLNContract.init(this, {
100
116
  address: address,
101
117
  signer: signer,
102
- rateLimit: options.rateLimit
118
+ rateLimit: options.rateLimit ?? this.zerokit.getRateLimit
103
119
  });
104
120
  this.started = true;
105
121
  }
@@ -146,10 +162,12 @@ class RLNInstance {
146
162
  if (!this.contract) {
147
163
  throw Error("RLN Contract is not initialized.");
148
164
  }
149
- let identity = "identity" in options ? options.identity : undefined;
165
+ let identity = "identity" in options && options.identity;
150
166
  if ("signature" in options) {
151
- identity = IdentityCredential.generateSeeded(arrayify(options.signature));
167
+ identity = this.zerokit.generateSeededIdentityCredential(options.signature);
152
168
  }
169
+ // eslint-disable-next-line no-console
170
+ console.log("registering membership", identity);
153
171
  if (!identity) {
154
172
  throw Error("Missing signature or identity to register membership.");
155
173
  }
@@ -182,12 +200,12 @@ class RLNInstance {
182
200
  throw Error("Failed to verify chain coordinates: no contract initialized.");
183
201
  }
184
202
  const registryAddress = credentials.membership.address;
185
- const currentRegistryAddress = this._contract.contract.address;
203
+ const currentRegistryAddress = this._contract.address;
186
204
  if (registryAddress !== currentRegistryAddress) {
187
205
  throw Error(`Failed to verify chain coordinates: credentials contract address=${registryAddress} is not equal to registryContract address=${currentRegistryAddress}`);
188
206
  }
189
207
  const chainId = credentials.membership.chainId;
190
- const network = await this._contract.contract.provider.getNetwork();
208
+ const network = await this._contract.provider.getNetwork();
191
209
  const currentChainId = network.chainId;
192
210
  if (chainId !== currentChainId) {
193
211
  throw Error(`Failed to verify chain coordinates: credentials chainID=${chainId} is not equal to registryContract chainID=${currentChainId}`);
@@ -8,9 +8,20 @@ import { epochIntToBytes, dateToEpoch } from './utils/epoch.js';
8
8
  class Zerokit {
9
9
  zkRLN;
10
10
  witnessCalculator;
11
- constructor(zkRLN, witnessCalculator) {
11
+ rateLimit;
12
+ constructor(zkRLN, witnessCalculator, rateLimit = DEFAULT_RATE_LIMIT) {
12
13
  this.zkRLN = zkRLN;
13
14
  this.witnessCalculator = witnessCalculator;
15
+ this.rateLimit = rateLimit;
16
+ }
17
+ get getZkRLN() {
18
+ return this.zkRLN;
19
+ }
20
+ get getWitnessCalculator() {
21
+ return this.witnessCalculator;
22
+ }
23
+ get getRateLimit() {
24
+ return this.rateLimit;
14
25
  }
15
26
  generateIdentityCredentials() {
16
27
  const memKeys = generateExtendedMembershipKey(this.zkRLN); // TODO: rename this function in zerokit rln-wasm
@@ -39,32 +50,33 @@ class Zerokit {
39
50
  getMerkleRoot() {
40
51
  return getRoot(this.zkRLN);
41
52
  }
42
- serializeMessage(uint8Msg, memIndex, epoch, idKey, rateLimit = DEFAULT_RATE_LIMIT) {
53
+ serializeMessage(uint8Msg, memIndex, epoch, idKey, rateLimit) {
43
54
  // calculate message length
44
55
  const msgLen = writeUIntLE(new Uint8Array(8), uint8Msg.length, 0, 8);
45
56
  const memIndexBytes = writeUIntLE(new Uint8Array(8), memIndex, 0, 8);
46
- const rateLimitBytes = writeUIntLE(new Uint8Array(8), rateLimit, 0, 8);
57
+ const rateLimitBytes = writeUIntLE(new Uint8Array(8), rateLimit ?? this.rateLimit, 0, 8);
47
58
  // [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> | rate_limit<8> ]
48
59
  return concatenate(idKey, memIndexBytes, epoch, msgLen, uint8Msg, rateLimitBytes);
49
60
  }
50
- async generateRLNProof(msg, index, epoch, idSecretHash, rateLimit = DEFAULT_RATE_LIMIT) {
61
+ async generateRLNProof(msg, index, epoch, idSecretHash, rateLimit) {
51
62
  if (epoch === undefined) {
52
63
  epoch = epochIntToBytes(dateToEpoch(new Date()));
53
64
  }
54
65
  else if (epoch instanceof Date) {
55
66
  epoch = epochIntToBytes(dateToEpoch(epoch));
56
67
  }
68
+ const effectiveRateLimit = rateLimit ?? this.rateLimit;
57
69
  if (epoch.length !== 32)
58
70
  throw new Error("invalid epoch");
59
71
  if (idSecretHash.length !== 32)
60
72
  throw new Error("invalid id secret hash");
61
73
  if (index < 0)
62
74
  throw new Error("index must be >= 0");
63
- if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
64
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
75
+ if (effectiveRateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
76
+ effectiveRateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
65
77
  throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
66
78
  }
67
- const serialized_msg = this.serializeMessage(msg, index, epoch, idSecretHash, rateLimit);
79
+ const serialized_msg = this.serializeMessage(msg, index, epoch, idSecretHash, effectiveRateLimit);
68
80
  const rlnWitness = getSerializedRLNWitness(this.zkRLN, serialized_msg);
69
81
  const inputs = RLNWitnessToJson(this.zkRLN, rlnWitness);
70
82
  const calculatedWitness = await this.witnessCalculator.calculateWitness(inputs, false);
@@ -81,9 +93,7 @@ class Zerokit {
81
93
  }
82
94
  // calculate message length
83
95
  const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
84
- const rateLimitBytes = rateLimit
85
- ? writeUIntLE(new Uint8Array(8), rateLimit, 0, 8)
86
- : new Uint8Array(8); // Zero if not specified
96
+ const rateLimitBytes = writeUIntLE(new Uint8Array(8), rateLimit ?? this.rateLimit, 0, 8);
87
97
  return verifyRLNProof(this.zkRLN, concatenate(pBytes, msgLen, msg, rateLimitBytes));
88
98
  }
89
99
  verifyWithRoots(proof, msg, roots, rateLimit) {
@@ -96,9 +106,7 @@ class Zerokit {
96
106
  }
97
107
  // calculate message length
98
108
  const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
99
- const rateLimitBytes = rateLimit
100
- ? writeUIntLE(new Uint8Array(8), rateLimit, 0, 8)
101
- : new Uint8Array(8); // Zero if not specified
109
+ const rateLimitBytes = writeUIntLE(new Uint8Array(8), rateLimit ?? this.rateLimit, 0, 8);
102
110
  const rootsBytes = concatenate(...roots);
103
111
  return verifyWithRoots(this.zkRLN, concatenate(pBytes, msgLen, msg, rateLimitBytes), rootsBytes);
104
112
  }
@@ -112,9 +120,7 @@ class Zerokit {
112
120
  }
113
121
  // calculate message length
114
122
  const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
115
- const rateLimitBytes = rateLimit
116
- ? writeUIntLE(new Uint8Array(8), rateLimit, 0, 8)
117
- : new Uint8Array(8); // Zero if not specified
123
+ const rateLimitBytes = writeUIntLE(new Uint8Array(8), rateLimit ?? this.rateLimit, 0, 8);
118
124
  return verifyWithRoots(this.zkRLN, concatenate(pBytes, msgLen, msg, rateLimitBytes), new Uint8Array());
119
125
  }
120
126
  }