@waku/rln 0.1.5-f39d215.0 → 0.1.5-f6b9809.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.
- package/bundle/_virtual/utils.js +2 -2
- package/bundle/_virtual/utils2.js +2 -2
- package/bundle/index.js +2 -2
- package/bundle/packages/rln/dist/contract/constants.js +2 -5
- package/bundle/packages/rln/dist/contract/{rln_light_contract.js → rln_base_contract.js} +165 -177
- package/bundle/packages/rln/dist/contract/rln_contract.js +9 -419
- package/bundle/packages/rln/dist/contract/types.js +9 -0
- package/bundle/packages/rln/dist/create.js +1 -1
- package/bundle/packages/rln/dist/{rln_light.js → credentials_manager.js} +114 -48
- package/bundle/packages/rln/dist/identity.js +0 -9
- package/bundle/packages/rln/dist/keystore/keystore.js +27 -13
- package/bundle/packages/rln/dist/rln.js +56 -166
- package/bundle/packages/rln/dist/zerokit.js +5 -5
- package/bundle/packages/rln/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +1 -1
- package/bundle/packages/rln/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +2 -2
- package/bundle/packages/rln/node_modules/@noble/hashes/_sha2.js +1 -1
- package/bundle/packages/rln/node_modules/@noble/hashes/hmac.js +1 -1
- package/bundle/packages/rln/node_modules/@noble/hashes/pbkdf2.js +1 -1
- package/bundle/packages/rln/node_modules/@noble/hashes/scrypt.js +1 -1
- package/bundle/packages/rln/node_modules/@noble/hashes/sha256.js +1 -1
- package/bundle/packages/rln/node_modules/@noble/hashes/sha512.js +1 -1
- package/bundle/packages/rln/node_modules/@noble/hashes/utils.js +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/contract/constants.d.ts +1 -1
- package/dist/contract/constants.js +1 -1
- package/dist/contract/constants.js.map +1 -1
- package/dist/contract/{rln_light_contract.d.ts → rln_base_contract.d.ts} +24 -58
- package/dist/contract/{rln_light_contract.js → rln_base_contract.js} +165 -177
- package/dist/contract/rln_base_contract.js.map +1 -0
- package/dist/contract/rln_contract.d.ts +5 -122
- package/dist/contract/rln_contract.js +8 -417
- package/dist/contract/rln_contract.js.map +1 -1
- package/dist/contract/types.d.ts +45 -0
- package/dist/contract/types.js +8 -0
- package/dist/contract/types.js.map +1 -0
- package/dist/create.js +1 -1
- package/dist/create.js.map +1 -1
- package/dist/credentials_manager.d.ts +44 -0
- package/dist/credentials_manager.js +197 -0
- package/dist/credentials_manager.js.map +1 -0
- package/dist/identity.d.ts +0 -1
- package/dist/identity.js +0 -9
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/keystore/keystore.d.ts +1 -0
- package/dist/keystore/keystore.js +27 -13
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/rln.d.ts +9 -52
- package/dist/rln.js +54 -163
- package/dist/rln.js.map +1 -1
- package/dist/types.d.ts +27 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/zerokit.d.ts +3 -3
- package/dist/zerokit.js +5 -5
- package/dist/zerokit.js.map +1 -1
- package/package.json +1 -1
- package/src/contract/constants.ts +1 -1
- package/src/contract/{rln_light_contract.ts → rln_base_contract.ts} +271 -313
- package/src/contract/rln_contract.ts +9 -663
- package/src/contract/types.ts +53 -0
- package/src/create.ts +1 -1
- package/src/credentials_manager.ts +282 -0
- package/src/identity.ts +0 -10
- package/src/index.ts +4 -4
- package/src/keystore/keystore.ts +49 -25
- package/src/rln.ts +67 -258
- package/src/types.ts +31 -0
- package/src/zerokit.ts +3 -3
- package/dist/contract/rln_light_contract.js.map +0 -1
- package/dist/rln_light.d.ts +0 -64
- package/dist/rln_light.js +0 -144
- package/dist/rln_light.js.map +0 -1
- package/src/rln_light.ts +0 -235
package/bundle/_virtual/utils.js
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
var utils = {
|
1
|
+
var utils = {};
|
2
2
|
|
3
|
-
export { utils as
|
3
|
+
export { utils as __exports };
|
@@ -1,3 +1,3 @@
|
|
1
|
-
var utils = {};
|
1
|
+
var utils = {exports: {}};
|
2
2
|
|
3
|
-
export { utils as
|
3
|
+
export { utils as __module };
|
package/bundle/index.js
CHANGED
@@ -2,13 +2,13 @@ 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
4
|
export { LINEA_CONTRACT } from './packages/rln/dist/contract/constants.js';
|
5
|
-
export {
|
5
|
+
export { RLNBaseContract } from './packages/rln/dist/contract/rln_base_contract.js';
|
6
6
|
export { createRLN } from './packages/rln/dist/create.js';
|
7
|
+
export { RLNCredentialsManager } from './packages/rln/dist/credentials_manager.js';
|
7
8
|
export { IdentityCredential } from './packages/rln/dist/identity.js';
|
8
9
|
export { Keystore } from './packages/rln/dist/keystore/keystore.js';
|
9
10
|
export { Proof } from './packages/rln/dist/proof.js';
|
10
11
|
export { RLNInstance } from './packages/rln/dist/rln.js';
|
11
|
-
export { RLNLightInstance } from './packages/rln/dist/rln_light.js';
|
12
12
|
export { MerkleRootTracker } from './packages/rln/dist/root_tracker.js';
|
13
13
|
export { extractMetaMaskSigner } from './packages/rln/dist/utils/metamask.js';
|
14
14
|
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:
|
4
|
+
chainId: 59141,
|
5
5
|
address: "0xb9cd878c90e49f797b4431fbf4fb333108cb90e6",
|
6
6
|
abi: RLN_ABI
|
7
7
|
};
|
@@ -17,10 +17,7 @@ const RATE_LIMIT_TIERS = {
|
|
17
17
|
// Global rate limit parameters
|
18
18
|
const RATE_LIMIT_PARAMS = {
|
19
19
|
MIN_RATE: RATE_LIMIT_TIERS.LOW,
|
20
|
-
MAX_RATE: RATE_LIMIT_TIERS.HIGH
|
21
|
-
MAX_TOTAL_RATE: 160_000, // Maximum total rate limit across all memberships
|
22
|
-
EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
|
23
|
-
};
|
20
|
+
MAX_RATE: RATE_LIMIT_TIERS.HIGH};
|
24
21
|
const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
|
25
22
|
|
26
23
|
export { DEFAULT_RATE_LIMIT, LINEA_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS };
|
@@ -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 { MembershipState } from './types.js';
|
18
19
|
import { Contract } from '../../../../node_modules/@ethersproject/contracts/lib.esm/index.js';
|
19
20
|
import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
|
20
21
|
|
21
|
-
const log = new Logger("waku:rln:contract");
|
22
|
-
|
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,29 @@ class RLNLightContract {
|
|
35
29
|
_membershipErasedFilter;
|
36
30
|
_membersExpiredFilter;
|
37
31
|
/**
|
38
|
-
*
|
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.
|
55
37
|
this.contract = contract || new Contract(address, RLN_ABI, signer);
|
38
|
+
this.rateLimit = rateLimit;
|
56
39
|
// Initialize event filters
|
57
40
|
this._membersFilter = this.contract.filters.MembershipRegistered();
|
58
41
|
this._membershipErasedFilter = this.contract.filters.MembershipErased();
|
59
42
|
this._membersExpiredFilter = this.contract.filters.MembershipExpired();
|
43
|
+
// Initialize members and subscriptions
|
44
|
+
this.fetchMembers()
|
45
|
+
.then(() => {
|
46
|
+
this.subscribeToMembers();
|
47
|
+
})
|
48
|
+
.catch((error) => {
|
49
|
+
log.error("Failed to initialize members", { error });
|
50
|
+
});
|
51
|
+
// Validate rate limit asynchronously
|
52
|
+
this.validateRateLimit(rateLimit).catch((error) => {
|
53
|
+
log.error("Failed to validate initial rate limit", { error });
|
54
|
+
});
|
60
55
|
}
|
61
56
|
/**
|
62
57
|
* Gets the current rate limit for this contract instance
|
@@ -98,7 +93,7 @@ class RLNLightContract {
|
|
98
93
|
*/
|
99
94
|
async getMaxTotalRateLimit() {
|
100
95
|
const maxTotalRate = await this.contract.maxTotalRateLimit();
|
101
|
-
return
|
96
|
+
return maxTotalRate.toNumber();
|
102
97
|
}
|
103
98
|
/**
|
104
99
|
* Gets the current total rate limit usage across all memberships
|
@@ -106,7 +101,7 @@ class RLNLightContract {
|
|
106
101
|
*/
|
107
102
|
async getCurrentTotalRateLimit() {
|
108
103
|
const currentTotal = await this.contract.currentTotalRateLimit();
|
109
|
-
return
|
104
|
+
return currentTotal.toNumber();
|
110
105
|
}
|
111
106
|
/**
|
112
107
|
* Gets the remaining available total rate limit that can be allocated
|
@@ -117,51 +112,32 @@ class RLNLightContract {
|
|
117
112
|
this.contract.maxTotalRateLimit(),
|
118
113
|
this.contract.currentTotalRateLimit()
|
119
114
|
]);
|
120
|
-
return
|
121
|
-
.sub(BigNumber.from(currentTotal))
|
122
|
-
.toNumber();
|
115
|
+
return Number(maxTotal) - Number(currentTotal);
|
123
116
|
}
|
124
117
|
/**
|
125
118
|
* Updates the rate limit for future registrations
|
126
119
|
* @param newRateLimit The new rate limit to use
|
127
120
|
*/
|
128
121
|
async setRateLimit(newRateLimit) {
|
122
|
+
await this.validateRateLimit(newRateLimit);
|
129
123
|
this.rateLimit = newRateLimit;
|
130
124
|
}
|
131
125
|
get members() {
|
132
126
|
const sortedMembers = Array.from(this._members.values()).sort((left, right) => left.index.toNumber() - right.index.toNumber());
|
133
127
|
return sortedMembers;
|
134
128
|
}
|
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
129
|
async fetchMembers(options = {}) {
|
154
|
-
const registeredMemberEvents = await queryFilter(this.contract, {
|
130
|
+
const registeredMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
|
155
131
|
fromBlock: this.deployBlock,
|
156
132
|
...options,
|
157
133
|
membersFilter: this.membersFilter
|
158
134
|
});
|
159
|
-
const removedMemberEvents = await queryFilter(this.contract, {
|
135
|
+
const removedMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
|
160
136
|
fromBlock: this.deployBlock,
|
161
137
|
...options,
|
162
138
|
membersFilter: this.membershipErasedFilter
|
163
139
|
});
|
164
|
-
const expiredMemberEvents = await queryFilter(this.contract, {
|
140
|
+
const expiredMemberEvents = await RLNBaseContract.queryFilter(this.contract, {
|
165
141
|
fromBlock: this.deployBlock,
|
166
142
|
...options,
|
167
143
|
membersFilter: this.membersExpiredFilter
|
@@ -173,6 +149,29 @@ class RLNLightContract {
|
|
173
149
|
];
|
174
150
|
this.processEvents(events);
|
175
151
|
}
|
152
|
+
static async queryFilter(contract, options) {
|
153
|
+
const FETCH_CHUNK = 5;
|
154
|
+
const BLOCK_RANGE = 3000;
|
155
|
+
const { fromBlock, membersFilter, fetchRange = BLOCK_RANGE, fetchChunks = FETCH_CHUNK } = options;
|
156
|
+
if (fromBlock === undefined) {
|
157
|
+
return contract.queryFilter(membersFilter);
|
158
|
+
}
|
159
|
+
if (!contract.provider) {
|
160
|
+
throw Error("No provider found on the contract.");
|
161
|
+
}
|
162
|
+
const toBlock = await contract.provider.getBlockNumber();
|
163
|
+
if (toBlock - fromBlock < fetchRange) {
|
164
|
+
return contract.queryFilter(membersFilter, fromBlock, toBlock);
|
165
|
+
}
|
166
|
+
const events = [];
|
167
|
+
const chunks = RLNBaseContract.splitToChunks(fromBlock, toBlock, fetchRange);
|
168
|
+
for (const portion of RLNBaseContract.takeN(chunks, fetchChunks)) {
|
169
|
+
const promises = portion.map(([left, right]) => RLNBaseContract.ignoreErrors(contract.queryFilter(membersFilter, left, right), []));
|
170
|
+
const fetchedEvents = await Promise.all(promises);
|
171
|
+
events.push(fetchedEvents.flatMap((v) => v));
|
172
|
+
}
|
173
|
+
return events.flatMap((v) => v);
|
174
|
+
}
|
176
175
|
processEvents(events) {
|
177
176
|
const toRemoveTable = new Map();
|
178
177
|
const toInsertTable = new Map();
|
@@ -208,6 +207,38 @@ class RLNLightContract {
|
|
208
207
|
}
|
209
208
|
});
|
210
209
|
}
|
210
|
+
static splitToChunks(from, to, step) {
|
211
|
+
const chunks = [];
|
212
|
+
let left = from;
|
213
|
+
while (left < to) {
|
214
|
+
const right = left + step < to ? left + step : to;
|
215
|
+
chunks.push([left, right]);
|
216
|
+
left = right;
|
217
|
+
}
|
218
|
+
return chunks;
|
219
|
+
}
|
220
|
+
static *takeN(array, size) {
|
221
|
+
let start = 0;
|
222
|
+
while (start < array.length) {
|
223
|
+
const portion = array.slice(start, start + size);
|
224
|
+
yield portion;
|
225
|
+
start += size;
|
226
|
+
}
|
227
|
+
}
|
228
|
+
static async ignoreErrors(promise, defaultValue) {
|
229
|
+
try {
|
230
|
+
return await promise;
|
231
|
+
}
|
232
|
+
catch (err) {
|
233
|
+
if (err instanceof Error) {
|
234
|
+
log.info(`Ignoring an error during query: ${err.message}`);
|
235
|
+
}
|
236
|
+
else {
|
237
|
+
log.info(`Ignoring an unknown error during query`);
|
238
|
+
}
|
239
|
+
return defaultValue;
|
240
|
+
}
|
241
|
+
}
|
211
242
|
subscribeToMembers() {
|
212
243
|
this.contract.on(this.membersFilter, (_idCommitment, _membershipRateLimit, _index, event) => {
|
213
244
|
this.processEvents([event]);
|
@@ -219,6 +250,61 @@ class RLNLightContract {
|
|
219
250
|
this.processEvents([event]);
|
220
251
|
});
|
221
252
|
}
|
253
|
+
async getMembershipInfo(idCommitment) {
|
254
|
+
try {
|
255
|
+
const membershipData = await this.contract.memberships(idCommitment);
|
256
|
+
const currentBlock = await this.contract.provider.getBlockNumber();
|
257
|
+
let state;
|
258
|
+
const gracePeriodEnd = membershipData.gracePeriodStartTimestamp.add(membershipData.gracePeriodDuration);
|
259
|
+
if (currentBlock < membershipData.gracePeriodStartTimestamp) {
|
260
|
+
state = MembershipState.Active;
|
261
|
+
}
|
262
|
+
else if (currentBlock < gracePeriodEnd) {
|
263
|
+
state = MembershipState.GracePeriod;
|
264
|
+
}
|
265
|
+
else {
|
266
|
+
state = MembershipState.Expired;
|
267
|
+
}
|
268
|
+
return {
|
269
|
+
index: membershipData.index,
|
270
|
+
idCommitment,
|
271
|
+
rateLimit: membershipData.rateLimit.toNumber(),
|
272
|
+
startBlock: membershipData.gracePeriodStartTimestamp.toNumber(),
|
273
|
+
endBlock: gracePeriodEnd.toNumber(),
|
274
|
+
state,
|
275
|
+
depositAmount: membershipData.depositAmount,
|
276
|
+
activeDuration: membershipData.activeDuration,
|
277
|
+
gracePeriodDuration: membershipData.gracePeriodDuration,
|
278
|
+
holder: membershipData.holder,
|
279
|
+
token: membershipData.token
|
280
|
+
};
|
281
|
+
}
|
282
|
+
catch (error) {
|
283
|
+
return undefined;
|
284
|
+
}
|
285
|
+
}
|
286
|
+
async extendMembership(idCommitment) {
|
287
|
+
return this.contract.extendMemberships([idCommitment]);
|
288
|
+
}
|
289
|
+
async eraseMembership(idCommitment, eraseFromMembershipSet = true) {
|
290
|
+
return this.contract.eraseMemberships([idCommitment], eraseFromMembershipSet);
|
291
|
+
}
|
292
|
+
async registerMembership(idCommitment, rateLimit = DEFAULT_RATE_LIMIT) {
|
293
|
+
if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
|
294
|
+
rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
|
295
|
+
throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
|
296
|
+
}
|
297
|
+
return this.contract.register(idCommitment, rateLimit, []);
|
298
|
+
}
|
299
|
+
async withdraw(token) {
|
300
|
+
try {
|
301
|
+
const tx = await this.contract.withdraw(token);
|
302
|
+
await tx.wait();
|
303
|
+
}
|
304
|
+
catch (error) {
|
305
|
+
log.error(`Error in withdraw: ${error.message}`);
|
306
|
+
}
|
307
|
+
}
|
222
308
|
async registerWithIdentity(identity) {
|
223
309
|
try {
|
224
310
|
log.info(`Registering identity with rate limit: ${this.rateLimit} messages/epoch`);
|
@@ -253,12 +339,12 @@ class RLNLightContract {
|
|
253
339
|
`and rate limit ${decodedData.membershipRateLimit}`);
|
254
340
|
const network = await this.contract.provider.getNetwork();
|
255
341
|
const address = this.contract.address;
|
256
|
-
const membershipId = decodedData.index
|
342
|
+
const membershipId = Number(decodedData.index);
|
257
343
|
return {
|
258
344
|
identity,
|
259
345
|
membership: {
|
260
346
|
address,
|
261
|
-
treeIndex:
|
347
|
+
treeIndex: membershipId,
|
262
348
|
chainId: network.chainId.toString(),
|
263
349
|
rateLimit: decodedData.membershipRateLimit.toNumber()
|
264
350
|
}
|
@@ -293,29 +379,6 @@ class RLNLightContract {
|
|
293
379
|
}
|
294
380
|
}
|
295
381
|
}
|
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
382
|
async registerWithPermitAndErase(identity, permit, idCommitmentsToErase) {
|
320
383
|
try {
|
321
384
|
log.info(`Registering identity with permit and rate limit: ${this.rateLimit} messages/epoch`);
|
@@ -335,12 +398,12 @@ class RLNLightContract {
|
|
335
398
|
`Rate limit: ${decodedData.membershipRateLimit}, Erased ${idCommitmentsToErase.length} commitments`);
|
336
399
|
const network = await this.contract.provider.getNetwork();
|
337
400
|
const address = this.contract.address;
|
338
|
-
const membershipId = decodedData.index
|
401
|
+
const membershipId = Number(decodedData.index);
|
339
402
|
return {
|
340
403
|
identity,
|
341
404
|
membership: {
|
342
405
|
address,
|
343
|
-
treeIndex:
|
406
|
+
treeIndex: membershipId,
|
344
407
|
chainId: network.chainId.toString(),
|
345
408
|
rateLimit: decodedData.membershipRateLimit.toNumber()
|
346
409
|
}
|
@@ -351,57 +414,38 @@ class RLNLightContract {
|
|
351
414
|
return undefined;
|
352
415
|
}
|
353
416
|
}
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
417
|
+
/**
|
418
|
+
* Validates that the rate limit is within the allowed range
|
419
|
+
* @throws Error if the rate limit is outside the allowed range
|
420
|
+
*/
|
421
|
+
async validateRateLimit(rateLimit) {
|
422
|
+
const [minRate, maxRate] = await Promise.all([
|
423
|
+
this.contract.minMembershipRateLimit(),
|
424
|
+
this.contract.maxMembershipRateLimit()
|
425
|
+
]);
|
426
|
+
const minRateNum = BigNumber.from(minRate).toNumber();
|
427
|
+
const maxRateNum = BigNumber.from(maxRate).toNumber();
|
428
|
+
if (rateLimit < minRateNum || rateLimit > maxRateNum) {
|
429
|
+
throw new Error(`Rate limit must be between ${minRateNum} and ${maxRateNum} messages per epoch`);
|
361
430
|
}
|
362
431
|
}
|
363
|
-
|
364
|
-
|
365
|
-
|
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;
|
432
|
+
get membersFilter() {
|
433
|
+
if (!this._membersFilter) {
|
434
|
+
throw Error("Members filter was not initialized.");
|
391
435
|
}
|
436
|
+
return this._membersFilter;
|
392
437
|
}
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
return this.
|
438
|
+
get membershipErasedFilter() {
|
439
|
+
if (!this._membershipErasedFilter) {
|
440
|
+
throw Error("MembershipErased filter was not initialized.");
|
441
|
+
}
|
442
|
+
return this._membershipErasedFilter;
|
398
443
|
}
|
399
|
-
|
400
|
-
if (
|
401
|
-
|
402
|
-
throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
|
444
|
+
get membersExpiredFilter() {
|
445
|
+
if (!this._membersExpiredFilter) {
|
446
|
+
throw Error("MembersExpired filter was not initialized.");
|
403
447
|
}
|
404
|
-
return this.
|
448
|
+
return this._membersExpiredFilter;
|
405
449
|
}
|
406
450
|
async getMemberIndex(idCommitment) {
|
407
451
|
try {
|
@@ -417,61 +461,5 @@ class RLNLightContract {
|
|
417
461
|
}
|
418
462
|
}
|
419
463
|
}
|
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
464
|
|
477
|
-
export {
|
465
|
+
export { RLNBaseContract };
|