@waku/rln 0.1.1-8928376 → 0.1.1-9b1e818

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.
@@ -1,21 +1,29 @@
1
+ import { hexToBytes } from "@waku/utils/bytes";
1
2
  import { ethers } from "ethers";
2
3
 
4
+ import { zeroPadLE } from "./byte_utils.js";
3
5
  import { RLN_REGISTRY_ABI, RLN_STORAGE_ABI } from "./constants.js";
4
6
  import { IdentityCredential, RLNInstance } from "./rln.js";
5
7
  import { MerkleRootTracker } from "./root_tracker.js";
6
8
 
7
9
  type Member = {
8
- pubkey: string;
9
- index: number;
10
+ idCommitment: string;
11
+ index: ethers.BigNumber;
10
12
  };
11
13
 
12
14
  type Provider = ethers.Signer | ethers.providers.Provider;
13
15
 
14
- type ContractOptions = {
15
- address: string;
16
+ type RLNContractOptions = {
16
17
  provider: Provider;
18
+ registryAddress: string;
17
19
  };
18
20
 
21
+ type RLNStorageOptions = {
22
+ storageIndex?: number;
23
+ };
24
+
25
+ type RLNContractInitOptions = RLNContractOptions & RLNStorageOptions;
26
+
19
27
  type FetchMembersOptions = {
20
28
  fromBlock?: number;
21
29
  fetchRange?: number;
@@ -31,11 +39,11 @@ export class RLNContract {
31
39
  private storageContract: undefined | ethers.Contract;
32
40
  private _membersFilter: undefined | ethers.EventFilter;
33
41
 
34
- private _members: Member[] = [];
42
+ private _members: Map<number, Member> = new Map();
35
43
 
36
44
  public static async init(
37
45
  rlnInstance: RLNInstance,
38
- options: ContractOptions
46
+ options: RLNContractInitOptions
39
47
  ): Promise<RLNContract> {
40
48
  const rlnContract = new RLNContract(rlnInstance, options);
41
49
 
@@ -48,25 +56,34 @@ export class RLNContract {
48
56
 
49
57
  constructor(
50
58
  rlnInstance: RLNInstance,
51
- { address, provider }: ContractOptions
59
+ { registryAddress, provider }: RLNContractOptions
52
60
  ) {
53
61
  const initialRoot = rlnInstance.getMerkleRoot();
54
62
 
55
63
  this.registryContract = new ethers.Contract(
56
- address,
64
+ registryAddress,
57
65
  RLN_REGISTRY_ABI,
58
66
  provider
59
67
  );
60
68
  this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
61
69
  }
62
70
 
63
- private async initStorageContract(provider: Provider): Promise<void> {
64
- const index = await this.registryContract.usingStorageIndex();
65
- const address = await this.registryContract.storages(index);
71
+ private async initStorageContract(
72
+ provider: Provider,
73
+ options: RLNStorageOptions = {}
74
+ ): Promise<void> {
75
+ const storageIndex = options?.storageIndex
76
+ ? options.storageIndex
77
+ : await this.registryContract.usingStorageIndex();
78
+ const storageAddress = await this.registryContract.storages(storageIndex);
79
+
80
+ if (!storageAddress || storageAddress === ethers.constants.AddressZero) {
81
+ throw Error("No RLN Storage initialized on registry contract.");
82
+ }
66
83
 
67
- this.storageIndex = index;
84
+ this.storageIndex = storageIndex;
68
85
  this.storageContract = new ethers.Contract(
69
- address,
86
+ storageAddress,
70
87
  RLN_STORAGE_ABI,
71
88
  provider
72
89
  );
@@ -77,13 +94,16 @@ export class RLNContract {
77
94
 
78
95
  public get contract(): ethers.Contract {
79
96
  if (!this.storageContract) {
80
- throw Error("Storage contract was not initialized.");
97
+ throw Error("Storage contract was not initialized");
81
98
  }
82
99
  return this.storageContract as ethers.Contract;
83
100
  }
84
101
 
85
102
  public get members(): Member[] {
86
- return this._members;
103
+ const sortedMembers = Array.from(this._members.values()).sort(
104
+ (left, right) => left.index.toNumber() - right.index.toNumber()
105
+ );
106
+ return sortedMembers;
87
107
  }
88
108
 
89
109
  private get membersFilter(): ethers.EventFilter {
@@ -115,13 +135,13 @@ export class RLNContract {
115
135
  }
116
136
 
117
137
  if (evt.removed) {
118
- const index: number = evt.args.index;
138
+ const index: ethers.BigNumber = evt.args.index;
119
139
  const toRemoveVal = toRemoveTable.get(evt.blockNumber);
120
140
  if (toRemoveVal != undefined) {
121
- toRemoveVal.push(index);
141
+ toRemoveVal.push(index.toNumber());
122
142
  toRemoveTable.set(evt.blockNumber, toRemoveVal);
123
143
  } else {
124
- toRemoveTable.set(evt.blockNumber, [index]);
144
+ toRemoveTable.set(evt.blockNumber, [index.toNumber()]);
125
145
  }
126
146
  } else {
127
147
  let eventsPerBlock = toInsertTable.get(evt.blockNumber);
@@ -132,10 +152,10 @@ export class RLNContract {
132
152
  eventsPerBlock.push(evt);
133
153
  toInsertTable.set(evt.blockNumber, eventsPerBlock);
134
154
  }
135
-
136
- this.removeMembers(rlnInstance, toRemoveTable);
137
- this.insertMembers(rlnInstance, toInsertTable);
138
155
  });
156
+
157
+ this.removeMembers(rlnInstance, toRemoveTable);
158
+ this.insertMembers(rlnInstance, toInsertTable);
139
159
  }
140
160
 
141
161
  private insertMembers(
@@ -144,18 +164,19 @@ export class RLNContract {
144
164
  ): void {
145
165
  toInsert.forEach((events: ethers.Event[], blockNumber: number) => {
146
166
  events.forEach((evt) => {
147
- if (!evt.args) {
167
+ const _idCommitment = evt?.args?.idCommitment;
168
+ const index: ethers.BigNumber = evt?.args?.index;
169
+
170
+ if (!_idCommitment || !index) {
148
171
  return;
149
172
  }
150
173
 
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
- );
174
+ const idCommitment = zeroPadLE(hexToBytes(_idCommitment?._hex), 32);
157
175
  rlnInstance.insertMember(idCommitment);
158
- this.members.push({ index, pubkey });
176
+ this._members.set(index.toNumber(), {
177
+ index,
178
+ idCommitment: _idCommitment?._hex,
179
+ });
159
180
  });
160
181
 
161
182
  const currentRoot = rlnInstance.getMerkleRoot();
@@ -170,9 +191,8 @@ export class RLNContract {
170
191
  const removeDescending = new Map([...toRemove].sort().reverse());
171
192
  removeDescending.forEach((indexes: number[], blockNumber: number) => {
172
193
  indexes.forEach((index) => {
173
- const idx = this.members.findIndex((m) => m.index === index);
174
- if (idx > -1) {
175
- this.members.splice(idx, 1);
194
+ if (this._members.has(index)) {
195
+ this._members.delete(index);
176
196
  }
177
197
  rlnInstance.deleteMember(index);
178
198
  });
@@ -183,14 +203,14 @@ export class RLNContract {
183
203
 
184
204
  public subscribeToMembers(rlnInstance: RLNInstance): void {
185
205
  this.contract.on(this.membersFilter, (_pubkey, _index, event) =>
186
- this.processEvents(rlnInstance, event)
206
+ this.processEvents(rlnInstance, [event])
187
207
  );
188
208
  }
189
209
 
190
210
  public async registerWithSignature(
191
211
  rlnInstance: RLNInstance,
192
212
  signature: string
193
- ): Promise<ethers.Event | undefined> {
213
+ ): Promise<Member | undefined> {
194
214
  const identityCredential =
195
215
  await rlnInstance.generateSeededIdentityCredential(signature);
196
216
 
@@ -199,23 +219,36 @@ export class RLNContract {
199
219
 
200
220
  public async registerWithKey(
201
221
  credential: IdentityCredential
202
- ): Promise<ethers.Event | undefined> {
203
- if (!this.storageIndex) {
222
+ ): Promise<Member | undefined> {
223
+ if (this.storageIndex === undefined) {
204
224
  throw Error(
205
225
  "Cannot register credential, no storage contract index found."
206
226
  );
207
227
  }
208
228
  const txRegisterResponse: ethers.ContractTransaction =
209
- await this.registryContract.register(
229
+ await this.registryContract["register(uint16,uint256)"](
210
230
  this.storageIndex,
211
231
  credential.IDCommitmentBigInt,
212
- {
213
- gasLimit: 100000,
214
- }
232
+ { gasLimit: 100000 }
215
233
  );
216
234
  const txRegisterReceipt = await txRegisterResponse.wait();
217
235
 
218
- return txRegisterReceipt?.events?.[0];
236
+ // assumption: register(uint16,uint256) emits one event
237
+ const memberRegistered = txRegisterReceipt?.events?.[0];
238
+
239
+ if (!memberRegistered) {
240
+ return undefined;
241
+ }
242
+
243
+ const decodedData = this.contract.interface.decodeEventLog(
244
+ "MemberRegistered",
245
+ memberRegistered.data
246
+ );
247
+
248
+ return {
249
+ idCommitment: decodedData.idCommitment,
250
+ index: decodedData.index,
251
+ };
219
252
  }
220
253
 
221
254
  public roots(): Uint8Array[] {