@waku/rln 0.1.6-006cd41.0 → 0.1.6-6d86b6f.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 (87) hide show
  1. package/bundle/_virtual/index2.js +1 -1
  2. package/bundle/index.js +2 -1
  3. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/checksum.js +3 -3
  4. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/cipher.js +4 -4
  5. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/class.js +7 -7
  6. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/functional.js +7 -7
  7. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/index.js +6 -6
  8. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/kdf.js +5 -5
  9. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/password.js +1 -1
  10. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/schema-validation-generated.js +1 -1
  11. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/schema-validation.js +2 -2
  12. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/types.js +1 -1
  13. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/_assert.js +1 -1
  14. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/_sha2.js +3 -3
  15. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/_u64.js +1 -1
  16. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/cryptoBrowser.js +1 -1
  17. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/hmac.js +3 -3
  18. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/pbkdf2.js +4 -4
  19. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/scrypt.js +5 -5
  20. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/sha256.js +3 -3
  21. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/sha512.js +4 -4
  22. package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/utils.js +2 -2
  23. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/aes.js +3 -3
  24. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/pbkdf2.js +7 -7
  25. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +3 -3
  26. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/scrypt.js +3 -3
  27. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/sha256.js +3 -3
  28. package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +7 -7
  29. package/bundle/node_modules/@ethersproject/keccak256/lib.esm/index.js +1 -1
  30. package/bundle/node_modules/@noble/hashes/esm/_assert.js +6 -32
  31. package/bundle/node_modules/@noble/hashes/esm/_md.js +22 -11
  32. package/bundle/node_modules/@noble/hashes/esm/_u64.js +4 -3
  33. package/bundle/{packages/rln/node_modules → node_modules}/@noble/hashes/esm/hmac.js +19 -10
  34. package/bundle/{packages/rln/node_modules/@noble/hashes/esm/sha256.js → node_modules/@noble/hashes/esm/sha2.js} +36 -50
  35. package/bundle/node_modules/@noble/hashes/esm/sha256.js +5 -102
  36. package/bundle/node_modules/@noble/hashes/esm/sha3.js +30 -24
  37. package/bundle/node_modules/@noble/hashes/esm/utils.js +69 -18
  38. package/bundle/node_modules/bn.js/lib/bn.js +1 -0
  39. package/bundle/node_modules/ethereum-cryptography/esm/sha256.js +1 -1
  40. package/bundle/node_modules/{@ethersproject/keccak256/node_modules/js-sha3 → js-sha3}/src/sha3.js +2 -2
  41. package/bundle/packages/rln/dist/contract/constants.js +1 -0
  42. package/bundle/packages/rln/dist/contract/rln_base_contract.js +127 -71
  43. package/bundle/packages/rln/dist/credentials_manager.js +3 -3
  44. package/bundle/packages/rln/dist/keystore/cipher.js +3 -3
  45. package/bundle/packages/rln/dist/keystore/keystore.js +1 -1
  46. package/dist/.tsbuildinfo +1 -1
  47. package/dist/contract/index.d.ts +1 -0
  48. package/dist/contract/index.js +1 -0
  49. package/dist/contract/index.js.map +1 -1
  50. package/dist/contract/rln_base_contract.d.ts +32 -22
  51. package/dist/contract/rln_base_contract.js +127 -71
  52. package/dist/contract/rln_base_contract.js.map +1 -1
  53. package/dist/contract/types.d.ts +5 -0
  54. package/dist/contract/types.js.map +1 -1
  55. package/dist/credentials_manager.js +1 -1
  56. package/dist/credentials_manager.js.map +1 -1
  57. package/dist/index.d.ts +2 -1
  58. package/dist/index.js +1 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/keystore/keystore.js.map +1 -1
  61. package/dist/keystore/types.d.ts +2 -2
  62. package/package.json +1 -1
  63. package/src/contract/index.ts +1 -0
  64. package/src/contract/rln_base_contract.ts +166 -102
  65. package/src/contract/types.ts +5 -0
  66. package/src/credentials_manager.ts +1 -1
  67. package/src/index.ts +3 -1
  68. package/src/keystore/keystore.ts +4 -2
  69. package/src/keystore/types.ts +2 -2
  70. package/bundle/packages/rln/node_modules/@noble/hashes/esm/_assert.js +0 -43
  71. package/bundle/packages/rln/node_modules/@noble/hashes/esm/_sha2.js +0 -116
  72. package/bundle/packages/rln/node_modules/@noble/hashes/esm/utils.js +0 -43
  73. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/index.js +0 -0
  74. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/md5.js +0 -0
  75. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/nil.js +0 -0
  76. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/parse.js +0 -0
  77. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/regex.js +0 -0
  78. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/rng.js +0 -0
  79. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/sha1.js +0 -0
  80. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/stringify.js +0 -0
  81. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v1.js +0 -0
  82. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v3.js +0 -0
  83. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v35.js +0 -0
  84. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v4.js +0 -0
  85. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v5.js +0 -0
  86. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/validate.js +0 -0
  87. /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/version.js +0 -0
@@ -1,2 +1,3 @@
1
1
  export { RLNContract } from "./rln_contract.js";
2
2
  export * from "./constants.js";
3
+ export * from "./types.js";
@@ -22,6 +22,8 @@ export class RLNBaseContract {
22
22
  public contract: ethers.Contract;
23
23
  private deployBlock: undefined | number;
24
24
  private rateLimit: number;
25
+ private minRateLimit?: number;
26
+ private maxRateLimit?: number;
25
27
 
26
28
  protected _members: Map<number, Member> = new Map();
27
29
  private _membersFilter: ethers.EventFilter;
@@ -29,19 +31,9 @@ export class RLNBaseContract {
29
31
  private _membersExpiredFilter: ethers.EventFilter;
30
32
 
31
33
  /**
32
- * Constructor for RLNBaseContract.
33
- * Allows injecting a mocked contract for testing purposes.
34
+ * Private constructor for RLNBaseContract. Use static create() instead.
34
35
  */
35
- 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
-
36
+ protected constructor(options: RLNContractInitOptions) {
45
37
  const {
46
38
  address,
47
39
  signer,
@@ -49,15 +41,51 @@ 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
+
73
+ /**
74
+ * Static async factory to create and initialize RLNBaseContract
75
+ */
76
+ public static async create(
77
+ options: RLNContractInitOptions
78
+ ): Promise<RLNBaseContract> {
79
+ const instance = new RLNBaseContract(options);
80
+ const [min, max] = await Promise.all([
81
+ instance.contract.minMembershipRateLimit(),
82
+ instance.contract.maxMembershipRateLimit()
83
+ ]);
84
+ instance.minRateLimit = ethers.BigNumber.from(min).toNumber();
85
+ instance.maxRateLimit = ethers.BigNumber.from(max).toNumber();
86
+
87
+ instance.validateRateLimit(instance.rateLimit);
88
+ return instance;
61
89
  }
62
90
 
63
91
  /**
@@ -82,21 +110,21 @@ export class RLNBaseContract {
82
110
  }
83
111
 
84
112
  /**
85
- * Gets the minimum allowed rate limit from the contract
86
- * @returns Promise<number> The minimum rate limit in messages per epoch
113
+ * Gets the minimum allowed rate limit (cached)
87
114
  */
88
- public async getMinRateLimit(): Promise<number> {
89
- const minRate = await this.contract.minMembershipRateLimit();
90
- return ethers.BigNumber.from(minRate).toNumber();
115
+ public getMinRateLimit(): number {
116
+ if (this.minRateLimit === undefined)
117
+ throw new Error("minRateLimit not initialized");
118
+ return this.minRateLimit;
91
119
  }
92
120
 
93
121
  /**
94
- * Gets the maximum allowed rate limit from the contract
95
- * @returns Promise<number> The maximum rate limit in messages per epoch
122
+ * Gets the maximum allowed rate limit (cached)
96
123
  */
97
- public async getMaxRateLimit(): Promise<number> {
98
- const maxRate = await this.contract.maxMembershipRateLimit();
99
- return ethers.BigNumber.from(maxRate).toNumber();
124
+ public getMaxRateLimit(): number {
125
+ if (this.maxRateLimit === undefined)
126
+ throw new Error("maxRateLimit not initialized");
127
+ return this.maxRateLimit;
100
128
  }
101
129
 
102
130
  /**
@@ -133,7 +161,7 @@ export class RLNBaseContract {
133
161
  * Updates the rate limit for future registrations
134
162
  * @param newRateLimit The new rate limit to use
135
163
  */
136
- public async setRateLimit(newRateLimit: number): Promise<void> {
164
+ public setRateLimit(newRateLimit: number): void {
137
165
  this.validateRateLimit(newRateLimit);
138
166
  this.rateLimit = newRateLimit;
139
167
  }
@@ -324,7 +352,7 @@ export class RLNBaseContract {
324
352
  this.contract.on(
325
353
  this.membersFilter,
326
354
  (
327
- _idCommitment: string,
355
+ _idCommitment: bigint,
328
356
  _membershipRateLimit: ethers.BigNumber,
329
357
  _index: ethers.BigNumber,
330
358
  event: ethers.Event
@@ -336,7 +364,7 @@ export class RLNBaseContract {
336
364
  this.contract.on(
337
365
  this.membershipErasedFilter,
338
366
  (
339
- _idCommitment: string,
367
+ _idCommitment: bigint,
340
368
  _membershipRateLimit: ethers.BigNumber,
341
369
  _index: ethers.BigNumber,
342
370
  event: ethers.Event
@@ -348,7 +376,7 @@ export class RLNBaseContract {
348
376
  this.contract.on(
349
377
  this.membersExpiredFilter,
350
378
  (
351
- _idCommitment: string,
379
+ _idCommitment: bigint,
352
380
  _membershipRateLimit: ethers.BigNumber,
353
381
  _index: ethers.BigNumber,
354
382
  event: ethers.Event
@@ -358,94 +386,89 @@ export class RLNBaseContract {
358
386
  );
359
387
  }
360
388
 
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
389
  public async getMembershipInfo(
399
- idCommitment: string
390
+ idCommitmentBigInt: bigint
400
391
  ): Promise<MembershipInfo | undefined> {
401
392
  try {
402
- const [startBlock, endBlock, rateLimit] =
403
- await this.contract.getMembershipInfo(idCommitment);
393
+ const membershipData =
394
+ await this.contract.memberships(idCommitmentBigInt);
404
395
  const currentBlock = await this.contract.provider.getBlockNumber();
396
+ const [
397
+ depositAmount,
398
+ activeDuration,
399
+ gracePeriodStartTimestamp,
400
+ gracePeriodDuration,
401
+ rateLimit,
402
+ index,
403
+ holder,
404
+ token
405
+ ] = membershipData;
406
+
407
+ const gracePeriodEnd = gracePeriodStartTimestamp.add(gracePeriodDuration);
405
408
 
406
409
  let state: MembershipState;
407
- if (currentBlock < startBlock) {
410
+ if (currentBlock < gracePeriodStartTimestamp.toNumber()) {
408
411
  state = MembershipState.Active;
409
- } else if (currentBlock < endBlock) {
412
+ } else if (currentBlock < gracePeriodEnd.toNumber()) {
410
413
  state = MembershipState.GracePeriod;
411
414
  } else {
412
415
  state = MembershipState.Expired;
413
416
  }
414
417
 
415
- const index = await this.getMemberIndex(idCommitment);
416
- if (!index) return undefined;
417
-
418
418
  return {
419
419
  index,
420
- idCommitment,
421
- rateLimit: rateLimit.toNumber(),
422
- startBlock: startBlock.toNumber(),
423
- endBlock: endBlock.toNumber(),
424
- state
420
+ idCommitment: idCommitmentBigInt.toString(),
421
+ rateLimit: Number(rateLimit),
422
+ startBlock: gracePeriodStartTimestamp.toNumber(),
423
+ endBlock: gracePeriodEnd.toNumber(),
424
+ state,
425
+ depositAmount,
426
+ activeDuration,
427
+ gracePeriodDuration,
428
+ holder,
429
+ token
425
430
  };
426
431
  } catch (error) {
432
+ log.error("Error in getMembershipInfo:", error);
427
433
  return undefined;
428
434
  }
429
435
  }
430
436
 
431
437
  public async extendMembership(
432
- idCommitment: string
438
+ idCommitmentBigInt: bigint
433
439
  ): Promise<ethers.ContractTransaction> {
434
- return this.contract.extendMemberships([idCommitment]);
440
+ const tx = await this.contract.extendMemberships([idCommitmentBigInt]);
441
+ await tx.wait();
442
+ return tx;
435
443
  }
436
444
 
437
445
  public async eraseMembership(
438
- idCommitment: string,
446
+ idCommitmentBigInt: bigint,
439
447
  eraseFromMembershipSet: boolean = true
440
448
  ): Promise<ethers.ContractTransaction> {
441
- return this.contract.eraseMemberships(
442
- [idCommitment],
443
- eraseFromMembershipSet
449
+ if (
450
+ !(await this.isExpired(idCommitmentBigInt)) ||
451
+ !(await this.isInGracePeriod(idCommitmentBigInt))
452
+ ) {
453
+ throw new Error("Membership is not expired or in grace period");
454
+ }
455
+
456
+ const estimatedGas = await this.contract.estimateGas[
457
+ "eraseMemberships(uint256[],bool)"
458
+ ]([idCommitmentBigInt], eraseFromMembershipSet);
459
+ const gasLimit = estimatedGas.add(10000);
460
+
461
+ const tx = await this.contract["eraseMemberships(uint256[],bool)"](
462
+ [idCommitmentBigInt],
463
+ eraseFromMembershipSet,
464
+ { gasLimit }
444
465
  );
466
+ await tx.wait();
467
+ return tx;
445
468
  }
446
469
 
447
470
  public async registerMembership(
448
- idCommitment: string,
471
+ idCommitmentBigInt: bigint,
449
472
  rateLimit: number = DEFAULT_RATE_LIMIT
450
473
  ): Promise<ethers.ContractTransaction> {
451
474
  if (
@@ -456,12 +479,12 @@ export class RLNBaseContract {
456
479
  `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
457
480
  );
458
481
  }
459
- return this.contract.register(idCommitment, rateLimit, []);
482
+ return this.contract.register(idCommitmentBigInt, rateLimit, []);
460
483
  }
461
484
 
462
- public async withdraw(token: string, holder: string): Promise<void> {
485
+ public async withdraw(token: string, from: string): Promise<void> {
463
486
  try {
464
- const tx = await this.contract.withdraw(token, { from: holder });
487
+ const tx = await this.contract.withdraw(token, from);
465
488
  await tx.wait();
466
489
  } catch (error) {
467
490
  log.error(`Error in withdraw: ${(error as Error).message}`);
@@ -478,7 +501,7 @@ export class RLNBaseContract {
478
501
 
479
502
  // Check if the ID commitment is already registered
480
503
  const existingIndex = await this.getMemberIndex(
481
- identity.IDCommitmentBigInt.toString()
504
+ identity.IDCommitmentBigInt
482
505
  );
483
506
  if (existingIndex) {
484
507
  throw new Error(
@@ -516,7 +539,7 @@ export class RLNBaseContract {
516
539
  }
517
540
 
518
541
  const memberRegistered = txRegisterReceipt.events?.find(
519
- (event) => event.event === "MembershipRegistered"
542
+ (event: ethers.Event) => event.event === "MembershipRegistered"
520
543
  );
521
544
 
522
545
  if (!memberRegistered || !memberRegistered.args) {
@@ -610,7 +633,7 @@ export class RLNBaseContract {
610
633
  const txRegisterReceipt = await txRegisterResponse.wait();
611
634
 
612
635
  const memberRegistered = txRegisterReceipt.events?.find(
613
- (event) => event.event === "MembershipRegistered"
636
+ (event: ethers.Event) => event.event === "MembershipRegistered"
614
637
  );
615
638
 
616
639
  if (!memberRegistered || !memberRegistered.args) {
@@ -653,16 +676,16 @@ export class RLNBaseContract {
653
676
  }
654
677
 
655
678
  /**
656
- * Validates that the rate limit is within the allowed range
679
+ * Validates that the rate limit is within the allowed range (sync)
657
680
  * @throws Error if the rate limit is outside the allowed range
658
681
  */
659
682
  private validateRateLimit(rateLimit: number): void {
660
- if (
661
- rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
662
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
663
- ) {
683
+ if (this.minRateLimit === undefined || this.maxRateLimit === undefined) {
684
+ throw new Error("Rate limits not initialized");
685
+ }
686
+ if (rateLimit < this.minRateLimit || rateLimit > this.maxRateLimit) {
664
687
  throw new Error(
665
- `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE} messages per epoch`
688
+ `Rate limit must be between ${this.minRateLimit} and ${this.maxRateLimit} messages per epoch`
666
689
  );
667
690
  }
668
691
  }
@@ -689,11 +712,11 @@ export class RLNBaseContract {
689
712
  }
690
713
 
691
714
  private async getMemberIndex(
692
- idCommitment: string
715
+ idCommitmentBigInt: bigint
693
716
  ): Promise<ethers.BigNumber | undefined> {
694
717
  try {
695
718
  const events = await this.contract.queryFilter(
696
- this.contract.filters.MembershipRegistered(idCommitment)
719
+ this.contract.filters.MembershipRegistered(idCommitmentBigInt)
697
720
  );
698
721
  if (events.length === 0) return undefined;
699
722
 
@@ -704,4 +727,45 @@ export class RLNBaseContract {
704
727
  return undefined;
705
728
  }
706
729
  }
730
+
731
+ public async getMembershipStatus(
732
+ idCommitment: bigint
733
+ ): Promise<"expired" | "grace" | "active"> {
734
+ const [isExpired, isInGrace] = await Promise.all([
735
+ this.contract.isExpired(idCommitment),
736
+ this.contract.isInGracePeriod(idCommitment)
737
+ ]);
738
+
739
+ if (isExpired) return "expired";
740
+ if (isInGrace) return "grace";
741
+ return "active";
742
+ }
743
+
744
+ /**
745
+ * Checks if a membership is expired for the given idCommitment
746
+ * @param idCommitmentBigInt The idCommitment as bigint
747
+ * @returns Promise<boolean> True if expired, false otherwise
748
+ */
749
+ public async isExpired(idCommitmentBigInt: bigint): Promise<boolean> {
750
+ try {
751
+ return await this.contract.isExpired(idCommitmentBigInt);
752
+ } catch (error) {
753
+ log.error("Error in isExpired:", error);
754
+ return false;
755
+ }
756
+ }
757
+
758
+ /**
759
+ * Checks if a membership is in grace period for the given idCommitment
760
+ * @param idCommitmentBigInt The idCommitment as bigint
761
+ * @returns Promise<boolean> True if in grace period, false otherwise
762
+ */
763
+ public async isInGracePeriod(idCommitmentBigInt: bigint): Promise<boolean> {
764
+ try {
765
+ return await this.contract.isInGracePeriod(idCommitmentBigInt);
766
+ } catch (error) {
767
+ log.error("Error in isInGracePeriod:", error);
768
+ return false;
769
+ }
770
+ }
707
771
  }
@@ -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 {
@@ -80,7 +80,7 @@ export class RLNCredentialsManager {
80
80
 
81
81
  this.credentials = credentials;
82
82
  this.signer = signer!;
83
- this.contract = new RLNBaseContract({
83
+ this.contract = await RLNBaseContract.create({
84
84
  address: address!,
85
85
  signer: signer!,
86
86
  rateLimit: rateLimit ?? this.zerokit?.rateLimit
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;
@@ -1,43 +0,0 @@
1
- function number(n) {
2
- if (!Number.isSafeInteger(n) || n < 0)
3
- throw new Error(`Wrong positive integer: ${n}`);
4
- }
5
- function bool(b) {
6
- if (typeof b !== 'boolean')
7
- throw new Error(`Expected boolean, not ${b}`);
8
- }
9
- function bytes(b, ...lengths) {
10
- if (!(b instanceof Uint8Array))
11
- throw new TypeError('Expected Uint8Array');
12
- if (lengths.length > 0 && !lengths.includes(b.length))
13
- throw new TypeError(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
14
- }
15
- function hash(hash) {
16
- if (typeof hash !== 'function' || typeof hash.create !== 'function')
17
- throw new Error('Hash should be wrapped by utils.wrapConstructor');
18
- number(hash.outputLen);
19
- number(hash.blockLen);
20
- }
21
- function exists(instance, checkFinished = true) {
22
- if (instance.destroyed)
23
- throw new Error('Hash instance has been destroyed');
24
- if (checkFinished && instance.finished)
25
- throw new Error('Hash#digest() has already been called');
26
- }
27
- function output(out, instance) {
28
- bytes(out);
29
- const min = instance.outputLen;
30
- if (out.length < min) {
31
- throw new Error(`digestInto() expects output buffer of length at least ${min}`);
32
- }
33
- }
34
- const assert = {
35
- number,
36
- bool,
37
- bytes,
38
- hash,
39
- exists,
40
- output,
41
- };
42
-
43
- export { bool, bytes, assert as default, exists, hash, number, output };
@@ -1,116 +0,0 @@
1
- import assert from './_assert.js';
2
- import { Hash, createView, toBytes } from './utils.js';
3
-
4
- // Polyfill for Safari 14
5
- function setBigUint64(view, byteOffset, value, isLE) {
6
- if (typeof view.setBigUint64 === 'function')
7
- return view.setBigUint64(byteOffset, value, isLE);
8
- const _32n = BigInt(32);
9
- const _u32_max = BigInt(0xffffffff);
10
- const wh = Number((value >> _32n) & _u32_max);
11
- const wl = Number(value & _u32_max);
12
- const h = isLE ? 4 : 0;
13
- const l = isLE ? 0 : 4;
14
- view.setUint32(byteOffset + h, wh, isLE);
15
- view.setUint32(byteOffset + l, wl, isLE);
16
- }
17
- // Base SHA2 class (RFC 6234)
18
- class SHA2 extends Hash {
19
- constructor(blockLen, outputLen, padOffset, isLE) {
20
- super();
21
- this.blockLen = blockLen;
22
- this.outputLen = outputLen;
23
- this.padOffset = padOffset;
24
- this.isLE = isLE;
25
- this.finished = false;
26
- this.length = 0;
27
- this.pos = 0;
28
- this.destroyed = false;
29
- this.buffer = new Uint8Array(blockLen);
30
- this.view = createView(this.buffer);
31
- }
32
- update(data) {
33
- assert.exists(this);
34
- const { view, buffer, blockLen } = this;
35
- data = toBytes(data);
36
- const len = data.length;
37
- for (let pos = 0; pos < len;) {
38
- const take = Math.min(blockLen - this.pos, len - pos);
39
- // Fast path: we have at least one block in input, cast it to view and process
40
- if (take === blockLen) {
41
- const dataView = createView(data);
42
- for (; blockLen <= len - pos; pos += blockLen)
43
- this.process(dataView, pos);
44
- continue;
45
- }
46
- buffer.set(data.subarray(pos, pos + take), this.pos);
47
- this.pos += take;
48
- pos += take;
49
- if (this.pos === blockLen) {
50
- this.process(view, 0);
51
- this.pos = 0;
52
- }
53
- }
54
- this.length += data.length;
55
- this.roundClean();
56
- return this;
57
- }
58
- digestInto(out) {
59
- assert.exists(this);
60
- assert.output(out, this);
61
- this.finished = true;
62
- // Padding
63
- // We can avoid allocation of buffer for padding completely if it
64
- // was previously not allocated here. But it won't change performance.
65
- const { buffer, view, blockLen, isLE } = this;
66
- let { pos } = this;
67
- // append the bit '1' to the message
68
- buffer[pos++] = 0b10000000;
69
- this.buffer.subarray(pos).fill(0);
70
- // we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
71
- if (this.padOffset > blockLen - pos) {
72
- this.process(view, 0);
73
- pos = 0;
74
- }
75
- // Pad until full block byte with zeros
76
- for (let i = pos; i < blockLen; i++)
77
- buffer[i] = 0;
78
- // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
79
- // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
80
- // So we just write lowest 64 bits of that value.
81
- setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
82
- this.process(view, 0);
83
- const oview = createView(out);
84
- const len = this.outputLen;
85
- // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
86
- if (len % 4)
87
- throw new Error('_sha2: outputLen should be aligned to 32bit');
88
- const outLen = len / 4;
89
- const state = this.get();
90
- if (outLen > state.length)
91
- throw new Error('_sha2: outputLen bigger than state');
92
- for (let i = 0; i < outLen; i++)
93
- oview.setUint32(4 * i, state[i], isLE);
94
- }
95
- digest() {
96
- const { buffer, outputLen } = this;
97
- this.digestInto(buffer);
98
- const res = buffer.slice(0, outputLen);
99
- this.destroy();
100
- return res;
101
- }
102
- _cloneInto(to) {
103
- to || (to = new this.constructor());
104
- to.set(...this.get());
105
- const { blockLen, buffer, length, finished, destroyed, pos } = this;
106
- to.length = length;
107
- to.pos = pos;
108
- to.finished = finished;
109
- to.destroyed = destroyed;
110
- if (length % blockLen)
111
- to.buffer.set(buffer);
112
- return to;
113
- }
114
- }
115
-
116
- export { SHA2 };