@waku/rln 0.1.5-1d384f2.0 → 0.1.5-35b50c3.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 +2 -1
- package/bundle/packages/rln/dist/contract/constants.js +1 -0
- package/bundle/packages/rln/dist/contract/rln_base_contract.js +69 -64
- package/dist/.tsbuildinfo +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 +5 -11
- package/dist/contract/rln_base_contract.js +69 -64
- package/dist/contract/rln_base_contract.js.map +1 -1
- package/dist/contract/types.d.ts +5 -0
- package/dist/contract/types.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.js.map +1 -1
- package/dist/keystore/types.d.ts +2 -2
- package/package.json +1 -1
- package/src/contract/index.ts +1 -0
- package/src/contract/rln_base_contract.ts +97 -93
- package/src/contract/types.ts +5 -0
- package/src/index.ts +3 -1
- package/src/keystore/keystore.ts +4 -2
- package/src/keystore/types.ts +2 -2
@@ -1,3 +1,4 @@
|
|
1
|
+
/* eslint-disable no-console */
|
1
2
|
import { Logger } from "@waku/utils";
|
2
3
|
import { ethers } from "ethers";
|
3
4
|
|
@@ -33,15 +34,6 @@ export class RLNBaseContract {
|
|
33
34
|
* Allows injecting a mocked contract for testing purposes.
|
34
35
|
*/
|
35
36
|
public constructor(options: RLNContractInitOptions) {
|
36
|
-
// Initialize members and subscriptions
|
37
|
-
this.fetchMembers()
|
38
|
-
.then(() => {
|
39
|
-
this.subscribeToMembers();
|
40
|
-
})
|
41
|
-
.catch((error) => {
|
42
|
-
log.error("Failed to initialize members", { error });
|
43
|
-
});
|
44
|
-
|
45
37
|
const {
|
46
38
|
address,
|
47
39
|
signer,
|
@@ -49,15 +41,38 @@ export class RLNBaseContract {
|
|
49
41
|
contract
|
50
42
|
} = options;
|
51
43
|
|
52
|
-
|
44
|
+
log.info("Initializing RLNBaseContract", { address, rateLimit });
|
53
45
|
|
54
46
|
this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
|
55
47
|
this.rateLimit = rateLimit;
|
56
48
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
49
|
+
try {
|
50
|
+
log.info("Setting up event filters");
|
51
|
+
// Initialize event filters
|
52
|
+
this._membersFilter = this.contract.filters.MembershipRegistered();
|
53
|
+
this._membershipErasedFilter = this.contract.filters.MembershipErased();
|
54
|
+
this._membersExpiredFilter = this.contract.filters.MembershipExpired();
|
55
|
+
log.info("Event filters initialized successfully");
|
56
|
+
} catch (error) {
|
57
|
+
log.error("Failed to initialize event filters", { error });
|
58
|
+
throw new Error(
|
59
|
+
"Failed to initialize event filters: " + (error as Error).message
|
60
|
+
);
|
61
|
+
}
|
62
|
+
|
63
|
+
// Initialize members and subscriptions
|
64
|
+
this.fetchMembers()
|
65
|
+
.then(() => {
|
66
|
+
this.subscribeToMembers();
|
67
|
+
})
|
68
|
+
.catch((error) => {
|
69
|
+
log.error("Failed to initialize members", { error });
|
70
|
+
});
|
71
|
+
|
72
|
+
// Validate rate limit asynchronously
|
73
|
+
this.validateRateLimit(rateLimit).catch((error) => {
|
74
|
+
log.error("Failed to validate initial rate limit", { error });
|
75
|
+
});
|
61
76
|
}
|
62
77
|
|
63
78
|
/**
|
@@ -134,7 +149,7 @@ export class RLNBaseContract {
|
|
134
149
|
* @param newRateLimit The new rate limit to use
|
135
150
|
*/
|
136
151
|
public async setRateLimit(newRateLimit: number): Promise<void> {
|
137
|
-
this.validateRateLimit(newRateLimit);
|
152
|
+
await this.validateRateLimit(newRateLimit);
|
138
153
|
this.rateLimit = newRateLimit;
|
139
154
|
}
|
140
155
|
|
@@ -324,7 +339,7 @@ export class RLNBaseContract {
|
|
324
339
|
this.contract.on(
|
325
340
|
this.membersFilter,
|
326
341
|
(
|
327
|
-
_idCommitment:
|
342
|
+
_idCommitment: bigint,
|
328
343
|
_membershipRateLimit: ethers.BigNumber,
|
329
344
|
_index: ethers.BigNumber,
|
330
345
|
event: ethers.Event
|
@@ -336,7 +351,7 @@ export class RLNBaseContract {
|
|
336
351
|
this.contract.on(
|
337
352
|
this.membershipErasedFilter,
|
338
353
|
(
|
339
|
-
_idCommitment:
|
354
|
+
_idCommitment: bigint,
|
340
355
|
_membershipRateLimit: ethers.BigNumber,
|
341
356
|
_index: ethers.BigNumber,
|
342
357
|
event: ethers.Event
|
@@ -348,7 +363,7 @@ export class RLNBaseContract {
|
|
348
363
|
this.contract.on(
|
349
364
|
this.membersExpiredFilter,
|
350
365
|
(
|
351
|
-
_idCommitment:
|
366
|
+
_idCommitment: bigint,
|
352
367
|
_membershipRateLimit: ethers.BigNumber,
|
353
368
|
_index: ethers.BigNumber,
|
354
369
|
event: ethers.Event
|
@@ -358,94 +373,87 @@ export class RLNBaseContract {
|
|
358
373
|
);
|
359
374
|
}
|
360
375
|
|
361
|
-
/**
|
362
|
-
* Helper method to get remaining messages in current epoch
|
363
|
-
* @param membershipId The ID of the membership to check
|
364
|
-
* @returns number of remaining messages allowed in current epoch
|
365
|
-
*/
|
366
|
-
public async getRemainingMessages(membershipId: number): Promise<number> {
|
367
|
-
try {
|
368
|
-
const [startTime, , rateLimit] =
|
369
|
-
await this.contract.getMembershipInfo(membershipId);
|
370
|
-
|
371
|
-
// Calculate current epoch
|
372
|
-
const currentTime = Math.floor(Date.now() / 1000);
|
373
|
-
const epochsPassed = Math.floor(
|
374
|
-
(currentTime - startTime) / RATE_LIMIT_PARAMS.EPOCH_LENGTH
|
375
|
-
);
|
376
|
-
const currentEpochStart =
|
377
|
-
startTime + epochsPassed * RATE_LIMIT_PARAMS.EPOCH_LENGTH;
|
378
|
-
|
379
|
-
// Get message count in current epoch using contract's function
|
380
|
-
const messageCount = await this.contract.getMessageCount(
|
381
|
-
membershipId,
|
382
|
-
currentEpochStart
|
383
|
-
);
|
384
|
-
return Math.max(
|
385
|
-
0,
|
386
|
-
ethers.BigNumber.from(rateLimit)
|
387
|
-
.sub(ethers.BigNumber.from(messageCount))
|
388
|
-
.toNumber()
|
389
|
-
);
|
390
|
-
} catch (error) {
|
391
|
-
log.error(
|
392
|
-
`Error getting remaining messages: ${(error as Error).message}`
|
393
|
-
);
|
394
|
-
return 0; // Fail safe: assume no messages remaining on error
|
395
|
-
}
|
396
|
-
}
|
397
|
-
|
398
376
|
public async getMembershipInfo(
|
399
|
-
|
377
|
+
idCommitmentBigInt: bigint
|
400
378
|
): Promise<MembershipInfo | undefined> {
|
401
379
|
try {
|
402
|
-
const
|
403
|
-
await this.contract.
|
380
|
+
const membershipData =
|
381
|
+
await this.contract.memberships(idCommitmentBigInt);
|
404
382
|
const currentBlock = await this.contract.provider.getBlockNumber();
|
383
|
+
console.log("membershipData", membershipData);
|
384
|
+
|
385
|
+
const [
|
386
|
+
depositAmount,
|
387
|
+
activeDuration,
|
388
|
+
gracePeriodStartTimestamp,
|
389
|
+
gracePeriodDuration,
|
390
|
+
rateLimit,
|
391
|
+
index,
|
392
|
+
holder,
|
393
|
+
token
|
394
|
+
] = membershipData;
|
395
|
+
|
396
|
+
const gracePeriodEnd = gracePeriodStartTimestamp.add(gracePeriodDuration);
|
405
397
|
|
406
398
|
let state: MembershipState;
|
407
|
-
if (currentBlock <
|
399
|
+
if (currentBlock < gracePeriodStartTimestamp.toNumber()) {
|
408
400
|
state = MembershipState.Active;
|
409
|
-
} else if (currentBlock <
|
401
|
+
} else if (currentBlock < gracePeriodEnd.toNumber()) {
|
410
402
|
state = MembershipState.GracePeriod;
|
411
403
|
} else {
|
412
404
|
state = MembershipState.Expired;
|
413
405
|
}
|
414
406
|
|
415
|
-
const index = await this.getMemberIndex(idCommitment);
|
416
|
-
if (!index) return undefined;
|
417
|
-
|
418
407
|
return {
|
419
408
|
index,
|
420
|
-
idCommitment,
|
421
|
-
rateLimit: rateLimit
|
422
|
-
startBlock:
|
423
|
-
endBlock:
|
424
|
-
state
|
409
|
+
idCommitment: idCommitmentBigInt.toString(),
|
410
|
+
rateLimit: Number(rateLimit),
|
411
|
+
startBlock: gracePeriodStartTimestamp.toNumber(),
|
412
|
+
endBlock: gracePeriodEnd.toNumber(),
|
413
|
+
state,
|
414
|
+
depositAmount,
|
415
|
+
activeDuration,
|
416
|
+
gracePeriodDuration,
|
417
|
+
holder,
|
418
|
+
token
|
425
419
|
};
|
426
420
|
} catch (error) {
|
421
|
+
console.error("Error in getMembershipInfo:", error);
|
427
422
|
return undefined;
|
428
423
|
}
|
429
424
|
}
|
430
425
|
|
431
426
|
public async extendMembership(
|
432
|
-
|
427
|
+
idCommitmentBigInt: bigint
|
433
428
|
): Promise<ethers.ContractTransaction> {
|
434
|
-
|
429
|
+
const tx = await this.contract.extendMemberships([idCommitmentBigInt]);
|
430
|
+
await tx.wait();
|
431
|
+
return tx;
|
435
432
|
}
|
436
433
|
|
437
434
|
public async eraseMembership(
|
438
|
-
|
435
|
+
idCommitmentBigInt: bigint,
|
439
436
|
eraseFromMembershipSet: boolean = true
|
440
437
|
): Promise<ethers.ContractTransaction> {
|
441
|
-
|
442
|
-
[
|
438
|
+
const tx = await this.contract.eraseMemberships(
|
439
|
+
[idCommitmentBigInt],
|
443
440
|
eraseFromMembershipSet
|
444
441
|
);
|
442
|
+
await tx.wait();
|
443
|
+
return tx;
|
444
|
+
}
|
445
|
+
|
446
|
+
public async withdraw(token: string, from: string): Promise<void> {
|
447
|
+
try {
|
448
|
+
const tx = await this.contract.withdraw(token, from);
|
449
|
+
await tx.wait();
|
450
|
+
} catch (error) {
|
451
|
+
log.error(`Error in withdraw: ${(error as Error).message}`);
|
452
|
+
}
|
445
453
|
}
|
446
454
|
|
447
455
|
public async registerMembership(
|
448
|
-
|
456
|
+
idCommitmentBigInt: bigint,
|
449
457
|
rateLimit: number = DEFAULT_RATE_LIMIT
|
450
458
|
): Promise<ethers.ContractTransaction> {
|
451
459
|
if (
|
@@ -456,16 +464,7 @@ export class RLNBaseContract {
|
|
456
464
|
`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
|
457
465
|
);
|
458
466
|
}
|
459
|
-
return this.contract.register(
|
460
|
-
}
|
461
|
-
|
462
|
-
public async withdraw(token: string, holder: string): Promise<void> {
|
463
|
-
try {
|
464
|
-
const tx = await this.contract.withdraw(token, { from: holder });
|
465
|
-
await tx.wait();
|
466
|
-
} catch (error) {
|
467
|
-
log.error(`Error in withdraw: ${(error as Error).message}`);
|
468
|
-
}
|
467
|
+
return this.contract.register(idCommitmentBigInt, rateLimit, []);
|
469
468
|
}
|
470
469
|
|
471
470
|
public async registerWithIdentity(
|
@@ -478,7 +477,7 @@ export class RLNBaseContract {
|
|
478
477
|
|
479
478
|
// Check if the ID commitment is already registered
|
480
479
|
const existingIndex = await this.getMemberIndex(
|
481
|
-
identity.IDCommitmentBigInt
|
480
|
+
identity.IDCommitmentBigInt
|
482
481
|
);
|
483
482
|
if (existingIndex) {
|
484
483
|
throw new Error(
|
@@ -656,13 +655,18 @@ export class RLNBaseContract {
|
|
656
655
|
* Validates that the rate limit is within the allowed range
|
657
656
|
* @throws Error if the rate limit is outside the allowed range
|
658
657
|
*/
|
659
|
-
private validateRateLimit(rateLimit: number): void {
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
)
|
658
|
+
private async validateRateLimit(rateLimit: number): Promise<void> {
|
659
|
+
const [minRate, maxRate] = await Promise.all([
|
660
|
+
this.contract.minMembershipRateLimit(),
|
661
|
+
this.contract.maxMembershipRateLimit()
|
662
|
+
]);
|
663
|
+
|
664
|
+
const minRateNum = ethers.BigNumber.from(minRate).toNumber();
|
665
|
+
const maxRateNum = ethers.BigNumber.from(maxRate).toNumber();
|
666
|
+
|
667
|
+
if (rateLimit < minRateNum || rateLimit > maxRateNum) {
|
664
668
|
throw new Error(
|
665
|
-
`Rate limit must be between ${
|
669
|
+
`Rate limit must be between ${minRateNum} and ${maxRateNum} messages per epoch`
|
666
670
|
);
|
667
671
|
}
|
668
672
|
}
|
@@ -689,11 +693,11 @@ export class RLNBaseContract {
|
|
689
693
|
}
|
690
694
|
|
691
695
|
private async getMemberIndex(
|
692
|
-
|
696
|
+
idCommitmentBigInt: bigint
|
693
697
|
): Promise<ethers.BigNumber | undefined> {
|
694
698
|
try {
|
695
699
|
const events = await this.contract.queryFilter(
|
696
|
-
this.contract.filters.MembershipRegistered(
|
700
|
+
this.contract.filters.MembershipRegistered(idCommitmentBigInt)
|
697
701
|
);
|
698
702
|
if (events.length === 0) return undefined;
|
699
703
|
|
package/src/contract/types.ts
CHANGED
@@ -38,6 +38,11 @@ export interface MembershipInfo {
|
|
38
38
|
startBlock: number;
|
39
39
|
endBlock: number;
|
40
40
|
state: MembershipState;
|
41
|
+
depositAmount: ethers.BigNumber;
|
42
|
+
activeDuration: number;
|
43
|
+
gracePeriodDuration: number;
|
44
|
+
holder: string;
|
45
|
+
token: string;
|
41
46
|
}
|
42
47
|
|
43
48
|
export enum MembershipState {
|
package/src/index.ts
CHANGED
package/src/keystore/keystore.ts
CHANGED
@@ -21,8 +21,8 @@ import { isCredentialValid, isKeystoreValid } from "./schema_validator.js";
|
|
21
21
|
import type {
|
22
22
|
Keccak256Hash,
|
23
23
|
KeystoreEntity,
|
24
|
+
KeystoreMembershipInfo,
|
24
25
|
MembershipHash,
|
25
|
-
MembershipInfo,
|
26
26
|
Password,
|
27
27
|
Sha256Hash
|
28
28
|
} from "./types.js";
|
@@ -310,7 +310,9 @@ export class Keystore {
|
|
310
310
|
|
311
311
|
// follows nwaku implementation
|
312
312
|
// https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L111
|
313
|
-
private static computeMembershipHash(
|
313
|
+
private static computeMembershipHash(
|
314
|
+
info: KeystoreMembershipInfo
|
315
|
+
): MembershipHash {
|
314
316
|
return bytesToHex(
|
315
317
|
sha256(utf8ToBytes(`${info.chainId}${info.address}${info.treeIndex}`))
|
316
318
|
).toUpperCase();
|
package/src/keystore/types.ts
CHANGED
@@ -7,7 +7,7 @@ export type Password = string | Uint8Array;
|
|
7
7
|
|
8
8
|
// see reference
|
9
9
|
// https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L111
|
10
|
-
export type
|
10
|
+
export type KeystoreMembershipInfo = {
|
11
11
|
chainId: string;
|
12
12
|
address: string;
|
13
13
|
treeIndex: number;
|
@@ -16,7 +16,7 @@ export type MembershipInfo = {
|
|
16
16
|
|
17
17
|
export type KeystoreEntity = {
|
18
18
|
identity: IdentityCredential;
|
19
|
-
membership:
|
19
|
+
membership: KeystoreMembershipInfo;
|
20
20
|
};
|
21
21
|
|
22
22
|
export type DecryptedCredentials = KeystoreEntity;
|