@waku/rln 0.1.5-053bb95.0 → 0.1.5-164df63.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 (158) hide show
  1. package/bundle/_virtual/utils.js +2 -2
  2. package/bundle/_virtual/utils2.js +2 -2
  3. package/bundle/index.js +2 -1
  4. package/bundle/packages/rln/dist/contract/constants.js +6 -2
  5. package/bundle/packages/rln/dist/contract/rln_base_contract.js +282 -146
  6. package/bundle/packages/rln/dist/contract/rln_contract.js +74 -89
  7. package/bundle/packages/rln/dist/credentials_manager.js +1 -1
  8. package/bundle/packages/rln/dist/identity.js +0 -8
  9. package/bundle/packages/rln/dist/keystore/keystore.js +28 -15
  10. package/bundle/packages/rln/dist/utils/bytes.js +8 -2
  11. package/bundle/packages/rln/dist/utils/metamask.js +2 -2
  12. package/bundle/packages/rln/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +1 -1
  13. package/bundle/packages/rln/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +2 -2
  14. package/bundle/packages/rln/node_modules/@noble/hashes/_sha2.js +1 -1
  15. package/bundle/packages/rln/node_modules/@noble/hashes/hmac.js +1 -1
  16. package/bundle/packages/rln/node_modules/@noble/hashes/pbkdf2.js +1 -1
  17. package/bundle/packages/rln/node_modules/@noble/hashes/scrypt.js +1 -1
  18. package/bundle/packages/rln/node_modules/@noble/hashes/sha256.js +1 -1
  19. package/bundle/packages/rln/node_modules/@noble/hashes/sha512.js +1 -1
  20. package/bundle/packages/rln/node_modules/@noble/hashes/utils.js +1 -1
  21. package/dist/.tsbuildinfo +1 -1
  22. package/dist/contract/constants.d.ts +1 -1
  23. package/dist/contract/constants.js +1 -1
  24. package/dist/contract/constants.js.map +1 -1
  25. package/dist/contract/index.d.ts +1 -0
  26. package/dist/contract/index.js +1 -0
  27. package/dist/contract/index.js.map +1 -1
  28. package/dist/contract/rln_base_contract.d.ts +27 -25
  29. package/dist/contract/rln_base_contract.js +280 -144
  30. package/dist/contract/rln_base_contract.js.map +1 -1
  31. package/dist/contract/rln_contract.d.ts +4 -24
  32. package/dist/contract/rln_contract.js +74 -89
  33. package/dist/contract/rln_contract.js.map +1 -1
  34. package/dist/contract/types.d.ts +5 -0
  35. package/dist/contract/types.js.map +1 -1
  36. package/dist/credentials_manager.js +1 -1
  37. package/dist/credentials_manager.js.map +1 -1
  38. package/dist/identity.d.ts +0 -1
  39. package/dist/identity.js +0 -8
  40. package/dist/identity.js.map +1 -1
  41. package/dist/index.d.ts +2 -1
  42. package/dist/index.js +1 -0
  43. package/dist/index.js.map +1 -1
  44. package/dist/keystore/keystore.d.ts +1 -0
  45. package/dist/keystore/keystore.js +28 -15
  46. package/dist/keystore/keystore.js.map +1 -1
  47. package/dist/keystore/types.d.ts +2 -2
  48. package/dist/utils/bytes.js +8 -2
  49. package/dist/utils/bytes.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/contract/constants.ts +1 -1
  52. package/src/contract/index.ts +1 -0
  53. package/src/contract/rln_base_contract.ts +428 -216
  54. package/src/contract/rln_contract.ts +95 -120
  55. package/src/contract/types.ts +5 -0
  56. package/src/credentials_manager.ts +1 -1
  57. package/src/identity.ts +0 -9
  58. package/src/index.ts +3 -1
  59. package/src/keystore/keystore.ts +54 -29
  60. package/src/keystore/types.ts +2 -2
  61. package/src/utils/bytes.ts +10 -2
  62. package/bundle/_virtual/__node-resolve_empty.js +0 -6
  63. package/bundle/_virtual/_node-resolve_empty.js +0 -3
  64. package/bundle/_virtual/bn.js +0 -3
  65. package/bundle/_virtual/common.js +0 -3
  66. package/bundle/_virtual/common2.js +0 -3
  67. package/bundle/_virtual/hash.js +0 -3
  68. package/bundle/_virtual/inherits_browser.js +0 -3
  69. package/bundle/_virtual/ripemd.js +0 -3
  70. package/bundle/_virtual/sha.js +0 -3
  71. package/bundle/_virtual/sha3.js +0 -3
  72. package/bundle/_virtual/utils3.js +0 -3
  73. package/bundle/node_modules/@ethersproject/abi/lib.esm/_version.js +0 -3
  74. package/bundle/node_modules/@ethersproject/abi/lib.esm/abi-coder.js +0 -96
  75. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/abstract-coder.js +0 -148
  76. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/address.js +0 -26
  77. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/anonymous.js +0 -20
  78. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/array.js +0 -210
  79. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/boolean.js +0 -18
  80. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/bytes.js +0 -30
  81. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/fixed-bytes.js +0 -26
  82. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/null.js +0 -22
  83. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/number.js +0 -43
  84. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/string.js +0 -19
  85. package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/tuple.js +0 -58
  86. package/bundle/node_modules/@ethersproject/abi/lib.esm/fragments.js +0 -854
  87. package/bundle/node_modules/@ethersproject/abi/lib.esm/interface.js +0 -609
  88. package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/_version.js +0 -3
  89. package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/index.js +0 -66
  90. package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/_version.js +0 -3
  91. package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/index.js +0 -302
  92. package/bundle/node_modules/@ethersproject/address/lib.esm/_version.js +0 -3
  93. package/bundle/node_modules/@ethersproject/address/lib.esm/index.js +0 -110
  94. package/bundle/node_modules/@ethersproject/base64/lib.esm/base64.js +0 -20
  95. package/bundle/node_modules/@ethersproject/basex/lib.esm/index.js +0 -120
  96. package/bundle/node_modules/@ethersproject/bignumber/lib.esm/_version.js +0 -3
  97. package/bundle/node_modules/@ethersproject/bignumber/lib.esm/bignumber.js +0 -287
  98. package/bundle/node_modules/@ethersproject/bytes/lib.esm/_version.js +0 -3
  99. package/bundle/node_modules/@ethersproject/bytes/lib.esm/index.js +0 -402
  100. package/bundle/node_modules/@ethersproject/constants/lib.esm/addresses.js +0 -3
  101. package/bundle/node_modules/@ethersproject/constants/lib.esm/bignumbers.js +0 -8
  102. package/bundle/node_modules/@ethersproject/constants/lib.esm/hashes.js +0 -3
  103. package/bundle/node_modules/@ethersproject/contracts/lib.esm/_version.js +0 -3
  104. package/bundle/node_modules/@ethersproject/contracts/lib.esm/index.js +0 -893
  105. package/bundle/node_modules/@ethersproject/hash/lib.esm/_version.js +0 -3
  106. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/decoder.js +0 -256
  107. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/include.js +0 -36
  108. package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/lib.js +0 -135
  109. package/bundle/node_modules/@ethersproject/hash/lib.esm/id.js +0 -8
  110. package/bundle/node_modules/@ethersproject/hash/lib.esm/namehash.js +0 -64
  111. package/bundle/node_modules/@ethersproject/hash/lib.esm/typed-data.js +0 -443
  112. package/bundle/node_modules/@ethersproject/keccak256/lib.esm/index.js +0 -8
  113. package/bundle/node_modules/@ethersproject/keccak256/node_modules/js-sha3/src/sha3.js +0 -660
  114. package/bundle/node_modules/@ethersproject/logger/lib.esm/_version.js +0 -3
  115. package/bundle/node_modules/@ethersproject/logger/lib.esm/index.js +0 -352
  116. package/bundle/node_modules/@ethersproject/networks/lib.esm/_version.js +0 -3
  117. package/bundle/node_modules/@ethersproject/networks/lib.esm/index.js +0 -248
  118. package/bundle/node_modules/@ethersproject/properties/lib.esm/_version.js +0 -3
  119. package/bundle/node_modules/@ethersproject/properties/lib.esm/index.js +0 -127
  120. package/bundle/node_modules/@ethersproject/providers/lib.esm/_version.js +0 -3
  121. package/bundle/node_modules/@ethersproject/providers/lib.esm/base-provider.js +0 -2007
  122. package/bundle/node_modules/@ethersproject/providers/lib.esm/formatter.js +0 -422
  123. package/bundle/node_modules/@ethersproject/providers/lib.esm/json-rpc-provider.js +0 -674
  124. package/bundle/node_modules/@ethersproject/providers/lib.esm/web3-provider.js +0 -132
  125. package/bundle/node_modules/@ethersproject/rlp/lib.esm/_version.js +0 -3
  126. package/bundle/node_modules/@ethersproject/rlp/lib.esm/index.js +0 -120
  127. package/bundle/node_modules/@ethersproject/sha2/lib.esm/sha2.js +0 -8
  128. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/_version.js +0 -3
  129. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/elliptic.js +0 -2430
  130. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/index.js +0 -76
  131. package/bundle/node_modules/@ethersproject/strings/lib.esm/_version.js +0 -3
  132. package/bundle/node_modules/@ethersproject/strings/lib.esm/utf8.js +0 -219
  133. package/bundle/node_modules/@ethersproject/transactions/lib.esm/_version.js +0 -3
  134. package/bundle/node_modules/@ethersproject/transactions/lib.esm/index.js +0 -279
  135. package/bundle/node_modules/@ethersproject/web/lib.esm/_version.js +0 -3
  136. package/bundle/node_modules/@ethersproject/web/lib.esm/geturl.js +0 -69
  137. package/bundle/node_modules/@ethersproject/web/lib.esm/index.js +0 -404
  138. package/bundle/node_modules/bech32/index.js +0 -187
  139. package/bundle/node_modules/bn.js/lib/bn.js +0 -3361
  140. package/bundle/node_modules/hash.js/lib/hash/common.js +0 -97
  141. package/bundle/node_modules/hash.js/lib/hash/hmac.js +0 -51
  142. package/bundle/node_modules/hash.js/lib/hash/ripemd.js +0 -152
  143. package/bundle/node_modules/hash.js/lib/hash/sha/1.js +0 -81
  144. package/bundle/node_modules/hash.js/lib/hash/sha/224.js +0 -33
  145. package/bundle/node_modules/hash.js/lib/hash/sha/256.js +0 -113
  146. package/bundle/node_modules/hash.js/lib/hash/sha/384.js +0 -39
  147. package/bundle/node_modules/hash.js/lib/hash/sha/512.js +0 -336
  148. package/bundle/node_modules/hash.js/lib/hash/sha/common.js +0 -53
  149. package/bundle/node_modules/hash.js/lib/hash/sha.js +0 -14
  150. package/bundle/node_modules/hash.js/lib/hash/utils.js +0 -282
  151. package/bundle/node_modules/hash.js/lib/hash.js +0 -33
  152. package/bundle/node_modules/inherits/inherits_browser.js +0 -33
  153. package/bundle/node_modules/minimalistic-assert/index.js +0 -13
  154. package/bundle/packages/rln/dist/contract/errors.js +0 -62
  155. package/dist/contract/errors.d.ts +0 -30
  156. package/dist/contract/errors.js +0 -61
  157. package/dist/contract/errors.js.map +0 -1
  158. package/src/contract/errors.ts +0 -75
@@ -1,3 +1,3 @@
1
- var utils = {exports: {}};
1
+ var utils = {};
2
2
 
3
- export { utils as __module };
3
+ export { utils as __exports };
@@ -1,3 +1,3 @@
1
- var utils = {};
1
+ var utils = {exports: {}};
2
2
 
3
- export { utils as __exports };
3
+ export { utils as __module };
package/bundle/index.js CHANGED
@@ -1,7 +1,8 @@
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';
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';
5
6
  export { RLNBaseContract } from './packages/rln/dist/contract/rln_base_contract.js';
6
7
  export { createRLN } from './packages/rln/dist/create.js';
7
8
  export { RLNCredentialsManager } from './packages/rln/dist/credentials_manager.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,12 +12,16 @@ 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
18
19
  const RATE_LIMIT_PARAMS = {
19
20
  MIN_RATE: RATE_LIMIT_TIERS.LOW,
20
- MAX_RATE: RATE_LIMIT_TIERS.HIGH};
21
+ MAX_RATE: RATE_LIMIT_TIERS.HIGH,
22
+ MAX_TOTAL_RATE: 160_000, // Maximum total rate limit across all memberships
23
+ EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
24
+ };
21
25
  const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
22
26
 
23
27
  export { DEFAULT_RATE_LIMIT, LINEA_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS };
@@ -15,20 +15,53 @@ 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 { RLNContractError, InvalidMembershipError, MembershipNotFoundError, MembershipExistsError, RateLimitExceededError, InvalidRateLimitError, TransactionError } from './errors.js';
19
18
  import { MembershipState } from './types.js';
20
- import { Contract } from '../../../../node_modules/@ethersproject/contracts/lib.esm/index.js';
21
- import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
19
+ import { Contract } from '@ethersproject/contracts';
20
+ import { BigNumber } from '@ethersproject/bignumber';
22
21
 
22
+ /* eslint-disable no-console */
23
23
  const log = new Logger("waku:rln:contract:base");
24
24
  class RLNBaseContract {
25
25
  contract;
26
+ deployBlock;
26
27
  rateLimit;
28
+ _members = new Map();
29
+ _membersFilter;
30
+ _membershipErasedFilter;
31
+ _membersExpiredFilter;
32
+ /**
33
+ * Constructor for RLNBaseContract.
34
+ * Allows injecting a mocked contract for testing purposes.
35
+ */
27
36
  constructor(options) {
28
37
  const { address, signer, rateLimit = DEFAULT_RATE_LIMIT, contract } = options;
29
- this.validateRateLimit(rateLimit);
38
+ log.info("Initializing RLNBaseContract", { address, rateLimit });
30
39
  this.contract = contract || new Contract(address, RLN_ABI, signer);
31
40
  this.rateLimit = rateLimit;
41
+ try {
42
+ log.info("Setting up event filters");
43
+ // Initialize event filters
44
+ this._membersFilter = this.contract.filters.MembershipRegistered();
45
+ this._membershipErasedFilter = this.contract.filters.MembershipErased();
46
+ this._membersExpiredFilter = this.contract.filters.MembershipExpired();
47
+ log.info("Event filters initialized successfully");
48
+ }
49
+ catch (error) {
50
+ log.error("Failed to initialize event filters", { error });
51
+ throw new Error("Failed to initialize event filters: " + error.message);
52
+ }
53
+ // Initialize members and subscriptions
54
+ this.fetchMembers()
55
+ .then(() => {
56
+ this.subscribeToMembers();
57
+ })
58
+ .catch((error) => {
59
+ log.error("Failed to initialize members", { error });
60
+ });
61
+ // Validate rate limit asynchronously
62
+ this.validateRateLimit(rateLimit).catch((error) => {
63
+ log.error("Failed to validate initial rate limit", { error });
64
+ });
32
65
  }
33
66
  /**
34
67
  * Gets the current rate limit for this contract instance
@@ -96,221 +129,299 @@ class RLNBaseContract {
96
129
  * @param newRateLimit The new rate limit to use
97
130
  */
98
131
  async setRateLimit(newRateLimit) {
99
- this.validateRateLimit(newRateLimit);
132
+ await this.validateRateLimit(newRateLimit);
100
133
  this.rateLimit = newRateLimit;
101
134
  }
102
- /**
103
- * Gets all members in the given range
104
- * @param startIndex Start index (inclusive)
105
- * @param endIndex End index (exclusive)
106
- */
107
- async getMembersInRange(startIndex, endIndex) {
108
- try {
109
- // Get all commitments in one call
110
- const idCommitments = await this.contract.getRateCommitmentsInRangeBoundsInclusive(startIndex, endIndex - 1 // -1 because getRateCommitmentsInRangeBoundsInclusive is inclusive
111
- );
112
- // Get membership info for each commitment in a single batch
113
- const membershipPromises = idCommitments.map((idCommitment) => this.contract
114
- .memberships(idCommitment)
115
- .then((info) => ({
116
- idCommitment: idCommitment.toString(),
117
- index: BigNumber.from(info.index)
118
- }))
119
- .catch(() => null) // Skip invalid members
120
- );
121
- // Wait for all promises to resolve
122
- const members = (await Promise.all(membershipPromises)).filter((m) => m !== null);
123
- return members;
135
+ get members() {
136
+ const sortedMembers = Array.from(this._members.values()).sort((left, right) => left.index.toNumber() - right.index.toNumber());
137
+ return sortedMembers;
138
+ }
139
+ async fetchMembers(options = {}) {
140
+ const registeredMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
141
+ fromBlock: this.deployBlock,
142
+ ...options,
143
+ membersFilter: this.membersFilter
144
+ });
145
+ const removedMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
146
+ fromBlock: this.deployBlock,
147
+ ...options,
148
+ membersFilter: this.membershipErasedFilter
149
+ });
150
+ const expiredMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
151
+ fromBlock: this.deployBlock,
152
+ ...options,
153
+ membersFilter: this.membersExpiredFilter
154
+ });
155
+ const events = [
156
+ ...registeredMemberEvents,
157
+ ...removedMemberEvents,
158
+ ...expiredMemberEvents
159
+ ];
160
+ this.processEvents(events);
161
+ }
162
+ static async queryFilter(contract, options) {
163
+ const FETCH_CHUNK = 5;
164
+ const BLOCK_RANGE = 3000;
165
+ const { fromBlock, membersFilter, fetchRange = BLOCK_RANGE, fetchChunks = FETCH_CHUNK } = options;
166
+ if (fromBlock === undefined) {
167
+ return contract.queryFilter(membersFilter);
124
168
  }
125
- catch (error) {
126
- if (error instanceof Error &&
127
- error.message.includes("InvalidPaginationQuery")) {
128
- throw new RLNContractError(`Invalid pagination range: start=${startIndex}, end=${endIndex}`);
169
+ if (!contract.provider) {
170
+ throw Error("No provider found on the contract.");
171
+ }
172
+ const toBlock = await contract.provider.getBlockNumber();
173
+ if (toBlock - fromBlock < fetchRange) {
174
+ return contract.queryFilter(membersFilter, fromBlock, toBlock);
175
+ }
176
+ const events = [];
177
+ const chunks = RLNBaseContract.splitToChunks(fromBlock, toBlock, fetchRange);
178
+ for (const portion of RLNBaseContract.takeN(chunks, fetchChunks)) {
179
+ const promises = portion.map(([left, right]) => RLNBaseContract.ignoreErrors(contract.queryFilter(membersFilter, left, right), []));
180
+ const fetchedEvents = await Promise.all(promises);
181
+ events.push(fetchedEvents.flatMap((v) => v));
182
+ }
183
+ return events.flatMap((v) => v);
184
+ }
185
+ processEvents(events) {
186
+ const toRemoveTable = new Map();
187
+ const toInsertTable = new Map();
188
+ events.forEach((evt) => {
189
+ if (!evt.args) {
190
+ return;
129
191
  }
130
- throw error;
192
+ if (evt.event === "MembershipErased" ||
193
+ evt.event === "MembershipExpired") {
194
+ let index = evt.args.index;
195
+ if (!index) {
196
+ return;
197
+ }
198
+ if (typeof index === "number" || typeof index === "string") {
199
+ index = BigNumber.from(index);
200
+ }
201
+ const toRemoveVal = toRemoveTable.get(evt.blockNumber);
202
+ if (toRemoveVal != undefined) {
203
+ toRemoveVal.push(index.toNumber());
204
+ toRemoveTable.set(evt.blockNumber, toRemoveVal);
205
+ }
206
+ else {
207
+ toRemoveTable.set(evt.blockNumber, [index.toNumber()]);
208
+ }
209
+ }
210
+ else if (evt.event === "MembershipRegistered") {
211
+ let eventsPerBlock = toInsertTable.get(evt.blockNumber);
212
+ if (eventsPerBlock == undefined) {
213
+ eventsPerBlock = [];
214
+ }
215
+ eventsPerBlock.push(evt);
216
+ toInsertTable.set(evt.blockNumber, eventsPerBlock);
217
+ }
218
+ });
219
+ }
220
+ static splitToChunks(from, to, step) {
221
+ const chunks = [];
222
+ let left = from;
223
+ while (left < to) {
224
+ const right = left + step < to ? left + step : to;
225
+ chunks.push([left, right]);
226
+ left = right;
131
227
  }
228
+ return chunks;
132
229
  }
133
- /**
134
- * Gets all current members
135
- */
136
- async getAllMembers() {
137
- const nextIndex = (await this.contract.nextFreeIndex()).toNumber();
138
- return this.getMembersInRange(0, nextIndex);
230
+ static *takeN(array, size) {
231
+ let start = 0;
232
+ while (start < array.length) {
233
+ const portion = array.slice(start, start + size);
234
+ yield portion;
235
+ start += size;
236
+ }
139
237
  }
140
- /**
141
- * Gets the member index if it exists, or null if it doesn't
142
- * Throws only on actual errors (invalid input, network issues, etc)
143
- */
144
- async getMemberIndex(idCommitment) {
238
+ static async ignoreErrors(promise, defaultValue) {
145
239
  try {
146
- const isValid = await this.contract.isInMembershipSet(idCommitment);
147
- if (!isValid) {
148
- return null;
149
- }
150
- const membershipInfo = await this.contract.memberships(idCommitment);
151
- return BigNumber.from(membershipInfo.index);
240
+ return await promise;
152
241
  }
153
- catch (error) {
154
- log.error(`Error getting member index: ${error.message}`);
155
- throw new InvalidMembershipError(idCommitment);
242
+ catch (err) {
243
+ if (err instanceof Error) {
244
+ log.info(`Ignoring an error during query: ${err.message}`);
245
+ }
246
+ else {
247
+ log.info(`Ignoring an unknown error during query`);
248
+ }
249
+ return defaultValue;
156
250
  }
157
251
  }
158
- async getMembershipInfo(idCommitment) {
252
+ subscribeToMembers() {
253
+ this.contract.on(this.membersFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
254
+ this.processEvents([event]);
255
+ });
256
+ this.contract.on(this.membershipErasedFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
257
+ this.processEvents([event]);
258
+ });
259
+ this.contract.on(this.membersExpiredFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
260
+ this.processEvents([event]);
261
+ });
262
+ }
263
+ async getMembershipInfo(idCommitmentBigInt) {
159
264
  try {
160
- const [startBlock, endBlock, rateLimit] = await this.contract.getMembershipInfo(idCommitment);
265
+ const membershipData = await this.contract.memberships(idCommitmentBigInt);
161
266
  const currentBlock = await this.contract.provider.getBlockNumber();
267
+ console.log("membershipData", membershipData);
268
+ const [depositAmount, activeDuration, gracePeriodStartTimestamp, gracePeriodDuration, rateLimit, index, holder, token] = membershipData;
269
+ const gracePeriodEnd = gracePeriodStartTimestamp.add(gracePeriodDuration);
162
270
  let state;
163
- if (currentBlock < startBlock) {
271
+ if (currentBlock < gracePeriodStartTimestamp.toNumber()) {
164
272
  state = MembershipState.Active;
165
273
  }
166
- else if (currentBlock < endBlock) {
274
+ else if (currentBlock < gracePeriodEnd.toNumber()) {
167
275
  state = MembershipState.GracePeriod;
168
276
  }
169
277
  else {
170
278
  state = MembershipState.Expired;
171
279
  }
172
- const index = await this.getMemberIndex(idCommitment);
173
- if (index === null) {
174
- throw new MembershipNotFoundError(idCommitment);
175
- }
176
280
  return {
177
281
  index,
178
- idCommitment,
179
- rateLimit: rateLimit.toNumber(),
180
- startBlock: startBlock.toNumber(),
181
- endBlock: endBlock.toNumber(),
182
- state
282
+ idCommitment: idCommitmentBigInt.toString(),
283
+ rateLimit: Number(rateLimit),
284
+ startBlock: gracePeriodStartTimestamp.toNumber(),
285
+ endBlock: gracePeriodEnd.toNumber(),
286
+ state,
287
+ depositAmount,
288
+ activeDuration,
289
+ gracePeriodDuration,
290
+ holder,
291
+ token
183
292
  };
184
293
  }
185
294
  catch (error) {
186
- if (error instanceof RLNContractError) {
187
- throw error;
188
- }
189
- log.error(`Error getting membership info: ${error.message}`);
190
- throw new InvalidMembershipError(idCommitment);
295
+ log.error("Error in getMembershipInfo:", error);
296
+ return undefined;
191
297
  }
192
298
  }
193
- async extendMembership(idCommitment) {
194
- const tx = await this.contract.extendMemberships([idCommitment]);
195
- await this.confirmTransaction(tx, "MembershipExtended", (event) => ({
196
- idCommitment: event.args.idCommitment,
197
- endBlock: event.args.endBlock
198
- }));
299
+ async extendMembership(idCommitmentBigInt) {
300
+ const tx = await this.contract.extendMemberships([idCommitmentBigInt]);
301
+ await tx.wait();
302
+ return tx;
199
303
  }
200
- async eraseMembership(idCommitment, eraseFromMembershipSet = true) {
201
- const tx = await this.contract.eraseMemberships([idCommitment], eraseFromMembershipSet);
202
- await this.confirmTransaction(tx, "MembershipErased", (event) => ({
203
- idCommitment: event.args.idCommitment,
204
- index: event.args.index
205
- }));
304
+ async eraseMembership(idCommitmentBigInt, eraseFromMembershipSet = true) {
305
+ console.log(Object.keys(this.contract));
306
+ const tx = await this.contract.eraseMemberships([idCommitmentBigInt], eraseFromMembershipSet);
307
+ await tx.wait();
308
+ return tx;
206
309
  }
207
- async registerMembership(idCommitment, rateLimit = DEFAULT_RATE_LIMIT) {
208
- if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
209
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
210
- throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
211
- }
212
- const tx = await this.contract.register(idCommitment, rateLimit, []);
213
- await this.confirmTransaction(tx, "MembershipRegistered", (event) => ({
214
- idCommitment: event.args.idCommitment,
215
- membershipRateLimit: event.args.membershipRateLimit,
216
- index: event.args.index
217
- }));
218
- }
219
- async withdraw(token, holder) {
310
+ async withdraw(token, from) {
220
311
  try {
221
- const tx = await this.contract.withdraw(token, { from: holder });
222
- await this.confirmTransaction(tx, "TokenWithdrawn", (event) => ({
223
- token: event.args.token,
224
- holder: event.args.holder,
225
- amount: event.args.amount
226
- }));
312
+ const tx = await this.contract.withdraw(token, from);
313
+ await tx.wait();
227
314
  }
228
315
  catch (error) {
229
316
  log.error(`Error in withdraw: ${error.message}`);
230
- throw error;
231
317
  }
232
318
  }
319
+ async registerMembership(idCommitmentBigInt, rateLimit = DEFAULT_RATE_LIMIT) {
320
+ if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
321
+ rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
322
+ throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
323
+ }
324
+ return this.contract.register(idCommitmentBigInt, rateLimit, []);
325
+ }
233
326
  async registerWithIdentity(identity) {
234
327
  try {
235
328
  log.info(`Registering identity with rate limit: ${this.rateLimit} messages/epoch`);
236
329
  // Check if the ID commitment is already registered
237
- const existingIndex = await this.getMemberIndex(identity.IDCommitmentBigInt.toString());
238
- if (existingIndex !== null) {
239
- throw new MembershipExistsError(identity.IDCommitmentBigInt.toString(), existingIndex.toString());
330
+ const existingIndex = await this.getMemberIndex(identity.IDCommitmentBigInt);
331
+ if (existingIndex) {
332
+ throw new Error(`ID commitment is already registered with index ${existingIndex}`);
240
333
  }
241
334
  // Check if there's enough remaining rate limit
242
335
  const remainingRateLimit = await this.getRemainingTotalRateLimit();
243
336
  if (remainingRateLimit < this.rateLimit) {
244
- throw new RateLimitExceededError(this.rateLimit, remainingRateLimit);
337
+ throw new Error(`Not enough remaining rate limit. Requested: ${this.rateLimit}, Available: ${remainingRateLimit}`);
245
338
  }
246
339
  const estimatedGas = await this.contract.estimateGas.register(identity.IDCommitmentBigInt, this.rateLimit, []);
247
340
  const gasLimit = estimatedGas.add(10000);
248
- const tx = await this.contract.register(identity.IDCommitmentBigInt, this.rateLimit, [], { gasLimit });
249
- const decodedData = await this.confirmTransaction(tx, "MembershipRegistered", (event) => ({
250
- idCommitment: event.args.idCommitment,
251
- membershipRateLimit: event.args.membershipRateLimit,
252
- index: event.args.index
253
- }));
341
+ const txRegisterResponse = await this.contract.register(identity.IDCommitmentBigInt, this.rateLimit, [], { gasLimit });
342
+ const txRegisterReceipt = await txRegisterResponse.wait();
343
+ if (txRegisterReceipt.status === 0) {
344
+ throw new Error("Transaction failed on-chain");
345
+ }
346
+ const memberRegistered = txRegisterReceipt.events?.find((event) => event.event === "MembershipRegistered");
347
+ if (!memberRegistered || !memberRegistered.args) {
348
+ log.error("Failed to register membership: No MembershipRegistered event found");
349
+ return undefined;
350
+ }
351
+ const decodedData = {
352
+ idCommitment: memberRegistered.args.idCommitment,
353
+ membershipRateLimit: memberRegistered.args.membershipRateLimit,
354
+ index: memberRegistered.args.index
355
+ };
254
356
  log.info(`Successfully registered membership with index ${decodedData.index} ` +
255
357
  `and rate limit ${decodedData.membershipRateLimit}`);
256
358
  const network = await this.contract.provider.getNetwork();
257
359
  const address = this.contract.address;
258
- const membershipId = decodedData.index.toString();
360
+ const membershipId = Number(decodedData.index);
259
361
  return {
260
362
  identity,
261
363
  membership: {
262
364
  address,
263
- treeIndex: parseInt(membershipId),
365
+ treeIndex: membershipId,
264
366
  chainId: network.chainId.toString(),
265
367
  rateLimit: decodedData.membershipRateLimit.toNumber()
266
368
  }
267
369
  };
268
370
  }
269
371
  catch (error) {
270
- if (error instanceof RLNContractError) {
271
- throw error;
272
- }
273
372
  if (error instanceof Error) {
274
373
  const errorMessage = error.message;
275
374
  log.error("registerWithIdentity - error message:", errorMessage);
276
375
  log.error("registerWithIdentity - error stack:", error.stack);
277
- // Map contract errors to our custom errors
376
+ // Try to extract more specific error information
278
377
  if (errorMessage.includes("CannotExceedMaxTotalRateLimit")) {
279
- throw new RateLimitExceededError(this.rateLimit, await this.getRemainingTotalRateLimit());
378
+ throw new Error("Registration failed: Cannot exceed maximum total rate limit");
280
379
  }
281
380
  else if (errorMessage.includes("InvalidIdCommitment")) {
282
- throw new InvalidMembershipError(identity.IDCommitmentBigInt.toString());
381
+ throw new Error("Registration failed: Invalid ID commitment");
283
382
  }
284
383
  else if (errorMessage.includes("InvalidMembershipRateLimit")) {
285
- throw new InvalidRateLimitError(this.rateLimit, RATE_LIMIT_PARAMS.MIN_RATE, RATE_LIMIT_PARAMS.MAX_RATE);
384
+ throw new Error("Registration failed: Invalid membership rate limit");
286
385
  }
287
386
  else if (errorMessage.includes("execution reverted")) {
288
- throw new TransactionError("Contract execution reverted. Check contract requirements.");
387
+ throw new Error("Contract execution reverted. Check contract requirements.");
388
+ }
389
+ else {
390
+ throw new Error(`Error in registerWithIdentity: ${errorMessage}`);
289
391
  }
290
- throw new RLNContractError(`Error in registerWithIdentity: ${errorMessage}`);
291
392
  }
292
- throw new RLNContractError("Unknown error in registerWithIdentity");
393
+ else {
394
+ throw new Error("Unknown error in registerWithIdentity", {
395
+ cause: error
396
+ });
397
+ }
293
398
  }
294
399
  }
295
400
  async registerWithPermitAndErase(identity, permit, idCommitmentsToErase) {
296
401
  try {
297
402
  log.info(`Registering identity with permit and rate limit: ${this.rateLimit} messages/epoch`);
298
- const tx = await this.contract.registerWithPermit(permit.owner, permit.deadline, permit.v, permit.r, permit.s, identity.IDCommitmentBigInt, this.rateLimit, idCommitmentsToErase.map((id) => BigNumber.from(id)));
299
- const decodedData = await this.confirmTransaction(tx, "MembershipRegistered", (event) => ({
300
- idCommitment: event.args.idCommitment,
301
- membershipRateLimit: event.args.membershipRateLimit,
302
- index: event.args.index
303
- }));
403
+ const txRegisterResponse = await this.contract.registerWithPermit(permit.owner, permit.deadline, permit.v, permit.r, permit.s, identity.IDCommitmentBigInt, this.rateLimit, idCommitmentsToErase.map((id) => BigNumber.from(id)));
404
+ const txRegisterReceipt = await txRegisterResponse.wait();
405
+ const memberRegistered = txRegisterReceipt.events?.find((event) => event.event === "MembershipRegistered");
406
+ if (!memberRegistered || !memberRegistered.args) {
407
+ log.error("Failed to register membership with permit: No MembershipRegistered event found");
408
+ return undefined;
409
+ }
410
+ const decodedData = {
411
+ idCommitment: memberRegistered.args.idCommitment,
412
+ membershipRateLimit: memberRegistered.args.membershipRateLimit,
413
+ index: memberRegistered.args.index
414
+ };
304
415
  log.info(`Successfully registered membership with permit. Index: ${decodedData.index}, ` +
305
416
  `Rate limit: ${decodedData.membershipRateLimit}, Erased ${idCommitmentsToErase.length} commitments`);
306
417
  const network = await this.contract.provider.getNetwork();
307
418
  const address = this.contract.address;
308
- const membershipId = decodedData.index.toString();
419
+ const membershipId = Number(decodedData.index);
309
420
  return {
310
421
  identity,
311
422
  membership: {
312
423
  address,
313
- treeIndex: parseInt(membershipId),
424
+ treeIndex: membershipId,
314
425
  chainId: network.chainId.toString(),
315
426
  rateLimit: decodedData.membershipRateLimit.toNumber()
316
427
  }
@@ -318,29 +429,54 @@ class RLNBaseContract {
318
429
  }
319
430
  catch (error) {
320
431
  log.error(`Error in registerWithPermitAndErase: ${error.message}`);
321
- throw error;
432
+ return undefined;
322
433
  }
323
434
  }
324
435
  /**
325
436
  * Validates that the rate limit is within the allowed range
326
437
  * @throws Error if the rate limit is outside the allowed range
327
438
  */
328
- validateRateLimit(rateLimit) {
329
- if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
330
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
331
- throw new InvalidRateLimitError(rateLimit, RATE_LIMIT_PARAMS.MIN_RATE, RATE_LIMIT_PARAMS.MAX_RATE);
439
+ async validateRateLimit(rateLimit) {
440
+ const [minRate, maxRate] = await Promise.all([
441
+ this.contract.minMembershipRateLimit(),
442
+ this.contract.maxMembershipRateLimit()
443
+ ]);
444
+ const minRateNum = BigNumber.from(minRate).toNumber();
445
+ const maxRateNum = BigNumber.from(maxRate).toNumber();
446
+ if (rateLimit < minRateNum || rateLimit > maxRateNum) {
447
+ throw new Error(`Rate limit must be between ${minRateNum} and ${maxRateNum} messages per epoch`);
332
448
  }
333
449
  }
334
- /**
335
- * Helper to confirm a transaction and extract event data
336
- */
337
- async confirmTransaction(tx, expectedEvent, transform) {
338
- const receipt = await tx.wait();
339
- const event = receipt.events?.find((e) => e.event === expectedEvent);
340
- if (!event || !event.args) {
341
- throw new TransactionError(`Expected event ${expectedEvent} not found`);
450
+ get membersFilter() {
451
+ if (!this._membersFilter) {
452
+ throw Error("Members filter was not initialized.");
453
+ }
454
+ return this._membersFilter;
455
+ }
456
+ get membershipErasedFilter() {
457
+ if (!this._membershipErasedFilter) {
458
+ throw Error("MembershipErased filter was not initialized.");
459
+ }
460
+ return this._membershipErasedFilter;
461
+ }
462
+ get membersExpiredFilter() {
463
+ if (!this._membersExpiredFilter) {
464
+ throw Error("MembersExpired filter was not initialized.");
465
+ }
466
+ return this._membersExpiredFilter;
467
+ }
468
+ async getMemberIndex(idCommitmentBigInt) {
469
+ try {
470
+ const events = await this.contract.queryFilter(this.contract.filters.MembershipRegistered(idCommitmentBigInt));
471
+ if (events.length === 0)
472
+ return undefined;
473
+ // Get the most recent registration event
474
+ const event = events[events.length - 1];
475
+ return event.args?.index;
476
+ }
477
+ catch (error) {
478
+ return undefined;
342
479
  }
343
- return transform(event);
344
480
  }
345
481
  }
346
482