@waku/rln 0.1.1 → 0.1.2-e1679b6

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