@waku/rln 0.1.5-ff0222a.0 → 0.1.6-b7e9b08.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/CHANGELOG.md +22 -0
- package/bundle/_virtual/index2.js +1 -1
- package/bundle/index.js +2 -2
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/checksum.js +3 -3
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/cipher.js +4 -4
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/class.js +7 -7
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/functional.js +7 -7
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/index.js +6 -6
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/kdf.js +5 -5
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/password.js +1 -1
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/schema-validation-generated.js +1 -1
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/schema-validation.js +2 -2
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/lib/types.js +1 -1
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/_assert.js +1 -1
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/_sha2.js +3 -3
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/_u64.js +1 -1
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/cryptoBrowser.js +1 -1
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/hmac.js +3 -3
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/pbkdf2.js +4 -4
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/scrypt.js +5 -5
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/sha256.js +3 -3
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/sha512.js +4 -4
- package/bundle/{packages/rln → node_modules/@chainsafe/bls-keystore}/node_modules/@noble/hashes/utils.js +2 -2
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/aes.js +3 -3
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/pbkdf2.js +7 -7
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +3 -3
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/scrypt.js +3 -3
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/sha256.js +3 -3
- package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +7 -7
- package/bundle/node_modules/@ethersproject/abi/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/address/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/bignumber/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/contracts/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/contracts/lib.esm/index.js +1 -1
- package/bundle/node_modules/@ethersproject/hash/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/networks/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/networks/lib.esm/index.js +19 -1
- package/bundle/node_modules/@ethersproject/properties/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/providers/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/signing-key/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/signing-key/lib.esm/elliptic.js +58 -10
- package/bundle/node_modules/@ethersproject/strings/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/transactions/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@ethersproject/web/lib.esm/_version.js +1 -1
- package/bundle/node_modules/@noble/hashes/esm/_assert.js +6 -32
- package/bundle/node_modules/@noble/hashes/esm/_md.js +22 -11
- package/bundle/node_modules/@noble/hashes/esm/_u64.js +4 -3
- package/bundle/{packages/rln/node_modules → node_modules}/@noble/hashes/esm/hmac.js +19 -10
- package/bundle/{packages/rln/node_modules/@noble/hashes/esm/sha256.js → node_modules/@noble/hashes/esm/sha2.js} +36 -50
- package/bundle/node_modules/@noble/hashes/esm/sha256.js +5 -102
- package/bundle/node_modules/@noble/hashes/esm/sha3.js +30 -24
- package/bundle/node_modules/@noble/hashes/esm/utils.js +69 -18
- package/bundle/node_modules/bn.js/lib/bn.js +1 -0
- package/bundle/node_modules/ethereum-cryptography/esm/sha256.js +1 -1
- package/bundle/packages/core/dist/lib/connection_manager/connection_manager.js +3 -0
- package/bundle/packages/core/dist/lib/connection_manager/keep_alive_manager.js +3 -3
- package/bundle/packages/core/dist/lib/filter/filter.js +3 -0
- package/bundle/packages/core/dist/lib/light_push/light_push.js +3 -0
- package/bundle/packages/core/dist/lib/metadata/metadata.js +3 -0
- package/bundle/packages/core/dist/lib/store/store.js +3 -3
- package/bundle/packages/proto/dist/generated/sds_message.js +59 -3
- package/bundle/packages/rln/dist/codec.js +3 -3
- package/bundle/packages/rln/dist/contract/constants.js +1 -1
- package/bundle/packages/rln/dist/contract/{rln_light_contract.js → rln_base_contract.js} +180 -180
- package/bundle/packages/rln/dist/contract/rln_contract.js +12 -422
- package/bundle/packages/rln/dist/contract/types.js +9 -0
- package/bundle/packages/rln/dist/create.js +1 -1
- package/bundle/packages/rln/dist/credentials_manager.js +215 -0
- package/bundle/packages/rln/dist/identity.js +0 -9
- package/bundle/packages/rln/dist/keystore/cipher.js +3 -3
- package/bundle/packages/rln/dist/keystore/keystore.js +32 -18
- package/bundle/packages/rln/dist/rln.js +59 -169
- package/bundle/packages/rln/dist/utils/epoch.js +3 -3
- package/bundle/packages/rln/dist/zerokit.js +5 -5
- package/bundle/packages/utils/dist/common/sharding/index.js +4 -4
- package/bundle/packages/utils/node_modules/@waku/interfaces/dist/connection_manager.js +19 -0
- package/bundle/packages/utils/node_modules/@waku/interfaces/dist/health_indicator.js +12 -0
- package/bundle/packages/utils/node_modules/@waku/interfaces/dist/protocols.js +92 -0
- 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} +25 -53
- package/dist/contract/{rln_light_contract.js → rln_base_contract.js} +177 -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 +40 -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} +294 -312
- package/src/contract/rln_contract.ts +9 -663
- package/src/contract/types.ts +48 -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/bundle/packages/rln/dist/rln_light.js +0 -149
- package/bundle/packages/rln/node_modules/@noble/hashes/esm/_assert.js +0 -43
- package/bundle/packages/rln/node_modules/@noble/hashes/esm/_sha2.js +0 -116
- package/bundle/packages/rln/node_modules/@noble/hashes/esm/utils.js +0 -43
- 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/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/index.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/md5.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/nil.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/parse.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/regex.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/rng.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/sha1.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/stringify.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v1.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v3.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v35.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v4.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v5.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/validate.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/version.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/uuid/dist/esm-browser/native.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/uuid/dist/esm-browser/rng.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/uuid/dist/esm-browser/stringify.js +0 -0
- /package/bundle/{packages/rln/node_modules → node_modules}/uuid/dist/esm-browser/v4.js +0 -0
- /package/bundle/packages/{interfaces → utils/node_modules/@waku/interfaces}/dist/constants.js +0 -0
@@ -1,84 +1,47 @@
|
|
1
1
|
import { Logger } from "@waku/utils";
|
2
2
|
import { ethers } from "ethers";
|
3
3
|
|
4
|
-
import
|
5
|
-
import
|
4
|
+
import { IdentityCredential } from "../identity.js";
|
5
|
+
import { DecryptedCredentials } from "../keystore/types.js";
|
6
6
|
|
7
7
|
import { RLN_ABI } from "./abi.js";
|
8
8
|
import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from "./constants.js";
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
interface RLNContractInitOptions extends RLNContractOptions {
|
24
|
-
contract?: ethers.Contract;
|
25
|
-
}
|
26
|
-
|
27
|
-
export interface MembershipRegisteredEvent {
|
28
|
-
idCommitment: string;
|
29
|
-
membershipRateLimit: ethers.BigNumber;
|
30
|
-
index: ethers.BigNumber;
|
31
|
-
}
|
32
|
-
|
33
|
-
type FetchMembersOptions = {
|
34
|
-
fromBlock?: number;
|
35
|
-
fetchRange?: number;
|
36
|
-
fetchChunks?: number;
|
37
|
-
};
|
38
|
-
|
39
|
-
export interface MembershipInfo {
|
40
|
-
index: ethers.BigNumber;
|
41
|
-
idCommitment: string;
|
42
|
-
rateLimit: number;
|
43
|
-
startBlock: number;
|
44
|
-
endBlock: number;
|
45
|
-
state: MembershipState;
|
46
|
-
}
|
47
|
-
|
48
|
-
export enum MembershipState {
|
49
|
-
Active = "Active",
|
50
|
-
GracePeriod = "GracePeriod",
|
51
|
-
Expired = "Expired",
|
52
|
-
ErasedAwaitsWithdrawal = "ErasedAwaitsWithdrawal"
|
53
|
-
}
|
54
|
-
|
55
|
-
export class RLNLightContract {
|
9
|
+
import {
|
10
|
+
CustomQueryOptions,
|
11
|
+
FetchMembersOptions,
|
12
|
+
Member,
|
13
|
+
MembershipInfo,
|
14
|
+
MembershipRegisteredEvent,
|
15
|
+
MembershipState,
|
16
|
+
RLNContractInitOptions
|
17
|
+
} from "./types.js";
|
18
|
+
|
19
|
+
const log = new Logger("waku:rln:contract:base");
|
20
|
+
|
21
|
+
export class RLNBaseContract {
|
56
22
|
public contract: ethers.Contract;
|
57
|
-
|
58
23
|
private deployBlock: undefined | number;
|
59
24
|
private rateLimit: number;
|
60
25
|
|
61
|
-
|
26
|
+
protected _members: Map<number, Member> = new Map();
|
62
27
|
private _membersFilter: ethers.EventFilter;
|
63
28
|
private _membershipErasedFilter: ethers.EventFilter;
|
64
29
|
private _membersExpiredFilter: ethers.EventFilter;
|
65
30
|
|
66
31
|
/**
|
67
|
-
*
|
32
|
+
* Constructor for RLNBaseContract.
|
68
33
|
* Allows injecting a mocked contract for testing purposes.
|
69
34
|
*/
|
70
|
-
public
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
35
|
+
public constructor(options: RLNContractInitOptions) {
|
36
|
+
// Initialize members and subscriptions
|
37
|
+
this.fetchMembers()
|
38
|
+
.then(() => {
|
39
|
+
this.subscribeToMembers();
|
40
|
+
})
|
41
|
+
.catch((error) => {
|
42
|
+
log.error("Failed to initialize members", { error });
|
43
|
+
});
|
77
44
|
|
78
|
-
return rlnContract;
|
79
|
-
}
|
80
|
-
|
81
|
-
private constructor(options: RLNContractInitOptions) {
|
82
45
|
const {
|
83
46
|
address,
|
84
47
|
signer,
|
@@ -86,19 +49,10 @@ export class RLNLightContract {
|
|
86
49
|
contract
|
87
50
|
} = options;
|
88
51
|
|
89
|
-
|
90
|
-
rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
|
91
|
-
rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
|
92
|
-
) {
|
93
|
-
throw new Error(
|
94
|
-
`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE} messages per epoch`
|
95
|
-
);
|
96
|
-
}
|
97
|
-
|
98
|
-
this.rateLimit = rateLimit;
|
52
|
+
this.validateRateLimit(rateLimit);
|
99
53
|
|
100
|
-
// Use the injected contract if provided; otherwise, instantiate a new one.
|
101
54
|
this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
|
55
|
+
this.rateLimit = rateLimit;
|
102
56
|
|
103
57
|
// Initialize event filters
|
104
58
|
this._membersFilter = this.contract.filters.MembershipRegistered();
|
@@ -151,7 +105,7 @@ export class RLNLightContract {
|
|
151
105
|
*/
|
152
106
|
public async getMaxTotalRateLimit(): Promise<number> {
|
153
107
|
const maxTotalRate = await this.contract.maxTotalRateLimit();
|
154
|
-
return
|
108
|
+
return maxTotalRate.toNumber();
|
155
109
|
}
|
156
110
|
|
157
111
|
/**
|
@@ -160,7 +114,7 @@ export class RLNLightContract {
|
|
160
114
|
*/
|
161
115
|
public async getCurrentTotalRateLimit(): Promise<number> {
|
162
116
|
const currentTotal = await this.contract.currentTotalRateLimit();
|
163
|
-
return
|
117
|
+
return currentTotal.toNumber();
|
164
118
|
}
|
165
119
|
|
166
120
|
/**
|
@@ -172,9 +126,7 @@ export class RLNLightContract {
|
|
172
126
|
this.contract.maxTotalRateLimit(),
|
173
127
|
this.contract.currentTotalRateLimit()
|
174
128
|
]);
|
175
|
-
return
|
176
|
-
.sub(ethers.BigNumber.from(currentTotal))
|
177
|
-
.toNumber();
|
129
|
+
return Number(maxTotal) - Number(currentTotal);
|
178
130
|
}
|
179
131
|
|
180
132
|
/**
|
@@ -182,6 +134,7 @@ export class RLNLightContract {
|
|
182
134
|
* @param newRateLimit The new rate limit to use
|
183
135
|
*/
|
184
136
|
public async setRateLimit(newRateLimit: number): Promise<void> {
|
137
|
+
this.validateRateLimit(newRateLimit);
|
185
138
|
this.rateLimit = newRateLimit;
|
186
139
|
}
|
187
140
|
|
@@ -192,43 +145,31 @@ export class RLNLightContract {
|
|
192
145
|
return sortedMembers;
|
193
146
|
}
|
194
147
|
|
195
|
-
private get membersFilter(): ethers.EventFilter {
|
196
|
-
if (!this._membersFilter) {
|
197
|
-
throw Error("Members filter was not initialized.");
|
198
|
-
}
|
199
|
-
return this._membersFilter;
|
200
|
-
}
|
201
|
-
|
202
|
-
private get membershipErasedFilter(): ethers.EventFilter {
|
203
|
-
if (!this._membershipErasedFilter) {
|
204
|
-
throw Error("MembershipErased filter was not initialized.");
|
205
|
-
}
|
206
|
-
return this._membershipErasedFilter;
|
207
|
-
}
|
208
|
-
|
209
|
-
private get membersExpiredFilter(): ethers.EventFilter {
|
210
|
-
if (!this._membersExpiredFilter) {
|
211
|
-
throw Error("MembersExpired filter was not initialized.");
|
212
|
-
}
|
213
|
-
return this._membersExpiredFilter;
|
214
|
-
}
|
215
|
-
|
216
148
|
public async fetchMembers(options: FetchMembersOptions = {}): Promise<void> {
|
217
|
-
const registeredMemberEvents = await queryFilter(
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
149
|
+
const registeredMemberEvents = await RLNBaseContract.queryFilter(
|
150
|
+
this.contract,
|
151
|
+
{
|
152
|
+
fromBlock: this.deployBlock,
|
153
|
+
...options,
|
154
|
+
membersFilter: this.membersFilter
|
155
|
+
}
|
156
|
+
);
|
157
|
+
const removedMemberEvents = await RLNBaseContract.queryFilter(
|
158
|
+
this.contract,
|
159
|
+
{
|
160
|
+
fromBlock: this.deployBlock,
|
161
|
+
...options,
|
162
|
+
membersFilter: this.membershipErasedFilter
|
163
|
+
}
|
164
|
+
);
|
165
|
+
const expiredMemberEvents = await RLNBaseContract.queryFilter(
|
166
|
+
this.contract,
|
167
|
+
{
|
168
|
+
fromBlock: this.deployBlock,
|
169
|
+
...options,
|
170
|
+
membersFilter: this.membersExpiredFilter
|
171
|
+
}
|
172
|
+
);
|
232
173
|
|
233
174
|
const events = [
|
234
175
|
...registeredMemberEvents,
|
@@ -238,6 +179,58 @@ export class RLNLightContract {
|
|
238
179
|
this.processEvents(events);
|
239
180
|
}
|
240
181
|
|
182
|
+
public static async queryFilter(
|
183
|
+
contract: ethers.Contract,
|
184
|
+
options: CustomQueryOptions
|
185
|
+
): Promise<ethers.Event[]> {
|
186
|
+
const FETCH_CHUNK = 5;
|
187
|
+
const BLOCK_RANGE = 3000;
|
188
|
+
|
189
|
+
const {
|
190
|
+
fromBlock,
|
191
|
+
membersFilter,
|
192
|
+
fetchRange = BLOCK_RANGE,
|
193
|
+
fetchChunks = FETCH_CHUNK
|
194
|
+
} = options;
|
195
|
+
|
196
|
+
if (fromBlock === undefined) {
|
197
|
+
return contract.queryFilter(membersFilter);
|
198
|
+
}
|
199
|
+
|
200
|
+
if (!contract.provider) {
|
201
|
+
throw Error("No provider found on the contract.");
|
202
|
+
}
|
203
|
+
|
204
|
+
const toBlock = await contract.provider.getBlockNumber();
|
205
|
+
|
206
|
+
if (toBlock - fromBlock < fetchRange) {
|
207
|
+
return contract.queryFilter(membersFilter, fromBlock, toBlock);
|
208
|
+
}
|
209
|
+
|
210
|
+
const events: ethers.Event[][] = [];
|
211
|
+
const chunks = RLNBaseContract.splitToChunks(
|
212
|
+
fromBlock,
|
213
|
+
toBlock,
|
214
|
+
fetchRange
|
215
|
+
);
|
216
|
+
|
217
|
+
for (const portion of RLNBaseContract.takeN<[number, number]>(
|
218
|
+
chunks,
|
219
|
+
fetchChunks
|
220
|
+
)) {
|
221
|
+
const promises = portion.map(([left, right]) =>
|
222
|
+
RLNBaseContract.ignoreErrors(
|
223
|
+
contract.queryFilter(membersFilter, left, right),
|
224
|
+
[]
|
225
|
+
)
|
226
|
+
);
|
227
|
+
const fetchedEvents = await Promise.all(promises);
|
228
|
+
events.push(fetchedEvents.flatMap((v) => v));
|
229
|
+
}
|
230
|
+
|
231
|
+
return events.flatMap((v) => v);
|
232
|
+
}
|
233
|
+
|
241
234
|
public processEvents(events: ethers.Event[]): void {
|
242
235
|
const toRemoveTable = new Map<number, number[]>();
|
243
236
|
const toInsertTable = new Map<number, ethers.Event[]>();
|
@@ -280,6 +273,53 @@ export class RLNLightContract {
|
|
280
273
|
});
|
281
274
|
}
|
282
275
|
|
276
|
+
public static splitToChunks(
|
277
|
+
from: number,
|
278
|
+
to: number,
|
279
|
+
step: number
|
280
|
+
): Array<[number, number]> {
|
281
|
+
const chunks: Array<[number, number]> = [];
|
282
|
+
|
283
|
+
let left = from;
|
284
|
+
while (left < to) {
|
285
|
+
const right = left + step < to ? left + step : to;
|
286
|
+
|
287
|
+
chunks.push([left, right] as [number, number]);
|
288
|
+
|
289
|
+
left = right;
|
290
|
+
}
|
291
|
+
|
292
|
+
return chunks;
|
293
|
+
}
|
294
|
+
|
295
|
+
public static *takeN<T>(array: T[], size: number): Iterable<T[]> {
|
296
|
+
let start = 0;
|
297
|
+
|
298
|
+
while (start < array.length) {
|
299
|
+
const portion = array.slice(start, start + size);
|
300
|
+
|
301
|
+
yield portion;
|
302
|
+
|
303
|
+
start += size;
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
307
|
+
public static async ignoreErrors<T>(
|
308
|
+
promise: Promise<T>,
|
309
|
+
defaultValue: T
|
310
|
+
): Promise<T> {
|
311
|
+
try {
|
312
|
+
return await promise;
|
313
|
+
} catch (err: unknown) {
|
314
|
+
if (err instanceof Error) {
|
315
|
+
log.info(`Ignoring an error during query: ${err.message}`);
|
316
|
+
} else {
|
317
|
+
log.info(`Ignoring an unknown error during query`);
|
318
|
+
}
|
319
|
+
return defaultValue;
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
283
323
|
public subscribeToMembers(): void {
|
284
324
|
this.contract.on(
|
285
325
|
this.membersFilter,
|
@@ -318,6 +358,116 @@ export class RLNLightContract {
|
|
318
358
|
);
|
319
359
|
}
|
320
360
|
|
361
|
+
/**
|
362
|
+
* Helper method to get remaining messages in current epoch
|
363
|
+
* @param membershipId The ID of the membership to check
|
364
|
+
* @returns number of remaining messages allowed in current epoch
|
365
|
+
*/
|
366
|
+
public async getRemainingMessages(membershipId: number): Promise<number> {
|
367
|
+
try {
|
368
|
+
const [startTime, , rateLimit] =
|
369
|
+
await this.contract.getMembershipInfo(membershipId);
|
370
|
+
|
371
|
+
// Calculate current epoch
|
372
|
+
const currentTime = Math.floor(Date.now() / 1000);
|
373
|
+
const epochsPassed = Math.floor(
|
374
|
+
(currentTime - startTime) / RATE_LIMIT_PARAMS.EPOCH_LENGTH
|
375
|
+
);
|
376
|
+
const currentEpochStart =
|
377
|
+
startTime + epochsPassed * RATE_LIMIT_PARAMS.EPOCH_LENGTH;
|
378
|
+
|
379
|
+
// Get message count in current epoch using contract's function
|
380
|
+
const messageCount = await this.contract.getMessageCount(
|
381
|
+
membershipId,
|
382
|
+
currentEpochStart
|
383
|
+
);
|
384
|
+
return Math.max(
|
385
|
+
0,
|
386
|
+
ethers.BigNumber.from(rateLimit)
|
387
|
+
.sub(ethers.BigNumber.from(messageCount))
|
388
|
+
.toNumber()
|
389
|
+
);
|
390
|
+
} catch (error) {
|
391
|
+
log.error(
|
392
|
+
`Error getting remaining messages: ${(error as Error).message}`
|
393
|
+
);
|
394
|
+
return 0; // Fail safe: assume no messages remaining on error
|
395
|
+
}
|
396
|
+
}
|
397
|
+
|
398
|
+
public async getMembershipInfo(
|
399
|
+
idCommitment: string
|
400
|
+
): Promise<MembershipInfo | undefined> {
|
401
|
+
try {
|
402
|
+
const [startBlock, endBlock, rateLimit] =
|
403
|
+
await this.contract.getMembershipInfo(idCommitment);
|
404
|
+
const currentBlock = await this.contract.provider.getBlockNumber();
|
405
|
+
|
406
|
+
let state: MembershipState;
|
407
|
+
if (currentBlock < startBlock) {
|
408
|
+
state = MembershipState.Active;
|
409
|
+
} else if (currentBlock < endBlock) {
|
410
|
+
state = MembershipState.GracePeriod;
|
411
|
+
} else {
|
412
|
+
state = MembershipState.Expired;
|
413
|
+
}
|
414
|
+
|
415
|
+
const index = await this.getMemberIndex(idCommitment);
|
416
|
+
if (!index) return undefined;
|
417
|
+
|
418
|
+
return {
|
419
|
+
index,
|
420
|
+
idCommitment,
|
421
|
+
rateLimit: rateLimit.toNumber(),
|
422
|
+
startBlock: startBlock.toNumber(),
|
423
|
+
endBlock: endBlock.toNumber(),
|
424
|
+
state
|
425
|
+
};
|
426
|
+
} catch (error) {
|
427
|
+
return undefined;
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
public async extendMembership(
|
432
|
+
idCommitment: string
|
433
|
+
): Promise<ethers.ContractTransaction> {
|
434
|
+
return this.contract.extendMemberships([idCommitment]);
|
435
|
+
}
|
436
|
+
|
437
|
+
public async eraseMembership(
|
438
|
+
idCommitment: string,
|
439
|
+
eraseFromMembershipSet: boolean = true
|
440
|
+
): Promise<ethers.ContractTransaction> {
|
441
|
+
return this.contract.eraseMemberships(
|
442
|
+
[idCommitment],
|
443
|
+
eraseFromMembershipSet
|
444
|
+
);
|
445
|
+
}
|
446
|
+
|
447
|
+
public async registerMembership(
|
448
|
+
idCommitment: string,
|
449
|
+
rateLimit: number = DEFAULT_RATE_LIMIT
|
450
|
+
): Promise<ethers.ContractTransaction> {
|
451
|
+
if (
|
452
|
+
rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
|
453
|
+
rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
|
454
|
+
) {
|
455
|
+
throw new Error(
|
456
|
+
`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
|
457
|
+
);
|
458
|
+
}
|
459
|
+
return this.contract.register(idCommitment, rateLimit, []);
|
460
|
+
}
|
461
|
+
|
462
|
+
public async withdraw(token: string, holder: string): Promise<void> {
|
463
|
+
try {
|
464
|
+
const tx = await this.contract.withdraw(token, { from: holder });
|
465
|
+
await tx.wait();
|
466
|
+
} catch (error) {
|
467
|
+
log.error(`Error in withdraw: ${(error as Error).message}`);
|
468
|
+
}
|
469
|
+
}
|
470
|
+
|
321
471
|
public async registerWithIdentity(
|
322
472
|
identity: IdentityCredential
|
323
473
|
): Promise<DecryptedCredentials | undefined> {
|
@@ -389,13 +539,13 @@ export class RLNLightContract {
|
|
389
539
|
|
390
540
|
const network = await this.contract.provider.getNetwork();
|
391
541
|
const address = this.contract.address;
|
392
|
-
const membershipId = decodedData.index
|
542
|
+
const membershipId = Number(decodedData.index);
|
393
543
|
|
394
544
|
return {
|
395
545
|
identity,
|
396
546
|
membership: {
|
397
547
|
address,
|
398
|
-
treeIndex:
|
548
|
+
treeIndex: membershipId,
|
399
549
|
chainId: network.chainId.toString(),
|
400
550
|
rateLimit: decodedData.membershipRateLimit.toNumber()
|
401
551
|
}
|
@@ -430,43 +580,6 @@ export class RLNLightContract {
|
|
430
580
|
}
|
431
581
|
}
|
432
582
|
|
433
|
-
/**
|
434
|
-
* Helper method to get remaining messages in current epoch
|
435
|
-
* @param membershipId The ID of the membership to check
|
436
|
-
* @returns number of remaining messages allowed in current epoch
|
437
|
-
*/
|
438
|
-
public async getRemainingMessages(membershipId: number): Promise<number> {
|
439
|
-
try {
|
440
|
-
const [startTime, , rateLimit] =
|
441
|
-
await this.contract.getMembershipInfo(membershipId);
|
442
|
-
|
443
|
-
// Calculate current epoch
|
444
|
-
const currentTime = Math.floor(Date.now() / 1000);
|
445
|
-
const epochsPassed = Math.floor(
|
446
|
-
(currentTime - startTime) / RATE_LIMIT_PARAMS.EPOCH_LENGTH
|
447
|
-
);
|
448
|
-
const currentEpochStart =
|
449
|
-
startTime + epochsPassed * RATE_LIMIT_PARAMS.EPOCH_LENGTH;
|
450
|
-
|
451
|
-
// Get message count in current epoch using contract's function
|
452
|
-
const messageCount = await this.contract.getMessageCount(
|
453
|
-
membershipId,
|
454
|
-
currentEpochStart
|
455
|
-
);
|
456
|
-
return Math.max(
|
457
|
-
0,
|
458
|
-
ethers.BigNumber.from(rateLimit)
|
459
|
-
.sub(ethers.BigNumber.from(messageCount))
|
460
|
-
.toNumber()
|
461
|
-
);
|
462
|
-
} catch (error) {
|
463
|
-
log.error(
|
464
|
-
`Error getting remaining messages: ${(error as Error).message}`
|
465
|
-
);
|
466
|
-
return 0; // Fail safe: assume no messages remaining on error
|
467
|
-
}
|
468
|
-
}
|
469
|
-
|
470
583
|
public async registerWithPermitAndErase(
|
471
584
|
identity: IdentityCredential,
|
472
585
|
permit: {
|
@@ -520,13 +633,13 @@ export class RLNLightContract {
|
|
520
633
|
|
521
634
|
const network = await this.contract.provider.getNetwork();
|
522
635
|
const address = this.contract.address;
|
523
|
-
const membershipId = decodedData.index
|
636
|
+
const membershipId = Number(decodedData.index);
|
524
637
|
|
525
638
|
return {
|
526
639
|
identity,
|
527
640
|
membership: {
|
528
641
|
address,
|
529
|
-
treeIndex:
|
642
|
+
treeIndex: membershipId,
|
530
643
|
chainId: network.chainId.toString(),
|
531
644
|
rateLimit: decodedData.membershipRateLimit.toNumber()
|
532
645
|
}
|
@@ -539,77 +652,40 @@ export class RLNLightContract {
|
|
539
652
|
}
|
540
653
|
}
|
541
654
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
655
|
+
/**
|
656
|
+
* Validates that the rate limit is within the allowed range
|
657
|
+
* @throws Error if the rate limit is outside the allowed range
|
658
|
+
*/
|
659
|
+
private validateRateLimit(rateLimit: number): void {
|
660
|
+
if (
|
661
|
+
rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
|
662
|
+
rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
|
663
|
+
) {
|
664
|
+
throw new Error(
|
665
|
+
`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE} messages per epoch`
|
666
|
+
);
|
548
667
|
}
|
549
668
|
}
|
550
669
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
try {
|
555
|
-
const [startBlock, endBlock, rateLimit] =
|
556
|
-
await this.contract.getMembershipInfo(idCommitment);
|
557
|
-
const currentBlock = await this.contract.provider.getBlockNumber();
|
558
|
-
|
559
|
-
let state: MembershipState;
|
560
|
-
if (currentBlock < startBlock) {
|
561
|
-
state = MembershipState.Active;
|
562
|
-
} else if (currentBlock < endBlock) {
|
563
|
-
state = MembershipState.GracePeriod;
|
564
|
-
} else {
|
565
|
-
state = MembershipState.Expired;
|
566
|
-
}
|
567
|
-
|
568
|
-
const index = await this.getMemberIndex(idCommitment);
|
569
|
-
if (!index) return undefined;
|
570
|
-
|
571
|
-
return {
|
572
|
-
index,
|
573
|
-
idCommitment,
|
574
|
-
rateLimit: rateLimit.toNumber(),
|
575
|
-
startBlock: startBlock.toNumber(),
|
576
|
-
endBlock: endBlock.toNumber(),
|
577
|
-
state
|
578
|
-
};
|
579
|
-
} catch (error) {
|
580
|
-
return undefined;
|
670
|
+
private get membersFilter(): ethers.EventFilter {
|
671
|
+
if (!this._membersFilter) {
|
672
|
+
throw Error("Members filter was not initialized.");
|
581
673
|
}
|
674
|
+
return this._membersFilter;
|
582
675
|
}
|
583
676
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
public async eraseMembership(
|
591
|
-
idCommitment: string,
|
592
|
-
eraseFromMembershipSet: boolean = true
|
593
|
-
): Promise<ethers.ContractTransaction> {
|
594
|
-
return this.contract.eraseMemberships(
|
595
|
-
[idCommitment],
|
596
|
-
eraseFromMembershipSet
|
597
|
-
);
|
677
|
+
private get membershipErasedFilter(): ethers.EventFilter {
|
678
|
+
if (!this._membershipErasedFilter) {
|
679
|
+
throw Error("MembershipErased filter was not initialized.");
|
680
|
+
}
|
681
|
+
return this._membershipErasedFilter;
|
598
682
|
}
|
599
683
|
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
): Promise<ethers.ContractTransaction> {
|
604
|
-
if (
|
605
|
-
rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
|
606
|
-
rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
|
607
|
-
) {
|
608
|
-
throw new Error(
|
609
|
-
`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
|
610
|
-
);
|
684
|
+
private get membersExpiredFilter(): ethers.EventFilter {
|
685
|
+
if (!this._membersExpiredFilter) {
|
686
|
+
throw Error("MembersExpired filter was not initialized.");
|
611
687
|
}
|
612
|
-
return this.
|
688
|
+
return this._membersExpiredFilter;
|
613
689
|
}
|
614
690
|
|
615
691
|
private async getMemberIndex(
|
@@ -629,97 +705,3 @@ export class RLNLightContract {
|
|
629
705
|
}
|
630
706
|
}
|
631
707
|
}
|
632
|
-
|
633
|
-
interface CustomQueryOptions extends FetchMembersOptions {
|
634
|
-
membersFilter: ethers.EventFilter;
|
635
|
-
}
|
636
|
-
|
637
|
-
// These values should be tested on other networks
|
638
|
-
const FETCH_CHUNK = 5;
|
639
|
-
const BLOCK_RANGE = 3000;
|
640
|
-
|
641
|
-
async function queryFilter(
|
642
|
-
contract: ethers.Contract,
|
643
|
-
options: CustomQueryOptions
|
644
|
-
): Promise<ethers.Event[]> {
|
645
|
-
const {
|
646
|
-
fromBlock,
|
647
|
-
membersFilter,
|
648
|
-
fetchRange = BLOCK_RANGE,
|
649
|
-
fetchChunks = FETCH_CHUNK
|
650
|
-
} = options;
|
651
|
-
|
652
|
-
if (fromBlock === undefined) {
|
653
|
-
return contract.queryFilter(membersFilter);
|
654
|
-
}
|
655
|
-
|
656
|
-
if (!contract.provider) {
|
657
|
-
throw Error("No provider found on the contract.");
|
658
|
-
}
|
659
|
-
|
660
|
-
const toBlock = await contract.provider.getBlockNumber();
|
661
|
-
|
662
|
-
if (toBlock - fromBlock < fetchRange) {
|
663
|
-
return contract.queryFilter(membersFilter, fromBlock, toBlock);
|
664
|
-
}
|
665
|
-
|
666
|
-
const events: ethers.Event[][] = [];
|
667
|
-
const chunks = splitToChunks(fromBlock, toBlock, fetchRange);
|
668
|
-
|
669
|
-
for (const portion of takeN<[number, number]>(chunks, fetchChunks)) {
|
670
|
-
const promises = portion.map(([left, right]) =>
|
671
|
-
ignoreErrors(contract.queryFilter(membersFilter, left, right), [])
|
672
|
-
);
|
673
|
-
const fetchedEvents = await Promise.all(promises);
|
674
|
-
events.push(fetchedEvents.flatMap((v) => v));
|
675
|
-
}
|
676
|
-
|
677
|
-
return events.flatMap((v) => v);
|
678
|
-
}
|
679
|
-
|
680
|
-
function splitToChunks(
|
681
|
-
from: number,
|
682
|
-
to: number,
|
683
|
-
step: number
|
684
|
-
): Array<[number, number]> {
|
685
|
-
const chunks: Array<[number, number]> = [];
|
686
|
-
|
687
|
-
let left = from;
|
688
|
-
while (left < to) {
|
689
|
-
const right = left + step < to ? left + step : to;
|
690
|
-
|
691
|
-
chunks.push([left, right] as [number, number]);
|
692
|
-
|
693
|
-
left = right;
|
694
|
-
}
|
695
|
-
|
696
|
-
return chunks;
|
697
|
-
}
|
698
|
-
|
699
|
-
function* takeN<T>(array: T[], size: number): Iterable<T[]> {
|
700
|
-
let start = 0;
|
701
|
-
|
702
|
-
while (start < array.length) {
|
703
|
-
const portion = array.slice(start, start + size);
|
704
|
-
|
705
|
-
yield portion;
|
706
|
-
|
707
|
-
start += size;
|
708
|
-
}
|
709
|
-
}
|
710
|
-
|
711
|
-
async function ignoreErrors<T>(
|
712
|
-
promise: Promise<T>,
|
713
|
-
defaultValue: T
|
714
|
-
): Promise<T> {
|
715
|
-
try {
|
716
|
-
return await promise;
|
717
|
-
} catch (err: unknown) {
|
718
|
-
if (err instanceof Error) {
|
719
|
-
log.info(`Ignoring an error during query: ${err.message}`);
|
720
|
-
} else {
|
721
|
-
log.info(`Ignoring an unknown error during query`);
|
722
|
-
}
|
723
|
-
return defaultValue;
|
724
|
-
}
|
725
|
-
}
|