@waku/rln 0.1.0-e52107d → 0.1.1-5b9414a

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.
Files changed (47) hide show
  1. package/bundle/index.js +22885 -288
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/byte_utils.d.ts +6 -0
  4. package/dist/byte_utils.js +9 -0
  5. package/dist/byte_utils.js.map +1 -1
  6. package/dist/constants.d.ts +3 -3
  7. package/dist/constants.js +64 -11
  8. package/dist/constants.js.map +1 -1
  9. package/dist/index.d.ts +3 -2
  10. package/dist/index.js +3 -2
  11. package/dist/index.js.map +1 -1
  12. package/dist/keystore/cipher.d.ts +4 -0
  13. package/dist/keystore/cipher.js +28 -0
  14. package/dist/keystore/cipher.js.map +1 -0
  15. package/dist/keystore/credential_validation_generated.d.ts +8 -0
  16. package/dist/keystore/credential_validation_generated.js +121 -0
  17. package/dist/keystore/credential_validation_generated.js.map +1 -0
  18. package/dist/keystore/index.d.ts +2 -0
  19. package/dist/keystore/index.js +3 -0
  20. package/dist/keystore/index.js.map +1 -0
  21. package/dist/keystore/keystore.d.ts +49 -0
  22. package/dist/keystore/keystore.js +182 -0
  23. package/dist/keystore/keystore.js.map +1 -0
  24. package/dist/keystore/keystore_validation_generated.d.ts +8 -0
  25. package/dist/keystore/keystore_validation_generated.js +75 -0
  26. package/dist/keystore/keystore_validation_generated.js.map +1 -0
  27. package/dist/keystore/schema_validator.d.ts +2 -0
  28. package/dist/keystore/schema_validator.js +18 -0
  29. package/dist/keystore/schema_validator.js.map +1 -0
  30. package/dist/keystore/types.d.ts +9 -0
  31. package/dist/keystore/types.js +2 -0
  32. package/dist/keystore/types.js.map +1 -0
  33. package/dist/message.d.ts +2 -1
  34. package/dist/message.js +5 -2
  35. package/dist/message.js.map +1 -1
  36. package/dist/rln.js +3 -11
  37. package/dist/rln.js.map +1 -1
  38. package/dist/rln_contract.d.ts +15 -5
  39. package/dist/rln_contract.js +96 -23
  40. package/dist/rln_contract.js.map +1 -1
  41. package/package.json +23 -8
  42. package/src/byte_utils.ts +10 -0
  43. package/src/constants.ts +65 -11
  44. package/src/index.ts +10 -3
  45. package/src/message.ts +7 -2
  46. package/src/rln.ts +3 -12
  47. package/src/rln_contract.ts +142 -34
@@ -1,16 +1,19 @@
1
1
  import { ethers } from "ethers";
2
2
 
3
- import { RLN_ABI } from "./constants.js";
3
+ import { RLN_REGISTRY_ABI, RLN_STORAGE_ABI } from "./constants.js";
4
4
  import { IdentityCredential, RLNInstance } from "./rln.js";
5
+ import { MerkleRootTracker } from "./root_tracker.js";
5
6
 
6
7
  type Member = {
7
8
  pubkey: string;
8
9
  index: number;
9
10
  };
10
11
 
12
+ type Provider = ethers.Signer | ethers.providers.Provider;
13
+
11
14
  type ContractOptions = {
12
15
  address: string;
13
- provider: ethers.Signer | ethers.providers.Provider;
16
+ provider: Provider;
14
17
  };
15
18
 
16
19
  type FetchMembersOptions = {
@@ -20,8 +23,13 @@ type FetchMembersOptions = {
20
23
  };
21
24
 
22
25
  export class RLNContract {
23
- private _contract: ethers.Contract;
24
- private membersFilter: ethers.EventFilter;
26
+ private registryContract: ethers.Contract;
27
+ private merkleRootTracker: MerkleRootTracker;
28
+
29
+ private deployBlock: undefined | number;
30
+ private storageIndex: undefined | number;
31
+ private storageContract: undefined | ethers.Contract;
32
+ private _membersFilter: undefined | ethers.EventFilter;
25
33
 
26
34
  private _members: Member[] = [];
27
35
 
@@ -29,65 +37,154 @@ export class RLNContract {
29
37
  rlnInstance: RLNInstance,
30
38
  options: ContractOptions
31
39
  ): Promise<RLNContract> {
32
- const rlnContract = new RLNContract(options);
40
+ const rlnContract = new RLNContract(rlnInstance, options);
33
41
 
42
+ await rlnContract.initStorageContract(options.provider);
34
43
  await rlnContract.fetchMembers(rlnInstance);
35
44
  rlnContract.subscribeToMembers(rlnInstance);
36
45
 
37
46
  return rlnContract;
38
47
  }
39
48
 
40
- constructor({ address, provider }: ContractOptions) {
41
- this._contract = new ethers.Contract(address, RLN_ABI, provider);
42
- this.membersFilter = this.contract.filters.MemberRegistered();
49
+ constructor(
50
+ rlnInstance: RLNInstance,
51
+ { address, provider }: ContractOptions
52
+ ) {
53
+ const initialRoot = rlnInstance.getMerkleRoot();
54
+
55
+ this.registryContract = new ethers.Contract(
56
+ address,
57
+ RLN_REGISTRY_ABI,
58
+ provider
59
+ );
60
+ this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
61
+ }
62
+
63
+ private async initStorageContract(provider: Provider): Promise<void> {
64
+ const index = await this.registryContract.usingStorageIndex();
65
+ const address = await this.registryContract.storages(index);
66
+
67
+ this.storageIndex = index;
68
+ this.storageContract = new ethers.Contract(
69
+ address,
70
+ RLN_STORAGE_ABI,
71
+ provider
72
+ );
73
+ this._membersFilter = this.storageContract.filters.MemberRegistered();
74
+
75
+ this.deployBlock = await this.storageContract.deployedBlockNumber();
43
76
  }
44
77
 
45
78
  public get contract(): ethers.Contract {
46
- return this._contract;
79
+ if (!this.storageContract) {
80
+ throw Error("Storage contract was not initialized.");
81
+ }
82
+ return this.storageContract as ethers.Contract;
47
83
  }
48
84
 
49
85
  public get members(): Member[] {
50
86
  return this._members;
51
87
  }
52
88
 
89
+ private get membersFilter(): ethers.EventFilter {
90
+ if (!this._membersFilter) {
91
+ throw Error("Members filter was not initialized.");
92
+ }
93
+ return this._membersFilter as ethers.EventFilter;
94
+ }
95
+
53
96
  public async fetchMembers(
54
97
  rlnInstance: RLNInstance,
55
98
  options: FetchMembersOptions = {}
56
99
  ): Promise<void> {
57
100
  const registeredMemberEvents = await queryFilter(this.contract, {
101
+ fromBlock: this.deployBlock,
58
102
  ...options,
59
103
  membersFilter: this.membersFilter,
60
104
  });
61
-
62
- for (const event of registeredMemberEvents) {
63
- this.addMemberFromEvent(rlnInstance, event);
64
- }
105
+ this.processEvents(rlnInstance, registeredMemberEvents);
65
106
  }
66
107
 
67
- public subscribeToMembers(rlnInstance: RLNInstance): void {
68
- this.contract.on(this.membersFilter, (_pubkey, _index, event) =>
69
- this.addMemberFromEvent(rlnInstance, event)
70
- );
108
+ public processEvents(rlnInstance: RLNInstance, events: ethers.Event[]): void {
109
+ const toRemoveTable = new Map<number, number[]>();
110
+ const toInsertTable = new Map<number, ethers.Event[]>();
111
+
112
+ events.forEach((evt) => {
113
+ if (!evt.args) {
114
+ return;
115
+ }
116
+
117
+ if (evt.removed) {
118
+ const index: number = evt.args.index;
119
+ const toRemoveVal = toRemoveTable.get(evt.blockNumber);
120
+ if (toRemoveVal != undefined) {
121
+ toRemoveVal.push(index);
122
+ toRemoveTable.set(evt.blockNumber, toRemoveVal);
123
+ } else {
124
+ toRemoveTable.set(evt.blockNumber, [index]);
125
+ }
126
+ } else {
127
+ let eventsPerBlock = toInsertTable.get(evt.blockNumber);
128
+ if (eventsPerBlock == undefined) {
129
+ eventsPerBlock = [];
130
+ }
131
+
132
+ eventsPerBlock.push(evt);
133
+ toInsertTable.set(evt.blockNumber, eventsPerBlock);
134
+ }
135
+
136
+ this.removeMembers(rlnInstance, toRemoveTable);
137
+ this.insertMembers(rlnInstance, toInsertTable);
138
+ });
71
139
  }
72
140
 
73
- private addMemberFromEvent(
141
+ private insertMembers(
74
142
  rlnInstance: RLNInstance,
75
- event: ethers.Event
143
+ toInsert: Map<number, ethers.Event[]>
76
144
  ): void {
77
- if (!event.args) {
78
- return;
79
- }
145
+ toInsert.forEach((events: ethers.Event[], blockNumber: number) => {
146
+ events.forEach((evt) => {
147
+ if (!evt.args) {
148
+ return;
149
+ }
150
+
151
+ const pubkey = evt.args.pubkey;
152
+ const index = evt.args.index;
153
+ const idCommitment = ethers.utils.zeroPad(
154
+ ethers.utils.arrayify(pubkey),
155
+ 32
156
+ );
157
+ rlnInstance.insertMember(idCommitment);
158
+ this.members.push({ index, pubkey });
159
+ });
80
160
 
81
- const pubkey: string = event.args.pubkey;
82
- const index: number = event.args.index;
161
+ const currentRoot = rlnInstance.getMerkleRoot();
162
+ this.merkleRootTracker.pushRoot(blockNumber, currentRoot);
163
+ });
164
+ }
165
+
166
+ private removeMembers(
167
+ rlnInstance: RLNInstance,
168
+ toRemove: Map<number, number[]>
169
+ ): void {
170
+ const removeDescending = new Map([...toRemove].sort().reverse());
171
+ removeDescending.forEach((indexes: number[], blockNumber: number) => {
172
+ indexes.forEach((index) => {
173
+ const idx = this.members.findIndex((m) => m.index === index);
174
+ if (idx > -1) {
175
+ this.members.splice(idx, 1);
176
+ }
177
+ rlnInstance.deleteMember(index);
178
+ });
83
179
 
84
- this.members.push({ index, pubkey });
180
+ this.merkleRootTracker.backFill(blockNumber);
181
+ });
182
+ }
85
183
 
86
- const idCommitment = ethers.utils.zeroPad(
87
- ethers.utils.arrayify(pubkey),
88
- 32
184
+ public subscribeToMembers(rlnInstance: RLNInstance): void {
185
+ this.contract.on(this.membersFilter, (_pubkey, _index, event) =>
186
+ this.processEvents(rlnInstance, event)
89
187
  );
90
- rlnInstance.insertMember(idCommitment);
91
188
  }
92
189
 
93
190
  public async registerWithSignature(
@@ -103,16 +200,27 @@ export class RLNContract {
103
200
  public async registerWithKey(
104
201
  credential: IdentityCredential
105
202
  ): Promise<ethers.Event | undefined> {
106
- const depositValue = await this.contract.MEMBERSHIP_DEPOSIT();
107
-
203
+ if (!this.storageIndex) {
204
+ throw Error(
205
+ "Cannot register credential, no storage contract index found."
206
+ );
207
+ }
108
208
  const txRegisterResponse: ethers.ContractTransaction =
109
- await this.contract.register(credential.IDCommitmentBigInt, {
110
- value: depositValue,
111
- });
209
+ await this.registryContract.register(
210
+ this.storageIndex,
211
+ credential.IDCommitmentBigInt,
212
+ {
213
+ gasLimit: 100000,
214
+ }
215
+ );
112
216
  const txRegisterReceipt = await txRegisterResponse.wait();
113
217
 
114
218
  return txRegisterReceipt?.events?.[0];
115
219
  }
220
+
221
+ public roots(): Uint8Array[] {
222
+ return this.merkleRootTracker.roots();
223
+ }
116
224
  }
117
225
 
118
226
  type CustomQueryOptions = FetchMembersOptions & {