@waku/rln 0.0.2-8a6571f.0 → 0.0.2-a3e7f15.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.
@@ -25,7 +25,8 @@ class RLNContract {
25
25
  rateLimit;
26
26
  _members = new Map();
27
27
  _membersFilter;
28
- _membersRemovedFilter;
28
+ _membershipErasedFilter;
29
+ _membersExpiredFilter;
29
30
  /**
30
31
  * Asynchronous initializer for RLNContract.
31
32
  * Allows injecting a mocked contract for testing purposes.
@@ -47,9 +48,10 @@ class RLNContract {
47
48
  // Use the injected contract if provided; otherwise, instantiate a new one.
48
49
  this.contract = contract || new Contract(address, RLN_ABI, signer);
49
50
  this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
50
- // Initialize event filters for MembershipRegistered and MembershipErased
51
+ // Initialize event filters
51
52
  this._membersFilter = this.contract.filters.MembershipRegistered();
52
- this._membersRemovedFilter = this.contract.filters.MembershipErased();
53
+ this._membershipErasedFilter = this.contract.filters.MembershipErased();
54
+ this._membersExpiredFilter = this.contract.filters.MembershipExpired();
53
55
  }
54
56
  /**
55
57
  * Gets the current rate limit for this contract instance
@@ -110,7 +112,7 @@ class RLNContract {
110
112
  this.contract.maxTotalRateLimit(),
111
113
  this.contract.currentTotalRateLimit()
112
114
  ]);
113
- return maxTotal.sub(currentTotal).toNumber();
115
+ return Number(maxTotal) - Number(currentTotal);
114
116
  }
115
117
  /**
116
118
  * Updates the rate limit for future registrations
@@ -129,11 +131,17 @@ class RLNContract {
129
131
  }
130
132
  return this._membersFilter;
131
133
  }
132
- get membersRemovedFilter() {
133
- if (!this._membersRemovedFilter) {
134
- throw Error("MembersErased filter was not initialized.");
134
+ get membershipErasedFilter() {
135
+ if (!this._membershipErasedFilter) {
136
+ throw Error("MembershipErased filter was not initialized.");
135
137
  }
136
- return this._membersRemovedFilter;
138
+ return this._membershipErasedFilter;
139
+ }
140
+ get membersExpiredFilter() {
141
+ if (!this._membersExpiredFilter) {
142
+ throw Error("MembersExpired filter was not initialized.");
143
+ }
144
+ return this._membersExpiredFilter;
137
145
  }
138
146
  async fetchMembers(rlnInstance, options = {}) {
139
147
  const registeredMemberEvents = await queryFilter(this.contract, {
@@ -144,9 +152,18 @@ class RLNContract {
144
152
  const removedMemberEvents = await queryFilter(this.contract, {
145
153
  fromBlock: this.deployBlock,
146
154
  ...options,
147
- membersFilter: this.membersRemovedFilter
155
+ membersFilter: this.membershipErasedFilter
148
156
  });
149
- const events = [...registeredMemberEvents, ...removedMemberEvents];
157
+ const expiredMemberEvents = await queryFilter(this.contract, {
158
+ fromBlock: this.deployBlock,
159
+ ...options,
160
+ membersFilter: this.membersExpiredFilter
161
+ });
162
+ const events = [
163
+ ...registeredMemberEvents,
164
+ ...removedMemberEvents,
165
+ ...expiredMemberEvents
166
+ ];
150
167
  this.processEvents(rlnInstance, events);
151
168
  }
152
169
  processEvents(rlnInstance, events) {
@@ -156,8 +173,15 @@ class RLNContract {
156
173
  if (!evt.args) {
157
174
  return;
158
175
  }
159
- if (evt.event === "MembershipErased") {
160
- const index = evt.args.index;
176
+ if (evt.event === "MembershipErased" ||
177
+ evt.event === "MembershipExpired") {
178
+ let index = evt.args.index;
179
+ if (!index) {
180
+ return;
181
+ }
182
+ if (typeof index === "number" || typeof index === "string") {
183
+ index = BigNumber.from(index);
184
+ }
161
185
  const toRemoveVal = toRemoveTable.get(evt.blockNumber);
162
186
  if (toRemoveVal != undefined) {
163
187
  toRemoveVal.push(index.toNumber());
@@ -185,13 +209,17 @@ class RLNContract {
185
209
  if (!evt.args)
186
210
  return;
187
211
  const _idCommitment = evt.args.idCommitment;
188
- const index = evt.args.index;
212
+ let index = evt.args.index;
189
213
  if (!_idCommitment || !index) {
190
214
  return;
191
215
  }
216
+ if (typeof index === "number" || typeof index === "string") {
217
+ index = BigNumber.from(index);
218
+ }
192
219
  const idCommitment = zeroPadLE(hexToBytes(_idCommitment), 32);
193
220
  rlnInstance.zerokit.insertMember(idCommitment);
194
- this._members.set(index.toNumber(), {
221
+ const numericIndex = index.toNumber();
222
+ this._members.set(numericIndex, {
195
223
  index,
196
224
  idCommitment: _idCommitment
197
225
  });
@@ -213,18 +241,36 @@ class RLNContract {
213
241
  });
214
242
  }
215
243
  subscribeToMembers(rlnInstance) {
216
- this.contract.on(this.membersFilter, (_idCommitment, _rateLimit, _index, event) => {
244
+ this.contract.on(this.membersFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
245
+ this.processEvents(rlnInstance, [event]);
246
+ });
247
+ this.contract.on(this.membershipErasedFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
217
248
  this.processEvents(rlnInstance, [event]);
218
249
  });
219
- this.contract.on(this.membersRemovedFilter, (_idCommitment, _rateLimit, _index, event) => {
250
+ this.contract.on(this.membersExpiredFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
220
251
  this.processEvents(rlnInstance, [event]);
221
252
  });
222
253
  }
223
254
  async registerWithIdentity(identity) {
224
255
  try {
225
256
  log.info(`Registering identity with rate limit: ${this.rateLimit} messages/epoch`);
226
- const txRegisterResponse = await this.contract.register(identity.IDCommitmentBigInt, this.rateLimit, [], { gasLimit: 300000 });
257
+ // Check if the ID commitment is already registered
258
+ const existingIndex = await this.getMemberIndex(identity.IDCommitmentBigInt.toString());
259
+ if (existingIndex) {
260
+ throw new Error(`ID commitment is already registered with index ${existingIndex}`);
261
+ }
262
+ // Check if there's enough remaining rate limit
263
+ const remainingRateLimit = await this.getRemainingTotalRateLimit();
264
+ if (remainingRateLimit < this.rateLimit) {
265
+ throw new Error(`Not enough remaining rate limit. Requested: ${this.rateLimit}, Available: ${remainingRateLimit}`);
266
+ }
267
+ const estimatedGas = await this.contract.estimateGas.register(identity.IDCommitmentBigInt, this.rateLimit, []);
268
+ const gasLimit = estimatedGas.add(10000);
269
+ const txRegisterResponse = await this.contract.register(identity.IDCommitmentBigInt, this.rateLimit, [], { gasLimit });
227
270
  const txRegisterReceipt = await txRegisterResponse.wait();
271
+ if (txRegisterReceipt.status === 0) {
272
+ throw new Error("Transaction failed on-chain");
273
+ }
228
274
  const memberRegistered = txRegisterReceipt.events?.find((event) => event.event === "MembershipRegistered");
229
275
  if (!memberRegistered || !memberRegistered.args) {
230
276
  log.error("Failed to register membership: No MembershipRegistered event found");
@@ -232,14 +278,14 @@ class RLNContract {
232
278
  }
233
279
  const decodedData = {
234
280
  idCommitment: memberRegistered.args.idCommitment,
235
- rateLimit: memberRegistered.args.rateLimit,
281
+ membershipRateLimit: memberRegistered.args.membershipRateLimit,
236
282
  index: memberRegistered.args.index
237
283
  };
238
284
  log.info(`Successfully registered membership with index ${decodedData.index} ` +
239
- `and rate limit ${decodedData.rateLimit}`);
285
+ `and rate limit ${decodedData.membershipRateLimit}`);
240
286
  const network = await this.contract.provider.getNetwork();
241
287
  const address = this.contract.address;
242
- const membershipId = decodedData.index.toNumber();
288
+ const membershipId = Number(decodedData.index);
243
289
  return {
244
290
  identity,
245
291
  membership: {
@@ -250,8 +296,32 @@ class RLNContract {
250
296
  };
251
297
  }
252
298
  catch (error) {
253
- log.error(`Error in registerWithIdentity: ${error.message}`);
254
- return undefined;
299
+ if (error instanceof Error) {
300
+ const errorMessage = error.message;
301
+ log.error("registerWithIdentity - error message:", errorMessage);
302
+ log.error("registerWithIdentity - error stack:", error.stack);
303
+ // Try to extract more specific error information
304
+ if (errorMessage.includes("CannotExceedMaxTotalRateLimit")) {
305
+ throw new Error("Registration failed: Cannot exceed maximum total rate limit");
306
+ }
307
+ else if (errorMessage.includes("InvalidIdCommitment")) {
308
+ throw new Error("Registration failed: Invalid ID commitment");
309
+ }
310
+ else if (errorMessage.includes("InvalidMembershipRateLimit")) {
311
+ throw new Error("Registration failed: Invalid membership rate limit");
312
+ }
313
+ else if (errorMessage.includes("execution reverted")) {
314
+ throw new Error("Contract execution reverted. Check contract requirements.");
315
+ }
316
+ else {
317
+ throw new Error(`Error in registerWithIdentity: ${errorMessage}`);
318
+ }
319
+ }
320
+ else {
321
+ throw new Error("Unknown error in registerWithIdentity", {
322
+ cause: error
323
+ });
324
+ }
255
325
  }
256
326
  }
257
327
  /**
@@ -287,14 +357,14 @@ class RLNContract {
287
357
  }
288
358
  const decodedData = {
289
359
  idCommitment: memberRegistered.args.idCommitment,
290
- rateLimit: memberRegistered.args.rateLimit,
360
+ membershipRateLimit: memberRegistered.args.membershipRateLimit,
291
361
  index: memberRegistered.args.index
292
362
  };
293
363
  log.info(`Successfully registered membership with permit. Index: ${decodedData.index}, ` +
294
- `Rate limit: ${decodedData.rateLimit}, Erased ${idCommitmentsToErase.length} commitments`);
364
+ `Rate limit: ${decodedData.membershipRateLimit}, Erased ${idCommitmentsToErase.length} commitments`);
295
365
  const network = await this.contract.provider.getNetwork();
296
366
  const address = this.contract.address;
297
- const membershipId = decodedData.index.toNumber();
367
+ const membershipId = Number(decodedData.index);
298
368
  return {
299
369
  identity,
300
370
  membership: {
@@ -100,8 +100,6 @@ class RLNInstance {
100
100
  return this._signer;
101
101
  }
102
102
  async start(options = {}) {
103
- // eslint-disable-next-line no-console
104
- console.log("starting", options);
105
103
  if (this.started || this.starting) {
106
104
  return;
107
105
  }
@@ -133,12 +131,6 @@ class RLNInstance {
133
131
  if (address === SEPOLIA_CONTRACT.address) {
134
132
  chainId = SEPOLIA_CONTRACT.chainId;
135
133
  }
136
- // eslint-disable-next-line no-console
137
- console.log({
138
- chainId,
139
- address,
140
- SEPOLIA_CONTRACT
141
- });
142
134
  const signer = options.signer || (await extractMetaMaskSigner());
143
135
  const currentChainId = await signer.getChainId();
144
136
  if (chainId && chainId !== currentChainId) {