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