@waku/rln 0.0.2-c41b319.0 → 0.0.2-c8128d1.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/index.js +1 -1
- package/bundle/packages/interfaces/dist/protocols.js +40 -45
- package/bundle/packages/rln/dist/contract/abi.js +648 -0
- package/bundle/packages/rln/dist/contract/constants.js +8 -13
- package/bundle/packages/rln/dist/contract/rln_contract.js +148 -25
- package/bundle/packages/rln/dist/identity.js +0 -24
- package/bundle/packages/rln/dist/rln.js +33 -15
- package/bundle/packages/rln/dist/zerokit.js +22 -16
- package/dist/.tsbuildinfo +1 -1
- package/dist/contract/{abi/rlnv2.d.ts → abi.d.ts} +22 -18
- package/dist/contract/abi.js +647 -0
- package/dist/contract/abi.js.map +1 -0
- package/dist/contract/constants.d.ts +22 -23
- package/dist/contract/constants.js +7 -12
- package/dist/contract/constants.js.map +1 -1
- package/dist/contract/rln_contract.d.ts +13 -3
- package/dist/contract/rln_contract.js +148 -25
- package/dist/contract/rln_contract.js.map +1 -1
- package/dist/identity.d.ts +0 -1
- package/dist/identity.js +0 -24
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/rln.js +33 -14
- package/dist/rln.js.map +1 -1
- package/dist/zerokit.d.ts +5 -1
- package/dist/zerokit.js +22 -16
- package/dist/zerokit.js.map +1 -1
- package/package.json +1 -1
- package/src/contract/abi.ts +646 -0
- package/src/contract/constants.ts +8 -14
- package/src/contract/rln_contract.ts +227 -27
- package/src/identity.ts +0 -42
- package/src/index.ts +2 -2
- package/src/rln.ts +48 -14
- package/src/zerokit.ts +45 -16
- package/bundle/node_modules/@iden3/js-crypto/dist/browser/esm/index.js +0 -7
- package/bundle/node_modules/@stablelib/binary/lib/binary.js +0 -22
- package/bundle/node_modules/@stablelib/chacha/lib/chacha.js +0 -245
- package/bundle/node_modules/@stablelib/wipe/lib/wipe.js +0 -26
- package/bundle/packages/rln/dist/contract/abi/rlnv2.js +0 -394
- package/dist/contract/abi/rlnv2.js +0 -393
- package/dist/contract/abi/rlnv2.js.map +0 -1
- package/src/contract/abi/rlnv2.ts +0 -392
@@ -1,3 +1,4 @@
|
|
1
|
+
/* eslint-disable no-console */
|
1
2
|
import { Logger } from "@waku/utils";
|
2
3
|
import { hexToBytes } from "@waku/utils/bytes";
|
3
4
|
import { ethers } from "ethers";
|
@@ -8,7 +9,7 @@ import type { RLNInstance } from "../rln.js";
|
|
8
9
|
import { MerkleRootTracker } from "../root_tracker.js";
|
9
10
|
import { zeroPadLE } from "../utils/bytes.js";
|
10
11
|
|
11
|
-
import {
|
12
|
+
import { RLN_ABI } from "./abi.js";
|
12
13
|
import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from "./constants.js";
|
13
14
|
|
14
15
|
const log = new Logger("waku:rln:contract");
|
@@ -30,7 +31,7 @@ interface RLNContractInitOptions extends RLNContractOptions {
|
|
30
31
|
|
31
32
|
export interface MembershipRegisteredEvent {
|
32
33
|
idCommitment: string;
|
33
|
-
|
34
|
+
membershipRateLimit: ethers.BigNumber;
|
34
35
|
index: ethers.BigNumber;
|
35
36
|
}
|
36
37
|
|
@@ -66,6 +67,7 @@ export class RLNContract {
|
|
66
67
|
private _members: Map<number, Member> = new Map();
|
67
68
|
private _membersFilter: ethers.EventFilter;
|
68
69
|
private _membersRemovedFilter: ethers.EventFilter;
|
70
|
+
private _membersExpiredFilter: ethers.EventFilter;
|
69
71
|
|
70
72
|
/**
|
71
73
|
* Asynchronous initializer for RLNContract.
|
@@ -108,13 +110,13 @@ export class RLNContract {
|
|
108
110
|
const initialRoot = rlnInstance.zerokit.getMerkleRoot();
|
109
111
|
|
110
112
|
// Use the injected contract if provided; otherwise, instantiate a new one.
|
111
|
-
this.contract =
|
112
|
-
contract || new ethers.Contract(address, RLN_V2_ABI, signer);
|
113
|
+
this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
|
113
114
|
this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
|
114
115
|
|
115
|
-
// Initialize event filters
|
116
|
+
// Initialize event filters
|
116
117
|
this._membersFilter = this.contract.filters.MembershipRegistered();
|
117
|
-
this._membersRemovedFilter = this.contract.filters.
|
118
|
+
this._membersRemovedFilter = this.contract.filters.MembershipErased();
|
119
|
+
this._membersExpiredFilter = this.contract.filters.MembershipExpired();
|
118
120
|
}
|
119
121
|
|
120
122
|
/**
|
@@ -124,6 +126,20 @@ export class RLNContract {
|
|
124
126
|
return this.rateLimit;
|
125
127
|
}
|
126
128
|
|
129
|
+
/**
|
130
|
+
* Gets the contract address
|
131
|
+
*/
|
132
|
+
public get address(): string {
|
133
|
+
return this.contract.address;
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Gets the contract provider
|
138
|
+
*/
|
139
|
+
public get provider(): ethers.providers.Provider {
|
140
|
+
return this.contract.provider;
|
141
|
+
}
|
142
|
+
|
127
143
|
/**
|
128
144
|
* Gets the minimum allowed rate limit from the contract
|
129
145
|
* @returns Promise<number> The minimum rate limit in messages per epoch
|
@@ -196,11 +212,18 @@ export class RLNContract {
|
|
196
212
|
|
197
213
|
private get membersRemovedFilter(): ethers.EventFilter {
|
198
214
|
if (!this._membersRemovedFilter) {
|
199
|
-
throw Error("
|
215
|
+
throw Error("MembersErased filter was not initialized.");
|
200
216
|
}
|
201
217
|
return this._membersRemovedFilter;
|
202
218
|
}
|
203
219
|
|
220
|
+
private get membersExpiredFilter(): ethers.EventFilter {
|
221
|
+
if (!this._membersExpiredFilter) {
|
222
|
+
throw Error("MembersExpired filter was not initialized.");
|
223
|
+
}
|
224
|
+
return this._membersExpiredFilter;
|
225
|
+
}
|
226
|
+
|
204
227
|
public async fetchMembers(
|
205
228
|
rlnInstance: RLNInstance,
|
206
229
|
options: FetchMembersOptions = {}
|
@@ -215,8 +238,17 @@ export class RLNContract {
|
|
215
238
|
...options,
|
216
239
|
membersFilter: this.membersRemovedFilter
|
217
240
|
});
|
241
|
+
const expiredMemberEvents = await queryFilter(this.contract, {
|
242
|
+
fromBlock: this.deployBlock,
|
243
|
+
...options,
|
244
|
+
membersFilter: this.membersExpiredFilter
|
245
|
+
});
|
218
246
|
|
219
|
-
const events = [
|
247
|
+
const events = [
|
248
|
+
...registeredMemberEvents,
|
249
|
+
...removedMemberEvents,
|
250
|
+
...expiredMemberEvents
|
251
|
+
];
|
220
252
|
this.processEvents(rlnInstance, events);
|
221
253
|
}
|
222
254
|
|
@@ -229,8 +261,22 @@ export class RLNContract {
|
|
229
261
|
return;
|
230
262
|
}
|
231
263
|
|
232
|
-
if (
|
233
|
-
|
264
|
+
if (
|
265
|
+
evt.event === "MembershipErased" ||
|
266
|
+
evt.event === "MembershipExpired"
|
267
|
+
) {
|
268
|
+
// Both MembershipErased and MembershipExpired events should remove members
|
269
|
+
let index = evt.args.index;
|
270
|
+
|
271
|
+
if (!index) {
|
272
|
+
return;
|
273
|
+
}
|
274
|
+
|
275
|
+
// Convert index to ethers.BigNumber if it's not already
|
276
|
+
if (typeof index === "number" || typeof index === "string") {
|
277
|
+
index = ethers.BigNumber.from(index);
|
278
|
+
}
|
279
|
+
|
234
280
|
const toRemoveVal = toRemoveTable.get(evt.blockNumber);
|
235
281
|
if (toRemoveVal != undefined) {
|
236
282
|
toRemoveVal.push(index.toNumber());
|
@@ -262,16 +308,25 @@ export class RLNContract {
|
|
262
308
|
if (!evt.args) return;
|
263
309
|
|
264
310
|
const _idCommitment = evt.args.idCommitment as string;
|
265
|
-
|
311
|
+
let index = evt.args.index;
|
266
312
|
|
313
|
+
// Ensure index is an ethers.BigNumber
|
267
314
|
if (!_idCommitment || !index) {
|
268
315
|
return;
|
269
316
|
}
|
270
317
|
|
318
|
+
// Convert index to ethers.BigNumber if it's not already
|
319
|
+
if (typeof index === "number" || typeof index === "string") {
|
320
|
+
index = ethers.BigNumber.from(index);
|
321
|
+
}
|
322
|
+
|
271
323
|
const idCommitment = zeroPadLE(hexToBytes(_idCommitment), 32);
|
272
324
|
rlnInstance.zerokit.insertMember(idCommitment);
|
273
|
-
|
274
|
-
|
325
|
+
|
326
|
+
// Always store the numeric index as the key, but the BigNumber as the value
|
327
|
+
const numericIndex = index.toNumber();
|
328
|
+
this._members.set(numericIndex, {
|
329
|
+
index, // This is always a BigNumber
|
275
330
|
idCommitment: _idCommitment
|
276
331
|
});
|
277
332
|
});
|
@@ -303,7 +358,7 @@ export class RLNContract {
|
|
303
358
|
this.membersFilter,
|
304
359
|
(
|
305
360
|
_idCommitment: string,
|
306
|
-
|
361
|
+
_membershipRateLimit: ethers.BigNumber,
|
307
362
|
_index: ethers.BigNumber,
|
308
363
|
event: ethers.Event
|
309
364
|
) => {
|
@@ -315,6 +370,19 @@ export class RLNContract {
|
|
315
370
|
this.membersRemovedFilter,
|
316
371
|
(
|
317
372
|
_idCommitment: string,
|
373
|
+
_membershipRateLimit: ethers.BigNumber,
|
374
|
+
_index: ethers.BigNumber,
|
375
|
+
event: ethers.Event
|
376
|
+
) => {
|
377
|
+
this.processEvents(rlnInstance, [event]);
|
378
|
+
}
|
379
|
+
);
|
380
|
+
|
381
|
+
this.contract.on(
|
382
|
+
this.membersExpiredFilter,
|
383
|
+
(
|
384
|
+
_idCommitment: string,
|
385
|
+
_membershipRateLimit: ethers.BigNumber,
|
318
386
|
_index: ethers.BigNumber,
|
319
387
|
event: ethers.Event
|
320
388
|
) => {
|
@@ -327,10 +395,43 @@ export class RLNContract {
|
|
327
395
|
identity: IdentityCredential
|
328
396
|
): Promise<DecryptedCredentials | undefined> {
|
329
397
|
try {
|
398
|
+
console.log("registerWithIdentity - starting registration process");
|
399
|
+
console.log("registerWithIdentity - identity:", identity);
|
400
|
+
console.log(
|
401
|
+
"registerWithIdentity - IDCommitmentBigInt:",
|
402
|
+
identity.IDCommitmentBigInt.toString()
|
403
|
+
);
|
404
|
+
console.log("registerWithIdentity - rate limit:", this.rateLimit);
|
405
|
+
|
330
406
|
log.info(
|
331
407
|
`Registering identity with rate limit: ${this.rateLimit} messages/epoch`
|
332
408
|
);
|
333
409
|
|
410
|
+
// Check if the ID commitment is already registered
|
411
|
+
const existingIndex = await this.getMemberIndex(
|
412
|
+
identity.IDCommitmentBigInt.toString()
|
413
|
+
);
|
414
|
+
if (existingIndex) {
|
415
|
+
console.error(
|
416
|
+
`ID commitment is already registered with index ${existingIndex}`
|
417
|
+
);
|
418
|
+
throw new Error(
|
419
|
+
`ID commitment is already registered with index ${existingIndex}`
|
420
|
+
);
|
421
|
+
}
|
422
|
+
|
423
|
+
// Check if there's enough remaining rate limit
|
424
|
+
const remainingRateLimit = await this.getRemainingTotalRateLimit();
|
425
|
+
if (remainingRateLimit < this.rateLimit) {
|
426
|
+
console.error(
|
427
|
+
`Not enough remaining rate limit. Requested: ${this.rateLimit}, Available: ${remainingRateLimit}`
|
428
|
+
);
|
429
|
+
throw new Error(
|
430
|
+
`Not enough remaining rate limit. Requested: ${this.rateLimit}, Available: ${remainingRateLimit}`
|
431
|
+
);
|
432
|
+
}
|
433
|
+
|
434
|
+
console.log("registerWithIdentity - calling contract.register");
|
334
435
|
const txRegisterResponse: ethers.ContractTransaction =
|
335
436
|
await this.contract.register(
|
336
437
|
identity.IDCommitmentBigInt,
|
@@ -338,35 +439,97 @@ export class RLNContract {
|
|
338
439
|
[],
|
339
440
|
{ gasLimit: 300000 }
|
340
441
|
);
|
442
|
+
console.log(
|
443
|
+
"registerWithIdentity - txRegisterResponse:",
|
444
|
+
txRegisterResponse
|
445
|
+
);
|
446
|
+
console.log("registerWithIdentity - hash:", txRegisterResponse.hash);
|
447
|
+
console.log(
|
448
|
+
"registerWithIdentity - waiting for transaction confirmation..."
|
449
|
+
);
|
450
|
+
|
341
451
|
const txRegisterReceipt = await txRegisterResponse.wait();
|
452
|
+
console.log(
|
453
|
+
"registerWithIdentity - txRegisterReceipt:",
|
454
|
+
txRegisterReceipt
|
455
|
+
);
|
456
|
+
console.log(
|
457
|
+
"registerWithIdentity - transaction status:",
|
458
|
+
txRegisterReceipt.status
|
459
|
+
);
|
460
|
+
console.log(
|
461
|
+
"registerWithIdentity - block number:",
|
462
|
+
txRegisterReceipt.blockNumber
|
463
|
+
);
|
464
|
+
console.log(
|
465
|
+
"registerWithIdentity - gas used:",
|
466
|
+
txRegisterReceipt.gasUsed.toString()
|
467
|
+
);
|
468
|
+
|
469
|
+
// Check transaction status
|
470
|
+
if (txRegisterReceipt.status === 0) {
|
471
|
+
console.error("Transaction failed on-chain");
|
472
|
+
throw new Error("Transaction failed on-chain");
|
473
|
+
}
|
342
474
|
|
343
475
|
const memberRegistered = txRegisterReceipt.events?.find(
|
344
476
|
(event) => event.event === "MembershipRegistered"
|
345
477
|
);
|
478
|
+
console.log(
|
479
|
+
"registerWithIdentity - memberRegistered event:",
|
480
|
+
memberRegistered
|
481
|
+
);
|
346
482
|
|
347
483
|
if (!memberRegistered || !memberRegistered.args) {
|
348
|
-
log
|
484
|
+
console.log(
|
485
|
+
"registerWithIdentity - ERROR: no memberRegistered event found"
|
486
|
+
);
|
487
|
+
console.log(
|
488
|
+
"registerWithIdentity - all events:",
|
489
|
+
txRegisterReceipt.events
|
490
|
+
);
|
491
|
+
console.error(
|
349
492
|
"Failed to register membership: No MembershipRegistered event found"
|
350
493
|
);
|
351
494
|
return undefined;
|
352
495
|
}
|
353
496
|
|
497
|
+
console.log(
|
498
|
+
"registerWithIdentity - memberRegistered args:",
|
499
|
+
memberRegistered.args
|
500
|
+
);
|
354
501
|
const decodedData: MembershipRegisteredEvent = {
|
355
502
|
idCommitment: memberRegistered.args.idCommitment,
|
356
|
-
|
503
|
+
membershipRateLimit: memberRegistered.args.membershipRateLimit,
|
357
504
|
index: memberRegistered.args.index
|
358
505
|
};
|
506
|
+
console.log("registerWithIdentity - decodedData:", decodedData);
|
507
|
+
console.log(
|
508
|
+
"registerWithIdentity - index:",
|
509
|
+
decodedData.index.toString()
|
510
|
+
);
|
511
|
+
console.log(
|
512
|
+
"registerWithIdentity - membershipRateLimit:",
|
513
|
+
decodedData.membershipRateLimit.toString()
|
514
|
+
);
|
359
515
|
|
360
516
|
log.info(
|
361
517
|
`Successfully registered membership with index ${decodedData.index} ` +
|
362
|
-
`and rate limit ${decodedData.
|
518
|
+
`and rate limit ${decodedData.membershipRateLimit}`
|
363
519
|
);
|
364
520
|
|
521
|
+
console.log("registerWithIdentity - getting network information");
|
365
522
|
const network = await this.contract.provider.getNetwork();
|
523
|
+
console.log("registerWithIdentity - network:", network);
|
524
|
+
console.log("registerWithIdentity - chainId:", network.chainId);
|
525
|
+
|
366
526
|
const address = this.contract.address;
|
527
|
+
console.log("registerWithIdentity - contract address:", address);
|
528
|
+
|
367
529
|
const membershipId = decodedData.index.toNumber();
|
530
|
+
console.log("registerWithIdentity - membershipId:", membershipId);
|
368
531
|
|
369
|
-
|
532
|
+
const result = {
|
370
533
|
identity,
|
371
534
|
membership: {
|
372
535
|
address,
|
@@ -374,9 +537,41 @@ export class RLNContract {
|
|
374
537
|
chainId: network.chainId
|
375
538
|
}
|
376
539
|
};
|
540
|
+
console.log("registerWithIdentity - returning result:", result);
|
541
|
+
|
542
|
+
return result;
|
377
543
|
} catch (error) {
|
378
|
-
log
|
379
|
-
|
544
|
+
console.log("registerWithIdentity - ERROR:", error);
|
545
|
+
|
546
|
+
// Improved error handling to decode contract errors
|
547
|
+
if (error instanceof Error) {
|
548
|
+
const errorMessage = error.message;
|
549
|
+
console.log("registerWithIdentity - error message:", errorMessage);
|
550
|
+
console.log("registerWithIdentity - error stack:", error.stack);
|
551
|
+
|
552
|
+
// Try to extract more specific error information
|
553
|
+
if (errorMessage.includes("CannotExceedMaxTotalRateLimit")) {
|
554
|
+
console.error(
|
555
|
+
"Registration failed: Cannot exceed maximum total rate limit"
|
556
|
+
);
|
557
|
+
} else if (errorMessage.includes("InvalidIdCommitment")) {
|
558
|
+
console.error("Registration failed: Invalid ID commitment");
|
559
|
+
} else if (errorMessage.includes("InvalidMembershipRateLimit")) {
|
560
|
+
console.error("Registration failed: Invalid membership rate limit");
|
561
|
+
} else if (errorMessage.includes("execution reverted")) {
|
562
|
+
// Generic revert
|
563
|
+
console.error(
|
564
|
+
"Contract execution reverted. Check contract requirements."
|
565
|
+
);
|
566
|
+
} else {
|
567
|
+
console.error(`Error in registerWithIdentity: ${errorMessage}`);
|
568
|
+
}
|
569
|
+
} else {
|
570
|
+
console.error("Unknown error in registerWithIdentity");
|
571
|
+
}
|
572
|
+
|
573
|
+
// Re-throw the error to allow callers to handle it
|
574
|
+
throw error;
|
380
575
|
}
|
381
576
|
}
|
382
577
|
|
@@ -454,13 +649,13 @@ export class RLNContract {
|
|
454
649
|
|
455
650
|
const decodedData: MembershipRegisteredEvent = {
|
456
651
|
idCommitment: memberRegistered.args.idCommitment,
|
457
|
-
|
652
|
+
membershipRateLimit: memberRegistered.args.membershipRateLimit,
|
458
653
|
index: memberRegistered.args.index
|
459
654
|
};
|
460
655
|
|
461
656
|
log.info(
|
462
657
|
`Successfully registered membership with permit. Index: ${decodedData.index}, ` +
|
463
|
-
`Rate limit: ${decodedData.
|
658
|
+
`Rate limit: ${decodedData.membershipRateLimit}, Erased ${idCommitmentsToErase.length} commitments`
|
464
659
|
);
|
465
660
|
|
466
661
|
const network = await this.contract.provider.getNetwork();
|
@@ -531,18 +726,20 @@ export class RLNContract {
|
|
531
726
|
|
532
727
|
public async extendMembership(
|
533
728
|
idCommitment: string
|
534
|
-
): Promise<ethers.
|
535
|
-
|
729
|
+
): Promise<ethers.ContractReceipt> {
|
730
|
+
const tx = await this.contract.extendMemberships([idCommitment]);
|
731
|
+
return await tx.wait();
|
536
732
|
}
|
537
733
|
|
538
734
|
public async eraseMembership(
|
539
735
|
idCommitment: string,
|
540
736
|
eraseFromMembershipSet: boolean = true
|
541
|
-
): Promise<ethers.
|
542
|
-
|
737
|
+
): Promise<ethers.ContractReceipt> {
|
738
|
+
const tx = await this.contract.eraseMemberships(
|
543
739
|
[idCommitment],
|
544
740
|
eraseFromMembershipSet
|
545
741
|
);
|
742
|
+
return await tx.wait();
|
546
743
|
}
|
547
744
|
|
548
745
|
public async registerMembership(
|
@@ -557,7 +754,10 @@ export class RLNContract {
|
|
557
754
|
`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
|
558
755
|
);
|
559
756
|
}
|
560
|
-
|
757
|
+
console.log("registering membership", idCommitment, rateLimit);
|
758
|
+
const txn = this.contract.register(idCommitment, rateLimit, []);
|
759
|
+
console.log("txn", txn);
|
760
|
+
return txn;
|
561
761
|
}
|
562
762
|
|
563
763
|
private async getMemberIndex(
|
package/src/identity.ts
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
import { arrayify } from "@ethersproject/bytes";
|
2
|
-
import { keccak256 } from "@ethersproject/keccak256";
|
3
|
-
import { Poseidon } from "@iden3/js-crypto";
|
4
|
-
import { streamXOR } from "@stablelib/chacha";
|
5
|
-
|
6
1
|
import { buildBigIntFromUint8Array } from "./utils/index.js";
|
7
2
|
|
8
3
|
export class IdentityCredential {
|
@@ -33,41 +28,4 @@ export class IdentityCredential {
|
|
33
28
|
idCommitmentBigInt
|
34
29
|
);
|
35
30
|
}
|
36
|
-
|
37
|
-
public static generateSeeded(signature: Uint8Array): IdentityCredential {
|
38
|
-
// Generate deterministic seed from signature
|
39
|
-
const seed = arrayify(keccak256(signature));
|
40
|
-
|
41
|
-
// Use ChaCha for deterministic randomness (as in Rust code)
|
42
|
-
const nonce = new Uint8Array(12);
|
43
|
-
const idSecretHash = new Uint8Array(32);
|
44
|
-
streamXOR(seed, nonce, idSecretHash, idSecretHash);
|
45
|
-
|
46
|
-
// Convert to bigint for Poseidon
|
47
|
-
const secretBigInt = BigInt(
|
48
|
-
"0x" + Buffer.from(idSecretHash).toString("hex")
|
49
|
-
);
|
50
|
-
|
51
|
-
// Generate commitment using Poseidon
|
52
|
-
const idCommitmentBigInt = Poseidon.hash([secretBigInt]);
|
53
|
-
|
54
|
-
// Convert commitment back to Uint8Array
|
55
|
-
const idCommitment = arrayify(
|
56
|
-
"0x" + idCommitmentBigInt.toString(16).padStart(64, "0")
|
57
|
-
);
|
58
|
-
|
59
|
-
// Generate deterministic trapdoor and nullifier from the secret hash
|
60
|
-
const idTrapdoor = new Uint8Array(32);
|
61
|
-
const idNullifier = new Uint8Array(32);
|
62
|
-
streamXOR(idSecretHash, nonce, idTrapdoor, idTrapdoor);
|
63
|
-
streamXOR(idTrapdoor, nonce, idNullifier, idNullifier);
|
64
|
-
|
65
|
-
return new IdentityCredential(
|
66
|
-
idTrapdoor,
|
67
|
-
idNullifier,
|
68
|
-
idSecretHash,
|
69
|
-
idCommitment,
|
70
|
-
idCommitmentBigInt
|
71
|
-
);
|
72
|
-
}
|
73
31
|
}
|
package/src/index.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { RLNDecoder, RLNEncoder } from "./codec.js";
|
2
|
-
import {
|
2
|
+
import { RLN_ABI } from "./contract/abi.js";
|
3
3
|
import { RLNContract, SEPOLIA_CONTRACT } from "./contract/index.js";
|
4
4
|
import { createRLN } from "./create.js";
|
5
5
|
import { IdentityCredential } from "./identity.js";
|
@@ -21,5 +21,5 @@ export {
|
|
21
21
|
RLNContract,
|
22
22
|
SEPOLIA_CONTRACT,
|
23
23
|
extractMetaMaskSigner,
|
24
|
-
|
24
|
+
RLN_ABI
|
25
25
|
};
|
package/src/rln.ts
CHANGED
@@ -15,6 +15,7 @@ import {
|
|
15
15
|
type RLNDecoder,
|
16
16
|
type RLNEncoder
|
17
17
|
} from "./codec.js";
|
18
|
+
import { DEFAULT_RATE_LIMIT } from "./contract/constants.js";
|
18
19
|
import { RLNContract, SEPOLIA_CONTRACT } from "./contract/index.js";
|
19
20
|
import { IdentityCredential } from "./identity.js";
|
20
21
|
import { Keystore } from "./keystore/index.js";
|
@@ -32,15 +33,46 @@ import { Zerokit } from "./zerokit.js";
|
|
32
33
|
const log = new Logger("waku:rln");
|
33
34
|
|
34
35
|
async function loadWitnessCalculator(): Promise<WitnessCalculator> {
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
try {
|
37
|
+
const url = new URL("./resources/rln.wasm", import.meta.url);
|
38
|
+
const response = await fetch(url);
|
39
|
+
|
40
|
+
if (!response.ok) {
|
41
|
+
throw new Error(
|
42
|
+
`Failed to fetch witness calculator: ${response.status} ${response.statusText}`
|
43
|
+
);
|
44
|
+
}
|
45
|
+
|
46
|
+
return await wc.builder(
|
47
|
+
new Uint8Array(await response.arrayBuffer()),
|
48
|
+
false
|
49
|
+
);
|
50
|
+
} catch (error) {
|
51
|
+
log.error("Error loading witness calculator:", error);
|
52
|
+
throw new Error(
|
53
|
+
`Failed to load witness calculator: ${error instanceof Error ? error.message : String(error)}`
|
54
|
+
);
|
55
|
+
}
|
38
56
|
}
|
39
57
|
|
40
58
|
async function loadZkey(): Promise<Uint8Array> {
|
41
|
-
|
42
|
-
|
43
|
-
|
59
|
+
try {
|
60
|
+
const url = new URL("./resources/rln_final.zkey", import.meta.url);
|
61
|
+
const response = await fetch(url);
|
62
|
+
|
63
|
+
if (!response.ok) {
|
64
|
+
throw new Error(
|
65
|
+
`Failed to fetch zkey: ${response.status} ${response.statusText}`
|
66
|
+
);
|
67
|
+
}
|
68
|
+
|
69
|
+
return new Uint8Array(await response.arrayBuffer());
|
70
|
+
} catch (error) {
|
71
|
+
log.error("Error loading zkey:", error);
|
72
|
+
throw new Error(
|
73
|
+
`Failed to load zkey: ${error instanceof Error ? error.message : String(error)}`
|
74
|
+
);
|
75
|
+
}
|
44
76
|
}
|
45
77
|
|
46
78
|
/**
|
@@ -61,7 +93,7 @@ export async function create(): Promise<RLNInstance> {
|
|
61
93
|
|
62
94
|
const DEPTH = 20;
|
63
95
|
const zkRLN = zerokitRLN.newRLN(DEPTH, zkey, vkey);
|
64
|
-
const zerokit = new Zerokit(zkRLN, witnessCalculator);
|
96
|
+
const zerokit = new Zerokit(zkRLN, witnessCalculator, DEFAULT_RATE_LIMIT);
|
65
97
|
|
66
98
|
return new RLNInstance(zerokit);
|
67
99
|
} catch (error) {
|
@@ -142,7 +174,7 @@ export class RLNInstance {
|
|
142
174
|
this._contract = await RLNContract.init(this, {
|
143
175
|
address: address!,
|
144
176
|
signer: signer!,
|
145
|
-
rateLimit: options.rateLimit
|
177
|
+
rateLimit: options.rateLimit ?? this.zerokit.getRateLimit
|
146
178
|
});
|
147
179
|
this.started = true;
|
148
180
|
} finally {
|
@@ -214,15 +246,17 @@ export class RLNInstance {
|
|
214
246
|
throw Error("RLN Contract is not initialized.");
|
215
247
|
}
|
216
248
|
|
217
|
-
let identity
|
218
|
-
"identity" in options ? options.identity : undefined;
|
249
|
+
let identity = "identity" in options && options.identity;
|
219
250
|
|
220
251
|
if ("signature" in options) {
|
221
|
-
identity =
|
222
|
-
|
252
|
+
identity = this.zerokit.generateSeededIdentityCredential(
|
253
|
+
options.signature
|
223
254
|
);
|
224
255
|
}
|
225
256
|
|
257
|
+
// eslint-disable-next-line no-console
|
258
|
+
console.log("registering membership", identity);
|
259
|
+
|
226
260
|
if (!identity) {
|
227
261
|
throw Error("Missing signature or identity to register membership.");
|
228
262
|
}
|
@@ -272,7 +306,7 @@ export class RLNInstance {
|
|
272
306
|
}
|
273
307
|
|
274
308
|
const registryAddress = credentials.membership.address;
|
275
|
-
const currentRegistryAddress = this._contract.
|
309
|
+
const currentRegistryAddress = this._contract.address;
|
276
310
|
if (registryAddress !== currentRegistryAddress) {
|
277
311
|
throw Error(
|
278
312
|
`Failed to verify chain coordinates: credentials contract address=${registryAddress} is not equal to registryContract address=${currentRegistryAddress}`
|
@@ -280,7 +314,7 @@ export class RLNInstance {
|
|
280
314
|
}
|
281
315
|
|
282
316
|
const chainId = credentials.membership.chainId;
|
283
|
-
const network = await this._contract.
|
317
|
+
const network = await this._contract.provider.getNetwork();
|
284
318
|
const currentChainId = network.chainId;
|
285
319
|
if (chainId !== currentChainId) {
|
286
320
|
throw Error(
|