@waku/rln 0.1.5-cad3e7a.0 → 0.1.5-d0da8f8.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 +4 -3
- package/bundle/packages/rln/dist/contract/constants.js +2 -1
- package/bundle/packages/rln/dist/contract/{rln_light_contract.js → rln_base_contract.js} +189 -186
- package/bundle/packages/rln/dist/contract/rln_contract.js +10 -420
- 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 +31 -17
- package/bundle/packages/rln/dist/rln.js +57 -167
- package/bundle/packages/rln/dist/utils/bytes.js +8 -2
- package/bundle/packages/rln/dist/utils/metamask.js +2 -2
- 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/index.d.ts +1 -0
- package/dist/contract/index.js +1 -0
- package/dist/contract/index.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} +187 -184
- 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 +5 -4
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/keystore/keystore.d.ts +1 -0
- package/dist/keystore/keystore.js +31 -17
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/keystore/types.d.ts +3 -3
- package/dist/rln.d.ts +9 -52
- package/dist/rln.js +55 -164
- 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/utils/bytes.js +8 -2
- package/dist/utils/bytes.js.map +1 -1
- 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/index.ts +1 -0
- package/src/contract/{rln_light_contract.ts → rln_base_contract.ts} +306 -323
- 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 +7 -5
- package/src/keystore/keystore.ts +57 -31
- package/src/keystore/types.ts +3 -3
- package/src/rln.ts +68 -259
- package/src/types.ts +31 -0
- package/src/utils/bytes.ts +10 -2
- package/src/zerokit.ts +3 -3
- package/bundle/_virtual/__node-resolve_empty.js +0 -6
- package/bundle/_virtual/_node-resolve_empty.js +0 -3
- package/bundle/_virtual/bn.js +0 -3
- package/bundle/_virtual/common.js +0 -3
- package/bundle/_virtual/common2.js +0 -3
- package/bundle/_virtual/hash.js +0 -3
- package/bundle/_virtual/inherits_browser.js +0 -3
- package/bundle/_virtual/ripemd.js +0 -3
- package/bundle/_virtual/sha.js +0 -3
- package/bundle/_virtual/sha3.js +0 -3
- package/bundle/_virtual/utils3.js +0 -3
- package/bundle/node_modules/@ethersproject/abi/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/abi/lib.esm/abi-coder.js +0 -96
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/abstract-coder.js +0 -148
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/address.js +0 -26
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/anonymous.js +0 -20
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/array.js +0 -210
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/boolean.js +0 -18
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/bytes.js +0 -30
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/fixed-bytes.js +0 -26
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/null.js +0 -22
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/number.js +0 -43
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/string.js +0 -19
- package/bundle/node_modules/@ethersproject/abi/lib.esm/coders/tuple.js +0 -58
- package/bundle/node_modules/@ethersproject/abi/lib.esm/fragments.js +0 -854
- package/bundle/node_modules/@ethersproject/abi/lib.esm/interface.js +0 -609
- package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/index.js +0 -66
- package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/index.js +0 -302
- package/bundle/node_modules/@ethersproject/address/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/address/lib.esm/index.js +0 -110
- package/bundle/node_modules/@ethersproject/base64/lib.esm/base64.js +0 -20
- package/bundle/node_modules/@ethersproject/basex/lib.esm/index.js +0 -120
- package/bundle/node_modules/@ethersproject/bignumber/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/bignumber/lib.esm/bignumber.js +0 -287
- package/bundle/node_modules/@ethersproject/bytes/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/bytes/lib.esm/index.js +0 -402
- package/bundle/node_modules/@ethersproject/constants/lib.esm/addresses.js +0 -3
- package/bundle/node_modules/@ethersproject/constants/lib.esm/bignumbers.js +0 -8
- package/bundle/node_modules/@ethersproject/constants/lib.esm/hashes.js +0 -3
- package/bundle/node_modules/@ethersproject/contracts/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/contracts/lib.esm/index.js +0 -893
- package/bundle/node_modules/@ethersproject/hash/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/decoder.js +0 -256
- package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/include.js +0 -36
- package/bundle/node_modules/@ethersproject/hash/lib.esm/ens-normalize/lib.js +0 -135
- package/bundle/node_modules/@ethersproject/hash/lib.esm/id.js +0 -8
- package/bundle/node_modules/@ethersproject/hash/lib.esm/namehash.js +0 -64
- package/bundle/node_modules/@ethersproject/hash/lib.esm/typed-data.js +0 -443
- package/bundle/node_modules/@ethersproject/keccak256/lib.esm/index.js +0 -8
- package/bundle/node_modules/@ethersproject/keccak256/node_modules/js-sha3/src/sha3.js +0 -660
- package/bundle/node_modules/@ethersproject/logger/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/logger/lib.esm/index.js +0 -352
- package/bundle/node_modules/@ethersproject/networks/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/networks/lib.esm/index.js +0 -248
- package/bundle/node_modules/@ethersproject/properties/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/properties/lib.esm/index.js +0 -127
- package/bundle/node_modules/@ethersproject/providers/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/providers/lib.esm/base-provider.js +0 -2007
- package/bundle/node_modules/@ethersproject/providers/lib.esm/formatter.js +0 -422
- package/bundle/node_modules/@ethersproject/providers/lib.esm/json-rpc-provider.js +0 -674
- package/bundle/node_modules/@ethersproject/providers/lib.esm/web3-provider.js +0 -132
- package/bundle/node_modules/@ethersproject/rlp/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/rlp/lib.esm/index.js +0 -120
- package/bundle/node_modules/@ethersproject/sha2/lib.esm/sha2.js +0 -8
- package/bundle/node_modules/@ethersproject/signing-key/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/signing-key/lib.esm/elliptic.js +0 -2430
- package/bundle/node_modules/@ethersproject/signing-key/lib.esm/index.js +0 -76
- package/bundle/node_modules/@ethersproject/strings/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/strings/lib.esm/utf8.js +0 -219
- package/bundle/node_modules/@ethersproject/transactions/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/transactions/lib.esm/index.js +0 -279
- package/bundle/node_modules/@ethersproject/web/lib.esm/_version.js +0 -3
- package/bundle/node_modules/@ethersproject/web/lib.esm/geturl.js +0 -69
- package/bundle/node_modules/@ethersproject/web/lib.esm/index.js +0 -404
- package/bundle/node_modules/bech32/index.js +0 -187
- package/bundle/node_modules/bn.js/lib/bn.js +0 -3361
- package/bundle/node_modules/hash.js/lib/hash/common.js +0 -97
- package/bundle/node_modules/hash.js/lib/hash/hmac.js +0 -51
- package/bundle/node_modules/hash.js/lib/hash/ripemd.js +0 -152
- package/bundle/node_modules/hash.js/lib/hash/sha/1.js +0 -81
- package/bundle/node_modules/hash.js/lib/hash/sha/224.js +0 -33
- package/bundle/node_modules/hash.js/lib/hash/sha/256.js +0 -113
- package/bundle/node_modules/hash.js/lib/hash/sha/384.js +0 -39
- package/bundle/node_modules/hash.js/lib/hash/sha/512.js +0 -336
- package/bundle/node_modules/hash.js/lib/hash/sha/common.js +0 -53
- package/bundle/node_modules/hash.js/lib/hash/sha.js +0 -14
- package/bundle/node_modules/hash.js/lib/hash/utils.js +0 -282
- package/bundle/node_modules/hash.js/lib/hash.js +0 -33
- package/bundle/node_modules/inherits/inherits_browser.js +0 -33
- package/bundle/node_modules/minimalistic-assert/index.js +0 -13
- 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
@@ -1,84 +1,38 @@
|
|
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
|
-
options: RLNContractInitOptions
|
72
|
-
): Promise<RLNLightContract> {
|
73
|
-
const rlnContract = new RLNLightContract(options);
|
74
|
-
|
75
|
-
await rlnContract.fetchMembers();
|
76
|
-
rlnContract.subscribeToMembers();
|
77
|
-
|
78
|
-
return rlnContract;
|
79
|
-
}
|
80
|
-
|
81
|
-
private constructor(options: RLNContractInitOptions) {
|
35
|
+
public constructor(options: RLNContractInitOptions) {
|
82
36
|
const {
|
83
37
|
address,
|
84
38
|
signer,
|
@@ -86,24 +40,38 @@ export class RLNLightContract {
|
|
86
40
|
contract
|
87
41
|
} = options;
|
88
42
|
|
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
|
-
}
|
43
|
+
log.info("Initializing RLNBaseContract", { address, rateLimit });
|
97
44
|
|
45
|
+
this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
|
98
46
|
this.rateLimit = rateLimit;
|
99
47
|
|
100
|
-
|
101
|
-
|
48
|
+
try {
|
49
|
+
log.info("Setting up event filters");
|
50
|
+
// Initialize event filters
|
51
|
+
this._membersFilter = this.contract.filters.MembershipRegistered();
|
52
|
+
this._membershipErasedFilter = this.contract.filters.MembershipErased();
|
53
|
+
this._membersExpiredFilter = this.contract.filters.MembershipExpired();
|
54
|
+
log.info("Event filters initialized successfully");
|
55
|
+
} catch (error) {
|
56
|
+
log.error("Failed to initialize event filters", { error });
|
57
|
+
throw new Error(
|
58
|
+
"Failed to initialize event filters: " + (error as Error).message
|
59
|
+
);
|
60
|
+
}
|
102
61
|
|
103
|
-
// Initialize
|
104
|
-
this.
|
105
|
-
|
106
|
-
|
62
|
+
// Initialize members and subscriptions
|
63
|
+
this.fetchMembers()
|
64
|
+
.then(() => {
|
65
|
+
this.subscribeToMembers();
|
66
|
+
})
|
67
|
+
.catch((error) => {
|
68
|
+
log.error("Failed to initialize members", { error });
|
69
|
+
});
|
70
|
+
|
71
|
+
// Validate rate limit asynchronously
|
72
|
+
this.validateRateLimit(rateLimit).catch((error) => {
|
73
|
+
log.error("Failed to validate initial rate limit", { error });
|
74
|
+
});
|
107
75
|
}
|
108
76
|
|
109
77
|
/**
|
@@ -151,7 +119,7 @@ export class RLNLightContract {
|
|
151
119
|
*/
|
152
120
|
public async getMaxTotalRateLimit(): Promise<number> {
|
153
121
|
const maxTotalRate = await this.contract.maxTotalRateLimit();
|
154
|
-
return
|
122
|
+
return maxTotalRate.toNumber();
|
155
123
|
}
|
156
124
|
|
157
125
|
/**
|
@@ -160,7 +128,7 @@ export class RLNLightContract {
|
|
160
128
|
*/
|
161
129
|
public async getCurrentTotalRateLimit(): Promise<number> {
|
162
130
|
const currentTotal = await this.contract.currentTotalRateLimit();
|
163
|
-
return
|
131
|
+
return currentTotal.toNumber();
|
164
132
|
}
|
165
133
|
|
166
134
|
/**
|
@@ -172,9 +140,7 @@ export class RLNLightContract {
|
|
172
140
|
this.contract.maxTotalRateLimit(),
|
173
141
|
this.contract.currentTotalRateLimit()
|
174
142
|
]);
|
175
|
-
return
|
176
|
-
.sub(ethers.BigNumber.from(currentTotal))
|
177
|
-
.toNumber();
|
143
|
+
return Number(maxTotal) - Number(currentTotal);
|
178
144
|
}
|
179
145
|
|
180
146
|
/**
|
@@ -182,6 +148,7 @@ export class RLNLightContract {
|
|
182
148
|
* @param newRateLimit The new rate limit to use
|
183
149
|
*/
|
184
150
|
public async setRateLimit(newRateLimit: number): Promise<void> {
|
151
|
+
await this.validateRateLimit(newRateLimit);
|
185
152
|
this.rateLimit = newRateLimit;
|
186
153
|
}
|
187
154
|
|
@@ -192,43 +159,31 @@ export class RLNLightContract {
|
|
192
159
|
return sortedMembers;
|
193
160
|
}
|
194
161
|
|
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
162
|
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
|
-
|
163
|
+
const registeredMemberEvents = await RLNBaseContract.queryFilter(
|
164
|
+
this.contract,
|
165
|
+
{
|
166
|
+
fromBlock: this.deployBlock,
|
167
|
+
...options,
|
168
|
+
membersFilter: this.membersFilter
|
169
|
+
}
|
170
|
+
);
|
171
|
+
const removedMemberEvents = await RLNBaseContract.queryFilter(
|
172
|
+
this.contract,
|
173
|
+
{
|
174
|
+
fromBlock: this.deployBlock,
|
175
|
+
...options,
|
176
|
+
membersFilter: this.membershipErasedFilter
|
177
|
+
}
|
178
|
+
);
|
179
|
+
const expiredMemberEvents = await RLNBaseContract.queryFilter(
|
180
|
+
this.contract,
|
181
|
+
{
|
182
|
+
fromBlock: this.deployBlock,
|
183
|
+
...options,
|
184
|
+
membersFilter: this.membersExpiredFilter
|
185
|
+
}
|
186
|
+
);
|
232
187
|
|
233
188
|
const events = [
|
234
189
|
...registeredMemberEvents,
|
@@ -238,6 +193,58 @@ export class RLNLightContract {
|
|
238
193
|
this.processEvents(events);
|
239
194
|
}
|
240
195
|
|
196
|
+
public static async queryFilter(
|
197
|
+
contract: ethers.Contract,
|
198
|
+
options: CustomQueryOptions
|
199
|
+
): Promise<ethers.Event[]> {
|
200
|
+
const FETCH_CHUNK = 5;
|
201
|
+
const BLOCK_RANGE = 3000;
|
202
|
+
|
203
|
+
const {
|
204
|
+
fromBlock,
|
205
|
+
membersFilter,
|
206
|
+
fetchRange = BLOCK_RANGE,
|
207
|
+
fetchChunks = FETCH_CHUNK
|
208
|
+
} = options;
|
209
|
+
|
210
|
+
if (fromBlock === undefined) {
|
211
|
+
return contract.queryFilter(membersFilter);
|
212
|
+
}
|
213
|
+
|
214
|
+
if (!contract.provider) {
|
215
|
+
throw Error("No provider found on the contract.");
|
216
|
+
}
|
217
|
+
|
218
|
+
const toBlock = await contract.provider.getBlockNumber();
|
219
|
+
|
220
|
+
if (toBlock - fromBlock < fetchRange) {
|
221
|
+
return contract.queryFilter(membersFilter, fromBlock, toBlock);
|
222
|
+
}
|
223
|
+
|
224
|
+
const events: ethers.Event[][] = [];
|
225
|
+
const chunks = RLNBaseContract.splitToChunks(
|
226
|
+
fromBlock,
|
227
|
+
toBlock,
|
228
|
+
fetchRange
|
229
|
+
);
|
230
|
+
|
231
|
+
for (const portion of RLNBaseContract.takeN<[number, number]>(
|
232
|
+
chunks,
|
233
|
+
fetchChunks
|
234
|
+
)) {
|
235
|
+
const promises = portion.map(([left, right]) =>
|
236
|
+
RLNBaseContract.ignoreErrors(
|
237
|
+
contract.queryFilter(membersFilter, left, right),
|
238
|
+
[]
|
239
|
+
)
|
240
|
+
);
|
241
|
+
const fetchedEvents = await Promise.all(promises);
|
242
|
+
events.push(fetchedEvents.flatMap((v) => v));
|
243
|
+
}
|
244
|
+
|
245
|
+
return events.flatMap((v) => v);
|
246
|
+
}
|
247
|
+
|
241
248
|
public processEvents(events: ethers.Event[]): void {
|
242
249
|
const toRemoveTable = new Map<number, number[]>();
|
243
250
|
const toInsertTable = new Map<number, ethers.Event[]>();
|
@@ -280,11 +287,58 @@ export class RLNLightContract {
|
|
280
287
|
});
|
281
288
|
}
|
282
289
|
|
290
|
+
public static splitToChunks(
|
291
|
+
from: number,
|
292
|
+
to: number,
|
293
|
+
step: number
|
294
|
+
): Array<[number, number]> {
|
295
|
+
const chunks: Array<[number, number]> = [];
|
296
|
+
|
297
|
+
let left = from;
|
298
|
+
while (left < to) {
|
299
|
+
const right = left + step < to ? left + step : to;
|
300
|
+
|
301
|
+
chunks.push([left, right] as [number, number]);
|
302
|
+
|
303
|
+
left = right;
|
304
|
+
}
|
305
|
+
|
306
|
+
return chunks;
|
307
|
+
}
|
308
|
+
|
309
|
+
public static *takeN<T>(array: T[], size: number): Iterable<T[]> {
|
310
|
+
let start = 0;
|
311
|
+
|
312
|
+
while (start < array.length) {
|
313
|
+
const portion = array.slice(start, start + size);
|
314
|
+
|
315
|
+
yield portion;
|
316
|
+
|
317
|
+
start += size;
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
321
|
+
public static async ignoreErrors<T>(
|
322
|
+
promise: Promise<T>,
|
323
|
+
defaultValue: T
|
324
|
+
): Promise<T> {
|
325
|
+
try {
|
326
|
+
return await promise;
|
327
|
+
} catch (err: unknown) {
|
328
|
+
if (err instanceof Error) {
|
329
|
+
log.info(`Ignoring an error during query: ${err.message}`);
|
330
|
+
} else {
|
331
|
+
log.info(`Ignoring an unknown error during query`);
|
332
|
+
}
|
333
|
+
return defaultValue;
|
334
|
+
}
|
335
|
+
}
|
336
|
+
|
283
337
|
public subscribeToMembers(): void {
|
284
338
|
this.contract.on(
|
285
339
|
this.membersFilter,
|
286
340
|
(
|
287
|
-
_idCommitment:
|
341
|
+
_idCommitment: bigint,
|
288
342
|
_membershipRateLimit: ethers.BigNumber,
|
289
343
|
_index: ethers.BigNumber,
|
290
344
|
event: ethers.Event
|
@@ -296,7 +350,7 @@ export class RLNLightContract {
|
|
296
350
|
this.contract.on(
|
297
351
|
this.membershipErasedFilter,
|
298
352
|
(
|
299
|
-
_idCommitment:
|
353
|
+
_idCommitment: bigint,
|
300
354
|
_membershipRateLimit: ethers.BigNumber,
|
301
355
|
_index: ethers.BigNumber,
|
302
356
|
event: ethers.Event
|
@@ -308,7 +362,7 @@ export class RLNLightContract {
|
|
308
362
|
this.contract.on(
|
309
363
|
this.membersExpiredFilter,
|
310
364
|
(
|
311
|
-
_idCommitment:
|
365
|
+
_idCommitment: bigint,
|
312
366
|
_membershipRateLimit: ethers.BigNumber,
|
313
367
|
_index: ethers.BigNumber,
|
314
368
|
event: ethers.Event
|
@@ -318,6 +372,98 @@ export class RLNLightContract {
|
|
318
372
|
);
|
319
373
|
}
|
320
374
|
|
375
|
+
public async getMembershipInfo(
|
376
|
+
idCommitmentBigInt: bigint
|
377
|
+
): Promise<MembershipInfo | undefined> {
|
378
|
+
try {
|
379
|
+
const membershipData =
|
380
|
+
await this.contract.memberships(idCommitmentBigInt);
|
381
|
+
const currentBlock = await this.contract.provider.getBlockNumber();
|
382
|
+
const [
|
383
|
+
depositAmount,
|
384
|
+
activeDuration,
|
385
|
+
gracePeriodStartTimestamp,
|
386
|
+
gracePeriodDuration,
|
387
|
+
rateLimit,
|
388
|
+
index,
|
389
|
+
holder,
|
390
|
+
token
|
391
|
+
] = membershipData;
|
392
|
+
|
393
|
+
const gracePeriodEnd = gracePeriodStartTimestamp.add(gracePeriodDuration);
|
394
|
+
|
395
|
+
let state: MembershipState;
|
396
|
+
if (currentBlock < gracePeriodStartTimestamp.toNumber()) {
|
397
|
+
state = MembershipState.Active;
|
398
|
+
} else if (currentBlock < gracePeriodEnd.toNumber()) {
|
399
|
+
state = MembershipState.GracePeriod;
|
400
|
+
} else {
|
401
|
+
state = MembershipState.Expired;
|
402
|
+
}
|
403
|
+
|
404
|
+
return {
|
405
|
+
index,
|
406
|
+
idCommitment: idCommitmentBigInt.toString(),
|
407
|
+
rateLimit: Number(rateLimit),
|
408
|
+
startBlock: gracePeriodStartTimestamp.toNumber(),
|
409
|
+
endBlock: gracePeriodEnd.toNumber(),
|
410
|
+
state,
|
411
|
+
depositAmount,
|
412
|
+
activeDuration,
|
413
|
+
gracePeriodDuration,
|
414
|
+
holder,
|
415
|
+
token
|
416
|
+
};
|
417
|
+
} catch (error) {
|
418
|
+
log.error("Error in getMembershipInfo:", error);
|
419
|
+
return undefined;
|
420
|
+
}
|
421
|
+
}
|
422
|
+
|
423
|
+
public async extendMembership(
|
424
|
+
idCommitmentBigInt: bigint
|
425
|
+
): Promise<ethers.ContractTransaction> {
|
426
|
+
const tx = await this.contract.extendMemberships([idCommitmentBigInt]);
|
427
|
+
await tx.wait();
|
428
|
+
return tx;
|
429
|
+
}
|
430
|
+
|
431
|
+
public async eraseMembership(
|
432
|
+
idCommitmentBigInt: bigint,
|
433
|
+
eraseFromMembershipSet: boolean = true
|
434
|
+
): Promise<ethers.ContractTransaction> {
|
435
|
+
const tx = await this.contract["eraseMemberships(uint256[],bool)"](
|
436
|
+
[idCommitmentBigInt],
|
437
|
+
eraseFromMembershipSet
|
438
|
+
);
|
439
|
+
await tx.wait();
|
440
|
+
return tx;
|
441
|
+
}
|
442
|
+
|
443
|
+
public async registerMembership(
|
444
|
+
idCommitmentBigInt: bigint,
|
445
|
+
rateLimit: number = DEFAULT_RATE_LIMIT
|
446
|
+
): Promise<ethers.ContractTransaction> {
|
447
|
+
if (
|
448
|
+
rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
|
449
|
+
rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
|
450
|
+
) {
|
451
|
+
throw new Error(
|
452
|
+
`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
|
453
|
+
);
|
454
|
+
}
|
455
|
+
return this.contract.register(idCommitmentBigInt, rateLimit, []);
|
456
|
+
}
|
457
|
+
|
458
|
+
public async withdraw(token: string, from: string): Promise<void> {
|
459
|
+
try {
|
460
|
+
const tx = await this.contract.withdraw(token, from);
|
461
|
+
await tx.wait();
|
462
|
+
} catch (error) {
|
463
|
+
log.error(`Error in withdraw: ${(error as Error).message}`);
|
464
|
+
}
|
465
|
+
}
|
466
|
+
|
321
467
|
public async registerWithIdentity(
|
322
468
|
identity: IdentityCredential
|
323
469
|
): Promise<DecryptedCredentials | undefined> {
|
@@ -328,7 +474,7 @@ export class RLNLightContract {
|
|
328
474
|
|
329
475
|
// Check if the ID commitment is already registered
|
330
476
|
const existingIndex = await this.getMemberIndex(
|
331
|
-
identity.IDCommitmentBigInt
|
477
|
+
identity.IDCommitmentBigInt
|
332
478
|
);
|
333
479
|
if (existingIndex) {
|
334
480
|
throw new Error(
|
@@ -366,7 +512,7 @@ export class RLNLightContract {
|
|
366
512
|
}
|
367
513
|
|
368
514
|
const memberRegistered = txRegisterReceipt.events?.find(
|
369
|
-
(event) => event.event === "MembershipRegistered"
|
515
|
+
(event: ethers.Event) => event.event === "MembershipRegistered"
|
370
516
|
);
|
371
517
|
|
372
518
|
if (!memberRegistered || !memberRegistered.args) {
|
@@ -389,13 +535,13 @@ export class RLNLightContract {
|
|
389
535
|
|
390
536
|
const network = await this.contract.provider.getNetwork();
|
391
537
|
const address = this.contract.address;
|
392
|
-
const membershipId = decodedData.index
|
538
|
+
const membershipId = Number(decodedData.index);
|
393
539
|
|
394
540
|
return {
|
395
541
|
identity,
|
396
542
|
membership: {
|
397
543
|
address,
|
398
|
-
treeIndex:
|
544
|
+
treeIndex: membershipId,
|
399
545
|
chainId: network.chainId.toString(),
|
400
546
|
rateLimit: decodedData.membershipRateLimit.toNumber()
|
401
547
|
}
|
@@ -430,43 +576,6 @@ export class RLNLightContract {
|
|
430
576
|
}
|
431
577
|
}
|
432
578
|
|
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
579
|
public async registerWithPermitAndErase(
|
471
580
|
identity: IdentityCredential,
|
472
581
|
permit: {
|
@@ -497,7 +606,7 @@ export class RLNLightContract {
|
|
497
606
|
const txRegisterReceipt = await txRegisterResponse.wait();
|
498
607
|
|
499
608
|
const memberRegistered = txRegisterReceipt.events?.find(
|
500
|
-
(event) => event.event === "MembershipRegistered"
|
609
|
+
(event: ethers.Event) => event.event === "MembershipRegistered"
|
501
610
|
);
|
502
611
|
|
503
612
|
if (!memberRegistered || !memberRegistered.args) {
|
@@ -520,13 +629,13 @@ export class RLNLightContract {
|
|
520
629
|
|
521
630
|
const network = await this.contract.provider.getNetwork();
|
522
631
|
const address = this.contract.address;
|
523
|
-
const membershipId = decodedData.index
|
632
|
+
const membershipId = Number(decodedData.index);
|
524
633
|
|
525
634
|
return {
|
526
635
|
identity,
|
527
636
|
membership: {
|
528
637
|
address,
|
529
|
-
treeIndex:
|
638
|
+
treeIndex: membershipId,
|
530
639
|
chainId: network.chainId.toString(),
|
531
640
|
rateLimit: decodedData.membershipRateLimit.toNumber()
|
532
641
|
}
|
@@ -539,85 +648,53 @@ export class RLNLightContract {
|
|
539
648
|
}
|
540
649
|
}
|
541
650
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
public async getMembershipInfo(
|
552
|
-
idCommitment: string
|
553
|
-
): Promise<MembershipInfo | undefined> {
|
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
|
-
}
|
651
|
+
/**
|
652
|
+
* Validates that the rate limit is within the allowed range
|
653
|
+
* @throws Error if the rate limit is outside the allowed range
|
654
|
+
*/
|
655
|
+
private async validateRateLimit(rateLimit: number): Promise<void> {
|
656
|
+
const [minRate, maxRate] = await Promise.all([
|
657
|
+
this.contract.minMembershipRateLimit(),
|
658
|
+
this.contract.maxMembershipRateLimit()
|
659
|
+
]);
|
567
660
|
|
568
|
-
|
569
|
-
|
661
|
+
const minRateNum = ethers.BigNumber.from(minRate).toNumber();
|
662
|
+
const maxRateNum = ethers.BigNumber.from(maxRate).toNumber();
|
570
663
|
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
startBlock: startBlock.toNumber(),
|
576
|
-
endBlock: endBlock.toNumber(),
|
577
|
-
state
|
578
|
-
};
|
579
|
-
} catch (error) {
|
580
|
-
return undefined;
|
664
|
+
if (rateLimit < minRateNum || rateLimit > maxRateNum) {
|
665
|
+
throw new Error(
|
666
|
+
`Rate limit must be between ${minRateNum} and ${maxRateNum} messages per epoch`
|
667
|
+
);
|
581
668
|
}
|
582
669
|
}
|
583
670
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
671
|
+
private get membersFilter(): ethers.EventFilter {
|
672
|
+
if (!this._membersFilter) {
|
673
|
+
throw Error("Members filter was not initialized.");
|
674
|
+
}
|
675
|
+
return this._membersFilter;
|
588
676
|
}
|
589
677
|
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
return this.
|
595
|
-
[idCommitment],
|
596
|
-
eraseFromMembershipSet
|
597
|
-
);
|
678
|
+
private get membershipErasedFilter(): ethers.EventFilter {
|
679
|
+
if (!this._membershipErasedFilter) {
|
680
|
+
throw Error("MembershipErased filter was not initialized.");
|
681
|
+
}
|
682
|
+
return this._membershipErasedFilter;
|
598
683
|
}
|
599
684
|
|
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
|
-
);
|
685
|
+
private get membersExpiredFilter(): ethers.EventFilter {
|
686
|
+
if (!this._membersExpiredFilter) {
|
687
|
+
throw Error("MembersExpired filter was not initialized.");
|
611
688
|
}
|
612
|
-
return this.
|
689
|
+
return this._membersExpiredFilter;
|
613
690
|
}
|
614
691
|
|
615
692
|
private async getMemberIndex(
|
616
|
-
|
693
|
+
idCommitmentBigInt: bigint
|
617
694
|
): Promise<ethers.BigNumber | undefined> {
|
618
695
|
try {
|
619
696
|
const events = await this.contract.queryFilter(
|
620
|
-
this.contract.filters.MembershipRegistered(
|
697
|
+
this.contract.filters.MembershipRegistered(idCommitmentBigInt)
|
621
698
|
);
|
622
699
|
if (events.length === 0) return undefined;
|
623
700
|
|
@@ -629,97 +706,3 @@ export class RLNLightContract {
|
|
629
706
|
}
|
630
707
|
}
|
631
708
|
}
|
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
|
-
}
|