@waku/rln 0.1.5-cad3e7a.0 → 0.1.5-d0da8f8.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 (179) hide show
  1. package/bundle/_virtual/utils.js +2 -2
  2. package/bundle/_virtual/utils2.js +2 -2
  3. package/bundle/index.js +4 -3
  4. package/bundle/packages/rln/dist/contract/constants.js +2 -1
  5. package/bundle/packages/rln/dist/contract/{rln_light_contract.js → rln_base_contract.js} +189 -186
  6. package/bundle/packages/rln/dist/contract/rln_contract.js +10 -420
  7. package/bundle/packages/rln/dist/contract/types.js +9 -0
  8. package/bundle/packages/rln/dist/create.js +1 -1
  9. package/bundle/packages/rln/dist/{rln_light.js → credentials_manager.js} +114 -48
  10. package/bundle/packages/rln/dist/identity.js +0 -9
  11. package/bundle/packages/rln/dist/keystore/keystore.js +31 -17
  12. package/bundle/packages/rln/dist/rln.js +57 -167
  13. package/bundle/packages/rln/dist/utils/bytes.js +8 -2
  14. package/bundle/packages/rln/dist/utils/metamask.js +2 -2
  15. package/bundle/packages/rln/dist/zerokit.js +5 -5
  16. package/bundle/packages/rln/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +1 -1
  17. package/bundle/packages/rln/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +2 -2
  18. package/bundle/packages/rln/node_modules/@noble/hashes/_sha2.js +1 -1
  19. package/bundle/packages/rln/node_modules/@noble/hashes/hmac.js +1 -1
  20. package/bundle/packages/rln/node_modules/@noble/hashes/pbkdf2.js +1 -1
  21. package/bundle/packages/rln/node_modules/@noble/hashes/scrypt.js +1 -1
  22. package/bundle/packages/rln/node_modules/@noble/hashes/sha256.js +1 -1
  23. package/bundle/packages/rln/node_modules/@noble/hashes/sha512.js +1 -1
  24. package/bundle/packages/rln/node_modules/@noble/hashes/utils.js +1 -1
  25. package/dist/.tsbuildinfo +1 -1
  26. package/dist/contract/constants.d.ts +1 -1
  27. package/dist/contract/constants.js +1 -1
  28. package/dist/contract/constants.js.map +1 -1
  29. package/dist/contract/index.d.ts +1 -0
  30. package/dist/contract/index.js +1 -0
  31. package/dist/contract/index.js.map +1 -1
  32. package/dist/contract/{rln_light_contract.d.ts → rln_base_contract.d.ts} +24 -58
  33. package/dist/contract/{rln_light_contract.js → rln_base_contract.js} +187 -184
  34. package/dist/contract/rln_base_contract.js.map +1 -0
  35. package/dist/contract/rln_contract.d.ts +5 -122
  36. package/dist/contract/rln_contract.js +8 -417
  37. package/dist/contract/rln_contract.js.map +1 -1
  38. package/dist/contract/types.d.ts +45 -0
  39. package/dist/contract/types.js +8 -0
  40. package/dist/contract/types.js.map +1 -0
  41. package/dist/create.js +1 -1
  42. package/dist/create.js.map +1 -1
  43. package/dist/credentials_manager.d.ts +44 -0
  44. package/dist/credentials_manager.js +197 -0
  45. package/dist/credentials_manager.js.map +1 -0
  46. package/dist/identity.d.ts +0 -1
  47. package/dist/identity.js +0 -9
  48. package/dist/identity.js.map +1 -1
  49. package/dist/index.d.ts +5 -4
  50. package/dist/index.js +4 -3
  51. package/dist/index.js.map +1 -1
  52. package/dist/keystore/keystore.d.ts +1 -0
  53. package/dist/keystore/keystore.js +31 -17
  54. package/dist/keystore/keystore.js.map +1 -1
  55. package/dist/keystore/types.d.ts +3 -3
  56. package/dist/rln.d.ts +9 -52
  57. package/dist/rln.js +55 -164
  58. package/dist/rln.js.map +1 -1
  59. package/dist/types.d.ts +27 -0
  60. package/dist/types.js +2 -0
  61. package/dist/types.js.map +1 -0
  62. package/dist/utils/bytes.js +8 -2
  63. package/dist/utils/bytes.js.map +1 -1
  64. package/dist/zerokit.d.ts +3 -3
  65. package/dist/zerokit.js +5 -5
  66. package/dist/zerokit.js.map +1 -1
  67. package/package.json +1 -1
  68. package/src/contract/constants.ts +1 -1
  69. package/src/contract/index.ts +1 -0
  70. package/src/contract/{rln_light_contract.ts → rln_base_contract.ts} +306 -323
  71. package/src/contract/rln_contract.ts +9 -663
  72. package/src/contract/types.ts +53 -0
  73. package/src/create.ts +1 -1
  74. package/src/credentials_manager.ts +282 -0
  75. package/src/identity.ts +0 -10
  76. package/src/index.ts +7 -5
  77. package/src/keystore/keystore.ts +57 -31
  78. package/src/keystore/types.ts +3 -3
  79. package/src/rln.ts +68 -259
  80. package/src/types.ts +31 -0
  81. package/src/utils/bytes.ts +10 -2
  82. package/src/zerokit.ts +3 -3
  83. package/bundle/_virtual/__node-resolve_empty.js +0 -6
  84. package/bundle/_virtual/_node-resolve_empty.js +0 -3
  85. package/bundle/_virtual/bn.js +0 -3
  86. package/bundle/_virtual/common.js +0 -3
  87. package/bundle/_virtual/common2.js +0 -3
  88. package/bundle/_virtual/hash.js +0 -3
  89. package/bundle/_virtual/inherits_browser.js +0 -3
  90. package/bundle/_virtual/ripemd.js +0 -3
  91. package/bundle/_virtual/sha.js +0 -3
  92. package/bundle/_virtual/sha3.js +0 -3
  93. package/bundle/_virtual/utils3.js +0 -3
  94. package/bundle/node_modules/@ethersproject/abi/lib.esm/_version.js +0 -3
  95. package/bundle/node_modules/@ethersproject/abi/lib.esm/abi-coder.js +0 -96
  96. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/abstract-coder.js +0 -148
  97. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/address.js +0 -26
  98. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/anonymous.js +0 -20
  99. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/array.js +0 -210
  100. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/boolean.js +0 -18
  101. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/bytes.js +0 -30
  102. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/fixed-bytes.js +0 -26
  103. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/null.js +0 -22
  104. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/number.js +0 -43
  105. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/string.js +0 -19
  106. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/tuple.js +0 -58
  107. package/bundle/node_modules/@ethersproject/abi/lib.esm/fragments.js +0 -854
  108. package/bundle/node_modules/@ethersproject/abi/lib.esm/interface.js +0 -609
  109. package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/_version.js +0 -3
  110. package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/index.js +0 -66
  111. package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/_version.js +0 -3
  112. package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/index.js +0 -302
  113. package/bundle/node_modules/@ethersproject/address/lib.esm/_version.js +0 -3
  114. package/bundle/node_modules/@ethersproject/address/lib.esm/index.js +0 -110
  115. package/bundle/node_modules/@ethersproject/base64/lib.esm/base64.js +0 -20
  116. package/bundle/node_modules/@ethersproject/basex/lib.esm/index.js +0 -120
  117. package/bundle/node_modules/@ethersproject/bignumber/lib.esm/_version.js +0 -3
  118. package/bundle/node_modules/@ethersproject/bignumber/lib.esm/bignumber.js +0 -287
  119. package/bundle/node_modules/@ethersproject/bytes/lib.esm/_version.js +0 -3
  120. package/bundle/node_modules/@ethersproject/bytes/lib.esm/index.js +0 -402
  121. package/bundle/node_modules/@ethersproject/constants/lib.esm/addresses.js +0 -3
  122. package/bundle/node_modules/@ethersproject/constants/lib.esm/bignumbers.js +0 -8
  123. package/bundle/node_modules/@ethersproject/constants/lib.esm/hashes.js +0 -3
  124. package/bundle/node_modules/@ethersproject/contracts/lib.esm/_version.js +0 -3
  125. package/bundle/node_modules/@ethersproject/contracts/lib.esm/index.js +0 -893
  126. package/bundle/node_modules/@ethersproject/hash/lib.esm/_version.js +0 -3
  127. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/decoder.js +0 -256
  128. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/include.js +0 -36
  129. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/lib.js +0 -135
  130. package/bundle/node_modules/@ethersproject/hash/lib.esm/id.js +0 -8
  131. package/bundle/node_modules/@ethersproject/hash/lib.esm/namehash.js +0 -64
  132. package/bundle/node_modules/@ethersproject/hash/lib.esm/typed-data.js +0 -443
  133. package/bundle/node_modules/@ethersproject/keccak256/lib.esm/index.js +0 -8
  134. package/bundle/node_modules/@ethersproject/keccak256/node_modules/js-sha3/src/sha3.js +0 -660
  135. package/bundle/node_modules/@ethersproject/logger/lib.esm/_version.js +0 -3
  136. package/bundle/node_modules/@ethersproject/logger/lib.esm/index.js +0 -352
  137. package/bundle/node_modules/@ethersproject/networks/lib.esm/_version.js +0 -3
  138. package/bundle/node_modules/@ethersproject/networks/lib.esm/index.js +0 -248
  139. package/bundle/node_modules/@ethersproject/properties/lib.esm/_version.js +0 -3
  140. package/bundle/node_modules/@ethersproject/properties/lib.esm/index.js +0 -127
  141. package/bundle/node_modules/@ethersproject/providers/lib.esm/_version.js +0 -3
  142. package/bundle/node_modules/@ethersproject/providers/lib.esm/base-provider.js +0 -2007
  143. package/bundle/node_modules/@ethersproject/providers/lib.esm/formatter.js +0 -422
  144. package/bundle/node_modules/@ethersproject/providers/lib.esm/json-rpc-provider.js +0 -674
  145. package/bundle/node_modules/@ethersproject/providers/lib.esm/web3-provider.js +0 -132
  146. package/bundle/node_modules/@ethersproject/rlp/lib.esm/_version.js +0 -3
  147. package/bundle/node_modules/@ethersproject/rlp/lib.esm/index.js +0 -120
  148. package/bundle/node_modules/@ethersproject/sha2/lib.esm/sha2.js +0 -8
  149. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/_version.js +0 -3
  150. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/elliptic.js +0 -2430
  151. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/index.js +0 -76
  152. package/bundle/node_modules/@ethersproject/strings/lib.esm/_version.js +0 -3
  153. package/bundle/node_modules/@ethersproject/strings/lib.esm/utf8.js +0 -219
  154. package/bundle/node_modules/@ethersproject/transactions/lib.esm/_version.js +0 -3
  155. package/bundle/node_modules/@ethersproject/transactions/lib.esm/index.js +0 -279
  156. package/bundle/node_modules/@ethersproject/web/lib.esm/_version.js +0 -3
  157. package/bundle/node_modules/@ethersproject/web/lib.esm/geturl.js +0 -69
  158. package/bundle/node_modules/@ethersproject/web/lib.esm/index.js +0 -404
  159. package/bundle/node_modules/bech32/index.js +0 -187
  160. package/bundle/node_modules/bn.js/lib/bn.js +0 -3361
  161. package/bundle/node_modules/hash.js/lib/hash/common.js +0 -97
  162. package/bundle/node_modules/hash.js/lib/hash/hmac.js +0 -51
  163. package/bundle/node_modules/hash.js/lib/hash/ripemd.js +0 -152
  164. package/bundle/node_modules/hash.js/lib/hash/sha/1.js +0 -81
  165. package/bundle/node_modules/hash.js/lib/hash/sha/224.js +0 -33
  166. package/bundle/node_modules/hash.js/lib/hash/sha/256.js +0 -113
  167. package/bundle/node_modules/hash.js/lib/hash/sha/384.js +0 -39
  168. package/bundle/node_modules/hash.js/lib/hash/sha/512.js +0 -336
  169. package/bundle/node_modules/hash.js/lib/hash/sha/common.js +0 -53
  170. package/bundle/node_modules/hash.js/lib/hash/sha.js +0 -14
  171. package/bundle/node_modules/hash.js/lib/hash/utils.js +0 -282
  172. package/bundle/node_modules/hash.js/lib/hash.js +0 -33
  173. package/bundle/node_modules/inherits/inherits_browser.js +0 -33
  174. package/bundle/node_modules/minimalistic-assert/index.js +0 -13
  175. package/dist/contract/rln_light_contract.js.map +0 -1
  176. package/dist/rln_light.d.ts +0 -64
  177. package/dist/rln_light.js +0 -144
  178. package/dist/rln_light.js.map +0 -1
  179. package/src/rln_light.ts +0 -235
@@ -1,84 +1,38 @@
1
1
  import { Logger } from "@waku/utils";
2
2
  import { ethers } from "ethers";
3
3
 
4
- import type { IdentityCredential } from "../identity.js";
5
- import type { DecryptedCredentials } from "../keystore/index.js";
4
+ import { IdentityCredential } from "../identity.js";
5
+ import { DecryptedCredentials } from "../keystore/types.js";
6
6
 
7
7
  import { RLN_ABI } from "./abi.js";
8
8
  import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from "./constants.js";
9
-
10
- const log = new Logger("waku:rln:contract");
11
-
12
- type Member = {
13
- idCommitment: string;
14
- index: ethers.BigNumber;
15
- };
16
-
17
- interface RLNContractOptions {
18
- signer: ethers.Signer;
19
- address: string;
20
- rateLimit?: number;
21
- }
22
-
23
- interface RLNContractInitOptions extends RLNContractOptions {
24
- contract?: ethers.Contract;
25
- }
26
-
27
- export interface MembershipRegisteredEvent {
28
- idCommitment: string;
29
- membershipRateLimit: ethers.BigNumber;
30
- index: ethers.BigNumber;
31
- }
32
-
33
- type FetchMembersOptions = {
34
- fromBlock?: number;
35
- fetchRange?: number;
36
- fetchChunks?: number;
37
- };
38
-
39
- export interface MembershipInfo {
40
- index: ethers.BigNumber;
41
- idCommitment: string;
42
- rateLimit: number;
43
- startBlock: number;
44
- endBlock: number;
45
- state: MembershipState;
46
- }
47
-
48
- export enum MembershipState {
49
- Active = "Active",
50
- GracePeriod = "GracePeriod",
51
- Expired = "Expired",
52
- ErasedAwaitsWithdrawal = "ErasedAwaitsWithdrawal"
53
- }
54
-
55
- export class RLNLightContract {
9
+ import {
10
+ CustomQueryOptions,
11
+ FetchMembersOptions,
12
+ Member,
13
+ MembershipInfo,
14
+ MembershipRegisteredEvent,
15
+ MembershipState,
16
+ RLNContractInitOptions
17
+ } from "./types.js";
18
+
19
+ const log = new Logger("waku:rln:contract:base");
20
+
21
+ export class RLNBaseContract {
56
22
  public contract: ethers.Contract;
57
-
58
23
  private deployBlock: undefined | number;
59
24
  private rateLimit: number;
60
25
 
61
- private _members: Map<number, Member> = new Map();
26
+ protected _members: Map<number, Member> = new Map();
62
27
  private _membersFilter: ethers.EventFilter;
63
28
  private _membershipErasedFilter: ethers.EventFilter;
64
29
  private _membersExpiredFilter: ethers.EventFilter;
65
30
 
66
31
  /**
67
- * Asynchronous initializer for RLNContract.
32
+ * Constructor for RLNBaseContract.
68
33
  * Allows injecting a mocked contract for testing purposes.
69
34
  */
70
- public static async init(
71
- options: RLNContractInitOptions
72
- ): Promise<RLNLightContract> {
73
- const rlnContract = new RLNLightContract(options);
74
-
75
- await rlnContract.fetchMembers();
76
- rlnContract.subscribeToMembers();
77
-
78
- return rlnContract;
79
- }
80
-
81
- private constructor(options: RLNContractInitOptions) {
35
+ public constructor(options: RLNContractInitOptions) {
82
36
  const {
83
37
  address,
84
38
  signer,
@@ -86,24 +40,38 @@ export class RLNLightContract {
86
40
  contract
87
41
  } = options;
88
42
 
89
- if (
90
- rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
91
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
92
- ) {
93
- throw new Error(
94
- `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE} messages per epoch`
95
- );
96
- }
43
+ log.info("Initializing RLNBaseContract", { address, rateLimit });
97
44
 
45
+ this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
98
46
  this.rateLimit = rateLimit;
99
47
 
100
- // Use the injected contract if provided; otherwise, instantiate a new one.
101
- this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
48
+ try {
49
+ log.info("Setting up event filters");
50
+ // Initialize event filters
51
+ this._membersFilter = this.contract.filters.MembershipRegistered();
52
+ this._membershipErasedFilter = this.contract.filters.MembershipErased();
53
+ this._membersExpiredFilter = this.contract.filters.MembershipExpired();
54
+ log.info("Event filters initialized successfully");
55
+ } catch (error) {
56
+ log.error("Failed to initialize event filters", { error });
57
+ throw new Error(
58
+ "Failed to initialize event filters: " + (error as Error).message
59
+ );
60
+ }
102
61
 
103
- // Initialize event filters
104
- this._membersFilter = this.contract.filters.MembershipRegistered();
105
- this._membershipErasedFilter = this.contract.filters.MembershipErased();
106
- this._membersExpiredFilter = this.contract.filters.MembershipExpired();
62
+ // Initialize members and subscriptions
63
+ this.fetchMembers()
64
+ .then(() => {
65
+ this.subscribeToMembers();
66
+ })
67
+ .catch((error) => {
68
+ log.error("Failed to initialize members", { error });
69
+ });
70
+
71
+ // Validate rate limit asynchronously
72
+ this.validateRateLimit(rateLimit).catch((error) => {
73
+ log.error("Failed to validate initial rate limit", { error });
74
+ });
107
75
  }
108
76
 
109
77
  /**
@@ -151,7 +119,7 @@ export class RLNLightContract {
151
119
  */
152
120
  public async getMaxTotalRateLimit(): Promise<number> {
153
121
  const maxTotalRate = await this.contract.maxTotalRateLimit();
154
- return ethers.BigNumber.from(maxTotalRate).toNumber();
122
+ return maxTotalRate.toNumber();
155
123
  }
156
124
 
157
125
  /**
@@ -160,7 +128,7 @@ export class RLNLightContract {
160
128
  */
161
129
  public async getCurrentTotalRateLimit(): Promise<number> {
162
130
  const currentTotal = await this.contract.currentTotalRateLimit();
163
- return ethers.BigNumber.from(currentTotal).toNumber();
131
+ return currentTotal.toNumber();
164
132
  }
165
133
 
166
134
  /**
@@ -172,9 +140,7 @@ export class RLNLightContract {
172
140
  this.contract.maxTotalRateLimit(),
173
141
  this.contract.currentTotalRateLimit()
174
142
  ]);
175
- return ethers.BigNumber.from(maxTotal)
176
- .sub(ethers.BigNumber.from(currentTotal))
177
- .toNumber();
143
+ return Number(maxTotal) - Number(currentTotal);
178
144
  }
179
145
 
180
146
  /**
@@ -182,6 +148,7 @@ export class RLNLightContract {
182
148
  * @param newRateLimit The new rate limit to use
183
149
  */
184
150
  public async setRateLimit(newRateLimit: number): Promise<void> {
151
+ await this.validateRateLimit(newRateLimit);
185
152
  this.rateLimit = newRateLimit;
186
153
  }
187
154
 
@@ -192,43 +159,31 @@ export class RLNLightContract {
192
159
  return sortedMembers;
193
160
  }
194
161
 
195
- private get membersFilter(): ethers.EventFilter {
196
- if (!this._membersFilter) {
197
- throw Error("Members filter was not initialized.");
198
- }
199
- return this._membersFilter;
200
- }
201
-
202
- private get membershipErasedFilter(): ethers.EventFilter {
203
- if (!this._membershipErasedFilter) {
204
- throw Error("MembershipErased filter was not initialized.");
205
- }
206
- return this._membershipErasedFilter;
207
- }
208
-
209
- private get membersExpiredFilter(): ethers.EventFilter {
210
- if (!this._membersExpiredFilter) {
211
- throw Error("MembersExpired filter was not initialized.");
212
- }
213
- return this._membersExpiredFilter;
214
- }
215
-
216
162
  public async fetchMembers(options: FetchMembersOptions = {}): Promise<void> {
217
- const registeredMemberEvents = await queryFilter(this.contract, {
218
- fromBlock: this.deployBlock,
219
- ...options,
220
- membersFilter: this.membersFilter
221
- });
222
- const removedMemberEvents = await queryFilter(this.contract, {
223
- fromBlock: this.deployBlock,
224
- ...options,
225
- membersFilter: this.membershipErasedFilter
226
- });
227
- const expiredMemberEvents = await queryFilter(this.contract, {
228
- fromBlock: this.deployBlock,
229
- ...options,
230
- membersFilter: this.membersExpiredFilter
231
- });
163
+ const registeredMemberEvents = await RLNBaseContract.queryFilter(
164
+ this.contract,
165
+ {
166
+ fromBlock: this.deployBlock,
167
+ ...options,
168
+ membersFilter: this.membersFilter
169
+ }
170
+ );
171
+ const removedMemberEvents = await RLNBaseContract.queryFilter(
172
+ this.contract,
173
+ {
174
+ fromBlock: this.deployBlock,
175
+ ...options,
176
+ membersFilter: this.membershipErasedFilter
177
+ }
178
+ );
179
+ const expiredMemberEvents = await RLNBaseContract.queryFilter(
180
+ this.contract,
181
+ {
182
+ fromBlock: this.deployBlock,
183
+ ...options,
184
+ membersFilter: this.membersExpiredFilter
185
+ }
186
+ );
232
187
 
233
188
  const events = [
234
189
  ...registeredMemberEvents,
@@ -238,6 +193,58 @@ export class RLNLightContract {
238
193
  this.processEvents(events);
239
194
  }
240
195
 
196
+ public static async queryFilter(
197
+ contract: ethers.Contract,
198
+ options: CustomQueryOptions
199
+ ): Promise<ethers.Event[]> {
200
+ const FETCH_CHUNK = 5;
201
+ const BLOCK_RANGE = 3000;
202
+
203
+ const {
204
+ fromBlock,
205
+ membersFilter,
206
+ fetchRange = BLOCK_RANGE,
207
+ fetchChunks = FETCH_CHUNK
208
+ } = options;
209
+
210
+ if (fromBlock === undefined) {
211
+ return contract.queryFilter(membersFilter);
212
+ }
213
+
214
+ if (!contract.provider) {
215
+ throw Error("No provider found on the contract.");
216
+ }
217
+
218
+ const toBlock = await contract.provider.getBlockNumber();
219
+
220
+ if (toBlock - fromBlock < fetchRange) {
221
+ return contract.queryFilter(membersFilter, fromBlock, toBlock);
222
+ }
223
+
224
+ const events: ethers.Event[][] = [];
225
+ const chunks = RLNBaseContract.splitToChunks(
226
+ fromBlock,
227
+ toBlock,
228
+ fetchRange
229
+ );
230
+
231
+ for (const portion of RLNBaseContract.takeN<[number, number]>(
232
+ chunks,
233
+ fetchChunks
234
+ )) {
235
+ const promises = portion.map(([left, right]) =>
236
+ RLNBaseContract.ignoreErrors(
237
+ contract.queryFilter(membersFilter, left, right),
238
+ []
239
+ )
240
+ );
241
+ const fetchedEvents = await Promise.all(promises);
242
+ events.push(fetchedEvents.flatMap((v) => v));
243
+ }
244
+
245
+ return events.flatMap((v) => v);
246
+ }
247
+
241
248
  public processEvents(events: ethers.Event[]): void {
242
249
  const toRemoveTable = new Map<number, number[]>();
243
250
  const toInsertTable = new Map<number, ethers.Event[]>();
@@ -280,11 +287,58 @@ export class RLNLightContract {
280
287
  });
281
288
  }
282
289
 
290
+ public static splitToChunks(
291
+ from: number,
292
+ to: number,
293
+ step: number
294
+ ): Array<[number, number]> {
295
+ const chunks: Array<[number, number]> = [];
296
+
297
+ let left = from;
298
+ while (left < to) {
299
+ const right = left + step < to ? left + step : to;
300
+
301
+ chunks.push([left, right] as [number, number]);
302
+
303
+ left = right;
304
+ }
305
+
306
+ return chunks;
307
+ }
308
+
309
+ public static *takeN<T>(array: T[], size: number): Iterable<T[]> {
310
+ let start = 0;
311
+
312
+ while (start < array.length) {
313
+ const portion = array.slice(start, start + size);
314
+
315
+ yield portion;
316
+
317
+ start += size;
318
+ }
319
+ }
320
+
321
+ public static async ignoreErrors<T>(
322
+ promise: Promise<T>,
323
+ defaultValue: T
324
+ ): Promise<T> {
325
+ try {
326
+ return await promise;
327
+ } catch (err: unknown) {
328
+ if (err instanceof Error) {
329
+ log.info(`Ignoring an error during query: ${err.message}`);
330
+ } else {
331
+ log.info(`Ignoring an unknown error during query`);
332
+ }
333
+ return defaultValue;
334
+ }
335
+ }
336
+
283
337
  public subscribeToMembers(): void {
284
338
  this.contract.on(
285
339
  this.membersFilter,
286
340
  (
287
- _idCommitment: string,
341
+ _idCommitment: bigint,
288
342
  _membershipRateLimit: ethers.BigNumber,
289
343
  _index: ethers.BigNumber,
290
344
  event: ethers.Event
@@ -296,7 +350,7 @@ export class RLNLightContract {
296
350
  this.contract.on(
297
351
  this.membershipErasedFilter,
298
352
  (
299
- _idCommitment: string,
353
+ _idCommitment: bigint,
300
354
  _membershipRateLimit: ethers.BigNumber,
301
355
  _index: ethers.BigNumber,
302
356
  event: ethers.Event
@@ -308,7 +362,7 @@ export class RLNLightContract {
308
362
  this.contract.on(
309
363
  this.membersExpiredFilter,
310
364
  (
311
- _idCommitment: string,
365
+ _idCommitment: bigint,
312
366
  _membershipRateLimit: ethers.BigNumber,
313
367
  _index: ethers.BigNumber,
314
368
  event: ethers.Event
@@ -318,6 +372,98 @@ export class RLNLightContract {
318
372
  );
319
373
  }
320
374
 
375
+ public async getMembershipInfo(
376
+ idCommitmentBigInt: bigint
377
+ ): Promise<MembershipInfo | undefined> {
378
+ try {
379
+ const membershipData =
380
+ await this.contract.memberships(idCommitmentBigInt);
381
+ const currentBlock = await this.contract.provider.getBlockNumber();
382
+ const [
383
+ depositAmount,
384
+ activeDuration,
385
+ gracePeriodStartTimestamp,
386
+ gracePeriodDuration,
387
+ rateLimit,
388
+ index,
389
+ holder,
390
+ token
391
+ ] = membershipData;
392
+
393
+ const gracePeriodEnd = gracePeriodStartTimestamp.add(gracePeriodDuration);
394
+
395
+ let state: MembershipState;
396
+ if (currentBlock < gracePeriodStartTimestamp.toNumber()) {
397
+ state = MembershipState.Active;
398
+ } else if (currentBlock < gracePeriodEnd.toNumber()) {
399
+ state = MembershipState.GracePeriod;
400
+ } else {
401
+ state = MembershipState.Expired;
402
+ }
403
+
404
+ return {
405
+ index,
406
+ idCommitment: idCommitmentBigInt.toString(),
407
+ rateLimit: Number(rateLimit),
408
+ startBlock: gracePeriodStartTimestamp.toNumber(),
409
+ endBlock: gracePeriodEnd.toNumber(),
410
+ state,
411
+ depositAmount,
412
+ activeDuration,
413
+ gracePeriodDuration,
414
+ holder,
415
+ token
416
+ };
417
+ } catch (error) {
418
+ log.error("Error in getMembershipInfo:", error);
419
+ return undefined;
420
+ }
421
+ }
422
+
423
+ public async extendMembership(
424
+ idCommitmentBigInt: bigint
425
+ ): Promise<ethers.ContractTransaction> {
426
+ const tx = await this.contract.extendMemberships([idCommitmentBigInt]);
427
+ await tx.wait();
428
+ return tx;
429
+ }
430
+
431
+ public async eraseMembership(
432
+ idCommitmentBigInt: bigint,
433
+ eraseFromMembershipSet: boolean = true
434
+ ): Promise<ethers.ContractTransaction> {
435
+ const tx = await this.contract["eraseMemberships(uint256[],bool)"](
436
+ [idCommitmentBigInt],
437
+ eraseFromMembershipSet
438
+ );
439
+ await tx.wait();
440
+ return tx;
441
+ }
442
+
443
+ public async registerMembership(
444
+ idCommitmentBigInt: bigint,
445
+ rateLimit: number = DEFAULT_RATE_LIMIT
446
+ ): Promise<ethers.ContractTransaction> {
447
+ if (
448
+ rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
449
+ rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
450
+ ) {
451
+ throw new Error(
452
+ `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
453
+ );
454
+ }
455
+ return this.contract.register(idCommitmentBigInt, rateLimit, []);
456
+ }
457
+
458
+ public async withdraw(token: string, from: string): Promise<void> {
459
+ try {
460
+ const tx = await this.contract.withdraw(token, from);
461
+ await tx.wait();
462
+ } catch (error) {
463
+ log.error(`Error in withdraw: ${(error as Error).message}`);
464
+ }
465
+ }
466
+
321
467
  public async registerWithIdentity(
322
468
  identity: IdentityCredential
323
469
  ): Promise<DecryptedCredentials | undefined> {
@@ -328,7 +474,7 @@ export class RLNLightContract {
328
474
 
329
475
  // Check if the ID commitment is already registered
330
476
  const existingIndex = await this.getMemberIndex(
331
- identity.IDCommitmentBigInt.toString()
477
+ identity.IDCommitmentBigInt
332
478
  );
333
479
  if (existingIndex) {
334
480
  throw new Error(
@@ -366,7 +512,7 @@ export class RLNLightContract {
366
512
  }
367
513
 
368
514
  const memberRegistered = txRegisterReceipt.events?.find(
369
- (event) => event.event === "MembershipRegistered"
515
+ (event: ethers.Event) => event.event === "MembershipRegistered"
370
516
  );
371
517
 
372
518
  if (!memberRegistered || !memberRegistered.args) {
@@ -389,13 +535,13 @@ export class RLNLightContract {
389
535
 
390
536
  const network = await this.contract.provider.getNetwork();
391
537
  const address = this.contract.address;
392
- const membershipId = decodedData.index.toString();
538
+ const membershipId = Number(decodedData.index);
393
539
 
394
540
  return {
395
541
  identity,
396
542
  membership: {
397
543
  address,
398
- treeIndex: `0x${membershipId}`,
544
+ treeIndex: membershipId,
399
545
  chainId: network.chainId.toString(),
400
546
  rateLimit: decodedData.membershipRateLimit.toNumber()
401
547
  }
@@ -430,43 +576,6 @@ export class RLNLightContract {
430
576
  }
431
577
  }
432
578
 
433
- /**
434
- * Helper method to get remaining messages in current epoch
435
- * @param membershipId The ID of the membership to check
436
- * @returns number of remaining messages allowed in current epoch
437
- */
438
- public async getRemainingMessages(membershipId: number): Promise<number> {
439
- try {
440
- const [startTime, , rateLimit] =
441
- await this.contract.getMembershipInfo(membershipId);
442
-
443
- // Calculate current epoch
444
- const currentTime = Math.floor(Date.now() / 1000);
445
- const epochsPassed = Math.floor(
446
- (currentTime - startTime) / RATE_LIMIT_PARAMS.EPOCH_LENGTH
447
- );
448
- const currentEpochStart =
449
- startTime + epochsPassed * RATE_LIMIT_PARAMS.EPOCH_LENGTH;
450
-
451
- // Get message count in current epoch using contract's function
452
- const messageCount = await this.contract.getMessageCount(
453
- membershipId,
454
- currentEpochStart
455
- );
456
- return Math.max(
457
- 0,
458
- ethers.BigNumber.from(rateLimit)
459
- .sub(ethers.BigNumber.from(messageCount))
460
- .toNumber()
461
- );
462
- } catch (error) {
463
- log.error(
464
- `Error getting remaining messages: ${(error as Error).message}`
465
- );
466
- return 0; // Fail safe: assume no messages remaining on error
467
- }
468
- }
469
-
470
579
  public async registerWithPermitAndErase(
471
580
  identity: IdentityCredential,
472
581
  permit: {
@@ -497,7 +606,7 @@ export class RLNLightContract {
497
606
  const txRegisterReceipt = await txRegisterResponse.wait();
498
607
 
499
608
  const memberRegistered = txRegisterReceipt.events?.find(
500
- (event) => event.event === "MembershipRegistered"
609
+ (event: ethers.Event) => event.event === "MembershipRegistered"
501
610
  );
502
611
 
503
612
  if (!memberRegistered || !memberRegistered.args) {
@@ -520,13 +629,13 @@ export class RLNLightContract {
520
629
 
521
630
  const network = await this.contract.provider.getNetwork();
522
631
  const address = this.contract.address;
523
- const membershipId = decodedData.index.toString();
632
+ const membershipId = Number(decodedData.index);
524
633
 
525
634
  return {
526
635
  identity,
527
636
  membership: {
528
637
  address,
529
- treeIndex: `0x${membershipId}`,
638
+ treeIndex: membershipId,
530
639
  chainId: network.chainId.toString(),
531
640
  rateLimit: decodedData.membershipRateLimit.toNumber()
532
641
  }
@@ -539,85 +648,53 @@ export class RLNLightContract {
539
648
  }
540
649
  }
541
650
 
542
- public async withdraw(token: string, holder: string): Promise<void> {
543
- try {
544
- const tx = await this.contract.withdraw(token, { from: holder });
545
- await tx.wait();
546
- } catch (error) {
547
- log.error(`Error in withdraw: ${(error as Error).message}`);
548
- }
549
- }
550
-
551
- public async getMembershipInfo(
552
- idCommitment: string
553
- ): Promise<MembershipInfo | undefined> {
554
- try {
555
- const [startBlock, endBlock, rateLimit] =
556
- await this.contract.getMembershipInfo(idCommitment);
557
- const currentBlock = await this.contract.provider.getBlockNumber();
558
-
559
- let state: MembershipState;
560
- if (currentBlock < startBlock) {
561
- state = MembershipState.Active;
562
- } else if (currentBlock < endBlock) {
563
- state = MembershipState.GracePeriod;
564
- } else {
565
- state = MembershipState.Expired;
566
- }
651
+ /**
652
+ * Validates that the rate limit is within the allowed range
653
+ * @throws Error if the rate limit is outside the allowed range
654
+ */
655
+ private async validateRateLimit(rateLimit: number): Promise<void> {
656
+ const [minRate, maxRate] = await Promise.all([
657
+ this.contract.minMembershipRateLimit(),
658
+ this.contract.maxMembershipRateLimit()
659
+ ]);
567
660
 
568
- const index = await this.getMemberIndex(idCommitment);
569
- if (!index) return undefined;
661
+ const minRateNum = ethers.BigNumber.from(minRate).toNumber();
662
+ const maxRateNum = ethers.BigNumber.from(maxRate).toNumber();
570
663
 
571
- return {
572
- index,
573
- idCommitment,
574
- rateLimit: rateLimit.toNumber(),
575
- startBlock: startBlock.toNumber(),
576
- endBlock: endBlock.toNumber(),
577
- state
578
- };
579
- } catch (error) {
580
- return undefined;
664
+ if (rateLimit < minRateNum || rateLimit > maxRateNum) {
665
+ throw new Error(
666
+ `Rate limit must be between ${minRateNum} and ${maxRateNum} messages per epoch`
667
+ );
581
668
  }
582
669
  }
583
670
 
584
- public async extendMembership(
585
- idCommitment: string
586
- ): Promise<ethers.ContractTransaction> {
587
- return this.contract.extendMemberships([idCommitment]);
671
+ private get membersFilter(): ethers.EventFilter {
672
+ if (!this._membersFilter) {
673
+ throw Error("Members filter was not initialized.");
674
+ }
675
+ return this._membersFilter;
588
676
  }
589
677
 
590
- public async eraseMembership(
591
- idCommitment: string,
592
- eraseFromMembershipSet: boolean = true
593
- ): Promise<ethers.ContractTransaction> {
594
- return this.contract.eraseMemberships(
595
- [idCommitment],
596
- eraseFromMembershipSet
597
- );
678
+ private get membershipErasedFilter(): ethers.EventFilter {
679
+ if (!this._membershipErasedFilter) {
680
+ throw Error("MembershipErased filter was not initialized.");
681
+ }
682
+ return this._membershipErasedFilter;
598
683
  }
599
684
 
600
- public async registerMembership(
601
- idCommitment: string,
602
- rateLimit: number = DEFAULT_RATE_LIMIT
603
- ): Promise<ethers.ContractTransaction> {
604
- if (
605
- rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
606
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
607
- ) {
608
- throw new Error(
609
- `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
610
- );
685
+ private get membersExpiredFilter(): ethers.EventFilter {
686
+ if (!this._membersExpiredFilter) {
687
+ throw Error("MembersExpired filter was not initialized.");
611
688
  }
612
- return this.contract.register(idCommitment, rateLimit, []);
689
+ return this._membersExpiredFilter;
613
690
  }
614
691
 
615
692
  private async getMemberIndex(
616
- idCommitment: string
693
+ idCommitmentBigInt: bigint
617
694
  ): Promise<ethers.BigNumber | undefined> {
618
695
  try {
619
696
  const events = await this.contract.queryFilter(
620
- this.contract.filters.MembershipRegistered(idCommitment)
697
+ this.contract.filters.MembershipRegistered(idCommitmentBigInt)
621
698
  );
622
699
  if (events.length === 0) return undefined;
623
700
 
@@ -629,97 +706,3 @@ export class RLNLightContract {
629
706
  }
630
707
  }
631
708
  }
632
-
633
- interface CustomQueryOptions extends FetchMembersOptions {
634
- membersFilter: ethers.EventFilter;
635
- }
636
-
637
- // These values should be tested on other networks
638
- const FETCH_CHUNK = 5;
639
- const BLOCK_RANGE = 3000;
640
-
641
- async function queryFilter(
642
- contract: ethers.Contract,
643
- options: CustomQueryOptions
644
- ): Promise<ethers.Event[]> {
645
- const {
646
- fromBlock,
647
- membersFilter,
648
- fetchRange = BLOCK_RANGE,
649
- fetchChunks = FETCH_CHUNK
650
- } = options;
651
-
652
- if (fromBlock === undefined) {
653
- return contract.queryFilter(membersFilter);
654
- }
655
-
656
- if (!contract.provider) {
657
- throw Error("No provider found on the contract.");
658
- }
659
-
660
- const toBlock = await contract.provider.getBlockNumber();
661
-
662
- if (toBlock - fromBlock < fetchRange) {
663
- return contract.queryFilter(membersFilter, fromBlock, toBlock);
664
- }
665
-
666
- const events: ethers.Event[][] = [];
667
- const chunks = splitToChunks(fromBlock, toBlock, fetchRange);
668
-
669
- for (const portion of takeN<[number, number]>(chunks, fetchChunks)) {
670
- const promises = portion.map(([left, right]) =>
671
- ignoreErrors(contract.queryFilter(membersFilter, left, right), [])
672
- );
673
- const fetchedEvents = await Promise.all(promises);
674
- events.push(fetchedEvents.flatMap((v) => v));
675
- }
676
-
677
- return events.flatMap((v) => v);
678
- }
679
-
680
- function splitToChunks(
681
- from: number,
682
- to: number,
683
- step: number
684
- ): Array<[number, number]> {
685
- const chunks: Array<[number, number]> = [];
686
-
687
- let left = from;
688
- while (left < to) {
689
- const right = left + step < to ? left + step : to;
690
-
691
- chunks.push([left, right] as [number, number]);
692
-
693
- left = right;
694
- }
695
-
696
- return chunks;
697
- }
698
-
699
- function* takeN<T>(array: T[], size: number): Iterable<T[]> {
700
- let start = 0;
701
-
702
- while (start < array.length) {
703
- const portion = array.slice(start, start + size);
704
-
705
- yield portion;
706
-
707
- start += size;
708
- }
709
- }
710
-
711
- async function ignoreErrors<T>(
712
- promise: Promise<T>,
713
- defaultValue: T
714
- ): Promise<T> {
715
- try {
716
- return await promise;
717
- } catch (err: unknown) {
718
- if (err instanceof Error) {
719
- log.info(`Ignoring an error during query: ${err.message}`);
720
- } else {
721
- log.info(`Ignoring an unknown error during query`);
722
- }
723
- return defaultValue;
724
- }
725
- }