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