@vocdoni/davinci-sdk 0.0.2 → 0.0.3

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.js CHANGED
@@ -215,6 +215,281 @@ function assertCSPCensusProof(proof) {
215
215
  }
216
216
  }
217
217
 
218
+ var CensusType = /* @__PURE__ */ ((CensusType2) => {
219
+ CensusType2["PLAIN"] = "plain";
220
+ CensusType2["WEIGHTED"] = "weighted";
221
+ CensusType2["CSP"] = "csp";
222
+ return CensusType2;
223
+ })(CensusType || {});
224
+ class Census {
225
+ constructor(type) {
226
+ this._censusId = null;
227
+ this._censusRoot = null;
228
+ this._censusURI = null;
229
+ this._size = null;
230
+ this._type = type;
231
+ }
232
+ get censusId() {
233
+ return this._censusId;
234
+ }
235
+ get censusRoot() {
236
+ return this._censusRoot;
237
+ }
238
+ get censusURI() {
239
+ return this._censusURI;
240
+ }
241
+ get type() {
242
+ return this._type;
243
+ }
244
+ get size() {
245
+ return this._size;
246
+ }
247
+ get isPublished() {
248
+ return this._censusRoot !== null && this._censusURI !== null;
249
+ }
250
+ /**
251
+ * Convert CensusType to CensusOrigin enum for API compatibility
252
+ */
253
+ get censusOrigin() {
254
+ switch (this._type) {
255
+ case "plain" /* PLAIN */:
256
+ case "weighted" /* WEIGHTED */:
257
+ return CensusOrigin.CensusOriginMerkleTree;
258
+ case "csp" /* CSP */:
259
+ return CensusOrigin.CensusOriginCSP;
260
+ default:
261
+ throw new Error(`Unknown census type: ${this._type}`);
262
+ }
263
+ }
264
+ }
265
+
266
+ class PlainCensus extends Census {
267
+ constructor() {
268
+ super(CensusType.PLAIN);
269
+ this._participants = /* @__PURE__ */ new Set();
270
+ }
271
+ /**
272
+ * Add participant(s) with automatic weight=1
273
+ * @param addresses - Single address or array of addresses
274
+ */
275
+ add(addresses) {
276
+ const toAdd = Array.isArray(addresses) ? addresses : [addresses];
277
+ for (const address of toAdd) {
278
+ this.validateAddress(address);
279
+ this._participants.add(address.toLowerCase());
280
+ }
281
+ }
282
+ /**
283
+ * Remove participant by address
284
+ */
285
+ remove(address) {
286
+ this._participants.delete(address.toLowerCase());
287
+ }
288
+ /**
289
+ * Get all participants as CensusParticipant array (for API)
290
+ * All participants have weight="1"
291
+ */
292
+ get participants() {
293
+ return Array.from(this._participants).map((key) => ({
294
+ key,
295
+ weight: "1"
296
+ // Everyone has weight=1 in plain census
297
+ }));
298
+ }
299
+ /**
300
+ * Get addresses only
301
+ */
302
+ get addresses() {
303
+ return Array.from(this._participants);
304
+ }
305
+ validateAddress(address) {
306
+ if (!address || typeof address !== "string") {
307
+ throw new Error("Address is required and must be a string");
308
+ }
309
+ if (!/^(0x)?[0-9a-fA-F]{40}$/i.test(address)) {
310
+ throw new Error(`Invalid Ethereum address format: ${address}`);
311
+ }
312
+ }
313
+ /**
314
+ * Internal method called after publishing
315
+ * @internal
316
+ */
317
+ _setPublishedData(root, uri, size, censusId) {
318
+ this._censusRoot = root;
319
+ this._censusURI = uri;
320
+ this._size = size;
321
+ if (censusId) this._censusId = censusId;
322
+ }
323
+ }
324
+
325
+ class WeightedCensus extends Census {
326
+ constructor() {
327
+ super(CensusType.WEIGHTED);
328
+ this._participants = /* @__PURE__ */ new Map();
329
+ }
330
+ /**
331
+ * Add participant(s) with custom weights
332
+ * Weight can be provided as string, number, or bigint - will be converted to string internally
333
+ * @param participant - Single participant or array of participants with custom weights
334
+ */
335
+ add(participant) {
336
+ const toAdd = Array.isArray(participant) ? participant : [participant];
337
+ for (const p of toAdd) {
338
+ this.validateParticipant(p);
339
+ const weightString = this.normalizeWeight(p.weight);
340
+ this._participants.set(p.key.toLowerCase(), weightString);
341
+ }
342
+ }
343
+ /**
344
+ * Remove participant by address
345
+ */
346
+ remove(address) {
347
+ this._participants.delete(address.toLowerCase());
348
+ }
349
+ /**
350
+ * Get all participants as CensusParticipant array
351
+ */
352
+ get participants() {
353
+ return Array.from(this._participants.entries()).map(([key, weight]) => ({
354
+ key,
355
+ weight
356
+ }));
357
+ }
358
+ /**
359
+ * Get participant addresses
360
+ */
361
+ get addresses() {
362
+ return Array.from(this._participants.keys());
363
+ }
364
+ /**
365
+ * Get weight for specific address
366
+ */
367
+ getWeight(address) {
368
+ return this._participants.get(address.toLowerCase());
369
+ }
370
+ /**
371
+ * Normalizes weight from string, number, or bigint to string
372
+ */
373
+ normalizeWeight(weight) {
374
+ if (typeof weight === "string") {
375
+ if (!/^\d+$/.test(weight)) {
376
+ throw new Error(`Invalid weight format: ${weight}. Must be a positive integer.`);
377
+ }
378
+ return weight;
379
+ }
380
+ if (typeof weight === "number") {
381
+ if (!Number.isInteger(weight) || weight < 0) {
382
+ throw new Error(`Invalid weight: ${weight}. Must be a positive integer.`);
383
+ }
384
+ return weight.toString();
385
+ }
386
+ if (typeof weight === "bigint") {
387
+ if (weight < 0n) {
388
+ throw new Error(`Invalid weight: ${weight}. Must be a positive integer.`);
389
+ }
390
+ return weight.toString();
391
+ }
392
+ throw new Error(`Invalid weight type. Must be string, number, or bigint.`);
393
+ }
394
+ validateParticipant(participant) {
395
+ if (!participant.key || typeof participant.key !== "string") {
396
+ throw new Error("Participant key (address) is required");
397
+ }
398
+ if (!/^(0x)?[0-9a-fA-F]{40}$/i.test(participant.key)) {
399
+ throw new Error(`Invalid Ethereum address format: ${participant.key}`);
400
+ }
401
+ if (participant.weight === void 0 || participant.weight === null) {
402
+ throw new Error("Participant weight is required");
403
+ }
404
+ }
405
+ /**
406
+ * Internal method called after publishing
407
+ * @internal
408
+ */
409
+ _setPublishedData(root, uri, size, censusId) {
410
+ this._censusRoot = root;
411
+ this._censusURI = uri;
412
+ this._size = size;
413
+ if (censusId) this._censusId = censusId;
414
+ }
415
+ }
416
+
417
+ class CspCensus extends Census {
418
+ constructor(publicKey, cspURI, size) {
419
+ super(CensusType.CSP);
420
+ if (!/^(0x)?[0-9a-fA-F]+$/.test(publicKey)) {
421
+ throw new Error("Public key is missing or invalid");
422
+ }
423
+ try {
424
+ new URL(cspURI);
425
+ } catch {
426
+ throw new Error("CSP URI is missing or invalid");
427
+ }
428
+ this._publicKey = publicKey;
429
+ this._cspURI = cspURI;
430
+ this._censusRoot = publicKey;
431
+ this._censusURI = cspURI;
432
+ this._size = size;
433
+ }
434
+ get publicKey() {
435
+ return this._publicKey;
436
+ }
437
+ get cspURI() {
438
+ return this._cspURI;
439
+ }
440
+ }
441
+
442
+ class PublishedCensus extends Census {
443
+ constructor(type, root, uri, size) {
444
+ super(type);
445
+ this._censusRoot = root;
446
+ this._censusURI = uri;
447
+ this._size = size;
448
+ }
449
+ }
450
+
451
+ class CensusOrchestrator {
452
+ constructor(censusService) {
453
+ this.censusService = censusService;
454
+ }
455
+ /**
456
+ * Publishes a PlainCensus or WeightedCensus
457
+ * Creates a working census, adds participants, and publishes it
458
+ */
459
+ async publish(census) {
460
+ if (census.isPublished) {
461
+ throw new Error("Census is already published");
462
+ }
463
+ if (census.participants.length === 0) {
464
+ throw new Error("Cannot publish empty census");
465
+ }
466
+ const censusId = await this.censusService.createCensus();
467
+ await this.censusService.addParticipants(censusId, census.participants);
468
+ const publishResponse = await this.censusService.publishCensus(censusId);
469
+ census._setPublishedData(
470
+ publishResponse.root,
471
+ publishResponse.uri,
472
+ publishResponse.participantCount,
473
+ censusId
474
+ );
475
+ }
476
+ /**
477
+ * Gets census data for process creation
478
+ * Throws if census is not published
479
+ */
480
+ getCensusData(census) {
481
+ if (!census.isPublished) {
482
+ throw new Error("Census must be published before creating a process");
483
+ }
484
+ return {
485
+ type: census.censusOrigin,
486
+ root: census.censusRoot,
487
+ uri: census.censusURI,
488
+ size: census.size
489
+ };
490
+ }
491
+ }
492
+
218
493
  function createProcessSignatureMessage(processId) {
219
494
  const cleanProcessId = processId.replace(/^0x/, "").toLowerCase();
220
495
  return `I am creating a new voting process for the davinci.vote protocol identified with id ${cleanProcessId}`;
@@ -305,11 +580,15 @@ class VocdoniSequencerService extends BaseService {
305
580
  try {
306
581
  const response = await fetch(hashOrUrl);
307
582
  if (!response.ok) {
308
- throw new Error(`Failed to fetch metadata from URL: ${response.status} ${response.statusText}`);
583
+ throw new Error(
584
+ `Failed to fetch metadata from URL: ${response.status} ${response.statusText}`
585
+ );
309
586
  }
310
587
  return await response.json();
311
588
  } catch (error) {
312
- throw new Error(`Failed to fetch metadata from URL: ${error instanceof Error ? error.message : "Unknown error"}`);
589
+ throw new Error(
590
+ `Failed to fetch metadata from URL: ${error instanceof Error ? error.message : "Unknown error"}`
591
+ );
313
592
  }
314
593
  }
315
594
  if (!isHexString(hashOrUrl)) {
@@ -345,101 +624,6 @@ class VocdoniApiService {
345
624
  }
346
625
  }
347
626
 
348
- const DEFAULT_ENVIRONMENT_URLS = {
349
- dev: {
350
- sequencer: "https://sequencer-dev.davinci.vote",
351
- census: "https://c3-dev.davinci.vote",
352
- chain: "sepolia"
353
- },
354
- stg: {
355
- sequencer: "https://sequencer1.davinci.vote",
356
- census: "https://c3.davinci.vote",
357
- chain: "sepolia"
358
- },
359
- prod: {
360
- // TODO: Add production URLs when available
361
- sequencer: "",
362
- census: "",
363
- chain: "mainnet"
364
- }
365
- };
366
- function getEnvironmentConfig(environment) {
367
- return DEFAULT_ENVIRONMENT_URLS[environment];
368
- }
369
- function getEnvironmentUrls(environment) {
370
- const config = DEFAULT_ENVIRONMENT_URLS[environment];
371
- return {
372
- sequencer: config.sequencer,
373
- census: config.census
374
- };
375
- }
376
- function getEnvironmentChain(environment) {
377
- return DEFAULT_ENVIRONMENT_URLS[environment].chain;
378
- }
379
- function resolveConfiguration(options = {}) {
380
- const environment = options.environment || "prod";
381
- const defaultConfig = getEnvironmentConfig(environment);
382
- const resolvedConfig = { ...defaultConfig };
383
- if (options.customUrls) {
384
- if (options.customUrls.sequencer !== void 0) {
385
- resolvedConfig.sequencer = options.customUrls.sequencer;
386
- }
387
- if (options.customUrls.census !== void 0) {
388
- resolvedConfig.census = options.customUrls.census;
389
- }
390
- }
391
- if (options.customChain) {
392
- resolvedConfig.chain = options.customChain;
393
- }
394
- return resolvedConfig;
395
- }
396
- function resolveUrls(options = {}) {
397
- const config = resolveConfiguration(options);
398
- return {
399
- sequencer: config.sequencer,
400
- census: config.census
401
- };
402
- }
403
-
404
- var processRegistry = {
405
- sepolia: "0x50CA6A350f3A9C7B8a82eE7a4D5F0f21C54D68e3",
406
- uzh: "0x69B16f67Bd2fB18bD720379E9C1Ef5EaD3872d67",
407
- mainnet: "0x0",
408
- celo: "0xDda6c75d32c375946C8ae9be41B2F3539dB1118A"
409
- };
410
- var organizationRegistry = {
411
- sepolia: "0xF30678f579Fd89b86295503dC179d5d3aed47a98",
412
- uzh: "0xf7BCE4546805547bE526Ca864d6722Ed193E51Aa",
413
- mainnet: "0x0",
414
- celo: "0xE17D701EA8f34022F97fC2Ec68c73D42bF99D0BD"
415
- };
416
- var stateTransitionVerifierGroth16 = {
417
- sepolia: "0x96EcBbD6aB5fDC063E0fC426F2700290DeeAFE4E",
418
- uzh: "0x5e4673CD378F05cc3Ae25804539c91E711548741",
419
- mainnet: "0x0",
420
- celo: "0x2DaF913D423128258b2F378E320F9D9D3Be5eCf5"
421
- };
422
- var resultsVerifierGroth16 = {
423
- sepolia: "0x3ab37C40f7d0649f7a15BA3230f14AB29B51eDCC",
424
- uzh: "0x00c7F87731346F592197E49A90Ad6EC236Ad9985",
425
- mainnet: "0x0",
426
- celo: "0x808276962217AD1ED3af7D51bFc791903CAd9389"
427
- };
428
- var sequencerRegistry = {
429
- sepolia: "0x0",
430
- uzh: "0x0",
431
- mainnet: "0x0",
432
- celo: "0x0"
433
- };
434
- var addressesJson = {
435
- processRegistry: processRegistry,
436
- organizationRegistry: organizationRegistry,
437
- stateTransitionVerifierGroth16: stateTransitionVerifierGroth16,
438
- resultsVerifierGroth16: resultsVerifierGroth16,
439
- sequencerRegistry: sequencerRegistry
440
- };
441
-
442
- const deployedAddresses = addressesJson;
443
627
  var TxStatus = /* @__PURE__ */ ((TxStatus2) => {
444
628
  TxStatus2["Pending"] = "pending";
445
629
  TxStatus2["Completed"] = "completed";
@@ -458,19 +642,19 @@ class SmartContractService {
458
642
  * Sends a transaction and yields status events during its lifecycle.
459
643
  * This method handles the complete transaction flow from submission to completion,
460
644
  * including error handling and status updates.
461
- *
645
+ *
462
646
  * @template T - The type of the successful response data
463
647
  * @param txPromise - Promise resolving to the transaction response
464
648
  * @param responseHandler - Function to process the successful transaction result
465
649
  * @returns AsyncGenerator yielding transaction status events
466
- *
650
+ *
467
651
  * @example
468
652
  * ```typescript
469
653
  * const txStream = await this.sendTx(
470
654
  * contract.someMethod(),
471
655
  * async () => await contract.getUpdatedValue()
472
656
  * );
473
- *
657
+ *
474
658
  * for await (const event of txStream) {
475
659
  * switch (event.status) {
476
660
  * case TxStatus.Pending:
@@ -507,12 +691,12 @@ class SmartContractService {
507
691
  * Executes a transaction stream and returns the result or throws an error.
508
692
  * This is a convenience method that processes a transaction stream and either
509
693
  * returns the successful result or throws an appropriate error.
510
- *
694
+ *
511
695
  * @template T - The type of the successful response data
512
696
  * @param stream - AsyncGenerator of transaction status events
513
697
  * @returns Promise resolving to the successful response data
514
698
  * @throws Error if the transaction fails or reverts
515
- *
699
+ *
516
700
  * @example
517
701
  * ```typescript
518
702
  * try {
@@ -542,11 +726,11 @@ class SmartContractService {
542
726
  * Normalizes event listener arguments between different ethers.js versions.
543
727
  * This helper method ensures consistent event argument handling regardless of
544
728
  * whether the event payload follows ethers v5 or v6 format.
545
- *
729
+ *
546
730
  * @template Args - Tuple type representing the expected event arguments
547
731
  * @param callback - The event callback function to normalize
548
732
  * @returns Normalized event listener function
549
- *
733
+ *
550
734
  * @example
551
735
  * ```typescript
552
736
  * contract.on('Transfer', this.normalizeListener((from: string, to: string, amount: BigInt) => {
@@ -569,12 +753,12 @@ class SmartContractService {
569
753
  * Sets up an event listener with automatic fallback for RPCs that don't support eth_newFilter.
570
754
  * First attempts to use contract.on() which relies on eth_newFilter. If the RPC doesn't support
571
755
  * this method (error code -32601), automatically falls back to polling with queryFilter.
572
- *
756
+ *
573
757
  * @template Args - Tuple type representing the event arguments
574
758
  * @param contract - The contract instance to listen to
575
759
  * @param eventFilter - The event filter to listen for
576
760
  * @param callback - The callback function to invoke when the event occurs
577
- *
761
+ *
578
762
  * @example
579
763
  * ```typescript
580
764
  * this.setupEventListener(
@@ -600,13 +784,14 @@ class SmartContractService {
600
784
  };
601
785
  if ("send" in provider && typeof provider.send === "function") {
602
786
  try {
603
- await provider.send("eth_newFilter", [testFilter]);
787
+ const filterId = await provider.send("eth_newFilter", [testFilter]);
788
+ await provider.send("eth_getFilterChanges", [filterId]);
604
789
  contract.on(eventFilter, normalizedCallback);
605
790
  return;
606
791
  } catch (error) {
607
792
  if (this.isUnsupportedMethodError(error)) {
608
793
  console.warn(
609
- "RPC does not support eth_newFilter, falling back to polling for events. This may result in delayed event notifications."
794
+ "RPC does not fully support eth_newFilter/eth_getFilterChanges, falling back to polling for events. This may result in delayed event notifications."
610
795
  );
611
796
  this.setupPollingListener(contract, eventFilter, callback);
612
797
  return;
@@ -631,18 +816,23 @@ class SmartContractService {
631
816
  }
632
817
  }
633
818
  /**
634
- * Checks if an error indicates that the RPC method is unsupported (eth_newFilter).
635
- *
819
+ * Checks if an error indicates that the RPC method is unsupported or filter operations are not working.
820
+ * This includes:
821
+ * - Method not found (-32601): RPC doesn't support eth_newFilter
822
+ * - Filter not found (-32000): RPC doesn't properly maintain filters
823
+ *
636
824
  * @param error - The error to check
637
- * @returns true if the error indicates unsupported method
825
+ * @returns true if the error indicates unsupported or broken filter functionality
638
826
  */
639
827
  isUnsupportedMethodError(error) {
640
- return error?.code === -32601 || error?.error?.code === -32601 || error?.data?.code === -32601 || typeof error?.message === "string" && error.message.includes("unsupported method");
828
+ const isMethodNotFound = error?.code === -32601 || error?.error?.code === -32601 || error?.data?.code === -32601 || typeof error?.message === "string" && error.message.includes("unsupported method");
829
+ const isFilterNotFound = (error?.code === -32e3 || error?.error?.code === -32e3 || error?.code === "UNKNOWN_ERROR" && error?.error?.code === -32e3) && (error?.message?.includes("filter not found") || error?.error?.message?.includes("filter not found"));
830
+ return isMethodNotFound || isFilterNotFound;
641
831
  }
642
832
  /**
643
833
  * Sets up a polling-based event listener as fallback when eth_newFilter is not supported.
644
834
  * Periodically queries for new events and invokes the callback for each new event found.
645
- *
835
+ *
646
836
  * @template Args - Tuple type representing the event arguments
647
837
  * @param contract - The contract instance to poll
648
838
  * @param eventFilter - The event filter to poll for
@@ -694,7 +884,7 @@ class SmartContractService {
694
884
  }
695
885
  /**
696
886
  * Sets the polling interval for event listeners using the fallback mechanism.
697
- *
887
+ *
698
888
  * @param intervalMs - Polling interval in milliseconds
699
889
  */
700
890
  setEventPollingInterval(intervalMs) {
@@ -705,7 +895,7 @@ class SmartContractService {
705
895
  class ContractServiceError extends Error {
706
896
  /**
707
897
  * Creates a new ContractServiceError instance.
708
- *
898
+ *
709
899
  * @param message - The error message describing what went wrong
710
900
  * @param operation - The operation that was being performed when the error occurred
711
901
  */
@@ -858,7 +1048,7 @@ class ProcessRegistryService extends SmartContractService {
858
1048
  }
859
1049
  /**
860
1050
  * Sets the results for a voting process.
861
- *
1051
+ *
862
1052
  * @param processID - The ID of the process to set results for
863
1053
  * @param proof - Zero-knowledge proof validating the results
864
1054
  * @param input - Input data for the proof verification
@@ -866,11 +1056,7 @@ class ProcessRegistryService extends SmartContractService {
866
1056
  */
867
1057
  setProcessResults(processID, proof, input) {
868
1058
  return this.sendTx(
869
- this.contract.setProcessResults(
870
- processID,
871
- proof,
872
- input
873
- ).catch((e) => {
1059
+ this.contract.setProcessResults(processID, proof, input).catch((e) => {
874
1060
  throw new ProcessResultError(e.message, "setResults");
875
1061
  }),
876
1062
  async () => ({ success: true })
@@ -932,6 +1118,34 @@ class ProcessOrchestrationService {
932
1118
  this.organizationRegistry = organizationRegistry;
933
1119
  this.getCrypto = getCrypto;
934
1120
  this.signer = signer;
1121
+ this.censusOrchestrator = new CensusOrchestrator(apiService.census);
1122
+ }
1123
+ /**
1124
+ * Handles census - auto-publishes if needed and returns census config
1125
+ * @private
1126
+ */
1127
+ async handleCensus(census) {
1128
+ if ("isPublished" in census) {
1129
+ if (census instanceof PlainCensus || census instanceof WeightedCensus) {
1130
+ if (!census.isPublished) {
1131
+ const censusBaseURL = this.apiService.census?.["axios"]?.defaults?.baseURL;
1132
+ if (!censusBaseURL || censusBaseURL === "" || censusBaseURL === "undefined") {
1133
+ throw new Error(
1134
+ 'Census API URL is required to publish PlainCensus or WeightedCensus. Please provide "censusUrl" when initializing DavinciSDK, or use a pre-published census.'
1135
+ );
1136
+ }
1137
+ await this.censusOrchestrator.publish(census);
1138
+ }
1139
+ }
1140
+ const censusData = this.censusOrchestrator.getCensusData(census);
1141
+ return {
1142
+ type: censusData.type,
1143
+ root: censusData.root,
1144
+ size: censusData.size,
1145
+ uri: censusData.uri
1146
+ };
1147
+ }
1148
+ return census;
935
1149
  }
936
1150
  /**
937
1151
  * Gets user-friendly process information by transforming raw contract data
@@ -1007,10 +1221,10 @@ class ProcessOrchestrationService {
1007
1221
  /**
1008
1222
  * Creates a complete voting process and returns an async generator that yields transaction status events.
1009
1223
  * This method allows you to monitor the transaction progress in real-time.
1010
- *
1224
+ *
1011
1225
  * @param config - Process configuration
1012
1226
  * @returns AsyncGenerator yielding transaction status events with ProcessCreationResult
1013
- *
1227
+ *
1014
1228
  * @example
1015
1229
  * ```typescript
1016
1230
  * const stream = sdk.createProcessStream({
@@ -1021,7 +1235,7 @@ class ProcessOrchestrationService {
1021
1235
  * timing: { ... },
1022
1236
  * questions: [ ... ]
1023
1237
  * });
1024
- *
1238
+ *
1025
1239
  * for await (const event of stream) {
1026
1240
  * switch (event.status) {
1027
1241
  * case "pending":
@@ -1083,16 +1297,16 @@ class ProcessOrchestrationService {
1083
1297
  /**
1084
1298
  * Creates a complete voting process with minimal configuration.
1085
1299
  * This is the ultra-easy method for end users that handles all the complex orchestration internally.
1086
- *
1300
+ *
1087
1301
  * For real-time transaction status updates, use createProcessStream() instead.
1088
- *
1302
+ *
1089
1303
  * The method automatically:
1090
1304
  * - Gets encryption keys and initial state root from the sequencer
1091
1305
  * - Handles process creation signatures
1092
1306
  * - Coordinates between sequencer API and on-chain contract calls
1093
1307
  * - Creates and pushes metadata
1094
1308
  * - Submits the on-chain transaction
1095
- *
1309
+ *
1096
1310
  * @param config - Simplified process configuration
1097
1311
  * @returns Promise resolving to the process creation result
1098
1312
  */
@@ -1116,7 +1330,8 @@ class ProcessOrchestrationService {
1116
1330
  const { startTime, duration } = this.calculateTiming(config.timing);
1117
1331
  const signerAddress = await this.signer.getAddress();
1118
1332
  const processId = await this.processRegistry.getNextProcessId(signerAddress);
1119
- const censusRoot = config.census.root;
1333
+ const censusConfig = await this.handleCensus(config.census);
1334
+ const censusRoot = censusConfig.root;
1120
1335
  const ballotMode = config.ballot;
1121
1336
  const metadata = this.createMetadata(config);
1122
1337
  const metadataHash = await this.apiService.sequencer.pushMetadata(metadata);
@@ -1127,13 +1342,13 @@ class ProcessOrchestrationService {
1127
1342
  censusRoot,
1128
1343
  ballotMode,
1129
1344
  signature,
1130
- censusOrigin: config.census.type
1345
+ censusOrigin: censusConfig.type
1131
1346
  });
1132
1347
  const census = {
1133
- censusOrigin: config.census.type,
1134
- maxVotes: config.census.size.toString(),
1348
+ censusOrigin: censusConfig.type,
1349
+ maxVotes: censusConfig.size.toString(),
1135
1350
  censusRoot,
1136
- censusURI: config.census.uri
1351
+ censusURI: censusConfig.uri
1137
1352
  };
1138
1353
  return {
1139
1354
  processId,
@@ -1224,14 +1439,14 @@ class ProcessOrchestrationService {
1224
1439
  /**
1225
1440
  * Ends a voting process by setting its status to ENDED.
1226
1441
  * Returns an async generator that yields transaction status events.
1227
- *
1442
+ *
1228
1443
  * @param processId - The process ID to end
1229
1444
  * @returns AsyncGenerator yielding transaction status events
1230
- *
1445
+ *
1231
1446
  * @example
1232
1447
  * ```typescript
1233
1448
  * const stream = sdk.endProcessStream("0x1234567890abcdef...");
1234
- *
1449
+ *
1235
1450
  * for await (const event of stream) {
1236
1451
  * switch (event.status) {
1237
1452
  * case "pending":
@@ -1273,12 +1488,12 @@ class ProcessOrchestrationService {
1273
1488
  /**
1274
1489
  * Ends a voting process by setting its status to ENDED.
1275
1490
  * This is a simplified method that waits for transaction completion.
1276
- *
1491
+ *
1277
1492
  * For real-time transaction status updates, use endProcessStream() instead.
1278
- *
1493
+ *
1279
1494
  * @param processId - The process ID to end
1280
1495
  * @returns Promise resolving when the process is ended
1281
- *
1496
+ *
1282
1497
  * @example
1283
1498
  * ```typescript
1284
1499
  * await sdk.endProcess("0x1234567890abcdef...");
@@ -1300,14 +1515,14 @@ class ProcessOrchestrationService {
1300
1515
  /**
1301
1516
  * Pauses a voting process by setting its status to PAUSED.
1302
1517
  * Returns an async generator that yields transaction status events.
1303
- *
1518
+ *
1304
1519
  * @param processId - The process ID to pause
1305
1520
  * @returns AsyncGenerator yielding transaction status events
1306
- *
1521
+ *
1307
1522
  * @example
1308
1523
  * ```typescript
1309
1524
  * const stream = sdk.pauseProcessStream("0x1234567890abcdef...");
1310
- *
1525
+ *
1311
1526
  * for await (const event of stream) {
1312
1527
  * switch (event.status) {
1313
1528
  * case "pending":
@@ -1349,12 +1564,12 @@ class ProcessOrchestrationService {
1349
1564
  /**
1350
1565
  * Pauses a voting process by setting its status to PAUSED.
1351
1566
  * This is a simplified method that waits for transaction completion.
1352
- *
1567
+ *
1353
1568
  * For real-time transaction status updates, use pauseProcessStream() instead.
1354
- *
1569
+ *
1355
1570
  * @param processId - The process ID to pause
1356
1571
  * @returns Promise resolving when the process is paused
1357
- *
1572
+ *
1358
1573
  * @example
1359
1574
  * ```typescript
1360
1575
  * await sdk.pauseProcess("0x1234567890abcdef...");
@@ -1376,14 +1591,14 @@ class ProcessOrchestrationService {
1376
1591
  /**
1377
1592
  * Cancels a voting process by setting its status to CANCELED.
1378
1593
  * Returns an async generator that yields transaction status events.
1379
- *
1594
+ *
1380
1595
  * @param processId - The process ID to cancel
1381
1596
  * @returns AsyncGenerator yielding transaction status events
1382
- *
1597
+ *
1383
1598
  * @example
1384
1599
  * ```typescript
1385
1600
  * const stream = sdk.cancelProcessStream("0x1234567890abcdef...");
1386
- *
1601
+ *
1387
1602
  * for await (const event of stream) {
1388
1603
  * switch (event.status) {
1389
1604
  * case "pending":
@@ -1425,12 +1640,12 @@ class ProcessOrchestrationService {
1425
1640
  /**
1426
1641
  * Cancels a voting process by setting its status to CANCELED.
1427
1642
  * This is a simplified method that waits for transaction completion.
1428
- *
1643
+ *
1429
1644
  * For real-time transaction status updates, use cancelProcessStream() instead.
1430
- *
1645
+ *
1431
1646
  * @param processId - The process ID to cancel
1432
1647
  * @returns Promise resolving when the process is canceled
1433
- *
1648
+ *
1434
1649
  * @example
1435
1650
  * ```typescript
1436
1651
  * await sdk.cancelProcess("0x1234567890abcdef...");
@@ -1453,14 +1668,14 @@ class ProcessOrchestrationService {
1453
1668
  * Resumes a voting process by setting its status to READY.
1454
1669
  * This is typically used to resume a paused process.
1455
1670
  * Returns an async generator that yields transaction status events.
1456
- *
1671
+ *
1457
1672
  * @param processId - The process ID to resume
1458
1673
  * @returns AsyncGenerator yielding transaction status events
1459
- *
1674
+ *
1460
1675
  * @example
1461
1676
  * ```typescript
1462
1677
  * const stream = sdk.resumeProcessStream("0x1234567890abcdef...");
1463
- *
1678
+ *
1464
1679
  * for await (const event of stream) {
1465
1680
  * switch (event.status) {
1466
1681
  * case "pending":
@@ -1503,12 +1718,12 @@ class ProcessOrchestrationService {
1503
1718
  * Resumes a voting process by setting its status to READY.
1504
1719
  * This is typically used to resume a paused process.
1505
1720
  * This is a simplified method that waits for transaction completion.
1506
- *
1721
+ *
1507
1722
  * For real-time transaction status updates, use resumeProcessStream() instead.
1508
- *
1723
+ *
1509
1724
  * @param processId - The process ID to resume
1510
1725
  * @returns Promise resolving when the process is resumed
1511
- *
1726
+ *
1512
1727
  * @example
1513
1728
  * ```typescript
1514
1729
  * await sdk.resumeProcess("0x1234567890abcdef...");
@@ -1596,11 +1811,7 @@ class CircomProof {
1596
1811
  }
1597
1812
  this.zkeyCache.set(zkeyUrl, zkeyBin);
1598
1813
  }
1599
- const { proof, publicSignals } = await snarkjs.groth16.fullProve(
1600
- inputs,
1601
- wasmBin,
1602
- zkeyBin
1603
- );
1814
+ const { proof, publicSignals } = await snarkjs.groth16.fullProve(inputs, wasmBin, zkeyBin);
1604
1815
  return {
1605
1816
  proof,
1606
1817
  publicSignals
@@ -1635,11 +1846,13 @@ var VoteStatus = /* @__PURE__ */ ((VoteStatus2) => {
1635
1846
  })(VoteStatus || {});
1636
1847
 
1637
1848
  class VoteOrchestrationService {
1638
- constructor(apiService, getCrypto, signer, censusProviders = {}) {
1849
+ constructor(apiService, getCrypto, signer, censusProviders = {}, config = {}) {
1639
1850
  this.apiService = apiService;
1640
1851
  this.getCrypto = getCrypto;
1641
1852
  this.signer = signer;
1642
1853
  this.censusProviders = censusProviders;
1854
+ this.verifyCircuitFiles = config.verifyCircuitFiles ?? true;
1855
+ this.verifyProof = config.verifyProof ?? true;
1643
1856
  }
1644
1857
  /**
1645
1858
  * Submit a vote with simplified configuration
@@ -1648,7 +1861,7 @@ class VoteOrchestrationService {
1648
1861
  * - Gets census proof (Merkle or CSP)
1649
1862
  * - Generates cryptographic proofs
1650
1863
  * - Signs and submits the vote
1651
- *
1864
+ *
1652
1865
  * @param config - Simplified vote configuration
1653
1866
  * @returns Promise resolving to vote submission result
1654
1867
  */
@@ -1696,7 +1909,7 @@ class VoteOrchestrationService {
1696
1909
  }
1697
1910
  /**
1698
1911
  * Get the status of a submitted vote
1699
- *
1912
+ *
1700
1913
  * @param processId - The process ID
1701
1914
  * @param voteId - The vote ID
1702
1915
  * @returns Promise resolving to vote status information
@@ -1711,7 +1924,7 @@ class VoteOrchestrationService {
1711
1924
  }
1712
1925
  /**
1713
1926
  * Check if an address has voted in a process
1714
- *
1927
+ *
1715
1928
  * @param processId - The process ID
1716
1929
  * @param address - The voter's address
1717
1930
  * @returns Promise resolving to boolean indicating if the address has voted
@@ -1722,19 +1935,19 @@ class VoteOrchestrationService {
1722
1935
  /**
1723
1936
  * Watch vote status changes in real-time using an async generator.
1724
1937
  * Yields each status change as it happens, allowing for reactive UI updates.
1725
- *
1938
+ *
1726
1939
  * @param processId - The process ID
1727
1940
  * @param voteId - The vote ID
1728
1941
  * @param options - Optional configuration
1729
1942
  * @returns AsyncGenerator yielding vote status updates
1730
- *
1943
+ *
1731
1944
  * @example
1732
1945
  * ```typescript
1733
1946
  * const vote = await sdk.submitVote({ processId, choices: [1] });
1734
- *
1947
+ *
1735
1948
  * for await (const statusInfo of sdk.watchVoteStatus(vote.processId, vote.voteId)) {
1736
1949
  * console.log(`Vote status: ${statusInfo.status}`);
1737
- *
1950
+ *
1738
1951
  * switch (statusInfo.status) {
1739
1952
  * case VoteStatus.Pending:
1740
1953
  * console.log("⏳ Processing...");
@@ -1771,7 +1984,7 @@ class VoteOrchestrationService {
1771
1984
  /**
1772
1985
  * Wait for a vote to reach a specific status.
1773
1986
  * This is a simpler alternative to watchVoteStatus() that returns only the final status.
1774
- *
1987
+ *
1775
1988
  * @param processId - The process ID
1776
1989
  * @param voteId - The vote ID
1777
1990
  * @param targetStatus - The target status to wait for (default: "settled")
@@ -1874,12 +2087,20 @@ class VoteOrchestrationService {
1874
2087
  const circomProof = new CircomProof({
1875
2088
  wasmUrl: info.circuitUrl,
1876
2089
  zkeyUrl: info.provingKeyUrl,
1877
- vkeyUrl: info.verificationKeyUrl
2090
+ vkeyUrl: info.verificationKeyUrl,
2091
+ // Only pass hashes if verifyCircuitFiles is enabled
2092
+ ...this.verifyCircuitFiles && {
2093
+ wasmHash: info.circuitHash,
2094
+ zkeyHash: info.provingKeyHash,
2095
+ vkeyHash: info.verificationKeyHash
2096
+ }
1878
2097
  });
1879
2098
  const { proof, publicSignals } = await circomProof.generate(circomInputs);
1880
- const isValid = await circomProof.verify(proof, publicSignals);
1881
- if (!isValid) {
1882
- throw new Error("Generated proof is invalid");
2099
+ if (this.verifyProof) {
2100
+ const isValid = await circomProof.verify(proof, publicSignals);
2101
+ if (!isValid) {
2102
+ throw new Error("Generated proof is invalid");
2103
+ }
1883
2104
  }
1884
2105
  return { proof, publicSignals };
1885
2106
  }
@@ -1917,10 +2138,7 @@ class VoteOrchestrationService {
1917
2138
  class OrganizationRegistryService extends SmartContractService {
1918
2139
  constructor(contractAddress, runner) {
1919
2140
  super();
1920
- this.contract = davinciContracts.OrganizationRegistry__factory.connect(
1921
- contractAddress,
1922
- runner
1923
- );
2141
+ this.contract = davinciContracts.OrganizationRegistry__factory.connect(contractAddress, runner);
1924
2142
  }
1925
2143
  // ─── READ OPERATIONS ───────────────────────────────────────────────────────
1926
2144
  async getOrganization(id) {
@@ -2196,25 +2414,23 @@ class DavinciCrypto {
2196
2414
  class DavinciSDK {
2197
2415
  constructor(config) {
2198
2416
  this.initialized = false;
2199
- const resolvedConfig = resolveConfiguration({
2200
- environment: config.environment,
2201
- customUrls: {
2202
- sequencer: config.sequencerUrl,
2203
- census: config.censusUrl
2204
- },
2205
- customChain: config.chain
2206
- });
2417
+ const hasCustomAddresses = !!config.addresses && Object.keys(config.addresses).length > 0;
2207
2418
  this.config = {
2208
2419
  signer: config.signer,
2209
- sequencerUrl: config.sequencerUrl ?? resolvedConfig.sequencer,
2210
- censusUrl: config.censusUrl ?? resolvedConfig.census,
2211
- chain: config.chain ?? resolvedConfig.chain,
2212
- contractAddresses: config.contractAddresses || {},
2213
- useSequencerAddresses: config.useSequencerAddresses || false
2420
+ sequencerUrl: config.sequencerUrl,
2421
+ censusUrl: config.censusUrl,
2422
+ customAddresses: config.addresses || {},
2423
+ fetchAddressesFromSequencer: !hasCustomAddresses,
2424
+ // Automatic: fetch if no custom addresses
2425
+ verifyCircuitFiles: config.verifyCircuitFiles ?? true,
2426
+ // Default to true for security
2427
+ verifyProof: config.verifyProof ?? true
2428
+ // Default to true for security
2214
2429
  };
2215
2430
  this.apiService = new VocdoniApiService({
2216
2431
  sequencerURL: this.config.sequencerUrl,
2217
- censusURL: this.config.censusUrl
2432
+ censusURL: this.config.censusUrl || ""
2433
+ // Use empty string if not provided
2218
2434
  });
2219
2435
  this.censusProviders = config.censusProviders || {};
2220
2436
  }
@@ -2224,9 +2440,10 @@ class DavinciSDK {
2224
2440
  */
2225
2441
  async init() {
2226
2442
  if (this.initialized) return;
2227
- if (this.config.useSequencerAddresses) {
2228
- await this.updateContractAddressesFromSequencer();
2443
+ if (this.config.fetchAddressesFromSequencer) {
2444
+ await this.fetchContractAddressesFromSequencer();
2229
2445
  }
2446
+ if (!this.config.censusUrl) ;
2230
2447
  this.initialized = true;
2231
2448
  }
2232
2449
  /**
@@ -2238,28 +2455,34 @@ class DavinciSDK {
2238
2455
  /**
2239
2456
  * Get the process registry service for process management.
2240
2457
  * Requires a signer with a provider for blockchain interactions.
2241
- *
2458
+ *
2242
2459
  * @throws Error if signer does not have a provider
2243
2460
  */
2244
2461
  get processes() {
2245
2462
  this.ensureProvider();
2246
2463
  if (!this._processRegistry) {
2247
2464
  const processRegistryAddress = this.resolveContractAddress("processRegistry");
2248
- this._processRegistry = new ProcessRegistryService(processRegistryAddress, this.config.signer);
2465
+ this._processRegistry = new ProcessRegistryService(
2466
+ processRegistryAddress,
2467
+ this.config.signer
2468
+ );
2249
2469
  }
2250
2470
  return this._processRegistry;
2251
2471
  }
2252
2472
  /**
2253
2473
  * Get the organization registry service for organization management.
2254
2474
  * Requires a signer with a provider for blockchain interactions.
2255
- *
2475
+ *
2256
2476
  * @throws Error if signer does not have a provider
2257
2477
  */
2258
2478
  get organizations() {
2259
2479
  this.ensureProvider();
2260
2480
  if (!this._organizationRegistry) {
2261
2481
  const organizationRegistryAddress = this.resolveContractAddress("organizationRegistry");
2262
- this._organizationRegistry = new OrganizationRegistryService(organizationRegistryAddress, this.config.signer);
2482
+ this._organizationRegistry = new OrganizationRegistryService(
2483
+ organizationRegistryAddress,
2484
+ this.config.signer
2485
+ );
2263
2486
  }
2264
2487
  return this._organizationRegistry;
2265
2488
  }
@@ -2280,7 +2503,7 @@ class DavinciSDK {
2280
2503
  /**
2281
2504
  * Get the process orchestration service for simplified process creation.
2282
2505
  * Requires a signer with a provider for blockchain interactions.
2283
- *
2506
+ *
2284
2507
  * @throws Error if signer does not have a provider
2285
2508
  */
2286
2509
  get processOrchestrator() {
@@ -2305,7 +2528,11 @@ class DavinciSDK {
2305
2528
  this.apiService,
2306
2529
  () => this.getCrypto(),
2307
2530
  this.config.signer,
2308
- this.censusProviders
2531
+ this.censusProviders,
2532
+ {
2533
+ verifyCircuitFiles: this.config.verifyCircuitFiles,
2534
+ verifyProof: this.config.verifyProof
2535
+ }
2309
2536
  );
2310
2537
  }
2311
2538
  return this._voteOrchestrator;
@@ -2314,24 +2541,24 @@ class DavinciSDK {
2314
2541
  * Gets user-friendly process information from the blockchain.
2315
2542
  * This method fetches raw contract data and transforms it into a user-friendly format
2316
2543
  * that matches the ProcessConfig interface used for creation, plus additional runtime data.
2317
- *
2544
+ *
2318
2545
  * Requires a signer with a provider for blockchain interactions.
2319
- *
2546
+ *
2320
2547
  * @param processId - The process ID to fetch
2321
2548
  * @returns Promise resolving to user-friendly process information
2322
2549
  * @throws Error if signer does not have a provider
2323
- *
2550
+ *
2324
2551
  * @example
2325
2552
  * ```typescript
2326
2553
  * const processInfo = await sdk.getProcess("0x1234567890abcdef...");
2327
- *
2554
+ *
2328
2555
  * // Access the same fields as ProcessConfig
2329
2556
  * console.log("Title:", processInfo.title);
2330
2557
  * console.log("Description:", processInfo.description);
2331
2558
  * console.log("Questions:", processInfo.questions);
2332
2559
  * console.log("Census size:", processInfo.census.size);
2333
2560
  * console.log("Ballot config:", processInfo.ballot);
2334
- *
2561
+ *
2335
2562
  * // Plus additional runtime information
2336
2563
  * console.log("Status:", processInfo.status);
2337
2564
  * console.log("Creator:", processInfo.creator);
@@ -2339,7 +2566,7 @@ class DavinciSDK {
2339
2566
  * console.log("End date:", processInfo.endDate);
2340
2567
  * console.log("Duration:", processInfo.duration, "seconds");
2341
2568
  * console.log("Time remaining:", processInfo.timeRemaining, "seconds");
2342
- *
2569
+ *
2343
2570
  * // Access raw contract data if needed
2344
2571
  * console.log("Raw data:", processInfo.raw);
2345
2572
  * ```
@@ -2355,13 +2582,13 @@ class DavinciSDK {
2355
2582
  * Creates a complete voting process and returns an async generator that yields transaction status events.
2356
2583
  * This method allows you to monitor the transaction progress in real-time, including pending, completed,
2357
2584
  * failed, and reverted states.
2358
- *
2585
+ *
2359
2586
  * Requires a signer with a provider for blockchain interactions.
2360
- *
2587
+ *
2361
2588
  * @param config - Simplified process configuration
2362
2589
  * @returns AsyncGenerator yielding transaction status events
2363
2590
  * @throws Error if signer does not have a provider
2364
- *
2591
+ *
2365
2592
  * @example
2366
2593
  * ```typescript
2367
2594
  * const stream = sdk.createProcessStream({
@@ -2397,7 +2624,7 @@ class DavinciSDK {
2397
2624
  * }
2398
2625
  * ]
2399
2626
  * });
2400
- *
2627
+ *
2401
2628
  * // Monitor transaction progress
2402
2629
  * for await (const event of stream) {
2403
2630
  * switch (event.status) {
@@ -2432,22 +2659,22 @@ class DavinciSDK {
2432
2659
  /**
2433
2660
  * Creates a complete voting process with minimal configuration.
2434
2661
  * This is the ultra-easy method for end users that handles all the complex orchestration internally.
2435
- *
2662
+ *
2436
2663
  * For real-time transaction status updates, use createProcessStream() instead.
2437
- *
2664
+ *
2438
2665
  * Requires a signer with a provider for blockchain interactions.
2439
- *
2666
+ *
2440
2667
  * The method automatically:
2441
2668
  * - Gets encryption keys and initial state root from the sequencer
2442
2669
  * - Handles process creation signatures
2443
2670
  * - Coordinates between sequencer API and on-chain contract calls
2444
2671
  * - Creates and pushes metadata
2445
2672
  * - Submits the on-chain transaction
2446
- *
2673
+ *
2447
2674
  * @param config - Simplified process configuration
2448
2675
  * @returns Promise resolving to the process creation result
2449
2676
  * @throws Error if signer does not have a provider
2450
- *
2677
+ *
2451
2678
  * @example
2452
2679
  * ```typescript
2453
2680
  * // Option 1: Using duration (traditional approach)
@@ -2484,7 +2711,7 @@ class DavinciSDK {
2484
2711
  * }
2485
2712
  * ]
2486
2713
  * });
2487
- *
2714
+ *
2488
2715
  * // Option 2: Using start and end dates
2489
2716
  * const result2 = await sdk.createProcess({
2490
2717
  * title: "Weekend Vote",
@@ -2505,18 +2732,20 @@ class DavinciSDK {
2505
2732
  /**
2506
2733
  * Submit a vote with simplified configuration.
2507
2734
  * This is the ultra-easy method for end users that handles all the complex voting workflow internally.
2508
- *
2735
+ *
2509
2736
  * Does NOT require a provider - can be used with a bare Wallet for signing only.
2510
- *
2737
+ * IMPORTANT: Requires censusUrl to be configured in the SDK for fetching census proofs (unless using custom census providers).
2738
+ *
2511
2739
  * The method automatically:
2512
2740
  * - Fetches process information and validates voting is allowed
2513
2741
  * - Gets census proof (Merkle tree based)
2514
2742
  * - Generates cryptographic proofs and encrypts the vote
2515
2743
  * - Signs and submits the vote to the sequencer
2516
- *
2744
+ *
2517
2745
  * @param config - Simplified vote configuration
2518
2746
  * @returns Promise resolving to vote submission result
2519
- *
2747
+ * @throws Error if censusUrl is not configured (unless using custom census providers)
2748
+ *
2520
2749
  * @example
2521
2750
  * ```typescript
2522
2751
  * // Submit a vote with voter's private key
@@ -2525,14 +2754,14 @@ class DavinciSDK {
2525
2754
  * choices: [1, 0], // Vote for option 1 in question 1, option 0 in question 2
2526
2755
  * voterKey: "0x1234567890abcdef..." // Voter's private key
2527
2756
  * });
2528
- *
2757
+ *
2529
2758
  * console.log("Vote ID:", voteResult.voteId);
2530
2759
  * console.log("Status:", voteResult.status);
2531
- *
2760
+ *
2532
2761
  * // Submit a vote with a Wallet instance
2533
2762
  * import { Wallet } from "ethers";
2534
2763
  * const voterWallet = new Wallet("0x...");
2535
- *
2764
+ *
2536
2765
  * const voteResult2 = await sdk.submitVote({
2537
2766
  * processId: "0x1234567890abcdef...",
2538
2767
  * choices: [2], // Single question vote
@@ -2544,17 +2773,22 @@ class DavinciSDK {
2544
2773
  if (!this.initialized) {
2545
2774
  throw new Error("SDK must be initialized before submitting votes. Call sdk.init() first.");
2546
2775
  }
2776
+ if (!this.config.censusUrl && !this.censusProviders.merkle && !this.censusProviders.csp) {
2777
+ throw new Error(
2778
+ "Census URL is required for voting. Provide censusUrl in the SDK constructor config, or use custom census providers."
2779
+ );
2780
+ }
2547
2781
  return this.voteOrchestrator.submitVote(config);
2548
2782
  }
2549
2783
  /**
2550
2784
  * Get the status of a submitted vote.
2551
- *
2785
+ *
2552
2786
  * Does NOT require a provider - uses API calls only.
2553
- *
2787
+ *
2554
2788
  * @param processId - The process ID
2555
2789
  * @param voteId - The vote ID returned from submitVote()
2556
2790
  * @returns Promise resolving to vote status information
2557
- *
2791
+ *
2558
2792
  * @example
2559
2793
  * ```typescript
2560
2794
  * const statusInfo = await sdk.getVoteStatus(processId, voteId);
@@ -2570,13 +2804,13 @@ class DavinciSDK {
2570
2804
  }
2571
2805
  /**
2572
2806
  * Check if an address has voted in a process.
2573
- *
2807
+ *
2574
2808
  * Does NOT require a provider - uses API calls only.
2575
- *
2809
+ *
2576
2810
  * @param processId - The process ID
2577
2811
  * @param address - The voter's address
2578
2812
  * @returns Promise resolving to boolean indicating if the address has voted
2579
- *
2813
+ *
2580
2814
  * @example
2581
2815
  * ```typescript
2582
2816
  * const hasVoted = await sdk.hasAddressVoted(processId, "0x1234567890abcdef...");
@@ -2587,22 +2821,24 @@ class DavinciSDK {
2587
2821
  */
2588
2822
  async hasAddressVoted(processId, address) {
2589
2823
  if (!this.initialized) {
2590
- throw new Error("SDK must be initialized before checking vote status. Call sdk.init() first.");
2824
+ throw new Error(
2825
+ "SDK must be initialized before checking vote status. Call sdk.init() first."
2826
+ );
2591
2827
  }
2592
2828
  return this.voteOrchestrator.hasAddressVoted(processId, address);
2593
2829
  }
2594
2830
  /**
2595
2831
  * Watch vote status changes in real-time using an async generator.
2596
- * This method yields each status change as it happens, perfect for showing
2832
+ * This method yields each status change as it happens, perfect for showing
2597
2833
  * progress indicators in UI applications.
2598
- *
2834
+ *
2599
2835
  * Does NOT require a provider - uses API calls only.
2600
- *
2836
+ *
2601
2837
  * @param processId - The process ID
2602
2838
  * @param voteId - The vote ID
2603
2839
  * @param options - Optional configuration
2604
2840
  * @returns AsyncGenerator yielding vote status updates
2605
- *
2841
+ *
2606
2842
  * @example
2607
2843
  * ```typescript
2608
2844
  * // Submit vote
@@ -2610,11 +2846,11 @@ class DavinciSDK {
2610
2846
  * processId: "0x1234567890abcdef...",
2611
2847
  * choices: [1]
2612
2848
  * });
2613
- *
2849
+ *
2614
2850
  * // Watch status changes in real-time
2615
2851
  * for await (const statusInfo of sdk.watchVoteStatus(voteResult.processId, voteResult.voteId)) {
2616
2852
  * console.log(`Vote status: ${statusInfo.status}`);
2617
- *
2853
+ *
2618
2854
  * switch (statusInfo.status) {
2619
2855
  * case VoteStatus.Pending:
2620
2856
  * console.log("⏳ Processing...");
@@ -2634,7 +2870,9 @@ class DavinciSDK {
2634
2870
  */
2635
2871
  watchVoteStatus(processId, voteId, options) {
2636
2872
  if (!this.initialized) {
2637
- throw new Error("SDK must be initialized before watching vote status. Call sdk.init() first.");
2873
+ throw new Error(
2874
+ "SDK must be initialized before watching vote status. Call sdk.init() first."
2875
+ );
2638
2876
  }
2639
2877
  return this.voteOrchestrator.watchVoteStatus(processId, voteId, options);
2640
2878
  }
@@ -2642,16 +2880,16 @@ class DavinciSDK {
2642
2880
  * Wait for a vote to reach a specific status.
2643
2881
  * This is a simpler alternative to watchVoteStatus() that returns only the final status.
2644
2882
  * Useful for waiting for vote confirmation and processing without needing to handle each intermediate status.
2645
- *
2883
+ *
2646
2884
  * Does NOT require a provider - uses API calls only.
2647
- *
2885
+ *
2648
2886
  * @param processId - The process ID
2649
2887
  * @param voteId - The vote ID
2650
2888
  * @param targetStatus - The target status to wait for (default: "settled")
2651
2889
  * @param timeoutMs - Maximum time to wait in milliseconds (default: 300000 = 5 minutes)
2652
2890
  * @param pollIntervalMs - Polling interval in milliseconds (default: 5000 = 5 seconds)
2653
2891
  * @returns Promise resolving to final vote status
2654
- *
2892
+ *
2655
2893
  * @example
2656
2894
  * ```typescript
2657
2895
  * // Submit vote and wait for it to be settled
@@ -2659,7 +2897,7 @@ class DavinciSDK {
2659
2897
  * processId: "0x1234567890abcdef...",
2660
2898
  * choices: [1]
2661
2899
  * });
2662
- *
2900
+ *
2663
2901
  * // Wait for the vote to be fully processed
2664
2902
  * const finalStatus = await sdk.waitForVoteStatus(
2665
2903
  * voteResult.processId,
@@ -2668,31 +2906,39 @@ class DavinciSDK {
2668
2906
  * 300000, // 5 minute timeout
2669
2907
  * 5000 // Check every 5 seconds
2670
2908
  * );
2671
- *
2909
+ *
2672
2910
  * console.log("Vote final status:", finalStatus.status);
2673
2911
  * ```
2674
2912
  */
2675
2913
  async waitForVoteStatus(processId, voteId, targetStatus = VoteStatus.Settled, timeoutMs = 3e5, pollIntervalMs = 5e3) {
2676
2914
  if (!this.initialized) {
2677
- throw new Error("SDK must be initialized before waiting for vote status. Call sdk.init() first.");
2915
+ throw new Error(
2916
+ "SDK must be initialized before waiting for vote status. Call sdk.init() first."
2917
+ );
2678
2918
  }
2679
- return this.voteOrchestrator.waitForVoteStatus(processId, voteId, targetStatus, timeoutMs, pollIntervalMs);
2919
+ return this.voteOrchestrator.waitForVoteStatus(
2920
+ processId,
2921
+ voteId,
2922
+ targetStatus,
2923
+ timeoutMs,
2924
+ pollIntervalMs
2925
+ );
2680
2926
  }
2681
2927
  /**
2682
- * Ends a voting process by setting its status to ENDED and returns an async generator
2683
- * that yields transaction status events. This method allows you to monitor the
2928
+ * Ends a voting process by setting its status to ENDED and returns an async generator
2929
+ * that yields transaction status events. This method allows you to monitor the
2684
2930
  * transaction progress in real-time.
2685
- *
2931
+ *
2686
2932
  * Requires a signer with a provider for blockchain interactions.
2687
- *
2933
+ *
2688
2934
  * @param processId - The process ID to end
2689
2935
  * @returns AsyncGenerator yielding transaction status events
2690
2936
  * @throws Error if signer does not have a provider
2691
- *
2937
+ *
2692
2938
  * @example
2693
2939
  * ```typescript
2694
2940
  * const stream = sdk.endProcessStream("0x1234567890abcdef...");
2695
- *
2941
+ *
2696
2942
  * for await (const event of stream) {
2697
2943
  * switch (event.status) {
2698
2944
  * case TxStatus.Pending:
@@ -2721,15 +2967,15 @@ class DavinciSDK {
2721
2967
  /**
2722
2968
  * Ends a voting process by setting its status to ENDED.
2723
2969
  * This is the simplified method that waits for transaction completion.
2724
- *
2970
+ *
2725
2971
  * For real-time transaction status updates, use endProcessStream() instead.
2726
- *
2972
+ *
2727
2973
  * Requires a signer with a provider for blockchain interactions.
2728
- *
2974
+ *
2729
2975
  * @param processId - The process ID to end
2730
2976
  * @returns Promise resolving when the process is ended
2731
2977
  * @throws Error if signer does not have a provider
2732
- *
2978
+ *
2733
2979
  * @example
2734
2980
  * ```typescript
2735
2981
  * await sdk.endProcess("0x1234567890abcdef...");
@@ -2744,20 +2990,20 @@ class DavinciSDK {
2744
2990
  return this.processOrchestrator.endProcess(processId);
2745
2991
  }
2746
2992
  /**
2747
- * Pauses a voting process by setting its status to PAUSED and returns an async generator
2748
- * that yields transaction status events. This method allows you to monitor the
2993
+ * Pauses a voting process by setting its status to PAUSED and returns an async generator
2994
+ * that yields transaction status events. This method allows you to monitor the
2749
2995
  * transaction progress in real-time.
2750
- *
2996
+ *
2751
2997
  * Requires a signer with a provider for blockchain interactions.
2752
- *
2998
+ *
2753
2999
  * @param processId - The process ID to pause
2754
3000
  * @returns AsyncGenerator yielding transaction status events
2755
3001
  * @throws Error if signer does not have a provider
2756
- *
3002
+ *
2757
3003
  * @example
2758
3004
  * ```typescript
2759
3005
  * const stream = sdk.pauseProcessStream("0x1234567890abcdef...");
2760
- *
3006
+ *
2761
3007
  * for await (const event of stream) {
2762
3008
  * switch (event.status) {
2763
3009
  * case TxStatus.Pending:
@@ -2786,15 +3032,15 @@ class DavinciSDK {
2786
3032
  /**
2787
3033
  * Pauses a voting process by setting its status to PAUSED.
2788
3034
  * This is the simplified method that waits for transaction completion.
2789
- *
3035
+ *
2790
3036
  * For real-time transaction status updates, use pauseProcessStream() instead.
2791
- *
3037
+ *
2792
3038
  * Requires a signer with a provider for blockchain interactions.
2793
- *
3039
+ *
2794
3040
  * @param processId - The process ID to pause
2795
3041
  * @returns Promise resolving when the process is paused
2796
3042
  * @throws Error if signer does not have a provider
2797
- *
3043
+ *
2798
3044
  * @example
2799
3045
  * ```typescript
2800
3046
  * await sdk.pauseProcess("0x1234567890abcdef...");
@@ -2809,20 +3055,20 @@ class DavinciSDK {
2809
3055
  return this.processOrchestrator.pauseProcess(processId);
2810
3056
  }
2811
3057
  /**
2812
- * Cancels a voting process by setting its status to CANCELED and returns an async generator
2813
- * that yields transaction status events. This method allows you to monitor the
3058
+ * Cancels a voting process by setting its status to CANCELED and returns an async generator
3059
+ * that yields transaction status events. This method allows you to monitor the
2814
3060
  * transaction progress in real-time.
2815
- *
3061
+ *
2816
3062
  * Requires a signer with a provider for blockchain interactions.
2817
- *
3063
+ *
2818
3064
  * @param processId - The process ID to cancel
2819
3065
  * @returns AsyncGenerator yielding transaction status events
2820
3066
  * @throws Error if signer does not have a provider
2821
- *
3067
+ *
2822
3068
  * @example
2823
3069
  * ```typescript
2824
3070
  * const stream = sdk.cancelProcessStream("0x1234567890abcdef...");
2825
- *
3071
+ *
2826
3072
  * for await (const event of stream) {
2827
3073
  * switch (event.status) {
2828
3074
  * case TxStatus.Pending:
@@ -2851,15 +3097,15 @@ class DavinciSDK {
2851
3097
  /**
2852
3098
  * Cancels a voting process by setting its status to CANCELED.
2853
3099
  * This is the simplified method that waits for transaction completion.
2854
- *
3100
+ *
2855
3101
  * For real-time transaction status updates, use cancelProcessStream() instead.
2856
- *
3102
+ *
2857
3103
  * Requires a signer with a provider for blockchain interactions.
2858
- *
3104
+ *
2859
3105
  * @param processId - The process ID to cancel
2860
3106
  * @returns Promise resolving when the process is canceled
2861
3107
  * @throws Error if signer does not have a provider
2862
- *
3108
+ *
2863
3109
  * @example
2864
3110
  * ```typescript
2865
3111
  * await sdk.cancelProcess("0x1234567890abcdef...");
@@ -2874,19 +3120,19 @@ class DavinciSDK {
2874
3120
  return this.processOrchestrator.cancelProcess(processId);
2875
3121
  }
2876
3122
  /**
2877
- * Resumes a voting process by setting its status to READY and returns an async generator
3123
+ * Resumes a voting process by setting its status to READY and returns an async generator
2878
3124
  * that yields transaction status events. This is typically used to resume a paused process.
2879
- *
3125
+ *
2880
3126
  * Requires a signer with a provider for blockchain interactions.
2881
- *
3127
+ *
2882
3128
  * @param processId - The process ID to resume
2883
3129
  * @returns AsyncGenerator yielding transaction status events
2884
3130
  * @throws Error if signer does not have a provider
2885
- *
3131
+ *
2886
3132
  * @example
2887
3133
  * ```typescript
2888
3134
  * const stream = sdk.resumeProcessStream("0x1234567890abcdef...");
2889
- *
3135
+ *
2890
3136
  * for await (const event of stream) {
2891
3137
  * switch (event.status) {
2892
3138
  * case TxStatus.Pending:
@@ -2916,15 +3162,15 @@ class DavinciSDK {
2916
3162
  * Resumes a voting process by setting its status to READY.
2917
3163
  * This is typically used to resume a paused process.
2918
3164
  * This is the simplified method that waits for transaction completion.
2919
- *
3165
+ *
2920
3166
  * For real-time transaction status updates, use resumeProcessStream() instead.
2921
- *
3167
+ *
2922
3168
  * Requires a signer with a provider for blockchain interactions.
2923
- *
3169
+ *
2924
3170
  * @param processId - The process ID to resume
2925
3171
  * @returns Promise resolving when the process is resumed
2926
3172
  * @throws Error if signer does not have a provider
2927
- *
3173
+ *
2928
3174
  * @example
2929
3175
  * ```typescript
2930
3176
  * await sdk.resumeProcess("0x1234567890abcdef...");
@@ -2940,64 +3186,50 @@ class DavinciSDK {
2940
3186
  }
2941
3187
  /**
2942
3188
  * Resolve contract address based on configuration priority:
2943
- * 1. If useSequencerAddresses is true: addresses from sequencer (highest priority)
2944
- * 2. Custom addresses from config (if provided by user)
2945
- * 3. Default deployed addresses from npm package
3189
+ * 1. Custom addresses from user config (if provided)
3190
+ * 2. Addresses from sequencer (fetched during init if no custom addresses provided)
2946
3191
  */
2947
3192
  resolveContractAddress(contractName) {
2948
- if (this.config.useSequencerAddresses) {
2949
- return this.getDefaultContractAddress(contractName);
2950
- }
2951
- const customAddress = this.config.contractAddresses[contractName];
3193
+ const customAddress = this.config.customAddresses[contractName];
2952
3194
  if (customAddress) {
2953
3195
  return customAddress;
2954
3196
  }
2955
- return this.getDefaultContractAddress(contractName);
2956
- }
2957
- /**
2958
- * Get default contract address from deployed addresses
2959
- */
2960
- getDefaultContractAddress(contractName) {
2961
- const chain = this.config.chain;
2962
- switch (contractName) {
2963
- case "processRegistry":
2964
- return deployedAddresses.processRegistry[chain];
2965
- case "organizationRegistry":
2966
- return deployedAddresses.organizationRegistry[chain];
2967
- case "stateTransitionVerifier":
2968
- return deployedAddresses.stateTransitionVerifierGroth16[chain];
2969
- case "resultsVerifier":
2970
- return deployedAddresses.resultsVerifierGroth16[chain];
2971
- case "sequencerRegistry":
2972
- return deployedAddresses.sequencerRegistry[chain];
2973
- default:
2974
- throw new Error(`Unknown contract: ${contractName}`);
3197
+ if (!this.config.customAddresses[contractName]) {
3198
+ throw new Error(
3199
+ `Contract address for '${contractName}' not found. Make sure SDK is initialized with sdk.init() or provide custom addresses in config.`
3200
+ );
2975
3201
  }
3202
+ return this.config.customAddresses[contractName];
2976
3203
  }
2977
3204
  /**
2978
- * Update contract addresses from sequencer info if useSequencerAddresses is enabled
2979
- * Sequencer addresses have priority over user-provided addresses
3205
+ * Fetch contract addresses from sequencer info
3206
+ * This is called during init() if custom addresses are not provided
2980
3207
  */
2981
- async updateContractAddressesFromSequencer() {
3208
+ async fetchContractAddressesFromSequencer() {
2982
3209
  try {
2983
3210
  const info = await this.apiService.sequencer.getInfo();
2984
3211
  const contracts = info.contracts;
2985
3212
  if (contracts.process) {
3213
+ this.config.customAddresses.processRegistry = contracts.process;
2986
3214
  this._processRegistry = new ProcessRegistryService(contracts.process, this.config.signer);
2987
- this.config.contractAddresses.processRegistry = contracts.process;
2988
3215
  }
2989
3216
  if (contracts.organization) {
2990
- this._organizationRegistry = new OrganizationRegistryService(contracts.organization, this.config.signer);
2991
- this.config.contractAddresses.organizationRegistry = contracts.organization;
3217
+ this.config.customAddresses.organizationRegistry = contracts.organization;
3218
+ this._organizationRegistry = new OrganizationRegistryService(
3219
+ contracts.organization,
3220
+ this.config.signer
3221
+ );
2992
3222
  }
2993
3223
  if (contracts.stateTransitionVerifier) {
2994
- this.config.contractAddresses.stateTransitionVerifier = contracts.stateTransitionVerifier;
3224
+ this.config.customAddresses.stateTransitionVerifier = contracts.stateTransitionVerifier;
2995
3225
  }
2996
3226
  if (contracts.resultsVerifier) {
2997
- this.config.contractAddresses.resultsVerifier = contracts.resultsVerifier;
3227
+ this.config.customAddresses.resultsVerifier = contracts.resultsVerifier;
2998
3228
  }
2999
3229
  } catch (error) {
3000
- console.warn("Failed to fetch contract addresses from sequencer, using defaults:", error);
3230
+ throw new Error(
3231
+ `Failed to fetch contract addresses from sequencer: ${error instanceof Error ? error.message : String(error)}. You can provide custom addresses in the SDK config to avoid this error.`
3232
+ );
3001
3233
  }
3002
3234
  }
3003
3235
  /**
@@ -3027,10 +3259,13 @@ class DavinciSDK {
3027
3259
  }
3028
3260
 
3029
3261
  exports.BaseService = BaseService;
3262
+ exports.Census = Census;
3263
+ exports.CensusOrchestrator = CensusOrchestrator;
3030
3264
  exports.CensusOrigin = CensusOrigin;
3265
+ exports.CensusType = CensusType;
3031
3266
  exports.CircomProof = CircomProof;
3032
3267
  exports.ContractServiceError = ContractServiceError;
3033
- exports.DEFAULT_ENVIRONMENT_URLS = DEFAULT_ENVIRONMENT_URLS;
3268
+ exports.CspCensus = CspCensus;
3034
3269
  exports.DavinciCrypto = DavinciCrypto;
3035
3270
  exports.DavinciSDK = DavinciSDK;
3036
3271
  exports.ElectionMetadataTemplate = ElectionMetadataTemplate;
@@ -3040,6 +3275,7 @@ exports.OrganizationCreateError = OrganizationCreateError;
3040
3275
  exports.OrganizationDeleteError = OrganizationDeleteError;
3041
3276
  exports.OrganizationRegistryService = OrganizationRegistryService;
3042
3277
  exports.OrganizationUpdateError = OrganizationUpdateError;
3278
+ exports.PlainCensus = PlainCensus;
3043
3279
  exports.ProcessCensusError = ProcessCensusError;
3044
3280
  exports.ProcessCreateError = ProcessCreateError;
3045
3281
  exports.ProcessDurationError = ProcessDurationError;
@@ -3049,6 +3285,7 @@ exports.ProcessResultError = ProcessResultError;
3049
3285
  exports.ProcessStateTransitionError = ProcessStateTransitionError;
3050
3286
  exports.ProcessStatus = ProcessStatus;
3051
3287
  exports.ProcessStatusError = ProcessStatusError;
3288
+ exports.PublishedCensus = PublishedCensus;
3052
3289
  exports.SmartContractService = SmartContractService;
3053
3290
  exports.TxStatus = TxStatus;
3054
3291
  exports.VocdoniApiService = VocdoniApiService;
@@ -3056,18 +3293,13 @@ exports.VocdoniCensusService = VocdoniCensusService;
3056
3293
  exports.VocdoniSequencerService = VocdoniSequencerService;
3057
3294
  exports.VoteOrchestrationService = VoteOrchestrationService;
3058
3295
  exports.VoteStatus = VoteStatus;
3296
+ exports.WeightedCensus = WeightedCensus;
3059
3297
  exports.assertCSPCensusProof = assertCSPCensusProof;
3060
3298
  exports.assertMerkleCensusProof = assertMerkleCensusProof;
3061
3299
  exports.createProcessSignatureMessage = createProcessSignatureMessage;
3062
- exports.deployedAddresses = deployedAddresses;
3063
3300
  exports.getElectionMetadataTemplate = getElectionMetadataTemplate;
3064
- exports.getEnvironmentChain = getEnvironmentChain;
3065
- exports.getEnvironmentConfig = getEnvironmentConfig;
3066
- exports.getEnvironmentUrls = getEnvironmentUrls;
3067
3301
  exports.isCSPCensusProof = isCSPCensusProof;
3068
3302
  exports.isMerkleCensusProof = isMerkleCensusProof;
3069
- exports.resolveConfiguration = resolveConfiguration;
3070
- exports.resolveUrls = resolveUrls;
3071
3303
  exports.signProcessCreation = signProcessCreation;
3072
3304
  exports.validateProcessId = validateProcessId;
3073
3305
  //# sourceMappingURL=index.js.map