@waku/rln 0.1.5-1d384f2.0 → 0.1.5-35b50c3.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.
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  import { Logger } from "@waku/utils";
2
3
  import { ethers } from "ethers";
3
4
 
@@ -33,15 +34,6 @@ export class RLNBaseContract {
33
34
  * Allows injecting a mocked contract for testing purposes.
34
35
  */
35
36
  public constructor(options: RLNContractInitOptions) {
36
- // Initialize members and subscriptions
37
- this.fetchMembers()
38
- .then(() => {
39
- this.subscribeToMembers();
40
- })
41
- .catch((error) => {
42
- log.error("Failed to initialize members", { error });
43
- });
44
-
45
37
  const {
46
38
  address,
47
39
  signer,
@@ -49,15 +41,38 @@ export class RLNBaseContract {
49
41
  contract
50
42
  } = options;
51
43
 
52
- this.validateRateLimit(rateLimit);
44
+ log.info("Initializing RLNBaseContract", { address, rateLimit });
53
45
 
54
46
  this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
55
47
  this.rateLimit = rateLimit;
56
48
 
57
- // Initialize event filters
58
- this._membersFilter = this.contract.filters.MembershipRegistered();
59
- this._membershipErasedFilter = this.contract.filters.MembershipErased();
60
- this._membersExpiredFilter = this.contract.filters.MembershipExpired();
49
+ try {
50
+ log.info("Setting up event filters");
51
+ // Initialize event filters
52
+ this._membersFilter = this.contract.filters.MembershipRegistered();
53
+ this._membershipErasedFilter = this.contract.filters.MembershipErased();
54
+ this._membersExpiredFilter = this.contract.filters.MembershipExpired();
55
+ log.info("Event filters initialized successfully");
56
+ } catch (error) {
57
+ log.error("Failed to initialize event filters", { error });
58
+ throw new Error(
59
+ "Failed to initialize event filters: " + (error as Error).message
60
+ );
61
+ }
62
+
63
+ // Initialize members and subscriptions
64
+ this.fetchMembers()
65
+ .then(() => {
66
+ this.subscribeToMembers();
67
+ })
68
+ .catch((error) => {
69
+ log.error("Failed to initialize members", { error });
70
+ });
71
+
72
+ // Validate rate limit asynchronously
73
+ this.validateRateLimit(rateLimit).catch((error) => {
74
+ log.error("Failed to validate initial rate limit", { error });
75
+ });
61
76
  }
62
77
 
63
78
  /**
@@ -134,7 +149,7 @@ export class RLNBaseContract {
134
149
  * @param newRateLimit The new rate limit to use
135
150
  */
136
151
  public async setRateLimit(newRateLimit: number): Promise<void> {
137
- this.validateRateLimit(newRateLimit);
152
+ await this.validateRateLimit(newRateLimit);
138
153
  this.rateLimit = newRateLimit;
139
154
  }
140
155
 
@@ -324,7 +339,7 @@ export class RLNBaseContract {
324
339
  this.contract.on(
325
340
  this.membersFilter,
326
341
  (
327
- _idCommitment: string,
342
+ _idCommitment: bigint,
328
343
  _membershipRateLimit: ethers.BigNumber,
329
344
  _index: ethers.BigNumber,
330
345
  event: ethers.Event
@@ -336,7 +351,7 @@ export class RLNBaseContract {
336
351
  this.contract.on(
337
352
  this.membershipErasedFilter,
338
353
  (
339
- _idCommitment: string,
354
+ _idCommitment: bigint,
340
355
  _membershipRateLimit: ethers.BigNumber,
341
356
  _index: ethers.BigNumber,
342
357
  event: ethers.Event
@@ -348,7 +363,7 @@ export class RLNBaseContract {
348
363
  this.contract.on(
349
364
  this.membersExpiredFilter,
350
365
  (
351
- _idCommitment: string,
366
+ _idCommitment: bigint,
352
367
  _membershipRateLimit: ethers.BigNumber,
353
368
  _index: ethers.BigNumber,
354
369
  event: ethers.Event
@@ -358,94 +373,87 @@ export class RLNBaseContract {
358
373
  );
359
374
  }
360
375
 
361
- /**
362
- * Helper method to get remaining messages in current epoch
363
- * @param membershipId The ID of the membership to check
364
- * @returns number of remaining messages allowed in current epoch
365
- */
366
- public async getRemainingMessages(membershipId: number): Promise<number> {
367
- try {
368
- const [startTime, , rateLimit] =
369
- await this.contract.getMembershipInfo(membershipId);
370
-
371
- // Calculate current epoch
372
- const currentTime = Math.floor(Date.now() / 1000);
373
- const epochsPassed = Math.floor(
374
- (currentTime - startTime) / RATE_LIMIT_PARAMS.EPOCH_LENGTH
375
- );
376
- const currentEpochStart =
377
- startTime + epochsPassed * RATE_LIMIT_PARAMS.EPOCH_LENGTH;
378
-
379
- // Get message count in current epoch using contract's function
380
- const messageCount = await this.contract.getMessageCount(
381
- membershipId,
382
- currentEpochStart
383
- );
384
- return Math.max(
385
- 0,
386
- ethers.BigNumber.from(rateLimit)
387
- .sub(ethers.BigNumber.from(messageCount))
388
- .toNumber()
389
- );
390
- } catch (error) {
391
- log.error(
392
- `Error getting remaining messages: ${(error as Error).message}`
393
- );
394
- return 0; // Fail safe: assume no messages remaining on error
395
- }
396
- }
397
-
398
376
  public async getMembershipInfo(
399
- idCommitment: string
377
+ idCommitmentBigInt: bigint
400
378
  ): Promise<MembershipInfo | undefined> {
401
379
  try {
402
- const [startBlock, endBlock, rateLimit] =
403
- await this.contract.getMembershipInfo(idCommitment);
380
+ const membershipData =
381
+ await this.contract.memberships(idCommitmentBigInt);
404
382
  const currentBlock = await this.contract.provider.getBlockNumber();
383
+ console.log("membershipData", membershipData);
384
+
385
+ const [
386
+ depositAmount,
387
+ activeDuration,
388
+ gracePeriodStartTimestamp,
389
+ gracePeriodDuration,
390
+ rateLimit,
391
+ index,
392
+ holder,
393
+ token
394
+ ] = membershipData;
395
+
396
+ const gracePeriodEnd = gracePeriodStartTimestamp.add(gracePeriodDuration);
405
397
 
406
398
  let state: MembershipState;
407
- if (currentBlock < startBlock) {
399
+ if (currentBlock < gracePeriodStartTimestamp.toNumber()) {
408
400
  state = MembershipState.Active;
409
- } else if (currentBlock < endBlock) {
401
+ } else if (currentBlock < gracePeriodEnd.toNumber()) {
410
402
  state = MembershipState.GracePeriod;
411
403
  } else {
412
404
  state = MembershipState.Expired;
413
405
  }
414
406
 
415
- const index = await this.getMemberIndex(idCommitment);
416
- if (!index) return undefined;
417
-
418
407
  return {
419
408
  index,
420
- idCommitment,
421
- rateLimit: rateLimit.toNumber(),
422
- startBlock: startBlock.toNumber(),
423
- endBlock: endBlock.toNumber(),
424
- state
409
+ idCommitment: idCommitmentBigInt.toString(),
410
+ rateLimit: Number(rateLimit),
411
+ startBlock: gracePeriodStartTimestamp.toNumber(),
412
+ endBlock: gracePeriodEnd.toNumber(),
413
+ state,
414
+ depositAmount,
415
+ activeDuration,
416
+ gracePeriodDuration,
417
+ holder,
418
+ token
425
419
  };
426
420
  } catch (error) {
421
+ console.error("Error in getMembershipInfo:", error);
427
422
  return undefined;
428
423
  }
429
424
  }
430
425
 
431
426
  public async extendMembership(
432
- idCommitment: string
427
+ idCommitmentBigInt: bigint
433
428
  ): Promise<ethers.ContractTransaction> {
434
- return this.contract.extendMemberships([idCommitment]);
429
+ const tx = await this.contract.extendMemberships([idCommitmentBigInt]);
430
+ await tx.wait();
431
+ return tx;
435
432
  }
436
433
 
437
434
  public async eraseMembership(
438
- idCommitment: string,
435
+ idCommitmentBigInt: bigint,
439
436
  eraseFromMembershipSet: boolean = true
440
437
  ): Promise<ethers.ContractTransaction> {
441
- return this.contract.eraseMemberships(
442
- [idCommitment],
438
+ const tx = await this.contract.eraseMemberships(
439
+ [idCommitmentBigInt],
443
440
  eraseFromMembershipSet
444
441
  );
442
+ await tx.wait();
443
+ return tx;
444
+ }
445
+
446
+ public async withdraw(token: string, from: string): Promise<void> {
447
+ try {
448
+ const tx = await this.contract.withdraw(token, from);
449
+ await tx.wait();
450
+ } catch (error) {
451
+ log.error(`Error in withdraw: ${(error as Error).message}`);
452
+ }
445
453
  }
446
454
 
447
455
  public async registerMembership(
448
- idCommitment: string,
456
+ idCommitmentBigInt: bigint,
449
457
  rateLimit: number = DEFAULT_RATE_LIMIT
450
458
  ): Promise<ethers.ContractTransaction> {
451
459
  if (
@@ -456,16 +464,7 @@ export class RLNBaseContract {
456
464
  `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
457
465
  );
458
466
  }
459
- return this.contract.register(idCommitment, rateLimit, []);
460
- }
461
-
462
- public async withdraw(token: string, holder: string): Promise<void> {
463
- try {
464
- const tx = await this.contract.withdraw(token, { from: holder });
465
- await tx.wait();
466
- } catch (error) {
467
- log.error(`Error in withdraw: ${(error as Error).message}`);
468
- }
467
+ return this.contract.register(idCommitmentBigInt, rateLimit, []);
469
468
  }
470
469
 
471
470
  public async registerWithIdentity(
@@ -478,7 +477,7 @@ export class RLNBaseContract {
478
477
 
479
478
  // Check if the ID commitment is already registered
480
479
  const existingIndex = await this.getMemberIndex(
481
- identity.IDCommitmentBigInt.toString()
480
+ identity.IDCommitmentBigInt
482
481
  );
483
482
  if (existingIndex) {
484
483
  throw new Error(
@@ -656,13 +655,18 @@ export class RLNBaseContract {
656
655
  * Validates that the rate limit is within the allowed range
657
656
  * @throws Error if the rate limit is outside the allowed range
658
657
  */
659
- private validateRateLimit(rateLimit: number): void {
660
- if (
661
- rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
662
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
663
- ) {
658
+ private async validateRateLimit(rateLimit: number): Promise<void> {
659
+ const [minRate, maxRate] = await Promise.all([
660
+ this.contract.minMembershipRateLimit(),
661
+ this.contract.maxMembershipRateLimit()
662
+ ]);
663
+
664
+ const minRateNum = ethers.BigNumber.from(minRate).toNumber();
665
+ const maxRateNum = ethers.BigNumber.from(maxRate).toNumber();
666
+
667
+ if (rateLimit < minRateNum || rateLimit > maxRateNum) {
664
668
  throw new Error(
665
- `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE} messages per epoch`
669
+ `Rate limit must be between ${minRateNum} and ${maxRateNum} messages per epoch`
666
670
  );
667
671
  }
668
672
  }
@@ -689,11 +693,11 @@ export class RLNBaseContract {
689
693
  }
690
694
 
691
695
  private async getMemberIndex(
692
- idCommitment: string
696
+ idCommitmentBigInt: bigint
693
697
  ): Promise<ethers.BigNumber | undefined> {
694
698
  try {
695
699
  const events = await this.contract.queryFilter(
696
- this.contract.filters.MembershipRegistered(idCommitment)
700
+ this.contract.filters.MembershipRegistered(idCommitmentBigInt)
697
701
  );
698
702
  if (events.length === 0) return undefined;
699
703
 
@@ -38,6 +38,11 @@ export interface MembershipInfo {
38
38
  startBlock: number;
39
39
  endBlock: number;
40
40
  state: MembershipState;
41
+ depositAmount: ethers.BigNumber;
42
+ activeDuration: number;
43
+ gracePeriodDuration: number;
44
+ holder: string;
45
+ token: string;
41
46
  }
42
47
 
43
48
  export enum MembershipState {
package/src/index.ts CHANGED
@@ -34,7 +34,9 @@ export type {
34
34
  Keccak256Hash,
35
35
  KeystoreEntity,
36
36
  MembershipHash,
37
- MembershipInfo,
37
+ KeystoreMembershipInfo,
38
38
  Password,
39
39
  Sha256Hash
40
40
  } from "./keystore/types.js";
41
+
42
+ export * from "./contract/index.js";
@@ -21,8 +21,8 @@ import { isCredentialValid, isKeystoreValid } from "./schema_validator.js";
21
21
  import type {
22
22
  Keccak256Hash,
23
23
  KeystoreEntity,
24
+ KeystoreMembershipInfo,
24
25
  MembershipHash,
25
- MembershipInfo,
26
26
  Password,
27
27
  Sha256Hash
28
28
  } from "./types.js";
@@ -310,7 +310,9 @@ export class Keystore {
310
310
 
311
311
  // follows nwaku implementation
312
312
  // https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L111
313
- private static computeMembershipHash(info: MembershipInfo): MembershipHash {
313
+ private static computeMembershipHash(
314
+ info: KeystoreMembershipInfo
315
+ ): MembershipHash {
314
316
  return bytesToHex(
315
317
  sha256(utf8ToBytes(`${info.chainId}${info.address}${info.treeIndex}`))
316
318
  ).toUpperCase();
@@ -7,7 +7,7 @@ export type Password = string | Uint8Array;
7
7
 
8
8
  // see reference
9
9
  // https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L111
10
- export type MembershipInfo = {
10
+ export type KeystoreMembershipInfo = {
11
11
  chainId: string;
12
12
  address: string;
13
13
  treeIndex: number;
@@ -16,7 +16,7 @@ export type MembershipInfo = {
16
16
 
17
17
  export type KeystoreEntity = {
18
18
  identity: IdentityCredential;
19
- membership: MembershipInfo;
19
+ membership: KeystoreMembershipInfo;
20
20
  };
21
21
 
22
22
  export type DecryptedCredentials = KeystoreEntity;