@waku/rln 0.1.6-a8ca168.0 → 0.1.6-ace7ca2.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 +24 -4
- package/bundle/packages/rln/dist/credentials_manager.js +13 -16
- package/bundle/packages/rln/dist/identity.js +5 -8
- package/bundle/packages/rln/dist/keystore/keystore.js +15 -11
- package/bundle/packages/rln/dist/utils/bytes.js +14 -10
- package/dist/.tsbuildinfo +1 -1
- package/dist/contract/rln_base_contract.d.ts +1 -0
- package/dist/contract/rln_base_contract.js +24 -4
- 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 +4 -2
- package/dist/identity.js +5 -6
- package/dist/identity.js.map +1 -1
- package/dist/keystore/keystore.js +15 -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 +32 -11
- package/src/credentials_manager.ts +20 -27
- package/src/identity.ts +5 -7
- package/src/keystore/keystore.ts +28 -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,12 @@
|
|
1
|
-
import { buildBigIntFromUint8ArrayLE } from "./utils/index.js";
|
2
|
-
|
3
1
|
export class IdentityCredential {
|
2
|
+
/**
|
3
|
+
* All variables are in little-endian format
|
4
|
+
*/
|
4
5
|
public constructor(
|
5
6
|
public readonly IDTrapdoor: Uint8Array,
|
6
7
|
public readonly IDNullifier: Uint8Array,
|
7
8
|
public readonly IDSecretHash: Uint8Array,
|
8
|
-
public readonly IDCommitment: Uint8Array
|
9
|
-
public readonly IDCommitmentBigInt: bigint
|
9
|
+
public readonly IDCommitment: Uint8Array
|
10
10
|
) {}
|
11
11
|
|
12
12
|
public static fromBytes(memKeys: Uint8Array): IdentityCredential {
|
@@ -18,14 +18,12 @@ export class IdentityCredential {
|
|
18
18
|
const idNullifier = memKeys.subarray(32, 64);
|
19
19
|
const idSecretHash = memKeys.subarray(64, 96);
|
20
20
|
const idCommitment = memKeys.subarray(96, 128);
|
21
|
-
const idCommitmentBigInt = buildBigIntFromUint8ArrayLE(idCommitment);
|
22
21
|
|
23
22
|
return new IdentityCredential(
|
24
23
|
idTrapdoor,
|
25
24
|
idNullifier,
|
26
25
|
idSecretHash,
|
27
|
-
idCommitment
|
28
|
-
idCommitmentBigInt
|
26
|
+
idCommitment
|
29
27
|
);
|
30
28
|
}
|
31
29
|
}
|
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 {
|
@@ -250,26 +248,25 @@ export class Keystore {
|
|
250
248
|
const str = bytesToUtf8(bytes);
|
251
249
|
const obj = JSON.parse(str);
|
252
250
|
|
253
|
-
|
251
|
+
const idCommitmentLE = Keystore.fromArraylikeToBytes(
|
252
|
+
_.get(obj, "identityCredential.idCommitment", [])
|
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
|
+
);
|
263
|
+
|
254
264
|
return {
|
255
265
|
identity: {
|
256
|
-
IDCommitment:
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
_.get(obj, "identityCredential.idTrapdoor", [])
|
261
|
-
),
|
262
|
-
IDNullifier: Keystore.fromArraylikeToBytes(
|
263
|
-
_.get(obj, "identityCredential.idNullifier", [])
|
264
|
-
),
|
265
|
-
IDCommitmentBigInt: buildBigIntFromUint8ArrayLE(
|
266
|
-
Keystore.fromArraylikeToBytes(
|
267
|
-
_.get(obj, "identityCredential.idCommitment", [])
|
268
|
-
)
|
269
|
-
),
|
270
|
-
IDSecretHash: Keystore.fromArraylikeToBytes(
|
271
|
-
_.get(obj, "identityCredential.idSecretHash", [])
|
272
|
-
)
|
266
|
+
IDCommitment: idCommitmentLE,
|
267
|
+
IDTrapdoor: idTrapdoorLE,
|
268
|
+
IDNullifier: idNullifierLE,
|
269
|
+
IDSecretHash: idSecretHashLE
|
273
270
|
},
|
274
271
|
membership: {
|
275
272
|
treeIndex: _.get(obj, "treeIndex"),
|
@@ -321,14 +318,21 @@ export class Keystore {
|
|
321
318
|
// follows nwaku implementation
|
322
319
|
// https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
|
323
320
|
private static fromIdentityToBytes(options: KeystoreEntity): Uint8Array {
|
321
|
+
function toLittleEndian(bytes: Uint8Array): Uint8Array {
|
322
|
+
return new Uint8Array(bytes).reverse();
|
323
|
+
}
|
324
324
|
return utf8ToBytes(
|
325
325
|
JSON.stringify({
|
326
326
|
treeIndex: options.membership.treeIndex,
|
327
327
|
identityCredential: {
|
328
|
-
idCommitment: Array.from(
|
329
|
-
|
330
|
-
|
331
|
-
|
328
|
+
idCommitment: Array.from(
|
329
|
+
toLittleEndian(options.identity.IDCommitment)
|
330
|
+
),
|
331
|
+
idNullifier: Array.from(toLittleEndian(options.identity.IDNullifier)),
|
332
|
+
idSecretHash: Array.from(
|
333
|
+
toLittleEndian(options.identity.IDSecretHash)
|
334
|
+
),
|
335
|
+
idTrapdoor: Array.from(toLittleEndian(options.identity.IDTrapdoor))
|
332
336
|
},
|
333
337
|
membershipContract: {
|
334
338
|
chainId: options.membership.chainId,
|
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":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEpE,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,GAAG;IACZ,YAAY,EAAE,IAAI;IAClB,gBAAgB,EAAE,GAAG;CACtB,CAAC;AAcF,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;QACjB,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;QAC3C,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;KACzD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC;QACjE,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC;QAC7D,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAOD,MAAM,UAAU,0BAA0B,CACxC,YAA+B,EAAE;IAEjC,MAAM,OAAO,GAAG;QACd,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC;QACjE,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC;QAC7D,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC;KAC/D,CAAC;IAEF,MAAM,YAAY,GAAG;QACnB,sBAAsB,EAAE,GAAG,EAAE,CAC3B,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAChE,sBAAsB,EAAE,GAAG,EAAE,CAC3B,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAChE,iBAAiB,EAAE,GAAG,EAAE,CACtB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QACrE,qBAAqB,EAAE,GAAG,EAAE,CAC1B,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;QACzE,WAAW,EAAE,GAAG,EAAE,CAAC,EAAE;QACrB,QAAQ,EAAE,kBAAkB,EAAE;QAC9B,OAAO;QACP,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACd,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QAC9B,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YACf,IAAI,EAAE,GAAG,EAAE,CACT,OAAO,CAAC,OAAO,CAAC;gBACd,MAAM,EAAE,CAAC,sBAAsB,EAAE,CAAC;aACnC,CAAC;SACL,CAAC;QACF,WAAW,EAAE;YACX,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAC/D;QACD,SAAS,EAAE;YACT,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;SAClC;QACD,cAAc,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;QAC3C,SAAS,EAAE;YACT,QAAQ,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,CAAC;gBAChC,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;aACjB,CAAC;SACH;QACD,OAAO,EAAE,cAAc,CAAC,OAAO;KAChC,CAAC;IAEF,2CAA2C;IAC3C,MAAM,MAAM,GAAG;QACb,GAAG,YAAY;QACf,GAAG,SAAS;QACZ,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE;KACtD,CAAC;IAEF,OAAO,MAAoC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,YAAqB;IAC1D,OAAO;QACL,IAAI,EAAE;YACJ,YAAY,EACV,YAAY;gBACZ,oEAAoE;YACtE,mBAAmB,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC;YAC9D,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;SAChC;QACD,KAAK,EAAE,sBAAsB;KACH,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,kBAA0B;IAC3D,OAAO,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,QAA4B;IAE5B,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC;QACnC,IAAI,EAAE,GAAG,EAAE,CACT,OAAO,CAAC,OAAO,CAAC;YACd,MAAM,EAAE;gBACN;oBACE,KAAK,EAAE,sBAAsB;oBAC7B,IAAI,EAAE;wBACJ,YAAY,EAAE,kBAAkB,CAAC,QAAQ,CAAC,kBAAkB,CAAC;wBAC7D,mBAAmB,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC;wBAC9D,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;qBAChC;iBACF;aACF;SACF,CAAC;KACL,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,oBAAyB,EACzB,QAA4B,EAC5B,YAA6B,EAC7B,eAAgC;IAEhC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IAED,2BAA2B;IAC3B,MAAM,CACJ,YAAY,CAAC,UAAU,CACrB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAC7C,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,EACpC,KAAK,CAAC,KAAK,CAAC,KAAK,EACjB,KAAK,CAAC,KAAK,CAAC,MAAM,CACnB,CACF,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;IAEb,+BAA+B;IAC/B,MAAM,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC1D,MAAM,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAC5D,MAAM,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;QACjD,OAAO,EAAE,cAAc,CAAC,OAAO;QAC/B,SAAS,EAAE,CAAC;KACb,CAAC,CAAC;IAEH,0BAA0B;IAC1B,MAAM,oBAAoB,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAC/C,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,EAC3D,EAAE,CACH,CAAC;IACF,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CACtD,oBAAoB,CACrB,CAAC;AACJ,CAAC"}
|
@@ -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
|
-
}
|