@vocdoni/davinci-sdk 0.0.4 → 0.0.6

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/dist/index.umd.js CHANGED
@@ -564,11 +564,26 @@
564
564
  throw error;
565
565
  }
566
566
  }
567
- isAddressAbleToVote(processId, address) {
568
- return this.request({
567
+ async getAddressWeight(processId, address) {
568
+ const participant = await this.request({
569
569
  method: "GET",
570
570
  url: `/processes/${processId}/participants/${address}`
571
571
  });
572
+ return participant.weight;
573
+ }
574
+ async isAddressAbleToVote(processId, address) {
575
+ try {
576
+ await this.request({
577
+ method: "GET",
578
+ url: `/processes/${processId}/participants/${address}`
579
+ });
580
+ return true;
581
+ } catch (error) {
582
+ if (error?.code === 40001) {
583
+ return false;
584
+ }
585
+ throw error;
586
+ }
572
587
  }
573
588
  getInfo() {
574
589
  return this.request({
@@ -990,7 +1005,7 @@
990
1005
  return this.contract.stVerifier();
991
1006
  }
992
1007
  // ─── WRITES ────────────────────────────────────────────────────────
993
- newProcess(status, startTime, duration, ballotMode, census, metadata, encryptionKey, initStateRoot) {
1008
+ newProcess(status, startTime, duration, maxVoters, ballotMode, census, metadata, encryptionKey, initStateRoot) {
994
1009
  const contractCensus = {
995
1010
  censusOrigin: BigInt(census.censusOrigin),
996
1011
  censusRoot: census.censusRoot,
@@ -1001,6 +1016,7 @@
1001
1016
  status,
1002
1017
  startTime,
1003
1018
  duration,
1019
+ maxVoters,
1004
1020
  ballotMode,
1005
1021
  contractCensus,
1006
1022
  metadata,
@@ -1041,6 +1057,14 @@
1041
1057
  async () => ({ success: true })
1042
1058
  );
1043
1059
  }
1060
+ setProcessMaxVoters(processID, maxVoters) {
1061
+ return this.sendTx(
1062
+ this.contract.setProcessMaxVoters(processID, maxVoters).catch((e) => {
1063
+ throw new ProcessDurationError(e.message, "setMaxVoters");
1064
+ }),
1065
+ async () => ({ success: true })
1066
+ );
1067
+ }
1044
1068
  /**
1045
1069
  * Matches the on-chain `submitStateTransition(processId, proof, input)`
1046
1070
  */
@@ -1111,6 +1135,13 @@
1111
1135
  cb
1112
1136
  ).catch((err) => console.error("Error setting up ProcessResultsSet listener:", err));
1113
1137
  }
1138
+ onProcessMaxVotersChanged(cb) {
1139
+ this.setupEventListener(
1140
+ this.contract,
1141
+ this.contract.filters.ProcessMaxVotersChanged(),
1142
+ cb
1143
+ ).catch((err) => console.error("Error setting up ProcessMaxVotersChanged listener:", err));
1144
+ }
1114
1145
  removeAllListeners() {
1115
1146
  this.contract.removeAllListeners();
1116
1147
  this.clearPollingIntervals();
@@ -1216,9 +1247,10 @@
1216
1247
  endDate: new Date(endTime * 1e3),
1217
1248
  duration,
1218
1249
  timeRemaining,
1250
+ maxVoters: Number(rawProcess.maxVoters),
1219
1251
  result: rawProcess.result,
1220
- voteCount: Number(rawProcess.voteCount),
1221
- voteOverwriteCount: Number(rawProcess.voteOverwriteCount),
1252
+ votersCount: Number(rawProcess.votersCount),
1253
+ overwrittenVotesCount: Number(rawProcess.overwrittenVotesCount),
1222
1254
  metadataURI: rawProcess.metadataURI,
1223
1255
  raw: rawProcess
1224
1256
  };
@@ -1270,6 +1302,7 @@
1270
1302
  ProcessStatus.READY,
1271
1303
  data.startTime,
1272
1304
  data.duration,
1305
+ data.maxVoters,
1273
1306
  data.ballotMode,
1274
1307
  data.census,
1275
1308
  data.metadataUri,
@@ -1357,6 +1390,7 @@
1357
1390
  ballotMode,
1358
1391
  signature
1359
1392
  });
1393
+ const maxVoters = config.maxVoters ?? censusConfig.size;
1360
1394
  const census = {
1361
1395
  censusOrigin: censusConfig.type,
1362
1396
  censusRoot,
@@ -1366,6 +1400,7 @@
1366
1400
  processId,
1367
1401
  startTime,
1368
1402
  duration,
1403
+ maxVoters,
1369
1404
  censusRoot,
1370
1405
  ballotMode,
1371
1406
  metadataUri,
@@ -1752,6 +1787,84 @@
1752
1787
  }
1753
1788
  throw new Error("Resume process stream ended unexpectedly");
1754
1789
  }
1790
+ /**
1791
+ * Sets the maximum number of voters for a process.
1792
+ * Returns an async generator that yields transaction status events.
1793
+ *
1794
+ * @param processId - The process ID
1795
+ * @param maxVoters - The new maximum number of voters
1796
+ * @returns AsyncGenerator yielding transaction status events
1797
+ *
1798
+ * @example
1799
+ * ```typescript
1800
+ * const stream = sdk.setProcessMaxVotersStream("0x1234567890abcdef...", 500);
1801
+ *
1802
+ * for await (const event of stream) {
1803
+ * switch (event.status) {
1804
+ * case "pending":
1805
+ * console.log("Transaction pending:", event.hash);
1806
+ * break;
1807
+ * case "completed":
1808
+ * console.log("MaxVoters updated successfully");
1809
+ * break;
1810
+ * case "failed":
1811
+ * console.error("Transaction failed:", event.error);
1812
+ * break;
1813
+ * case "reverted":
1814
+ * console.error("Transaction reverted:", event.reason);
1815
+ * break;
1816
+ * }
1817
+ * }
1818
+ * ```
1819
+ */
1820
+ async *setProcessMaxVotersStream(processId, maxVoters) {
1821
+ const txStream = this.processRegistry.setProcessMaxVoters(processId, maxVoters);
1822
+ for await (const event of txStream) {
1823
+ if (event.status === TxStatus.Pending) {
1824
+ yield { status: TxStatus.Pending, hash: event.hash };
1825
+ } else if (event.status === TxStatus.Completed) {
1826
+ yield {
1827
+ status: TxStatus.Completed,
1828
+ response: { success: true }
1829
+ };
1830
+ break;
1831
+ } else if (event.status === TxStatus.Failed) {
1832
+ yield { status: TxStatus.Failed, error: event.error };
1833
+ break;
1834
+ } else if (event.status === TxStatus.Reverted) {
1835
+ yield { status: TxStatus.Reverted, reason: event.reason };
1836
+ break;
1837
+ }
1838
+ }
1839
+ }
1840
+ /**
1841
+ * Sets the maximum number of voters for a process.
1842
+ * This is a simplified method that waits for transaction completion.
1843
+ *
1844
+ * For real-time transaction status updates, use setProcessMaxVotersStream() instead.
1845
+ *
1846
+ * @param processId - The process ID
1847
+ * @param maxVoters - The new maximum number of voters
1848
+ * @returns Promise resolving when the maxVoters is updated
1849
+ *
1850
+ * @example
1851
+ * ```typescript
1852
+ * await sdk.setProcessMaxVoters("0x1234567890abcdef...", 500);
1853
+ * console.log("MaxVoters updated successfully");
1854
+ * ```
1855
+ */
1856
+ async setProcessMaxVoters(processId, maxVoters) {
1857
+ for await (const event of this.setProcessMaxVotersStream(processId, maxVoters)) {
1858
+ if (event.status === "completed") {
1859
+ return;
1860
+ } else if (event.status === "failed") {
1861
+ throw event.error;
1862
+ } else if (event.status === "reverted") {
1863
+ throw new Error(`Transaction reverted: ${event.reason || "unknown reason"}`);
1864
+ }
1865
+ }
1866
+ throw new Error("Set process maxVoters stream ended unexpectedly");
1867
+ }
1755
1868
  }
1756
1869
 
1757
1870
  class CircomProof {
@@ -2032,9 +2145,15 @@
2032
2145
  assertMerkleCensusProof(proof);
2033
2146
  return proof;
2034
2147
  } else {
2035
- const proof = await this.apiService.census.getCensusProof(censusRoot, voterAddress);
2036
- assertMerkleCensusProof(proof);
2037
- return proof;
2148
+ const weight = await this.apiService.sequencer.getAddressWeight(processId, voterAddress);
2149
+ return {
2150
+ root: censusRoot,
2151
+ address: voterAddress,
2152
+ weight,
2153
+ censusOrigin: CensusOrigin.CensusOriginMerkleTree,
2154
+ value: "",
2155
+ siblings: ""
2156
+ };
2038
2157
  }
2039
2158
  }
2040
2159
  if (censusOrigin === CensusOrigin.CensusOriginCSP) {
@@ -2844,29 +2963,55 @@
2844
2963
  return this.voteOrchestrator.hasAddressVoted(processId, address);
2845
2964
  }
2846
2965
  /**
2847
- * Check if an address is able to vote in a process and get participant information.
2966
+ * Check if an address is able to vote in a process (i.e., is in the census).
2848
2967
  *
2849
2968
  * Does NOT require a provider - uses API calls only.
2850
2969
  *
2851
2970
  * @param processId - The process ID
2852
2971
  * @param address - The voter's address
2853
- * @returns Promise resolving to participant information (key and weight)
2972
+ * @returns Promise resolving to boolean indicating if the address can vote
2854
2973
  *
2855
2974
  * @example
2856
2975
  * ```typescript
2857
- * const participantInfo = await sdk.isAddressAbleToVote(processId, "0x1234567890abcdef...");
2858
- * console.log("Address:", participantInfo.key);
2859
- * console.log("Weight:", participantInfo.weight);
2976
+ * const canVote = await sdk.isAddressAbleToVote(processId, "0x1234567890abcdef...");
2977
+ * if (canVote) {
2978
+ * console.log("This address can vote");
2979
+ * } else {
2980
+ * console.log("This address is not in the census");
2981
+ * }
2860
2982
  * ```
2861
2983
  */
2862
2984
  async isAddressAbleToVote(processId, address) {
2863
2985
  if (!this.initialized) {
2864
2986
  throw new Error(
2865
- "SDK must be initialized before checking participant info. Call sdk.init() first."
2987
+ "SDK must be initialized before checking if address can vote. Call sdk.init() first."
2866
2988
  );
2867
2989
  }
2868
2990
  return this.apiService.sequencer.isAddressAbleToVote(processId, address);
2869
2991
  }
2992
+ /**
2993
+ * Get the voting weight for an address in a process.
2994
+ *
2995
+ * Does NOT require a provider - uses API calls only.
2996
+ *
2997
+ * @param processId - The process ID
2998
+ * @param address - The voter's address
2999
+ * @returns Promise resolving to the address weight as a string
3000
+ *
3001
+ * @example
3002
+ * ```typescript
3003
+ * const weight = await sdk.getAddressWeight(processId, "0x1234567890abcdef...");
3004
+ * console.log("Address weight:", weight);
3005
+ * ```
3006
+ */
3007
+ async getAddressWeight(processId, address) {
3008
+ if (!this.initialized) {
3009
+ throw new Error(
3010
+ "SDK must be initialized before getting address weight. Call sdk.init() first."
3011
+ );
3012
+ }
3013
+ return this.apiService.sequencer.getAddressWeight(processId, address);
3014
+ }
2870
3015
  /**
2871
3016
  * Watch vote status changes in real-time using an async generator.
2872
3017
  * This method yields each status change as it happens, perfect for showing
@@ -3224,6 +3369,77 @@
3224
3369
  this.ensureProvider();
3225
3370
  return this.processOrchestrator.resumeProcess(processId);
3226
3371
  }
3372
+ /**
3373
+ * Sets the maximum number of voters for a process and returns an async generator
3374
+ * that yields transaction status events. This allows you to change the voter limit
3375
+ * after process creation.
3376
+ *
3377
+ * Requires a signer with a provider for blockchain interactions.
3378
+ *
3379
+ * @param processId - The process ID
3380
+ * @param maxVoters - The new maximum number of voters
3381
+ * @returns AsyncGenerator yielding transaction status events
3382
+ * @throws Error if signer does not have a provider
3383
+ *
3384
+ * @example
3385
+ * ```typescript
3386
+ * const stream = sdk.setProcessMaxVotersStream("0x1234567890abcdef...", 500);
3387
+ *
3388
+ * for await (const event of stream) {
3389
+ * switch (event.status) {
3390
+ * case TxStatus.Pending:
3391
+ * console.log("Transaction pending:", event.hash);
3392
+ * break;
3393
+ * case TxStatus.Completed:
3394
+ * console.log("MaxVoters updated successfully");
3395
+ * break;
3396
+ * case TxStatus.Failed:
3397
+ * console.error("Transaction failed:", event.error);
3398
+ * break;
3399
+ * case TxStatus.Reverted:
3400
+ * console.error("Transaction reverted:", event.reason);
3401
+ * break;
3402
+ * }
3403
+ * }
3404
+ * ```
3405
+ */
3406
+ setProcessMaxVotersStream(processId, maxVoters) {
3407
+ if (!this.initialized) {
3408
+ throw new Error(
3409
+ "SDK must be initialized before setting process maxVoters. Call sdk.init() first."
3410
+ );
3411
+ }
3412
+ this.ensureProvider();
3413
+ return this.processOrchestrator.setProcessMaxVotersStream(processId, maxVoters);
3414
+ }
3415
+ /**
3416
+ * Sets the maximum number of voters for a process.
3417
+ * This is the simplified method that waits for transaction completion.
3418
+ *
3419
+ * For real-time transaction status updates, use setProcessMaxVotersStream() instead.
3420
+ *
3421
+ * Requires a signer with a provider for blockchain interactions.
3422
+ *
3423
+ * @param processId - The process ID
3424
+ * @param maxVoters - The new maximum number of voters
3425
+ * @returns Promise resolving when the maxVoters is updated
3426
+ * @throws Error if signer does not have a provider
3427
+ *
3428
+ * @example
3429
+ * ```typescript
3430
+ * await sdk.setProcessMaxVoters("0x1234567890abcdef...", 500);
3431
+ * console.log("MaxVoters updated successfully");
3432
+ * ```
3433
+ */
3434
+ async setProcessMaxVoters(processId, maxVoters) {
3435
+ if (!this.initialized) {
3436
+ throw new Error(
3437
+ "SDK must be initialized before setting process maxVoters. Call sdk.init() first."
3438
+ );
3439
+ }
3440
+ this.ensureProvider();
3441
+ return this.processOrchestrator.setProcessMaxVoters(processId, maxVoters);
3442
+ }
3227
3443
  /**
3228
3444
  * Resolve contract address based on configuration priority:
3229
3445
  * 1. Custom addresses from user config (if provided)
@@ -174,36 +174,14 @@ interface GetProcessResponse {
174
174
  organizationId: string;
175
175
  encryptionKey: EncryptionKey;
176
176
  stateRoot: string;
177
- result: string[];
178
- startTime: number;
177
+ result: string[] | null;
178
+ startTime: string;
179
179
  duration: number;
180
180
  metadataURI: string;
181
181
  ballotMode: BallotMode;
182
182
  census: CensusData;
183
- metadata: {
184
- title: Record<string, string>;
185
- description: Record<string, string>;
186
- media: {
187
- header: string;
188
- logo: string;
189
- };
190
- questions: {
191
- title: Record<string, string>;
192
- description: Record<string, string>;
193
- choices: {
194
- title: Record<string, string>;
195
- value: number;
196
- meta: Record<string, string>;
197
- }[];
198
- meta: Record<string, string>;
199
- }[];
200
- processType: {
201
- name: string;
202
- properties: Record<string, string>;
203
- };
204
- };
205
- voteCount: string;
206
- voteOverwrittenCount: string;
183
+ votersCount: string;
184
+ overwrittenVotesCount: string;
207
185
  isAcceptingVotes: boolean;
208
186
  sequencerStats: {
209
187
  stateTransitionCount: number;
@@ -531,7 +509,8 @@ declare class VocdoniSequencerService extends BaseService {
531
509
  submitVote(vote: VoteRequest): Promise<void>;
532
510
  getVoteStatus(processId: string, voteId: string): Promise<VoteStatusResponse>;
533
511
  hasAddressVoted(processId: string, address: string): Promise<boolean>;
534
- isAddressAbleToVote(processId: string, address: string): Promise<ParticipantInfoResponse>;
512
+ getAddressWeight(processId: string, address: string): Promise<string>;
513
+ isAddressAbleToVote(processId: string, address: string): Promise<boolean>;
535
514
  getInfo(): Promise<InfoResponse>;
536
515
  pushMetadata(metadata: ElectionMetadata): Promise<string>;
537
516
  getMetadata(hashOrUrl: string): Promise<ElectionMetadata>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vocdoni/davinci-sdk",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@ethereumjs/common": "^4.4.0",
75
- "@vocdoni/davinci-contracts": "0.0.26",
75
+ "@vocdoni/davinci-contracts": "0.0.29",
76
76
  "axios": "^1.8.4",
77
77
  "ethers": "^6.7.1",
78
78
  "snarkjs": "^0.7.5"