@waku/rln 0.1.5-861a776.0 → 0.1.5-a824fff.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 (164) hide show
  1. package/bundle/index.js +4 -3
  2. package/bundle/packages/rln/dist/contract/constants.js +2 -1
  3. package/bundle/packages/rln/dist/contract/{rln_light_contract.js → rln_base_contract.js} +191 -186
  4. package/bundle/packages/rln/dist/contract/rln_contract.js +10 -420
  5. package/bundle/packages/rln/dist/contract/types.js +9 -0
  6. package/bundle/packages/rln/dist/create.js +1 -1
  7. package/bundle/packages/rln/dist/{rln_light.js → credentials_manager.js} +114 -48
  8. package/bundle/packages/rln/dist/identity.js +0 -9
  9. package/bundle/packages/rln/dist/keystore/keystore.js +31 -17
  10. package/bundle/packages/rln/dist/rln.js +56 -166
  11. package/bundle/packages/rln/dist/utils/metamask.js +2 -2
  12. package/bundle/packages/rln/dist/zerokit.js +5 -5
  13. package/dist/.tsbuildinfo +1 -1
  14. package/dist/contract/constants.d.ts +1 -1
  15. package/dist/contract/constants.js +1 -1
  16. package/dist/contract/constants.js.map +1 -1
  17. package/dist/contract/index.d.ts +1 -0
  18. package/dist/contract/index.js +1 -0
  19. package/dist/contract/index.js.map +1 -1
  20. package/dist/contract/{rln_light_contract.d.ts → rln_base_contract.d.ts} +24 -58
  21. package/dist/contract/{rln_light_contract.js → rln_base_contract.js} +189 -184
  22. package/dist/contract/rln_base_contract.js.map +1 -0
  23. package/dist/contract/rln_contract.d.ts +5 -122
  24. package/dist/contract/rln_contract.js +8 -417
  25. package/dist/contract/rln_contract.js.map +1 -1
  26. package/dist/contract/types.d.ts +45 -0
  27. package/dist/contract/types.js +8 -0
  28. package/dist/contract/types.js.map +1 -0
  29. package/dist/create.js +1 -1
  30. package/dist/create.js.map +1 -1
  31. package/dist/credentials_manager.d.ts +44 -0
  32. package/dist/credentials_manager.js +197 -0
  33. package/dist/credentials_manager.js.map +1 -0
  34. package/dist/identity.d.ts +0 -1
  35. package/dist/identity.js +0 -9
  36. package/dist/identity.js.map +1 -1
  37. package/dist/index.d.ts +5 -4
  38. package/dist/index.js +4 -3
  39. package/dist/index.js.map +1 -1
  40. package/dist/keystore/keystore.d.ts +1 -0
  41. package/dist/keystore/keystore.js +31 -17
  42. package/dist/keystore/keystore.js.map +1 -1
  43. package/dist/keystore/types.d.ts +2 -2
  44. package/dist/rln.d.ts +9 -52
  45. package/dist/rln.js +54 -163
  46. package/dist/rln.js.map +1 -1
  47. package/dist/types.d.ts +27 -0
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -0
  50. package/dist/zerokit.d.ts +3 -3
  51. package/dist/zerokit.js +5 -5
  52. package/dist/zerokit.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/contract/constants.ts +1 -1
  55. package/src/contract/index.ts +1 -0
  56. package/src/contract/{rln_light_contract.ts → rln_base_contract.ts} +312 -323
  57. package/src/contract/rln_contract.ts +9 -663
  58. package/src/contract/types.ts +53 -0
  59. package/src/create.ts +1 -1
  60. package/src/credentials_manager.ts +282 -0
  61. package/src/identity.ts +0 -10
  62. package/src/index.ts +7 -5
  63. package/src/keystore/keystore.ts +57 -31
  64. package/src/keystore/types.ts +2 -2
  65. package/src/rln.ts +67 -258
  66. package/src/types.ts +31 -0
  67. package/src/zerokit.ts +3 -3
  68. package/bundle/_virtual/__node-resolve_empty.js +0 -6
  69. package/bundle/_virtual/_node-resolve_empty.js +0 -3
  70. package/bundle/_virtual/bn.js +0 -3
  71. package/bundle/_virtual/common.js +0 -3
  72. package/bundle/_virtual/common2.js +0 -3
  73. package/bundle/_virtual/hash.js +0 -3
  74. package/bundle/_virtual/inherits_browser.js +0 -3
  75. package/bundle/_virtual/ripemd.js +0 -3
  76. package/bundle/_virtual/sha.js +0 -3
  77. package/bundle/_virtual/sha3.js +0 -3
  78. package/bundle/_virtual/utils3.js +0 -3
  79. package/bundle/node_modules/@ethersproject/abi/lib.esm/_version.js +0 -3
  80. package/bundle/node_modules/@ethersproject/abi/lib.esm/abi-coder.js +0 -96
  81. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/abstract-coder.js +0 -148
  82. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/address.js +0 -26
  83. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/anonymous.js +0 -20
  84. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/array.js +0 -210
  85. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/boolean.js +0 -18
  86. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/bytes.js +0 -30
  87. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/fixed-bytes.js +0 -26
  88. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/null.js +0 -22
  89. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/number.js +0 -43
  90. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/string.js +0 -19
  91. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/tuple.js +0 -58
  92. package/bundle/node_modules/@ethersproject/abi/lib.esm/fragments.js +0 -854
  93. package/bundle/node_modules/@ethersproject/abi/lib.esm/interface.js +0 -609
  94. package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/_version.js +0 -3
  95. package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/index.js +0 -66
  96. package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/_version.js +0 -3
  97. package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/index.js +0 -302
  98. package/bundle/node_modules/@ethersproject/address/lib.esm/_version.js +0 -3
  99. package/bundle/node_modules/@ethersproject/address/lib.esm/index.js +0 -110
  100. package/bundle/node_modules/@ethersproject/base64/lib.esm/base64.js +0 -20
  101. package/bundle/node_modules/@ethersproject/basex/lib.esm/index.js +0 -120
  102. package/bundle/node_modules/@ethersproject/bignumber/lib.esm/_version.js +0 -3
  103. package/bundle/node_modules/@ethersproject/bignumber/lib.esm/bignumber.js +0 -287
  104. package/bundle/node_modules/@ethersproject/bytes/lib.esm/_version.js +0 -3
  105. package/bundle/node_modules/@ethersproject/bytes/lib.esm/index.js +0 -402
  106. package/bundle/node_modules/@ethersproject/constants/lib.esm/addresses.js +0 -3
  107. package/bundle/node_modules/@ethersproject/constants/lib.esm/bignumbers.js +0 -8
  108. package/bundle/node_modules/@ethersproject/constants/lib.esm/hashes.js +0 -3
  109. package/bundle/node_modules/@ethersproject/contracts/lib.esm/_version.js +0 -3
  110. package/bundle/node_modules/@ethersproject/contracts/lib.esm/index.js +0 -893
  111. package/bundle/node_modules/@ethersproject/hash/lib.esm/_version.js +0 -3
  112. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/decoder.js +0 -256
  113. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/include.js +0 -36
  114. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/lib.js +0 -135
  115. package/bundle/node_modules/@ethersproject/hash/lib.esm/id.js +0 -8
  116. package/bundle/node_modules/@ethersproject/hash/lib.esm/namehash.js +0 -64
  117. package/bundle/node_modules/@ethersproject/hash/lib.esm/typed-data.js +0 -443
  118. package/bundle/node_modules/@ethersproject/keccak256/lib.esm/index.js +0 -8
  119. package/bundle/node_modules/@ethersproject/keccak256/node_modules/js-sha3/src/sha3.js +0 -660
  120. package/bundle/node_modules/@ethersproject/logger/lib.esm/_version.js +0 -3
  121. package/bundle/node_modules/@ethersproject/logger/lib.esm/index.js +0 -352
  122. package/bundle/node_modules/@ethersproject/networks/lib.esm/_version.js +0 -3
  123. package/bundle/node_modules/@ethersproject/networks/lib.esm/index.js +0 -248
  124. package/bundle/node_modules/@ethersproject/properties/lib.esm/_version.js +0 -3
  125. package/bundle/node_modules/@ethersproject/properties/lib.esm/index.js +0 -127
  126. package/bundle/node_modules/@ethersproject/providers/lib.esm/_version.js +0 -3
  127. package/bundle/node_modules/@ethersproject/providers/lib.esm/base-provider.js +0 -2007
  128. package/bundle/node_modules/@ethersproject/providers/lib.esm/formatter.js +0 -422
  129. package/bundle/node_modules/@ethersproject/providers/lib.esm/json-rpc-provider.js +0 -674
  130. package/bundle/node_modules/@ethersproject/providers/lib.esm/web3-provider.js +0 -132
  131. package/bundle/node_modules/@ethersproject/rlp/lib.esm/_version.js +0 -3
  132. package/bundle/node_modules/@ethersproject/rlp/lib.esm/index.js +0 -120
  133. package/bundle/node_modules/@ethersproject/sha2/lib.esm/sha2.js +0 -8
  134. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/_version.js +0 -3
  135. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/elliptic.js +0 -2430
  136. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/index.js +0 -76
  137. package/bundle/node_modules/@ethersproject/strings/lib.esm/_version.js +0 -3
  138. package/bundle/node_modules/@ethersproject/strings/lib.esm/utf8.js +0 -219
  139. package/bundle/node_modules/@ethersproject/transactions/lib.esm/_version.js +0 -3
  140. package/bundle/node_modules/@ethersproject/transactions/lib.esm/index.js +0 -279
  141. package/bundle/node_modules/@ethersproject/web/lib.esm/_version.js +0 -3
  142. package/bundle/node_modules/@ethersproject/web/lib.esm/geturl.js +0 -69
  143. package/bundle/node_modules/@ethersproject/web/lib.esm/index.js +0 -404
  144. package/bundle/node_modules/bech32/index.js +0 -187
  145. package/bundle/node_modules/bn.js/lib/bn.js +0 -3361
  146. package/bundle/node_modules/hash.js/lib/hash/common.js +0 -97
  147. package/bundle/node_modules/hash.js/lib/hash/hmac.js +0 -51
  148. package/bundle/node_modules/hash.js/lib/hash/ripemd.js +0 -152
  149. package/bundle/node_modules/hash.js/lib/hash/sha/1.js +0 -81
  150. package/bundle/node_modules/hash.js/lib/hash/sha/224.js +0 -33
  151. package/bundle/node_modules/hash.js/lib/hash/sha/256.js +0 -113
  152. package/bundle/node_modules/hash.js/lib/hash/sha/384.js +0 -39
  153. package/bundle/node_modules/hash.js/lib/hash/sha/512.js +0 -336
  154. package/bundle/node_modules/hash.js/lib/hash/sha/common.js +0 -53
  155. package/bundle/node_modules/hash.js/lib/hash/sha.js +0 -14
  156. package/bundle/node_modules/hash.js/lib/hash/utils.js +0 -282
  157. package/bundle/node_modules/hash.js/lib/hash.js +0 -33
  158. package/bundle/node_modules/inherits/inherits_browser.js +0 -33
  159. package/bundle/node_modules/minimalistic-assert/index.js +0 -13
  160. package/dist/contract/rln_light_contract.js.map +0 -1
  161. package/dist/rln_light.d.ts +0 -64
  162. package/dist/rln_light.js +0 -144
  163. package/dist/rln_light.js.map +0 -1
  164. package/src/rln_light.ts +0 -235
package/bundle/index.js CHANGED
@@ -1,14 +1,15 @@
1
1
  export { RLNDecoder, RLNEncoder } from './packages/rln/dist/codec.js';
2
2
  export { RLN_ABI } from './packages/rln/dist/contract/abi.js';
3
3
  export { RLNContract } from './packages/rln/dist/contract/rln_contract.js';
4
- export { LINEA_CONTRACT } from './packages/rln/dist/contract/constants.js';
5
- export { RLNLightContract } from './packages/rln/dist/contract/rln_light_contract.js';
4
+ export { DEFAULT_RATE_LIMIT, LINEA_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS } from './packages/rln/dist/contract/constants.js';
5
+ export { MembershipState } from './packages/rln/dist/contract/types.js';
6
+ export { RLNBaseContract } from './packages/rln/dist/contract/rln_base_contract.js';
6
7
  export { createRLN } from './packages/rln/dist/create.js';
8
+ export { RLNCredentialsManager } from './packages/rln/dist/credentials_manager.js';
7
9
  export { IdentityCredential } from './packages/rln/dist/identity.js';
8
10
  export { Keystore } from './packages/rln/dist/keystore/keystore.js';
9
11
  export { Proof } from './packages/rln/dist/proof.js';
10
12
  export { RLNInstance } from './packages/rln/dist/rln.js';
11
- export { RLNLightInstance } from './packages/rln/dist/rln_light.js';
12
13
  export { MerkleRootTracker } from './packages/rln/dist/root_tracker.js';
13
14
  export { extractMetaMaskSigner } from './packages/rln/dist/utils/metamask.js';
14
15
  import './packages/rln/dist/utils/epoch.js';
@@ -1,7 +1,7 @@
1
1
  import { RLN_ABI } from './abi.js';
2
2
 
3
3
  const LINEA_CONTRACT = {
4
- chainId: "59141",
4
+ chainId: 59141,
5
5
  address: "0xb9cd878c90e49f797b4431fbf4fb333108cb90e6",
6
6
  abi: RLN_ABI
7
7
  };
@@ -12,6 +12,7 @@ const LINEA_CONTRACT = {
12
12
  */
13
13
  const RATE_LIMIT_TIERS = {
14
14
  LOW: 20, // Suggested minimum rate - 20 messages per epoch
15
+ MEDIUM: 200,
15
16
  HIGH: 600 // Suggested maximum rate - 600 messages per epoch
16
17
  };
17
18
  // Global rate limit parameters
@@ -15,18 +15,12 @@ import '../../../../node_modules/multiformats/dist/src/codecs/json.js';
15
15
  import { Logger } from '../../../utils/dist/logger/index.js';
16
16
  import { RLN_ABI } from './abi.js';
17
17
  import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from './constants.js';
18
- import { Contract } from '../../../../node_modules/@ethersproject/contracts/lib.esm/index.js';
19
- import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
18
+ import { MembershipState } from './types.js';
19
+ import { Contract } from '@ethersproject/contracts';
20
+ import { BigNumber } from '@ethersproject/bignumber';
20
21
 
21
- const log = new Logger("waku:rln:contract");
22
- var MembershipState;
23
- (function (MembershipState) {
24
- MembershipState["Active"] = "Active";
25
- MembershipState["GracePeriod"] = "GracePeriod";
26
- MembershipState["Expired"] = "Expired";
27
- MembershipState["ErasedAwaitsWithdrawal"] = "ErasedAwaitsWithdrawal";
28
- })(MembershipState || (MembershipState = {}));
29
- class RLNLightContract {
22
+ const log = new Logger("waku:rln:contract:base");
23
+ class RLNBaseContract {
30
24
  contract;
31
25
  deployBlock;
32
26
  rateLimit;
@@ -35,28 +29,38 @@ class RLNLightContract {
35
29
  _membershipErasedFilter;
36
30
  _membersExpiredFilter;
37
31
  /**
38
- * Asynchronous initializer for RLNContract.
32
+ * Constructor for RLNBaseContract.
39
33
  * Allows injecting a mocked contract for testing purposes.
40
34
  */
41
- static async init(options) {
42
- const rlnContract = new RLNLightContract(options);
43
- await rlnContract.fetchMembers();
44
- rlnContract.subscribeToMembers();
45
- return rlnContract;
46
- }
47
35
  constructor(options) {
48
36
  const { address, signer, rateLimit = DEFAULT_RATE_LIMIT, contract } = options;
49
- if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
50
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
51
- throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE} messages per epoch`);
52
- }
53
- this.rateLimit = rateLimit;
54
- // Use the injected contract if provided; otherwise, instantiate a new one.
37
+ log.info("Initializing RLNBaseContract", { address, rateLimit });
55
38
  this.contract = contract || new Contract(address, RLN_ABI, signer);
56
- // Initialize event filters
57
- this._membersFilter = this.contract.filters.MembershipRegistered();
58
- this._membershipErasedFilter = this.contract.filters.MembershipErased();
59
- this._membersExpiredFilter = this.contract.filters.MembershipExpired();
39
+ this.rateLimit = rateLimit;
40
+ try {
41
+ log.info("Setting up event filters");
42
+ // Initialize event filters
43
+ this._membersFilter = this.contract.filters.MembershipRegistered();
44
+ this._membershipErasedFilter = this.contract.filters.MembershipErased();
45
+ this._membersExpiredFilter = this.contract.filters.MembershipExpired();
46
+ log.info("Event filters initialized successfully");
47
+ }
48
+ catch (error) {
49
+ log.error("Failed to initialize event filters", { error });
50
+ throw new Error("Failed to initialize event filters: " + error.message);
51
+ }
52
+ // Initialize members and subscriptions
53
+ this.fetchMembers()
54
+ .then(() => {
55
+ this.subscribeToMembers();
56
+ })
57
+ .catch((error) => {
58
+ log.error("Failed to initialize members", { error });
59
+ });
60
+ // Validate rate limit asynchronously
61
+ this.validateRateLimit(rateLimit).catch((error) => {
62
+ log.error("Failed to validate initial rate limit", { error });
63
+ });
60
64
  }
61
65
  /**
62
66
  * Gets the current rate limit for this contract instance
@@ -98,7 +102,7 @@ class RLNLightContract {
98
102
  */
99
103
  async getMaxTotalRateLimit() {
100
104
  const maxTotalRate = await this.contract.maxTotalRateLimit();
101
- return BigNumber.from(maxTotalRate).toNumber();
105
+ return maxTotalRate.toNumber();
102
106
  }
103
107
  /**
104
108
  * Gets the current total rate limit usage across all memberships
@@ -106,7 +110,7 @@ class RLNLightContract {
106
110
  */
107
111
  async getCurrentTotalRateLimit() {
108
112
  const currentTotal = await this.contract.currentTotalRateLimit();
109
- return BigNumber.from(currentTotal).toNumber();
113
+ return currentTotal.toNumber();
110
114
  }
111
115
  /**
112
116
  * Gets the remaining available total rate limit that can be allocated
@@ -117,51 +121,32 @@ class RLNLightContract {
117
121
  this.contract.maxTotalRateLimit(),
118
122
  this.contract.currentTotalRateLimit()
119
123
  ]);
120
- return BigNumber.from(maxTotal)
121
- .sub(BigNumber.from(currentTotal))
122
- .toNumber();
124
+ return Number(maxTotal) - Number(currentTotal);
123
125
  }
124
126
  /**
125
127
  * Updates the rate limit for future registrations
126
128
  * @param newRateLimit The new rate limit to use
127
129
  */
128
130
  async setRateLimit(newRateLimit) {
131
+ await this.validateRateLimit(newRateLimit);
129
132
  this.rateLimit = newRateLimit;
130
133
  }
131
134
  get members() {
132
135
  const sortedMembers = Array.from(this._members.values()).sort((left, right) => left.index.toNumber() - right.index.toNumber());
133
136
  return sortedMembers;
134
137
  }
135
- get membersFilter() {
136
- if (!this._membersFilter) {
137
- throw Error("Members filter was not initialized.");
138
- }
139
- return this._membersFilter;
140
- }
141
- get membershipErasedFilter() {
142
- if (!this._membershipErasedFilter) {
143
- throw Error("MembershipErased filter was not initialized.");
144
- }
145
- return this._membershipErasedFilter;
146
- }
147
- get membersExpiredFilter() {
148
- if (!this._membersExpiredFilter) {
149
- throw Error("MembersExpired filter was not initialized.");
150
- }
151
- return this._membersExpiredFilter;
152
- }
153
138
  async fetchMembers(options = {}) {
154
- const registeredMemberEvents = await queryFilter(this.contract, {
139
+ const registeredMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
155
140
  fromBlock: this.deployBlock,
156
141
  ...options,
157
142
  membersFilter: this.membersFilter
158
143
  });
159
- const removedMemberEvents = await queryFilter(this.contract, {
144
+ const removedMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
160
145
  fromBlock: this.deployBlock,
161
146
  ...options,
162
147
  membersFilter: this.membershipErasedFilter
163
148
  });
164
- const expiredMemberEvents = await queryFilter(this.contract, {
149
+ const expiredMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
165
150
  fromBlock: this.deployBlock,
166
151
  ...options,
167
152
  membersFilter: this.membersExpiredFilter
@@ -173,6 +158,29 @@ class RLNLightContract {
173
158
  ];
174
159
  this.processEvents(events);
175
160
  }
161
+ static async queryFilter(contract, options) {
162
+ const FETCH_CHUNK = 5;
163
+ const BLOCK_RANGE = 3000;
164
+ const { fromBlock, membersFilter, fetchRange = BLOCK_RANGE, fetchChunks = FETCH_CHUNK } = options;
165
+ if (fromBlock === undefined) {
166
+ return contract.queryFilter(membersFilter);
167
+ }
168
+ if (!contract.provider) {
169
+ throw Error("No provider found on the contract.");
170
+ }
171
+ const toBlock = await contract.provider.getBlockNumber();
172
+ if (toBlock - fromBlock < fetchRange) {
173
+ return contract.queryFilter(membersFilter, fromBlock, toBlock);
174
+ }
175
+ const events = [];
176
+ const chunks = RLNBaseContract.splitToChunks(fromBlock, toBlock, fetchRange);
177
+ for (const portion of RLNBaseContract.takeN(chunks, fetchChunks)) {
178
+ const promises = portion.map(([left, right]) => RLNBaseContract.ignoreErrors(contract.queryFilter(membersFilter, left, right), []));
179
+ const fetchedEvents = await Promise.all(promises);
180
+ events.push(fetchedEvents.flatMap((v) => v));
181
+ }
182
+ return events.flatMap((v) => v);
183
+ }
176
184
  processEvents(events) {
177
185
  const toRemoveTable = new Map();
178
186
  const toInsertTable = new Map();
@@ -208,6 +216,38 @@ class RLNLightContract {
208
216
  }
209
217
  });
210
218
  }
219
+ static splitToChunks(from, to, step) {
220
+ const chunks = [];
221
+ let left = from;
222
+ while (left < to) {
223
+ const right = left + step < to ? left + step : to;
224
+ chunks.push([left, right]);
225
+ left = right;
226
+ }
227
+ return chunks;
228
+ }
229
+ static *takeN(array, size) {
230
+ let start = 0;
231
+ while (start < array.length) {
232
+ const portion = array.slice(start, start + size);
233
+ yield portion;
234
+ start += size;
235
+ }
236
+ }
237
+ static async ignoreErrors(promise, defaultValue) {
238
+ try {
239
+ return await promise;
240
+ }
241
+ catch (err) {
242
+ if (err instanceof Error) {
243
+ log.info(`Ignoring an error during query: ${err.message}`);
244
+ }
245
+ else {
246
+ log.info(`Ignoring an unknown error during query`);
247
+ }
248
+ return defaultValue;
249
+ }
250
+ }
211
251
  subscribeToMembers() {
212
252
  this.contract.on(this.membersFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
213
253
  this.processEvents([event]);
@@ -219,11 +259,74 @@ class RLNLightContract {
219
259
  this.processEvents([event]);
220
260
  });
221
261
  }
262
+ async getMembershipInfo(idCommitmentBigInt) {
263
+ try {
264
+ const membershipData = await this.contract.memberships(idCommitmentBigInt);
265
+ const currentBlock = await this.contract.provider.getBlockNumber();
266
+ const [depositAmount, activeDuration, gracePeriodStartTimestamp, gracePeriodDuration, rateLimit, index, holder, token] = membershipData;
267
+ const gracePeriodEnd = gracePeriodStartTimestamp.add(gracePeriodDuration);
268
+ let state;
269
+ if (currentBlock < gracePeriodStartTimestamp.toNumber()) {
270
+ state = MembershipState.Active;
271
+ }
272
+ else if (currentBlock < gracePeriodEnd.toNumber()) {
273
+ state = MembershipState.GracePeriod;
274
+ }
275
+ else {
276
+ state = MembershipState.Expired;
277
+ }
278
+ return {
279
+ index,
280
+ idCommitment: idCommitmentBigInt.toString(),
281
+ rateLimit: Number(rateLimit),
282
+ startBlock: gracePeriodStartTimestamp.toNumber(),
283
+ endBlock: gracePeriodEnd.toNumber(),
284
+ state,
285
+ depositAmount,
286
+ activeDuration,
287
+ gracePeriodDuration,
288
+ holder,
289
+ token
290
+ };
291
+ }
292
+ catch (error) {
293
+ log.error("Error in getMembershipInfo:", error);
294
+ return undefined;
295
+ }
296
+ }
297
+ async extendMembership(idCommitmentBigInt) {
298
+ const tx = await this.contract.extendMemberships([idCommitmentBigInt]);
299
+ await tx.wait();
300
+ return tx;
301
+ }
302
+ async eraseMembership(idCommitmentBigInt, eraseFromMembershipSet = true) {
303
+ const estimatedGas = await this.contract.estimateGas["eraseMemberships(uint256[],bool)"]([idCommitmentBigInt], eraseFromMembershipSet);
304
+ const gasLimit = estimatedGas.add(10000);
305
+ const tx = await this.contract["eraseMemberships(uint256[],bool)"]([idCommitmentBigInt], eraseFromMembershipSet, { gasLimit });
306
+ await tx.wait();
307
+ return tx;
308
+ }
309
+ async registerMembership(idCommitmentBigInt, rateLimit = DEFAULT_RATE_LIMIT) {
310
+ if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
311
+ rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
312
+ throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
313
+ }
314
+ return this.contract.register(idCommitmentBigInt, rateLimit, []);
315
+ }
316
+ async withdraw(token, from) {
317
+ try {
318
+ const tx = await this.contract.withdraw(token, from);
319
+ await tx.wait();
320
+ }
321
+ catch (error) {
322
+ log.error(`Error in withdraw: ${error.message}`);
323
+ }
324
+ }
222
325
  async registerWithIdentity(identity) {
223
326
  try {
224
327
  log.info(`Registering identity with rate limit: ${this.rateLimit} messages/epoch`);
225
328
  // Check if the ID commitment is already registered
226
- const existingIndex = await this.getMemberIndex(identity.IDCommitmentBigInt.toString());
329
+ const existingIndex = await this.getMemberIndex(identity.IDCommitmentBigInt);
227
330
  if (existingIndex) {
228
331
  throw new Error(`ID commitment is already registered with index ${existingIndex}`);
229
332
  }
@@ -253,12 +356,12 @@ class RLNLightContract {
253
356
  `and rate limit ${decodedData.membershipRateLimit}`);
254
357
  const network = await this.contract.provider.getNetwork();
255
358
  const address = this.contract.address;
256
- const membershipId = decodedData.index.toString();
359
+ const membershipId = Number(decodedData.index);
257
360
  return {
258
361
  identity,
259
362
  membership: {
260
363
  address,
261
- treeIndex: parseInt(membershipId),
364
+ treeIndex: membershipId,
262
365
  chainId: network.chainId.toString(),
263
366
  rateLimit: decodedData.membershipRateLimit.toNumber()
264
367
  }
@@ -293,29 +396,6 @@ class RLNLightContract {
293
396
  }
294
397
  }
295
398
  }
296
- /**
297
- * Helper method to get remaining messages in current epoch
298
- * @param membershipId The ID of the membership to check
299
- * @returns number of remaining messages allowed in current epoch
300
- */
301
- async getRemainingMessages(membershipId) {
302
- try {
303
- const [startTime, , rateLimit] = await this.contract.getMembershipInfo(membershipId);
304
- // Calculate current epoch
305
- const currentTime = Math.floor(Date.now() / 1000);
306
- const epochsPassed = Math.floor((currentTime - startTime) / RATE_LIMIT_PARAMS.EPOCH_LENGTH);
307
- const currentEpochStart = startTime + epochsPassed * RATE_LIMIT_PARAMS.EPOCH_LENGTH;
308
- // Get message count in current epoch using contract's function
309
- const messageCount = await this.contract.getMessageCount(membershipId, currentEpochStart);
310
- return Math.max(0, BigNumber.from(rateLimit)
311
- .sub(BigNumber.from(messageCount))
312
- .toNumber());
313
- }
314
- catch (error) {
315
- log.error(`Error getting remaining messages: ${error.message}`);
316
- return 0; // Fail safe: assume no messages remaining on error
317
- }
318
- }
319
399
  async registerWithPermitAndErase(identity, permit, idCommitmentsToErase) {
320
400
  try {
321
401
  log.info(`Registering identity with permit and rate limit: ${this.rateLimit} messages/epoch`);
@@ -335,12 +415,12 @@ class RLNLightContract {
335
415
  `Rate limit: ${decodedData.membershipRateLimit}, Erased ${idCommitmentsToErase.length} commitments`);
336
416
  const network = await this.contract.provider.getNetwork();
337
417
  const address = this.contract.address;
338
- const membershipId = decodedData.index.toString();
418
+ const membershipId = Number(decodedData.index);
339
419
  return {
340
420
  identity,
341
421
  membership: {
342
422
  address,
343
- treeIndex: parseInt(membershipId),
423
+ treeIndex: membershipId,
344
424
  chainId: network.chainId.toString(),
345
425
  rateLimit: decodedData.membershipRateLimit.toNumber()
346
426
  }
@@ -351,61 +431,42 @@ class RLNLightContract {
351
431
  return undefined;
352
432
  }
353
433
  }
354
- async withdraw(token, holder) {
355
- try {
356
- const tx = await this.contract.withdraw(token, { from: holder });
357
- await tx.wait();
358
- }
359
- catch (error) {
360
- log.error(`Error in withdraw: ${error.message}`);
434
+ /**
435
+ * Validates that the rate limit is within the allowed range
436
+ * @throws Error if the rate limit is outside the allowed range
437
+ */
438
+ async validateRateLimit(rateLimit) {
439
+ const [minRate, maxRate] = await Promise.all([
440
+ this.contract.minMembershipRateLimit(),
441
+ this.contract.maxMembershipRateLimit()
442
+ ]);
443
+ const minRateNum = BigNumber.from(minRate).toNumber();
444
+ const maxRateNum = BigNumber.from(maxRate).toNumber();
445
+ if (rateLimit < minRateNum || rateLimit > maxRateNum) {
446
+ throw new Error(`Rate limit must be between ${minRateNum} and ${maxRateNum} messages per epoch`);
361
447
  }
362
448
  }
363
- async getMembershipInfo(idCommitment) {
364
- try {
365
- const [startBlock, endBlock, rateLimit] = await this.contract.getMembershipInfo(idCommitment);
366
- const currentBlock = await this.contract.provider.getBlockNumber();
367
- let state;
368
- if (currentBlock < startBlock) {
369
- state = MembershipState.Active;
370
- }
371
- else if (currentBlock < endBlock) {
372
- state = MembershipState.GracePeriod;
373
- }
374
- else {
375
- state = MembershipState.Expired;
376
- }
377
- const index = await this.getMemberIndex(idCommitment);
378
- if (!index)
379
- return undefined;
380
- return {
381
- index,
382
- idCommitment,
383
- rateLimit: rateLimit.toNumber(),
384
- startBlock: startBlock.toNumber(),
385
- endBlock: endBlock.toNumber(),
386
- state
387
- };
388
- }
389
- catch (error) {
390
- return undefined;
449
+ get membersFilter() {
450
+ if (!this._membersFilter) {
451
+ throw Error("Members filter was not initialized.");
391
452
  }
453
+ return this._membersFilter;
392
454
  }
393
- async extendMembership(idCommitment) {
394
- return this.contract.extendMemberships([idCommitment]);
395
- }
396
- async eraseMembership(idCommitment, eraseFromMembershipSet = true) {
397
- return this.contract.eraseMemberships([idCommitment], eraseFromMembershipSet);
455
+ get membershipErasedFilter() {
456
+ if (!this._membershipErasedFilter) {
457
+ throw Error("MembershipErased filter was not initialized.");
458
+ }
459
+ return this._membershipErasedFilter;
398
460
  }
399
- async registerMembership(idCommitment, rateLimit = DEFAULT_RATE_LIMIT) {
400
- if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
401
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
402
- throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
461
+ get membersExpiredFilter() {
462
+ if (!this._membersExpiredFilter) {
463
+ throw Error("MembersExpired filter was not initialized.");
403
464
  }
404
- return this.contract.register(idCommitment, rateLimit, []);
465
+ return this._membersExpiredFilter;
405
466
  }
406
- async getMemberIndex(idCommitment) {
467
+ async getMemberIndex(idCommitmentBigInt) {
407
468
  try {
408
- const events = await this.contract.queryFilter(this.contract.filters.MembershipRegistered(idCommitment));
469
+ const events = await this.contract.queryFilter(this.contract.filters.MembershipRegistered(idCommitmentBigInt));
409
470
  if (events.length === 0)
410
471
  return undefined;
411
472
  // Get the most recent registration event
@@ -417,61 +478,5 @@ class RLNLightContract {
417
478
  }
418
479
  }
419
480
  }
420
- // These values should be tested on other networks
421
- const FETCH_CHUNK = 5;
422
- const BLOCK_RANGE = 3000;
423
- async function queryFilter(contract, options) {
424
- const { fromBlock, membersFilter, fetchRange = BLOCK_RANGE, fetchChunks = FETCH_CHUNK } = options;
425
- if (fromBlock === undefined) {
426
- return contract.queryFilter(membersFilter);
427
- }
428
- if (!contract.provider) {
429
- throw Error("No provider found on the contract.");
430
- }
431
- const toBlock = await contract.provider.getBlockNumber();
432
- if (toBlock - fromBlock < fetchRange) {
433
- return contract.queryFilter(membersFilter, fromBlock, toBlock);
434
- }
435
- const events = [];
436
- const chunks = splitToChunks(fromBlock, toBlock, fetchRange);
437
- for (const portion of takeN(chunks, fetchChunks)) {
438
- const promises = portion.map(([left, right]) => ignoreErrors(contract.queryFilter(membersFilter, left, right), []));
439
- const fetchedEvents = await Promise.all(promises);
440
- events.push(fetchedEvents.flatMap((v) => v));
441
- }
442
- return events.flatMap((v) => v);
443
- }
444
- function splitToChunks(from, to, step) {
445
- const chunks = [];
446
- let left = from;
447
- while (left < to) {
448
- const right = left + step < to ? left + step : to;
449
- chunks.push([left, right]);
450
- left = right;
451
- }
452
- return chunks;
453
- }
454
- function* takeN(array, size) {
455
- let start = 0;
456
- while (start < array.length) {
457
- const portion = array.slice(start, start + size);
458
- yield portion;
459
- start += size;
460
- }
461
- }
462
- async function ignoreErrors(promise, defaultValue) {
463
- try {
464
- return await promise;
465
- }
466
- catch (err) {
467
- if (err instanceof Error) {
468
- log.info(`Ignoring an error during query: ${err.message}`);
469
- }
470
- else {
471
- log.info(`Ignoring an unknown error during query`);
472
- }
473
- return defaultValue;
474
- }
475
- }
476
481
 
477
- export { MembershipState, RLNLightContract };
482
+ export { RLNBaseContract };