@waku/rln 0.1.6-27c1236.0 → 0.1.6-2ce706d.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/packages/rln/dist/contract/rln_base_contract.js +10 -12
- package/bundle/packages/rln/dist/credentials_manager.js +13 -16
- package/bundle/packages/rln/dist/identity.js +37 -7
- package/bundle/packages/rln/dist/keystore/keystore.js +7 -11
- package/bundle/packages/rln/dist/utils/bytes.js +14 -10
- package/dist/.tsbuildinfo +1 -1
- package/dist/contract/rln_base_contract.d.ts +0 -5
- package/dist/contract/rln_base_contract.js +10 -12
- package/dist/contract/rln_base_contract.js.map +1 -1
- package/dist/credentials_manager.js +13 -16
- package/dist/credentials_manager.js.map +1 -1
- package/dist/identity.d.ts +11 -2
- package/dist/identity.js +23 -6
- package/dist/identity.js.map +1 -1
- package/dist/keystore/keystore.js +7 -11
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/utils/bytes.d.ts +2 -1
- package/dist/utils/bytes.js +13 -9
- package/dist/utils/bytes.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/contract/rln_base_contract.ts +12 -27
- package/src/credentials_manager.ts +20 -27
- package/src/identity.ts +32 -6
- package/src/keystore/keystore.ts +13 -24
- package/src/utils/bytes.ts +21 -19
- package/src/utils/index.ts +1 -1
- package/dist/contract/test-utils.d.ts +0 -39
- package/dist/contract/test-utils.js +0 -118
- package/dist/contract/test-utils.js.map +0 -1
- package/src/contract/test-utils.ts +0 -179
@@ -13,10 +13,7 @@ import type {
|
|
13
13
|
} from "./keystore/index.js";
|
14
14
|
import { KeystoreEntity, Password } from "./keystore/types.js";
|
15
15
|
import { RegisterMembershipOptions, StartRLNOptions } from "./types.js";
|
16
|
-
import {
|
17
|
-
buildBigIntFromUint8ArrayLE,
|
18
|
-
extractMetaMaskSigner
|
19
|
-
} from "./utils/index.js";
|
16
|
+
import { extractMetaMaskSigner, switchEndianness } from "./utils/index.js";
|
20
17
|
import { Zerokit } from "./zerokit.js";
|
21
18
|
|
22
19
|
const log = new Logger("waku:credentials");
|
@@ -261,35 +258,31 @@ export class RLNCredentialsManager {
|
|
261
258
|
|
262
259
|
// Generate deterministic values using HMAC-SHA256
|
263
260
|
// We use different context strings for each component to ensure they're different
|
264
|
-
const
|
265
|
-
const
|
266
|
-
|
267
|
-
|
268
|
-
|
261
|
+
const idTrapdoorBE = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
|
262
|
+
const idNullifierBE = hmac(
|
263
|
+
sha256,
|
264
|
+
seedBytes,
|
265
|
+
encoder.encode("IDNullifier")
|
266
|
+
);
|
269
267
|
|
270
|
-
const
|
268
|
+
const combinedBytes = new Uint8Array([...idTrapdoorBE, ...idNullifierBE]);
|
269
|
+
const idSecretHashBE = sha256(combinedBytes);
|
271
270
|
|
272
|
-
|
273
|
-
if (!this.contract) {
|
274
|
-
throw Error("RLN contract is not initialized");
|
275
|
-
}
|
271
|
+
const idCommitmentBE = sha256(idSecretHashBE);
|
276
272
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
idCommitmentBigInt = idCommitmentBigInt % idCommitmentBigIntLimit;
|
284
|
-
}
|
273
|
+
// All hashing functions return big-endian bytes
|
274
|
+
// We need to switch to little-endian for the identity credential
|
275
|
+
const idTrapdoorLE = switchEndianness(idTrapdoorBE);
|
276
|
+
const idNullifierLE = switchEndianness(idNullifierBE);
|
277
|
+
const idSecretHashLE = switchEndianness(idSecretHashBE);
|
278
|
+
const idCommitmentLE = switchEndianness(idCommitmentBE);
|
285
279
|
|
286
280
|
log.info("Successfully generated identity credential");
|
287
281
|
return new IdentityCredential(
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
idCommitmentBigInt
|
282
|
+
idTrapdoorLE,
|
283
|
+
idNullifierLE,
|
284
|
+
idSecretHashLE,
|
285
|
+
idCommitmentLE
|
293
286
|
);
|
294
287
|
}
|
295
288
|
}
|
package/src/identity.ts
CHANGED
@@ -1,12 +1,19 @@
|
|
1
|
-
import {
|
1
|
+
import { Logger } from "@waku/utils";
|
2
|
+
|
3
|
+
import { DEFAULT_Q } from "./contract/constants.js";
|
4
|
+
import { buildBigIntFromUint8ArrayBE } from "./utils/bytes.js";
|
5
|
+
|
6
|
+
const log = new Logger("waku:rln:identity");
|
2
7
|
|
3
8
|
export class IdentityCredential {
|
9
|
+
/**
|
10
|
+
* All variables are in little-endian format
|
11
|
+
*/
|
4
12
|
public constructor(
|
5
13
|
public readonly IDTrapdoor: Uint8Array,
|
6
14
|
public readonly IDNullifier: Uint8Array,
|
7
15
|
public readonly IDSecretHash: Uint8Array,
|
8
|
-
public readonly IDCommitment: Uint8Array
|
9
|
-
public readonly IDCommitmentBigInt: bigint
|
16
|
+
public readonly IDCommitment: Uint8Array
|
10
17
|
) {}
|
11
18
|
|
12
19
|
public static fromBytes(memKeys: Uint8Array): IdentityCredential {
|
@@ -18,14 +25,33 @@ export class IdentityCredential {
|
|
18
25
|
const idNullifier = memKeys.subarray(32, 64);
|
19
26
|
const idSecretHash = memKeys.subarray(64, 96);
|
20
27
|
const idCommitment = memKeys.subarray(96, 128);
|
21
|
-
const idCommitmentBigInt = buildBigIntFromUint8ArrayLE(idCommitment);
|
22
28
|
|
23
29
|
return new IdentityCredential(
|
24
30
|
idTrapdoor,
|
25
31
|
idNullifier,
|
26
32
|
idSecretHash,
|
27
|
-
idCommitment
|
28
|
-
idCommitmentBigInt
|
33
|
+
idCommitment
|
29
34
|
);
|
30
35
|
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Converts an ID commitment from bytes to a BigInt, normalizing it against a limit if needed
|
39
|
+
* @param bytes The ID commitment bytes to convert
|
40
|
+
* @param limit Optional limit to normalize against (Q value)
|
41
|
+
* @returns The ID commitment as a BigInt
|
42
|
+
*/
|
43
|
+
public static getIdCommitmentBigInt(
|
44
|
+
bytes: Uint8Array,
|
45
|
+
limit: bigint = DEFAULT_Q
|
46
|
+
): bigint {
|
47
|
+
let idCommitmentBigIntBE = buildBigIntFromUint8ArrayBE(bytes);
|
48
|
+
|
49
|
+
if (limit && idCommitmentBigIntBE >= limit) {
|
50
|
+
log.warn(
|
51
|
+
`ID commitment is greater than Q, reducing it by Q: ${idCommitmentBigIntBE} % ${limit}`
|
52
|
+
);
|
53
|
+
idCommitmentBigIntBE = idCommitmentBigIntBE % limit;
|
54
|
+
}
|
55
|
+
return idCommitmentBigIntBE;
|
56
|
+
}
|
31
57
|
}
|
package/src/keystore/keystore.ts
CHANGED
@@ -14,8 +14,6 @@ import {
|
|
14
14
|
import _ from "lodash";
|
15
15
|
import { v4 as uuidV4 } from "uuid";
|
16
16
|
|
17
|
-
import { buildBigIntFromUint8ArrayLE } from "../utils/bytes.js";
|
18
|
-
|
19
17
|
import { decryptEipKeystore, keccak256Checksum } from "./cipher.js";
|
20
18
|
import { isCredentialValid, isKeystoreValid } from "./schema_validator.js";
|
21
19
|
import type {
|
@@ -246,38 +244,29 @@ export class Keystore {
|
|
246
244
|
private static fromBytesToIdentity(
|
247
245
|
bytes: Uint8Array
|
248
246
|
): undefined | KeystoreEntity {
|
249
|
-
function fromLittleEndian(bytes: Uint8Array): Uint8Array {
|
250
|
-
return new Uint8Array(bytes).reverse();
|
251
|
-
}
|
252
247
|
try {
|
253
248
|
const str = bytesToUtf8(bytes);
|
254
249
|
const obj = JSON.parse(str);
|
255
250
|
|
256
|
-
// Use little-endian bytes directly for BigInt conversion (matches storage and contract expectation)
|
257
251
|
const idCommitmentLE = Keystore.fromArraylikeToBytes(
|
258
252
|
_.get(obj, "identityCredential.idCommitment", [])
|
259
253
|
);
|
254
|
+
const idTrapdoorLE = Keystore.fromArraylikeToBytes(
|
255
|
+
_.get(obj, "identityCredential.idTrapdoor", [])
|
256
|
+
);
|
257
|
+
const idNullifierLE = Keystore.fromArraylikeToBytes(
|
258
|
+
_.get(obj, "identityCredential.idNullifier", [])
|
259
|
+
);
|
260
|
+
const idSecretHashLE = Keystore.fromArraylikeToBytes(
|
261
|
+
_.get(obj, "identityCredential.idSecretHash", [])
|
262
|
+
);
|
260
263
|
|
261
264
|
return {
|
262
265
|
identity: {
|
263
|
-
IDCommitment:
|
264
|
-
IDTrapdoor:
|
265
|
-
|
266
|
-
|
267
|
-
)
|
268
|
-
),
|
269
|
-
IDNullifier: fromLittleEndian(
|
270
|
-
Keystore.fromArraylikeToBytes(
|
271
|
-
_.get(obj, "identityCredential.idNullifier", [])
|
272
|
-
)
|
273
|
-
),
|
274
|
-
// Do NOT reverse for BigInt conversion; use little-endian as stored
|
275
|
-
IDCommitmentBigInt: buildBigIntFromUint8ArrayLE(idCommitmentLE),
|
276
|
-
IDSecretHash: fromLittleEndian(
|
277
|
-
Keystore.fromArraylikeToBytes(
|
278
|
-
_.get(obj, "identityCredential.idSecretHash", [])
|
279
|
-
)
|
280
|
-
)
|
266
|
+
IDCommitment: idCommitmentLE,
|
267
|
+
IDTrapdoor: idTrapdoorLE,
|
268
|
+
IDNullifier: idNullifierLE,
|
269
|
+
IDSecretHash: idSecretHashLE
|
281
270
|
},
|
282
271
|
membership: {
|
283
272
|
treeIndex: _.get(obj, "treeIndex"),
|
package/src/utils/bytes.ts
CHANGED
@@ -17,18 +17,13 @@ export function concatenate(...input: Uint8Array[]): Uint8Array {
|
|
17
17
|
return result;
|
18
18
|
}
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
min: number
|
28
|
-
): void {
|
29
|
-
if (value > max || value < min)
|
30
|
-
throw new RangeError('"value" argument is out of bounds');
|
31
|
-
if (offset + ext > buf.length) throw new RangeError("Index out of range");
|
20
|
+
export function switchEndianness(bytes: Uint8Array): Uint8Array {
|
21
|
+
return new Uint8Array(bytes.reverse());
|
22
|
+
}
|
23
|
+
|
24
|
+
export function buildBigIntFromUint8ArrayBE(bytes: Uint8Array): bigint {
|
25
|
+
// Interpret bytes as big-endian
|
26
|
+
return bytes.reduce((acc, byte) => (acc << 8n) + BigInt(byte), 0n);
|
32
27
|
}
|
33
28
|
|
34
29
|
export function writeUIntLE(
|
@@ -56,13 +51,6 @@ export function writeUIntLE(
|
|
56
51
|
return buf;
|
57
52
|
}
|
58
53
|
|
59
|
-
export function buildBigIntFromUint8ArrayLE(bytes: Uint8Array): bigint {
|
60
|
-
return bytes.reduce(
|
61
|
-
(acc, byte, i) => acc + BigInt(byte) * (1n << (8n * BigInt(i))),
|
62
|
-
0n
|
63
|
-
);
|
64
|
-
}
|
65
|
-
|
66
54
|
/**
|
67
55
|
* Fills with zeros to set length
|
68
56
|
* @param array little endian Uint8Array
|
@@ -76,3 +64,17 @@ export function zeroPadLE(array: Uint8Array, length: number): Uint8Array {
|
|
76
64
|
}
|
77
65
|
return result;
|
78
66
|
}
|
67
|
+
|
68
|
+
// Adapted from https://github.com/feross/buffer
|
69
|
+
function checkInt(
|
70
|
+
buf: Uint8Array,
|
71
|
+
value: number,
|
72
|
+
offset: number,
|
73
|
+
ext: number,
|
74
|
+
max: number,
|
75
|
+
min: number
|
76
|
+
): void {
|
77
|
+
if (value > max || value < min)
|
78
|
+
throw new RangeError('"value" argument is out of bounds');
|
79
|
+
if (offset + ext > buf.length) throw new RangeError("Index out of range");
|
80
|
+
}
|
package/src/utils/index.ts
CHANGED
@@ -1,39 +0,0 @@
|
|
1
|
-
import * as ethers from "ethers";
|
2
|
-
import sinon from "sinon";
|
3
|
-
import type { IdentityCredential } from "../identity.js";
|
4
|
-
export declare const mockRateLimits: {
|
5
|
-
minRate: number;
|
6
|
-
maxRate: number;
|
7
|
-
maxTotalRate: number;
|
8
|
-
currentTotalRate: number;
|
9
|
-
};
|
10
|
-
type MockProvider = {
|
11
|
-
getLogs: () => never[];
|
12
|
-
getBlockNumber: () => Promise<number>;
|
13
|
-
getNetwork: () => Promise<{
|
14
|
-
chainId: number;
|
15
|
-
}>;
|
16
|
-
};
|
17
|
-
type MockFilters = {
|
18
|
-
MembershipRegistered: () => {
|
19
|
-
address: string;
|
20
|
-
};
|
21
|
-
MembershipErased: () => {
|
22
|
-
address: string;
|
23
|
-
};
|
24
|
-
MembershipExpired: () => {
|
25
|
-
address: string;
|
26
|
-
};
|
27
|
-
};
|
28
|
-
export declare function createMockProvider(): MockProvider;
|
29
|
-
export declare function createMockFilters(): MockFilters;
|
30
|
-
type ContractOverrides = Partial<{
|
31
|
-
filters: Record<string, unknown>;
|
32
|
-
[key: string]: unknown;
|
33
|
-
}>;
|
34
|
-
export declare function createMockRegistryContract(overrides?: ContractOverrides): ethers.Contract;
|
35
|
-
export declare function mockRLNRegisteredEvent(idCommitment?: string): ethers.Event;
|
36
|
-
export declare function formatIdCommitment(idCommitmentBigInt: bigint): string;
|
37
|
-
export declare function createRegisterStub(identity: IdentityCredential): sinon.SinonStub;
|
38
|
-
export declare function verifyRegistration(decryptedCredentials: any, identity: IdentityCredential, registerStub: sinon.SinonStub, insertMemberSpy: sinon.SinonStub): void;
|
39
|
-
export {};
|
@@ -1,118 +0,0 @@
|
|
1
|
-
import { hexToBytes } from "@waku/utils/bytes";
|
2
|
-
import { expect } from "chai";
|
3
|
-
import * as ethers from "ethers";
|
4
|
-
import sinon from "sinon";
|
5
|
-
import { DEFAULT_RATE_LIMIT, LINEA_CONTRACT } from "./constants.js";
|
6
|
-
export const mockRateLimits = {
|
7
|
-
minRate: 20,
|
8
|
-
maxRate: 600,
|
9
|
-
maxTotalRate: 1200,
|
10
|
-
currentTotalRate: 500
|
11
|
-
};
|
12
|
-
export function createMockProvider() {
|
13
|
-
return {
|
14
|
-
getLogs: () => [],
|
15
|
-
getBlockNumber: () => Promise.resolve(1000),
|
16
|
-
getNetwork: () => Promise.resolve({ chainId: 11155111 })
|
17
|
-
};
|
18
|
-
}
|
19
|
-
export function createMockFilters() {
|
20
|
-
return {
|
21
|
-
MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
|
22
|
-
MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
|
23
|
-
MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
|
24
|
-
};
|
25
|
-
}
|
26
|
-
export function createMockRegistryContract(overrides = {}) {
|
27
|
-
const filters = {
|
28
|
-
MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
|
29
|
-
MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
|
30
|
-
MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
|
31
|
-
};
|
32
|
-
const baseContract = {
|
33
|
-
minMembershipRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.minRate)),
|
34
|
-
maxMembershipRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxRate)),
|
35
|
-
maxTotalRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxTotalRate)),
|
36
|
-
currentTotalRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.currentTotalRate)),
|
37
|
-
queryFilter: () => [],
|
38
|
-
provider: createMockProvider(),
|
39
|
-
filters,
|
40
|
-
on: () => ({}),
|
41
|
-
removeAllListeners: () => ({}),
|
42
|
-
register: () => ({
|
43
|
-
wait: () => Promise.resolve({
|
44
|
-
events: [mockRLNRegisteredEvent()]
|
45
|
-
})
|
46
|
-
}),
|
47
|
-
estimateGas: {
|
48
|
-
register: () => Promise.resolve(ethers.BigNumber.from(100000))
|
49
|
-
},
|
50
|
-
functions: {
|
51
|
-
register: () => Promise.resolve()
|
52
|
-
},
|
53
|
-
getMemberIndex: () => Promise.resolve(null),
|
54
|
-
interface: {
|
55
|
-
getEvent: (eventName) => ({
|
56
|
-
name: eventName,
|
57
|
-
format: () => { }
|
58
|
-
})
|
59
|
-
},
|
60
|
-
address: LINEA_CONTRACT.address
|
61
|
-
};
|
62
|
-
// Merge overrides while preserving filters
|
63
|
-
const merged = {
|
64
|
-
...baseContract,
|
65
|
-
...overrides,
|
66
|
-
filters: { ...filters, ...(overrides.filters || {}) }
|
67
|
-
};
|
68
|
-
return merged;
|
69
|
-
}
|
70
|
-
export function mockRLNRegisteredEvent(idCommitment) {
|
71
|
-
return {
|
72
|
-
args: {
|
73
|
-
idCommitment: idCommitment ||
|
74
|
-
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
75
|
-
membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
|
76
|
-
index: ethers.BigNumber.from(1)
|
77
|
-
},
|
78
|
-
event: "MembershipRegistered"
|
79
|
-
};
|
80
|
-
}
|
81
|
-
export function formatIdCommitment(idCommitmentBigInt) {
|
82
|
-
return "0x" + idCommitmentBigInt.toString(16).padStart(64, "0");
|
83
|
-
}
|
84
|
-
export function createRegisterStub(identity) {
|
85
|
-
return sinon.stub().callsFake(() => ({
|
86
|
-
wait: () => Promise.resolve({
|
87
|
-
events: [
|
88
|
-
{
|
89
|
-
event: "MembershipRegistered",
|
90
|
-
args: {
|
91
|
-
idCommitment: formatIdCommitment(identity.IDCommitmentBigInt),
|
92
|
-
membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
|
93
|
-
index: ethers.BigNumber.from(1)
|
94
|
-
}
|
95
|
-
}
|
96
|
-
]
|
97
|
-
})
|
98
|
-
}));
|
99
|
-
}
|
100
|
-
export function verifyRegistration(decryptedCredentials, identity, registerStub, insertMemberSpy) {
|
101
|
-
if (!decryptedCredentials) {
|
102
|
-
throw new Error("Decrypted credentials should not be undefined");
|
103
|
-
}
|
104
|
-
// Verify registration call
|
105
|
-
expect(registerStub.calledWith(sinon.match.same(identity.IDCommitmentBigInt), sinon.match.same(DEFAULT_RATE_LIMIT), sinon.match.array, sinon.match.object)).to.be.true;
|
106
|
-
// Verify credential properties
|
107
|
-
expect(decryptedCredentials).to.have.property("identity");
|
108
|
-
expect(decryptedCredentials).to.have.property("membership");
|
109
|
-
expect(decryptedCredentials.membership).to.include({
|
110
|
-
address: LINEA_CONTRACT.address,
|
111
|
-
treeIndex: 1
|
112
|
-
});
|
113
|
-
// Verify member insertion
|
114
|
-
const expectedIdCommitment = ethers.utils.zeroPad(hexToBytes(formatIdCommitment(identity.IDCommitmentBigInt)), 32);
|
115
|
-
expect(insertMemberSpy.callCount).to.equal(1);
|
116
|
-
expect(insertMemberSpy.getCall(0).args[0]).to.deep.equal(expectedIdCommitment);
|
117
|
-
}
|
118
|
-
//# sourceMappingURL=test-utils.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/contract/test-utils.ts"],"names":[],"mappings":"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"}
|
@@ -1,179 +0,0 @@
|
|
1
|
-
import { hexToBytes } from "@waku/utils/bytes";
|
2
|
-
import { expect } from "chai";
|
3
|
-
import * as ethers from "ethers";
|
4
|
-
import sinon from "sinon";
|
5
|
-
|
6
|
-
import type { IdentityCredential } from "../identity.js";
|
7
|
-
|
8
|
-
import { DEFAULT_RATE_LIMIT, LINEA_CONTRACT } from "./constants.js";
|
9
|
-
|
10
|
-
export const mockRateLimits = {
|
11
|
-
minRate: 20,
|
12
|
-
maxRate: 600,
|
13
|
-
maxTotalRate: 1200,
|
14
|
-
currentTotalRate: 500
|
15
|
-
};
|
16
|
-
|
17
|
-
type MockProvider = {
|
18
|
-
getLogs: () => never[];
|
19
|
-
getBlockNumber: () => Promise<number>;
|
20
|
-
getNetwork: () => Promise<{ chainId: number }>;
|
21
|
-
};
|
22
|
-
|
23
|
-
type MockFilters = {
|
24
|
-
MembershipRegistered: () => { address: string };
|
25
|
-
MembershipErased: () => { address: string };
|
26
|
-
MembershipExpired: () => { address: string };
|
27
|
-
};
|
28
|
-
|
29
|
-
export function createMockProvider(): MockProvider {
|
30
|
-
return {
|
31
|
-
getLogs: () => [],
|
32
|
-
getBlockNumber: () => Promise.resolve(1000),
|
33
|
-
getNetwork: () => Promise.resolve({ chainId: 11155111 })
|
34
|
-
};
|
35
|
-
}
|
36
|
-
|
37
|
-
export function createMockFilters(): MockFilters {
|
38
|
-
return {
|
39
|
-
MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
|
40
|
-
MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
|
41
|
-
MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
|
42
|
-
};
|
43
|
-
}
|
44
|
-
|
45
|
-
type ContractOverrides = Partial<{
|
46
|
-
filters: Record<string, unknown>;
|
47
|
-
[key: string]: unknown;
|
48
|
-
}>;
|
49
|
-
|
50
|
-
export function createMockRegistryContract(
|
51
|
-
overrides: ContractOverrides = {}
|
52
|
-
): ethers.Contract {
|
53
|
-
const filters = {
|
54
|
-
MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
|
55
|
-
MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
|
56
|
-
MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
|
57
|
-
};
|
58
|
-
|
59
|
-
const baseContract = {
|
60
|
-
minMembershipRateLimit: () =>
|
61
|
-
Promise.resolve(ethers.BigNumber.from(mockRateLimits.minRate)),
|
62
|
-
maxMembershipRateLimit: () =>
|
63
|
-
Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxRate)),
|
64
|
-
maxTotalRateLimit: () =>
|
65
|
-
Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxTotalRate)),
|
66
|
-
currentTotalRateLimit: () =>
|
67
|
-
Promise.resolve(ethers.BigNumber.from(mockRateLimits.currentTotalRate)),
|
68
|
-
queryFilter: () => [],
|
69
|
-
provider: createMockProvider(),
|
70
|
-
filters,
|
71
|
-
on: () => ({}),
|
72
|
-
removeAllListeners: () => ({}),
|
73
|
-
register: () => ({
|
74
|
-
wait: () =>
|
75
|
-
Promise.resolve({
|
76
|
-
events: [mockRLNRegisteredEvent()]
|
77
|
-
})
|
78
|
-
}),
|
79
|
-
estimateGas: {
|
80
|
-
register: () => Promise.resolve(ethers.BigNumber.from(100000))
|
81
|
-
},
|
82
|
-
functions: {
|
83
|
-
register: () => Promise.resolve()
|
84
|
-
},
|
85
|
-
getMemberIndex: () => Promise.resolve(null),
|
86
|
-
interface: {
|
87
|
-
getEvent: (eventName: string) => ({
|
88
|
-
name: eventName,
|
89
|
-
format: () => {}
|
90
|
-
})
|
91
|
-
},
|
92
|
-
address: LINEA_CONTRACT.address
|
93
|
-
};
|
94
|
-
|
95
|
-
// Merge overrides while preserving filters
|
96
|
-
const merged = {
|
97
|
-
...baseContract,
|
98
|
-
...overrides,
|
99
|
-
filters: { ...filters, ...(overrides.filters || {}) }
|
100
|
-
};
|
101
|
-
|
102
|
-
return merged as unknown as ethers.Contract;
|
103
|
-
}
|
104
|
-
|
105
|
-
export function mockRLNRegisteredEvent(idCommitment?: string): ethers.Event {
|
106
|
-
return {
|
107
|
-
args: {
|
108
|
-
idCommitment:
|
109
|
-
idCommitment ||
|
110
|
-
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
111
|
-
membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
|
112
|
-
index: ethers.BigNumber.from(1)
|
113
|
-
},
|
114
|
-
event: "MembershipRegistered"
|
115
|
-
} as unknown as ethers.Event;
|
116
|
-
}
|
117
|
-
|
118
|
-
export function formatIdCommitment(idCommitmentBigInt: bigint): string {
|
119
|
-
return "0x" + idCommitmentBigInt.toString(16).padStart(64, "0");
|
120
|
-
}
|
121
|
-
|
122
|
-
export function createRegisterStub(
|
123
|
-
identity: IdentityCredential
|
124
|
-
): sinon.SinonStub {
|
125
|
-
return sinon.stub().callsFake(() => ({
|
126
|
-
wait: () =>
|
127
|
-
Promise.resolve({
|
128
|
-
events: [
|
129
|
-
{
|
130
|
-
event: "MembershipRegistered",
|
131
|
-
args: {
|
132
|
-
idCommitment: formatIdCommitment(identity.IDCommitmentBigInt),
|
133
|
-
membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
|
134
|
-
index: ethers.BigNumber.from(1)
|
135
|
-
}
|
136
|
-
}
|
137
|
-
]
|
138
|
-
})
|
139
|
-
}));
|
140
|
-
}
|
141
|
-
|
142
|
-
export function verifyRegistration(
|
143
|
-
decryptedCredentials: any,
|
144
|
-
identity: IdentityCredential,
|
145
|
-
registerStub: sinon.SinonStub,
|
146
|
-
insertMemberSpy: sinon.SinonStub
|
147
|
-
): void {
|
148
|
-
if (!decryptedCredentials) {
|
149
|
-
throw new Error("Decrypted credentials should not be undefined");
|
150
|
-
}
|
151
|
-
|
152
|
-
// Verify registration call
|
153
|
-
expect(
|
154
|
-
registerStub.calledWith(
|
155
|
-
sinon.match.same(identity.IDCommitmentBigInt),
|
156
|
-
sinon.match.same(DEFAULT_RATE_LIMIT),
|
157
|
-
sinon.match.array,
|
158
|
-
sinon.match.object
|
159
|
-
)
|
160
|
-
).to.be.true;
|
161
|
-
|
162
|
-
// Verify credential properties
|
163
|
-
expect(decryptedCredentials).to.have.property("identity");
|
164
|
-
expect(decryptedCredentials).to.have.property("membership");
|
165
|
-
expect(decryptedCredentials.membership).to.include({
|
166
|
-
address: LINEA_CONTRACT.address,
|
167
|
-
treeIndex: 1
|
168
|
-
});
|
169
|
-
|
170
|
-
// Verify member insertion
|
171
|
-
const expectedIdCommitment = ethers.utils.zeroPad(
|
172
|
-
hexToBytes(formatIdCommitment(identity.IDCommitmentBigInt)),
|
173
|
-
32
|
174
|
-
);
|
175
|
-
expect(insertMemberSpy.callCount).to.equal(1);
|
176
|
-
expect(insertMemberSpy.getCall(0).args[0]).to.deep.equal(
|
177
|
-
expectedIdCommitment
|
178
|
-
);
|
179
|
-
}
|