@vocdoni/davinci-sdk 0.0.2 → 0.0.4

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.mjs CHANGED
@@ -87,12 +87,12 @@ class VocdoniCensusService extends BaseService {
87
87
  super(baseURL);
88
88
  }
89
89
  /**
90
- * Constructs the URI for accessing a census by its root
91
- * @param censusRoot - The census root (hex-prefixed)
90
+ * Constructs the URI for accessing a census
91
+ * @param relativePath - The relative path
92
92
  * @returns The constructed URI for the census
93
93
  */
94
- getCensusUri(censusRoot) {
95
- return `${this.axios.defaults.baseURL}/censuses/${censusRoot}`;
94
+ getCensusUri(relativePath) {
95
+ return `${this.axios.defaults.baseURL}${relativePath}`;
96
96
  }
97
97
  createCensus() {
98
98
  return this.request({
@@ -161,10 +161,13 @@ class VocdoniCensusService extends BaseService {
161
161
  return this.request({
162
162
  method: "POST",
163
163
  url: `/censuses/${censusId}/publish`
164
- }).then((response) => ({
165
- ...response,
166
- uri: this.getCensusUri(response.root)
167
- }));
164
+ }).then((apiResponse) => {
165
+ const { censusUri, ...responseWithoutCensusUri } = apiResponse;
166
+ return {
167
+ ...responseWithoutCensusUri,
168
+ uri: this.getCensusUri(censusUri)
169
+ };
170
+ });
168
171
  }
169
172
  // BigQuery endpoints
170
173
  getSnapshots(params) {
@@ -194,13 +197,13 @@ var CensusOrigin = /* @__PURE__ */ ((CensusOrigin2) => {
194
197
  return CensusOrigin2;
195
198
  })(CensusOrigin || {});
196
199
  function isBaseCensusProof(proof) {
197
- return !!proof && typeof proof.root === "string" && typeof proof.address === "string" && typeof proof.weight === "string" && typeof proof.censusOrigin === "number" && Object.values(CensusOrigin).includes(proof.censusOrigin);
200
+ return !!proof && typeof proof.root === "string" && typeof proof.address === "string" && typeof proof.censusOrigin === "number" && Object.values(CensusOrigin).includes(proof.censusOrigin);
198
201
  }
199
202
  function isMerkleCensusProof(proof) {
200
- return isBaseCensusProof(proof) && proof.censusOrigin === 1 /* CensusOriginMerkleTree */ && typeof proof.value === "string" && typeof proof.siblings === "string";
203
+ return isBaseCensusProof(proof) && proof.censusOrigin === 1 /* CensusOriginMerkleTree */ && typeof proof.weight === "string" && typeof proof.value === "string" && typeof proof.siblings === "string";
201
204
  }
202
205
  function isCSPCensusProof(proof) {
203
- return isBaseCensusProof(proof) && proof.censusOrigin === 2 /* CensusOriginCSP */ && typeof proof.processId === "string" && typeof proof.publicKey === "string" && typeof proof.signature === "string";
206
+ return isBaseCensusProof(proof) && proof.censusOrigin === 2 /* CensusOriginCSP */ && typeof proof.weight === "string" && typeof proof.processId === "string" && typeof proof.publicKey === "string" && typeof proof.signature === "string";
204
207
  }
205
208
  function assertMerkleCensusProof(proof) {
206
209
  if (!isMerkleCensusProof(proof)) {
@@ -213,6 +216,281 @@ function assertCSPCensusProof(proof) {
213
216
  }
214
217
  }
215
218
 
219
+ var CensusType = /* @__PURE__ */ ((CensusType2) => {
220
+ CensusType2["PLAIN"] = "plain";
221
+ CensusType2["WEIGHTED"] = "weighted";
222
+ CensusType2["CSP"] = "csp";
223
+ return CensusType2;
224
+ })(CensusType || {});
225
+ class Census {
226
+ constructor(type) {
227
+ this._censusId = null;
228
+ this._censusRoot = null;
229
+ this._censusURI = null;
230
+ this._size = null;
231
+ this._type = type;
232
+ }
233
+ get censusId() {
234
+ return this._censusId;
235
+ }
236
+ get censusRoot() {
237
+ return this._censusRoot;
238
+ }
239
+ get censusURI() {
240
+ return this._censusURI;
241
+ }
242
+ get type() {
243
+ return this._type;
244
+ }
245
+ get size() {
246
+ return this._size;
247
+ }
248
+ get isPublished() {
249
+ return this._censusRoot !== null && this._censusURI !== null;
250
+ }
251
+ /**
252
+ * Convert CensusType to CensusOrigin enum for API compatibility
253
+ */
254
+ get censusOrigin() {
255
+ switch (this._type) {
256
+ case "plain" /* PLAIN */:
257
+ case "weighted" /* WEIGHTED */:
258
+ return CensusOrigin.CensusOriginMerkleTree;
259
+ case "csp" /* CSP */:
260
+ return CensusOrigin.CensusOriginCSP;
261
+ default:
262
+ throw new Error(`Unknown census type: ${this._type}`);
263
+ }
264
+ }
265
+ }
266
+
267
+ class PlainCensus extends Census {
268
+ constructor() {
269
+ super(CensusType.PLAIN);
270
+ this._participants = /* @__PURE__ */ new Set();
271
+ }
272
+ /**
273
+ * Add participant(s) with automatic weight=1
274
+ * @param addresses - Single address or array of addresses
275
+ */
276
+ add(addresses) {
277
+ const toAdd = Array.isArray(addresses) ? addresses : [addresses];
278
+ for (const address of toAdd) {
279
+ this.validateAddress(address);
280
+ this._participants.add(address.toLowerCase());
281
+ }
282
+ }
283
+ /**
284
+ * Remove participant by address
285
+ */
286
+ remove(address) {
287
+ this._participants.delete(address.toLowerCase());
288
+ }
289
+ /**
290
+ * Get all participants as CensusParticipant array (for API)
291
+ * All participants have weight="1"
292
+ */
293
+ get participants() {
294
+ return Array.from(this._participants).map((key) => ({
295
+ key,
296
+ weight: "1"
297
+ // Everyone has weight=1 in plain census
298
+ }));
299
+ }
300
+ /**
301
+ * Get addresses only
302
+ */
303
+ get addresses() {
304
+ return Array.from(this._participants);
305
+ }
306
+ validateAddress(address) {
307
+ if (!address || typeof address !== "string") {
308
+ throw new Error("Address is required and must be a string");
309
+ }
310
+ if (!/^(0x)?[0-9a-fA-F]{40}$/i.test(address)) {
311
+ throw new Error(`Invalid Ethereum address format: ${address}`);
312
+ }
313
+ }
314
+ /**
315
+ * Internal method called after publishing
316
+ * @internal
317
+ */
318
+ _setPublishedData(root, uri, size, censusId) {
319
+ this._censusRoot = root;
320
+ this._censusURI = uri;
321
+ this._size = size;
322
+ if (censusId) this._censusId = censusId;
323
+ }
324
+ }
325
+
326
+ class WeightedCensus extends Census {
327
+ constructor() {
328
+ super(CensusType.WEIGHTED);
329
+ this._participants = /* @__PURE__ */ new Map();
330
+ }
331
+ /**
332
+ * Add participant(s) with custom weights
333
+ * Weight can be provided as string, number, or bigint - will be converted to string internally
334
+ * @param participant - Single participant or array of participants with custom weights
335
+ */
336
+ add(participant) {
337
+ const toAdd = Array.isArray(participant) ? participant : [participant];
338
+ for (const p of toAdd) {
339
+ this.validateParticipant(p);
340
+ const weightString = this.normalizeWeight(p.weight);
341
+ this._participants.set(p.key.toLowerCase(), weightString);
342
+ }
343
+ }
344
+ /**
345
+ * Remove participant by address
346
+ */
347
+ remove(address) {
348
+ this._participants.delete(address.toLowerCase());
349
+ }
350
+ /**
351
+ * Get all participants as CensusParticipant array
352
+ */
353
+ get participants() {
354
+ return Array.from(this._participants.entries()).map(([key, weight]) => ({
355
+ key,
356
+ weight
357
+ }));
358
+ }
359
+ /**
360
+ * Get participant addresses
361
+ */
362
+ get addresses() {
363
+ return Array.from(this._participants.keys());
364
+ }
365
+ /**
366
+ * Get weight for specific address
367
+ */
368
+ getWeight(address) {
369
+ return this._participants.get(address.toLowerCase());
370
+ }
371
+ /**
372
+ * Normalizes weight from string, number, or bigint to string
373
+ */
374
+ normalizeWeight(weight) {
375
+ if (typeof weight === "string") {
376
+ if (!/^\d+$/.test(weight)) {
377
+ throw new Error(`Invalid weight format: ${weight}. Must be a positive integer.`);
378
+ }
379
+ return weight;
380
+ }
381
+ if (typeof weight === "number") {
382
+ if (!Number.isInteger(weight) || weight < 0) {
383
+ throw new Error(`Invalid weight: ${weight}. Must be a positive integer.`);
384
+ }
385
+ return weight.toString();
386
+ }
387
+ if (typeof weight === "bigint") {
388
+ if (weight < 0n) {
389
+ throw new Error(`Invalid weight: ${weight}. Must be a positive integer.`);
390
+ }
391
+ return weight.toString();
392
+ }
393
+ throw new Error(`Invalid weight type. Must be string, number, or bigint.`);
394
+ }
395
+ validateParticipant(participant) {
396
+ if (!participant.key || typeof participant.key !== "string") {
397
+ throw new Error("Participant key (address) is required");
398
+ }
399
+ if (!/^(0x)?[0-9a-fA-F]{40}$/i.test(participant.key)) {
400
+ throw new Error(`Invalid Ethereum address format: ${participant.key}`);
401
+ }
402
+ if (participant.weight === void 0 || participant.weight === null) {
403
+ throw new Error("Participant weight is required");
404
+ }
405
+ }
406
+ /**
407
+ * Internal method called after publishing
408
+ * @internal
409
+ */
410
+ _setPublishedData(root, uri, size, censusId) {
411
+ this._censusRoot = root;
412
+ this._censusURI = uri;
413
+ this._size = size;
414
+ if (censusId) this._censusId = censusId;
415
+ }
416
+ }
417
+
418
+ class CspCensus extends Census {
419
+ constructor(publicKey, cspURI, size) {
420
+ super(CensusType.CSP);
421
+ if (!/^(0x)?[0-9a-fA-F]+$/.test(publicKey)) {
422
+ throw new Error("Public key is missing or invalid");
423
+ }
424
+ try {
425
+ new URL(cspURI);
426
+ } catch {
427
+ throw new Error("CSP URI is missing or invalid");
428
+ }
429
+ this._publicKey = publicKey;
430
+ this._cspURI = cspURI;
431
+ this._censusRoot = publicKey;
432
+ this._censusURI = cspURI;
433
+ this._size = size;
434
+ }
435
+ get publicKey() {
436
+ return this._publicKey;
437
+ }
438
+ get cspURI() {
439
+ return this._cspURI;
440
+ }
441
+ }
442
+
443
+ class PublishedCensus extends Census {
444
+ constructor(type, root, uri, size) {
445
+ super(type);
446
+ this._censusRoot = root;
447
+ this._censusURI = uri;
448
+ this._size = size;
449
+ }
450
+ }
451
+
452
+ class CensusOrchestrator {
453
+ constructor(censusService) {
454
+ this.censusService = censusService;
455
+ }
456
+ /**
457
+ * Publishes a PlainCensus or WeightedCensus
458
+ * Creates a working census, adds participants, and publishes it
459
+ */
460
+ async publish(census) {
461
+ if (census.isPublished) {
462
+ throw new Error("Census is already published");
463
+ }
464
+ if (census.participants.length === 0) {
465
+ throw new Error("Cannot publish empty census");
466
+ }
467
+ const censusId = await this.censusService.createCensus();
468
+ await this.censusService.addParticipants(censusId, census.participants);
469
+ const publishResponse = await this.censusService.publishCensus(censusId);
470
+ census._setPublishedData(
471
+ publishResponse.root,
472
+ publishResponse.uri,
473
+ publishResponse.participantCount,
474
+ censusId
475
+ );
476
+ }
477
+ /**
478
+ * Gets census data for process creation
479
+ * Throws if census is not published
480
+ */
481
+ getCensusData(census) {
482
+ if (!census.isPublished) {
483
+ throw new Error("Census must be published before creating a process");
484
+ }
485
+ return {
486
+ type: census.censusOrigin,
487
+ root: census.censusRoot,
488
+ uri: census.censusURI,
489
+ size: census.size
490
+ };
491
+ }
492
+ }
493
+
216
494
  function createProcessSignatureMessage(processId) {
217
495
  const cleanProcessId = processId.replace(/^0x/, "").toLowerCase();
218
496
  return `I am creating a new voting process for the davinci.vote protocol identified with id ${cleanProcessId}`;
@@ -285,6 +563,12 @@ class VocdoniSequencerService extends BaseService {
285
563
  throw error;
286
564
  }
287
565
  }
566
+ isAddressAbleToVote(processId, address) {
567
+ return this.request({
568
+ method: "GET",
569
+ url: `/processes/${processId}/participants/${address}`
570
+ });
571
+ }
288
572
  getInfo() {
289
573
  return this.request({
290
574
  method: "GET",
@@ -303,11 +587,15 @@ class VocdoniSequencerService extends BaseService {
303
587
  try {
304
588
  const response = await fetch(hashOrUrl);
305
589
  if (!response.ok) {
306
- throw new Error(`Failed to fetch metadata from URL: ${response.status} ${response.statusText}`);
590
+ throw new Error(
591
+ `Failed to fetch metadata from URL: ${response.status} ${response.statusText}`
592
+ );
307
593
  }
308
594
  return await response.json();
309
595
  } catch (error) {
310
- throw new Error(`Failed to fetch metadata from URL: ${error instanceof Error ? error.message : "Unknown error"}`);
596
+ throw new Error(
597
+ `Failed to fetch metadata from URL: ${error instanceof Error ? error.message : "Unknown error"}`
598
+ );
311
599
  }
312
600
  }
313
601
  if (!isHexString(hashOrUrl)) {
@@ -343,101 +631,6 @@ class VocdoniApiService {
343
631
  }
344
632
  }
345
633
 
346
- const DEFAULT_ENVIRONMENT_URLS = {
347
- dev: {
348
- sequencer: "https://sequencer-dev.davinci.vote",
349
- census: "https://c3-dev.davinci.vote",
350
- chain: "sepolia"
351
- },
352
- stg: {
353
- sequencer: "https://sequencer1.davinci.vote",
354
- census: "https://c3.davinci.vote",
355
- chain: "sepolia"
356
- },
357
- prod: {
358
- // TODO: Add production URLs when available
359
- sequencer: "",
360
- census: "",
361
- chain: "mainnet"
362
- }
363
- };
364
- function getEnvironmentConfig(environment) {
365
- return DEFAULT_ENVIRONMENT_URLS[environment];
366
- }
367
- function getEnvironmentUrls(environment) {
368
- const config = DEFAULT_ENVIRONMENT_URLS[environment];
369
- return {
370
- sequencer: config.sequencer,
371
- census: config.census
372
- };
373
- }
374
- function getEnvironmentChain(environment) {
375
- return DEFAULT_ENVIRONMENT_URLS[environment].chain;
376
- }
377
- function resolveConfiguration(options = {}) {
378
- const environment = options.environment || "prod";
379
- const defaultConfig = getEnvironmentConfig(environment);
380
- const resolvedConfig = { ...defaultConfig };
381
- if (options.customUrls) {
382
- if (options.customUrls.sequencer !== void 0) {
383
- resolvedConfig.sequencer = options.customUrls.sequencer;
384
- }
385
- if (options.customUrls.census !== void 0) {
386
- resolvedConfig.census = options.customUrls.census;
387
- }
388
- }
389
- if (options.customChain) {
390
- resolvedConfig.chain = options.customChain;
391
- }
392
- return resolvedConfig;
393
- }
394
- function resolveUrls(options = {}) {
395
- const config = resolveConfiguration(options);
396
- return {
397
- sequencer: config.sequencer,
398
- census: config.census
399
- };
400
- }
401
-
402
- var processRegistry = {
403
- sepolia: "0x50CA6A350f3A9C7B8a82eE7a4D5F0f21C54D68e3",
404
- uzh: "0x69B16f67Bd2fB18bD720379E9C1Ef5EaD3872d67",
405
- mainnet: "0x0",
406
- celo: "0xDda6c75d32c375946C8ae9be41B2F3539dB1118A"
407
- };
408
- var organizationRegistry = {
409
- sepolia: "0xF30678f579Fd89b86295503dC179d5d3aed47a98",
410
- uzh: "0xf7BCE4546805547bE526Ca864d6722Ed193E51Aa",
411
- mainnet: "0x0",
412
- celo: "0xE17D701EA8f34022F97fC2Ec68c73D42bF99D0BD"
413
- };
414
- var stateTransitionVerifierGroth16 = {
415
- sepolia: "0x96EcBbD6aB5fDC063E0fC426F2700290DeeAFE4E",
416
- uzh: "0x5e4673CD378F05cc3Ae25804539c91E711548741",
417
- mainnet: "0x0",
418
- celo: "0x2DaF913D423128258b2F378E320F9D9D3Be5eCf5"
419
- };
420
- var resultsVerifierGroth16 = {
421
- sepolia: "0x3ab37C40f7d0649f7a15BA3230f14AB29B51eDCC",
422
- uzh: "0x00c7F87731346F592197E49A90Ad6EC236Ad9985",
423
- mainnet: "0x0",
424
- celo: "0x808276962217AD1ED3af7D51bFc791903CAd9389"
425
- };
426
- var sequencerRegistry = {
427
- sepolia: "0x0",
428
- uzh: "0x0",
429
- mainnet: "0x0",
430
- celo: "0x0"
431
- };
432
- var addressesJson = {
433
- processRegistry: processRegistry,
434
- organizationRegistry: organizationRegistry,
435
- stateTransitionVerifierGroth16: stateTransitionVerifierGroth16,
436
- resultsVerifierGroth16: resultsVerifierGroth16,
437
- sequencerRegistry: sequencerRegistry
438
- };
439
-
440
- const deployedAddresses = addressesJson;
441
634
  var TxStatus = /* @__PURE__ */ ((TxStatus2) => {
442
635
  TxStatus2["Pending"] = "pending";
443
636
  TxStatus2["Completed"] = "completed";
@@ -456,19 +649,19 @@ class SmartContractService {
456
649
  * Sends a transaction and yields status events during its lifecycle.
457
650
  * This method handles the complete transaction flow from submission to completion,
458
651
  * including error handling and status updates.
459
- *
652
+ *
460
653
  * @template T - The type of the successful response data
461
654
  * @param txPromise - Promise resolving to the transaction response
462
655
  * @param responseHandler - Function to process the successful transaction result
463
656
  * @returns AsyncGenerator yielding transaction status events
464
- *
657
+ *
465
658
  * @example
466
659
  * ```typescript
467
660
  * const txStream = await this.sendTx(
468
661
  * contract.someMethod(),
469
662
  * async () => await contract.getUpdatedValue()
470
663
  * );
471
- *
664
+ *
472
665
  * for await (const event of txStream) {
473
666
  * switch (event.status) {
474
667
  * case TxStatus.Pending:
@@ -505,12 +698,12 @@ class SmartContractService {
505
698
  * Executes a transaction stream and returns the result or throws an error.
506
699
  * This is a convenience method that processes a transaction stream and either
507
700
  * returns the successful result or throws an appropriate error.
508
- *
701
+ *
509
702
  * @template T - The type of the successful response data
510
703
  * @param stream - AsyncGenerator of transaction status events
511
704
  * @returns Promise resolving to the successful response data
512
705
  * @throws Error if the transaction fails or reverts
513
- *
706
+ *
514
707
  * @example
515
708
  * ```typescript
516
709
  * try {
@@ -540,11 +733,11 @@ class SmartContractService {
540
733
  * Normalizes event listener arguments between different ethers.js versions.
541
734
  * This helper method ensures consistent event argument handling regardless of
542
735
  * whether the event payload follows ethers v5 or v6 format.
543
- *
736
+ *
544
737
  * @template Args - Tuple type representing the expected event arguments
545
738
  * @param callback - The event callback function to normalize
546
739
  * @returns Normalized event listener function
547
- *
740
+ *
548
741
  * @example
549
742
  * ```typescript
550
743
  * contract.on('Transfer', this.normalizeListener((from: string, to: string, amount: BigInt) => {
@@ -567,12 +760,12 @@ class SmartContractService {
567
760
  * Sets up an event listener with automatic fallback for RPCs that don't support eth_newFilter.
568
761
  * First attempts to use contract.on() which relies on eth_newFilter. If the RPC doesn't support
569
762
  * this method (error code -32601), automatically falls back to polling with queryFilter.
570
- *
763
+ *
571
764
  * @template Args - Tuple type representing the event arguments
572
765
  * @param contract - The contract instance to listen to
573
766
  * @param eventFilter - The event filter to listen for
574
767
  * @param callback - The callback function to invoke when the event occurs
575
- *
768
+ *
576
769
  * @example
577
770
  * ```typescript
578
771
  * this.setupEventListener(
@@ -598,13 +791,14 @@ class SmartContractService {
598
791
  };
599
792
  if ("send" in provider && typeof provider.send === "function") {
600
793
  try {
601
- await provider.send("eth_newFilter", [testFilter]);
794
+ const filterId = await provider.send("eth_newFilter", [testFilter]);
795
+ await provider.send("eth_getFilterChanges", [filterId]);
602
796
  contract.on(eventFilter, normalizedCallback);
603
797
  return;
604
798
  } catch (error) {
605
799
  if (this.isUnsupportedMethodError(error)) {
606
800
  console.warn(
607
- "RPC does not support eth_newFilter, falling back to polling for events. This may result in delayed event notifications."
801
+ "RPC does not fully support eth_newFilter/eth_getFilterChanges, falling back to polling for events. This may result in delayed event notifications."
608
802
  );
609
803
  this.setupPollingListener(contract, eventFilter, callback);
610
804
  return;
@@ -629,18 +823,23 @@ class SmartContractService {
629
823
  }
630
824
  }
631
825
  /**
632
- * Checks if an error indicates that the RPC method is unsupported (eth_newFilter).
633
- *
826
+ * Checks if an error indicates that the RPC method is unsupported or filter operations are not working.
827
+ * This includes:
828
+ * - Method not found (-32601): RPC doesn't support eth_newFilter
829
+ * - Filter not found (-32000): RPC doesn't properly maintain filters
830
+ *
634
831
  * @param error - The error to check
635
- * @returns true if the error indicates unsupported method
832
+ * @returns true if the error indicates unsupported or broken filter functionality
636
833
  */
637
834
  isUnsupportedMethodError(error) {
638
- return error?.code === -32601 || error?.error?.code === -32601 || error?.data?.code === -32601 || typeof error?.message === "string" && error.message.includes("unsupported method");
835
+ const isMethodNotFound = error?.code === -32601 || error?.error?.code === -32601 || error?.data?.code === -32601 || typeof error?.message === "string" && error.message.includes("unsupported method");
836
+ 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"));
837
+ return isMethodNotFound || isFilterNotFound;
639
838
  }
640
839
  /**
641
840
  * Sets up a polling-based event listener as fallback when eth_newFilter is not supported.
642
841
  * Periodically queries for new events and invokes the callback for each new event found.
643
- *
842
+ *
644
843
  * @template Args - Tuple type representing the event arguments
645
844
  * @param contract - The contract instance to poll
646
845
  * @param eventFilter - The event filter to poll for
@@ -692,7 +891,7 @@ class SmartContractService {
692
891
  }
693
892
  /**
694
893
  * Sets the polling interval for event listeners using the fallback mechanism.
695
- *
894
+ *
696
895
  * @param intervalMs - Polling interval in milliseconds
697
896
  */
698
897
  setEventPollingInterval(intervalMs) {
@@ -703,7 +902,7 @@ class SmartContractService {
703
902
  class ContractServiceError extends Error {
704
903
  /**
705
904
  * Creates a new ContractServiceError instance.
706
- *
905
+ *
707
906
  * @param message - The error message describing what went wrong
708
907
  * @param operation - The operation that was being performed when the error occurred
709
908
  */
@@ -793,7 +992,6 @@ class ProcessRegistryService extends SmartContractService {
793
992
  newProcess(status, startTime, duration, ballotMode, census, metadata, encryptionKey, initStateRoot) {
794
993
  const contractCensus = {
795
994
  censusOrigin: BigInt(census.censusOrigin),
796
- maxVotes: BigInt(census.maxVotes),
797
995
  censusRoot: census.censusRoot,
798
996
  censusURI: census.censusURI
799
997
  };
@@ -824,7 +1022,6 @@ class ProcessRegistryService extends SmartContractService {
824
1022
  setProcessCensus(processID, census) {
825
1023
  const contractCensus = {
826
1024
  censusOrigin: BigInt(census.censusOrigin),
827
- maxVotes: BigInt(census.maxVotes),
828
1025
  censusRoot: census.censusRoot,
829
1026
  censusURI: census.censusURI
830
1027
  };
@@ -856,7 +1053,7 @@ class ProcessRegistryService extends SmartContractService {
856
1053
  }
857
1054
  /**
858
1055
  * Sets the results for a voting process.
859
- *
1056
+ *
860
1057
  * @param processID - The ID of the process to set results for
861
1058
  * @param proof - Zero-knowledge proof validating the results
862
1059
  * @param input - Input data for the proof verification
@@ -864,11 +1061,7 @@ class ProcessRegistryService extends SmartContractService {
864
1061
  */
865
1062
  setProcessResults(processID, proof, input) {
866
1063
  return this.sendTx(
867
- this.contract.setProcessResults(
868
- processID,
869
- proof,
870
- input
871
- ).catch((e) => {
1064
+ this.contract.setProcessResults(processID, proof, input).catch((e) => {
872
1065
  throw new ProcessResultError(e.message, "setResults");
873
1066
  }),
874
1067
  async () => ({ success: true })
@@ -930,6 +1123,34 @@ class ProcessOrchestrationService {
930
1123
  this.organizationRegistry = organizationRegistry;
931
1124
  this.getCrypto = getCrypto;
932
1125
  this.signer = signer;
1126
+ this.censusOrchestrator = new CensusOrchestrator(apiService.census);
1127
+ }
1128
+ /**
1129
+ * Handles census - auto-publishes if needed and returns census config
1130
+ * @private
1131
+ */
1132
+ async handleCensus(census) {
1133
+ if ("isPublished" in census) {
1134
+ if (census instanceof PlainCensus || census instanceof WeightedCensus) {
1135
+ if (!census.isPublished) {
1136
+ const censusBaseURL = this.apiService.census?.["axios"]?.defaults?.baseURL;
1137
+ if (!censusBaseURL || censusBaseURL === "" || censusBaseURL === "undefined") {
1138
+ throw new Error(
1139
+ 'Census API URL is required to publish PlainCensus or WeightedCensus. Please provide "censusUrl" when initializing DavinciSDK, or use a pre-published census.'
1140
+ );
1141
+ }
1142
+ await this.censusOrchestrator.publish(census);
1143
+ }
1144
+ }
1145
+ const censusData = this.censusOrchestrator.getCensusData(census);
1146
+ return {
1147
+ type: censusData.type,
1148
+ root: censusData.root,
1149
+ size: censusData.size,
1150
+ uri: censusData.uri
1151
+ };
1152
+ }
1153
+ return census;
933
1154
  }
934
1155
  /**
935
1156
  * Gets user-friendly process information by transforming raw contract data
@@ -969,7 +1190,6 @@ class ProcessOrchestrationService {
969
1190
  const census = {
970
1191
  type: Number(rawProcess.census.censusOrigin),
971
1192
  root: rawProcess.census.censusRoot,
972
- size: Number(rawProcess.census.maxVotes),
973
1193
  uri: rawProcess.census.censusURI || ""
974
1194
  };
975
1195
  const ballot = {
@@ -984,11 +1204,11 @@ class ProcessOrchestrationService {
984
1204
  };
985
1205
  return {
986
1206
  processId,
987
- title,
1207
+ title: title || "",
988
1208
  description,
989
1209
  census,
990
1210
  ballot,
991
- questions,
1211
+ questions: questions || [],
992
1212
  status: Number(rawProcess.status),
993
1213
  creator: rawProcess.organizationId,
994
1214
  startDate: new Date(startTime * 1e3),
@@ -1005,10 +1225,10 @@ class ProcessOrchestrationService {
1005
1225
  /**
1006
1226
  * Creates a complete voting process and returns an async generator that yields transaction status events.
1007
1227
  * This method allows you to monitor the transaction progress in real-time.
1008
- *
1228
+ *
1009
1229
  * @param config - Process configuration
1010
1230
  * @returns AsyncGenerator yielding transaction status events with ProcessCreationResult
1011
- *
1231
+ *
1012
1232
  * @example
1013
1233
  * ```typescript
1014
1234
  * const stream = sdk.createProcessStream({
@@ -1019,7 +1239,7 @@ class ProcessOrchestrationService {
1019
1239
  * timing: { ... },
1020
1240
  * questions: [ ... ]
1021
1241
  * });
1022
- *
1242
+ *
1023
1243
  * for await (const event of stream) {
1024
1244
  * switch (event.status) {
1025
1245
  * case "pending":
@@ -1081,16 +1301,16 @@ class ProcessOrchestrationService {
1081
1301
  /**
1082
1302
  * Creates a complete voting process with minimal configuration.
1083
1303
  * This is the ultra-easy method for end users that handles all the complex orchestration internally.
1084
- *
1304
+ *
1085
1305
  * For real-time transaction status updates, use createProcessStream() instead.
1086
- *
1306
+ *
1087
1307
  * The method automatically:
1088
1308
  * - Gets encryption keys and initial state root from the sequencer
1089
1309
  * - Handles process creation signatures
1090
1310
  * - Coordinates between sequencer API and on-chain contract calls
1091
1311
  * - Creates and pushes metadata
1092
1312
  * - Submits the on-chain transaction
1093
- *
1313
+ *
1094
1314
  * @param config - Simplified process configuration
1095
1315
  * @returns Promise resolving to the process creation result
1096
1316
  */
@@ -1114,24 +1334,32 @@ class ProcessOrchestrationService {
1114
1334
  const { startTime, duration } = this.calculateTiming(config.timing);
1115
1335
  const signerAddress = await this.signer.getAddress();
1116
1336
  const processId = await this.processRegistry.getNextProcessId(signerAddress);
1117
- const censusRoot = config.census.root;
1337
+ const censusConfig = await this.handleCensus(config.census);
1338
+ const censusRoot = censusConfig.root;
1118
1339
  const ballotMode = config.ballot;
1119
- const metadata = this.createMetadata(config);
1120
- const metadataHash = await this.apiService.sequencer.pushMetadata(metadata);
1121
- const metadataUri = this.apiService.sequencer.getMetadataUrl(metadataHash);
1340
+ let metadataUri;
1341
+ if ("metadataUri" in config) {
1342
+ metadataUri = config.metadataUri;
1343
+ } else {
1344
+ const metadata = this.createMetadata(config);
1345
+ const metadataHash = await this.apiService.sequencer.pushMetadata(metadata);
1346
+ metadataUri = this.apiService.sequencer.getMetadataUrl(metadataHash);
1347
+ }
1122
1348
  const signature = await signProcessCreation(processId, this.signer);
1123
1349
  const sequencerResult = await this.apiService.sequencer.createProcess({
1124
1350
  processId,
1125
- censusRoot,
1351
+ census: {
1352
+ censusOrigin: censusConfig.type,
1353
+ censusRoot,
1354
+ censusURI: censusConfig.uri
1355
+ },
1126
1356
  ballotMode,
1127
- signature,
1128
- censusOrigin: config.census.type
1357
+ signature
1129
1358
  });
1130
1359
  const census = {
1131
- censusOrigin: config.census.type,
1132
- maxVotes: config.census.size.toString(),
1360
+ censusOrigin: censusConfig.type,
1133
1361
  censusRoot,
1134
- censusURI: config.census.uri
1362
+ censusURI: censusConfig.uri
1135
1363
  };
1136
1364
  return {
1137
1365
  processId,
@@ -1198,15 +1426,13 @@ class ProcessOrchestrationService {
1198
1426
  throw new Error("Invalid date format. Use Date object, ISO string, or Unix timestamp.");
1199
1427
  }
1200
1428
  /**
1201
- * Creates metadata from the simplified configuration
1429
+ * Creates metadata from the configuration with metadata fields
1430
+ * This method should only be called with ProcessConfigWithMetadata
1202
1431
  */
1203
1432
  createMetadata(config) {
1204
1433
  const metadata = getElectionMetadataTemplate();
1205
1434
  metadata.title.default = config.title;
1206
1435
  metadata.description.default = config.description || "";
1207
- if (!config.questions || config.questions.length === 0) {
1208
- throw new Error("Questions are required. Please provide at least one question with choices.");
1209
- }
1210
1436
  metadata.questions = config.questions.map((q) => ({
1211
1437
  title: { default: q.title },
1212
1438
  description: { default: q.description || "" },
@@ -1222,14 +1448,14 @@ class ProcessOrchestrationService {
1222
1448
  /**
1223
1449
  * Ends a voting process by setting its status to ENDED.
1224
1450
  * Returns an async generator that yields transaction status events.
1225
- *
1451
+ *
1226
1452
  * @param processId - The process ID to end
1227
1453
  * @returns AsyncGenerator yielding transaction status events
1228
- *
1454
+ *
1229
1455
  * @example
1230
1456
  * ```typescript
1231
1457
  * const stream = sdk.endProcessStream("0x1234567890abcdef...");
1232
- *
1458
+ *
1233
1459
  * for await (const event of stream) {
1234
1460
  * switch (event.status) {
1235
1461
  * case "pending":
@@ -1271,12 +1497,12 @@ class ProcessOrchestrationService {
1271
1497
  /**
1272
1498
  * Ends a voting process by setting its status to ENDED.
1273
1499
  * This is a simplified method that waits for transaction completion.
1274
- *
1500
+ *
1275
1501
  * For real-time transaction status updates, use endProcessStream() instead.
1276
- *
1502
+ *
1277
1503
  * @param processId - The process ID to end
1278
1504
  * @returns Promise resolving when the process is ended
1279
- *
1505
+ *
1280
1506
  * @example
1281
1507
  * ```typescript
1282
1508
  * await sdk.endProcess("0x1234567890abcdef...");
@@ -1298,14 +1524,14 @@ class ProcessOrchestrationService {
1298
1524
  /**
1299
1525
  * Pauses a voting process by setting its status to PAUSED.
1300
1526
  * Returns an async generator that yields transaction status events.
1301
- *
1527
+ *
1302
1528
  * @param processId - The process ID to pause
1303
1529
  * @returns AsyncGenerator yielding transaction status events
1304
- *
1530
+ *
1305
1531
  * @example
1306
1532
  * ```typescript
1307
1533
  * const stream = sdk.pauseProcessStream("0x1234567890abcdef...");
1308
- *
1534
+ *
1309
1535
  * for await (const event of stream) {
1310
1536
  * switch (event.status) {
1311
1537
  * case "pending":
@@ -1347,12 +1573,12 @@ class ProcessOrchestrationService {
1347
1573
  /**
1348
1574
  * Pauses a voting process by setting its status to PAUSED.
1349
1575
  * This is a simplified method that waits for transaction completion.
1350
- *
1576
+ *
1351
1577
  * For real-time transaction status updates, use pauseProcessStream() instead.
1352
- *
1578
+ *
1353
1579
  * @param processId - The process ID to pause
1354
1580
  * @returns Promise resolving when the process is paused
1355
- *
1581
+ *
1356
1582
  * @example
1357
1583
  * ```typescript
1358
1584
  * await sdk.pauseProcess("0x1234567890abcdef...");
@@ -1374,14 +1600,14 @@ class ProcessOrchestrationService {
1374
1600
  /**
1375
1601
  * Cancels a voting process by setting its status to CANCELED.
1376
1602
  * Returns an async generator that yields transaction status events.
1377
- *
1603
+ *
1378
1604
  * @param processId - The process ID to cancel
1379
1605
  * @returns AsyncGenerator yielding transaction status events
1380
- *
1606
+ *
1381
1607
  * @example
1382
1608
  * ```typescript
1383
1609
  * const stream = sdk.cancelProcessStream("0x1234567890abcdef...");
1384
- *
1610
+ *
1385
1611
  * for await (const event of stream) {
1386
1612
  * switch (event.status) {
1387
1613
  * case "pending":
@@ -1423,12 +1649,12 @@ class ProcessOrchestrationService {
1423
1649
  /**
1424
1650
  * Cancels a voting process by setting its status to CANCELED.
1425
1651
  * This is a simplified method that waits for transaction completion.
1426
- *
1652
+ *
1427
1653
  * For real-time transaction status updates, use cancelProcessStream() instead.
1428
- *
1654
+ *
1429
1655
  * @param processId - The process ID to cancel
1430
1656
  * @returns Promise resolving when the process is canceled
1431
- *
1657
+ *
1432
1658
  * @example
1433
1659
  * ```typescript
1434
1660
  * await sdk.cancelProcess("0x1234567890abcdef...");
@@ -1451,14 +1677,14 @@ class ProcessOrchestrationService {
1451
1677
  * Resumes a voting process by setting its status to READY.
1452
1678
  * This is typically used to resume a paused process.
1453
1679
  * Returns an async generator that yields transaction status events.
1454
- *
1680
+ *
1455
1681
  * @param processId - The process ID to resume
1456
1682
  * @returns AsyncGenerator yielding transaction status events
1457
- *
1683
+ *
1458
1684
  * @example
1459
1685
  * ```typescript
1460
1686
  * const stream = sdk.resumeProcessStream("0x1234567890abcdef...");
1461
- *
1687
+ *
1462
1688
  * for await (const event of stream) {
1463
1689
  * switch (event.status) {
1464
1690
  * case "pending":
@@ -1501,12 +1727,12 @@ class ProcessOrchestrationService {
1501
1727
  * Resumes a voting process by setting its status to READY.
1502
1728
  * This is typically used to resume a paused process.
1503
1729
  * This is a simplified method that waits for transaction completion.
1504
- *
1730
+ *
1505
1731
  * For real-time transaction status updates, use resumeProcessStream() instead.
1506
- *
1732
+ *
1507
1733
  * @param processId - The process ID to resume
1508
1734
  * @returns Promise resolving when the process is resumed
1509
- *
1735
+ *
1510
1736
  * @example
1511
1737
  * ```typescript
1512
1738
  * await sdk.resumeProcess("0x1234567890abcdef...");
@@ -1594,11 +1820,7 @@ class CircomProof {
1594
1820
  }
1595
1821
  this.zkeyCache.set(zkeyUrl, zkeyBin);
1596
1822
  }
1597
- const { proof, publicSignals } = await groth16.fullProve(
1598
- inputs,
1599
- wasmBin,
1600
- zkeyBin
1601
- );
1823
+ const { proof, publicSignals } = await groth16.fullProve(inputs, wasmBin, zkeyBin);
1602
1824
  return {
1603
1825
  proof,
1604
1826
  publicSignals
@@ -1633,11 +1855,13 @@ var VoteStatus = /* @__PURE__ */ ((VoteStatus2) => {
1633
1855
  })(VoteStatus || {});
1634
1856
 
1635
1857
  class VoteOrchestrationService {
1636
- constructor(apiService, getCrypto, signer, censusProviders = {}) {
1858
+ constructor(apiService, getCrypto, signer, censusProviders = {}, config = {}) {
1637
1859
  this.apiService = apiService;
1638
1860
  this.getCrypto = getCrypto;
1639
1861
  this.signer = signer;
1640
1862
  this.censusProviders = censusProviders;
1863
+ this.verifyCircuitFiles = config.verifyCircuitFiles ?? true;
1864
+ this.verifyProof = config.verifyProof ?? true;
1641
1865
  }
1642
1866
  /**
1643
1867
  * Submit a vote with simplified configuration
@@ -1646,7 +1870,7 @@ class VoteOrchestrationService {
1646
1870
  * - Gets census proof (Merkle or CSP)
1647
1871
  * - Generates cryptographic proofs
1648
1872
  * - Signs and submits the vote
1649
- *
1873
+ *
1650
1874
  * @param config - Simplified vote configuration
1651
1875
  * @returns Promise resolving to vote submission result
1652
1876
  */
@@ -1673,16 +1897,19 @@ class VoteOrchestrationService {
1673
1897
  );
1674
1898
  const { proof } = await this.generateZkProof(circomInputs);
1675
1899
  const signature = await this.signVote(voteId);
1676
- await this.submitVoteRequest({
1900
+ const voteRequest = {
1677
1901
  processId: config.processId,
1678
- censusProof,
1679
1902
  ballot: cryptoOutput.ballot,
1680
1903
  ballotProof: proof,
1681
1904
  ballotInputsHash: cryptoOutput.ballotInputsHash,
1682
1905
  address: voterAddress,
1683
1906
  signature,
1684
1907
  voteId
1685
- });
1908
+ };
1909
+ if (process.census.censusOrigin === CensusOrigin.CensusOriginCSP) {
1910
+ voteRequest.censusProof = censusProof;
1911
+ }
1912
+ await this.submitVoteRequest(voteRequest);
1686
1913
  const status = await this.apiService.sequencer.getVoteStatus(config.processId, voteId);
1687
1914
  return {
1688
1915
  voteId,
@@ -1694,7 +1921,7 @@ class VoteOrchestrationService {
1694
1921
  }
1695
1922
  /**
1696
1923
  * Get the status of a submitted vote
1697
- *
1924
+ *
1698
1925
  * @param processId - The process ID
1699
1926
  * @param voteId - The vote ID
1700
1927
  * @returns Promise resolving to vote status information
@@ -1709,7 +1936,7 @@ class VoteOrchestrationService {
1709
1936
  }
1710
1937
  /**
1711
1938
  * Check if an address has voted in a process
1712
- *
1939
+ *
1713
1940
  * @param processId - The process ID
1714
1941
  * @param address - The voter's address
1715
1942
  * @returns Promise resolving to boolean indicating if the address has voted
@@ -1720,19 +1947,19 @@ class VoteOrchestrationService {
1720
1947
  /**
1721
1948
  * Watch vote status changes in real-time using an async generator.
1722
1949
  * Yields each status change as it happens, allowing for reactive UI updates.
1723
- *
1950
+ *
1724
1951
  * @param processId - The process ID
1725
1952
  * @param voteId - The vote ID
1726
1953
  * @param options - Optional configuration
1727
1954
  * @returns AsyncGenerator yielding vote status updates
1728
- *
1955
+ *
1729
1956
  * @example
1730
1957
  * ```typescript
1731
1958
  * const vote = await sdk.submitVote({ processId, choices: [1] });
1732
- *
1959
+ *
1733
1960
  * for await (const statusInfo of sdk.watchVoteStatus(vote.processId, vote.voteId)) {
1734
1961
  * console.log(`Vote status: ${statusInfo.status}`);
1735
- *
1962
+ *
1736
1963
  * switch (statusInfo.status) {
1737
1964
  * case VoteStatus.Pending:
1738
1965
  * console.log("⏳ Processing...");
@@ -1769,7 +1996,7 @@ class VoteOrchestrationService {
1769
1996
  /**
1770
1997
  * Wait for a vote to reach a specific status.
1771
1998
  * This is a simpler alternative to watchVoteStatus() that returns only the final status.
1772
- *
1999
+ *
1773
2000
  * @param processId - The process ID
1774
2001
  * @param voteId - The vote ID
1775
2002
  * @param targetStatus - The target status to wait for (default: "settled")
@@ -1872,12 +2099,20 @@ class VoteOrchestrationService {
1872
2099
  const circomProof = new CircomProof({
1873
2100
  wasmUrl: info.circuitUrl,
1874
2101
  zkeyUrl: info.provingKeyUrl,
1875
- vkeyUrl: info.verificationKeyUrl
2102
+ vkeyUrl: info.verificationKeyUrl,
2103
+ // Only pass hashes if verifyCircuitFiles is enabled
2104
+ ...this.verifyCircuitFiles && {
2105
+ wasmHash: info.circuitHash,
2106
+ zkeyHash: info.provingKeyHash,
2107
+ vkeyHash: info.verificationKeyHash
2108
+ }
1876
2109
  });
1877
2110
  const { proof, publicSignals } = await circomProof.generate(circomInputs);
1878
- const isValid = await circomProof.verify(proof, publicSignals);
1879
- if (!isValid) {
1880
- throw new Error("Generated proof is invalid");
2111
+ if (this.verifyProof) {
2112
+ const isValid = await circomProof.verify(proof, publicSignals);
2113
+ if (!isValid) {
2114
+ throw new Error("Generated proof is invalid");
2115
+ }
1881
2116
  }
1882
2117
  return { proof, publicSignals };
1883
2118
  }
@@ -1915,10 +2150,7 @@ class VoteOrchestrationService {
1915
2150
  class OrganizationRegistryService extends SmartContractService {
1916
2151
  constructor(contractAddress, runner) {
1917
2152
  super();
1918
- this.contract = OrganizationRegistry__factory.connect(
1919
- contractAddress,
1920
- runner
1921
- );
2153
+ this.contract = OrganizationRegistry__factory.connect(contractAddress, runner);
1922
2154
  }
1923
2155
  // ─── READ OPERATIONS ───────────────────────────────────────────────────────
1924
2156
  async getOrganization(id) {
@@ -2121,14 +2353,15 @@ class DavinciCrypto {
2121
2353
  * @param privKey - The private key in hex format
2122
2354
  * @param processId - The process ID in hex format
2123
2355
  * @param address - The address in hex format
2356
+ * @param weight - The vote weight as a decimal string
2124
2357
  * @returns The CSP proof as a parsed JSON object
2125
2358
  * @throws if called before `await init()`, or if Go returns an error
2126
2359
  */
2127
- async cspSign(censusOrigin, privKey, processId, address) {
2360
+ async cspSign(censusOrigin, privKey, processId, address, weight) {
2128
2361
  if (!this.initialized) {
2129
2362
  throw new Error("DavinciCrypto not initialized \u2014 call `await init()` first");
2130
2363
  }
2131
- const raw = globalThis.DavinciCrypto.cspSign(censusOrigin, privKey, processId, address);
2364
+ const raw = globalThis.DavinciCrypto.cspSign(censusOrigin, privKey, processId, address, weight);
2132
2365
  if (raw.error) {
2133
2366
  throw new Error(`Go/WASM cspSign error: ${raw.error}`);
2134
2367
  }
@@ -2142,13 +2375,14 @@ class DavinciCrypto {
2142
2375
  * @param censusOrigin - The census origin type (e.g., CensusOrigin.CensusOriginCSP)
2143
2376
  * @param root - The census root
2144
2377
  * @param address - The address
2378
+ * @param weight - The vote weight as a decimal string
2145
2379
  * @param processId - The process ID
2146
2380
  * @param publicKey - The public key
2147
2381
  * @param signature - The signature
2148
2382
  * @returns The verification result
2149
2383
  * @throws if called before `await init()`, or if Go returns an error
2150
2384
  */
2151
- async cspVerify(censusOrigin, root, address, processId, publicKey, signature) {
2385
+ async cspVerify(censusOrigin, root, address, weight, processId, publicKey, signature) {
2152
2386
  if (!this.initialized) {
2153
2387
  throw new Error("DavinciCrypto not initialized \u2014 call `await init()` first");
2154
2388
  }
@@ -2156,6 +2390,7 @@ class DavinciCrypto {
2156
2390
  censusOrigin,
2157
2391
  root,
2158
2392
  address,
2393
+ weight,
2159
2394
  processId,
2160
2395
  publicKey,
2161
2396
  signature
@@ -2194,25 +2429,23 @@ class DavinciCrypto {
2194
2429
  class DavinciSDK {
2195
2430
  constructor(config) {
2196
2431
  this.initialized = false;
2197
- const resolvedConfig = resolveConfiguration({
2198
- environment: config.environment,
2199
- customUrls: {
2200
- sequencer: config.sequencerUrl,
2201
- census: config.censusUrl
2202
- },
2203
- customChain: config.chain
2204
- });
2432
+ const hasCustomAddresses = !!config.addresses && Object.keys(config.addresses).length > 0;
2205
2433
  this.config = {
2206
2434
  signer: config.signer,
2207
- sequencerUrl: config.sequencerUrl ?? resolvedConfig.sequencer,
2208
- censusUrl: config.censusUrl ?? resolvedConfig.census,
2209
- chain: config.chain ?? resolvedConfig.chain,
2210
- contractAddresses: config.contractAddresses || {},
2211
- useSequencerAddresses: config.useSequencerAddresses || false
2435
+ sequencerUrl: config.sequencerUrl,
2436
+ censusUrl: config.censusUrl,
2437
+ customAddresses: config.addresses || {},
2438
+ fetchAddressesFromSequencer: !hasCustomAddresses,
2439
+ // Automatic: fetch if no custom addresses
2440
+ verifyCircuitFiles: config.verifyCircuitFiles ?? true,
2441
+ // Default to true for security
2442
+ verifyProof: config.verifyProof ?? true
2443
+ // Default to true for security
2212
2444
  };
2213
2445
  this.apiService = new VocdoniApiService({
2214
2446
  sequencerURL: this.config.sequencerUrl,
2215
- censusURL: this.config.censusUrl
2447
+ censusURL: this.config.censusUrl || ""
2448
+ // Use empty string if not provided
2216
2449
  });
2217
2450
  this.censusProviders = config.censusProviders || {};
2218
2451
  }
@@ -2222,9 +2455,10 @@ class DavinciSDK {
2222
2455
  */
2223
2456
  async init() {
2224
2457
  if (this.initialized) return;
2225
- if (this.config.useSequencerAddresses) {
2226
- await this.updateContractAddressesFromSequencer();
2458
+ if (this.config.fetchAddressesFromSequencer) {
2459
+ await this.fetchContractAddressesFromSequencer();
2227
2460
  }
2461
+ if (!this.config.censusUrl) ;
2228
2462
  this.initialized = true;
2229
2463
  }
2230
2464
  /**
@@ -2236,28 +2470,34 @@ class DavinciSDK {
2236
2470
  /**
2237
2471
  * Get the process registry service for process management.
2238
2472
  * Requires a signer with a provider for blockchain interactions.
2239
- *
2473
+ *
2240
2474
  * @throws Error if signer does not have a provider
2241
2475
  */
2242
2476
  get processes() {
2243
2477
  this.ensureProvider();
2244
2478
  if (!this._processRegistry) {
2245
2479
  const processRegistryAddress = this.resolveContractAddress("processRegistry");
2246
- this._processRegistry = new ProcessRegistryService(processRegistryAddress, this.config.signer);
2480
+ this._processRegistry = new ProcessRegistryService(
2481
+ processRegistryAddress,
2482
+ this.config.signer
2483
+ );
2247
2484
  }
2248
2485
  return this._processRegistry;
2249
2486
  }
2250
2487
  /**
2251
2488
  * Get the organization registry service for organization management.
2252
2489
  * Requires a signer with a provider for blockchain interactions.
2253
- *
2490
+ *
2254
2491
  * @throws Error if signer does not have a provider
2255
2492
  */
2256
2493
  get organizations() {
2257
2494
  this.ensureProvider();
2258
2495
  if (!this._organizationRegistry) {
2259
2496
  const organizationRegistryAddress = this.resolveContractAddress("organizationRegistry");
2260
- this._organizationRegistry = new OrganizationRegistryService(organizationRegistryAddress, this.config.signer);
2497
+ this._organizationRegistry = new OrganizationRegistryService(
2498
+ organizationRegistryAddress,
2499
+ this.config.signer
2500
+ );
2261
2501
  }
2262
2502
  return this._organizationRegistry;
2263
2503
  }
@@ -2278,7 +2518,7 @@ class DavinciSDK {
2278
2518
  /**
2279
2519
  * Get the process orchestration service for simplified process creation.
2280
2520
  * Requires a signer with a provider for blockchain interactions.
2281
- *
2521
+ *
2282
2522
  * @throws Error if signer does not have a provider
2283
2523
  */
2284
2524
  get processOrchestrator() {
@@ -2303,7 +2543,11 @@ class DavinciSDK {
2303
2543
  this.apiService,
2304
2544
  () => this.getCrypto(),
2305
2545
  this.config.signer,
2306
- this.censusProviders
2546
+ this.censusProviders,
2547
+ {
2548
+ verifyCircuitFiles: this.config.verifyCircuitFiles,
2549
+ verifyProof: this.config.verifyProof
2550
+ }
2307
2551
  );
2308
2552
  }
2309
2553
  return this._voteOrchestrator;
@@ -2312,24 +2556,24 @@ class DavinciSDK {
2312
2556
  * Gets user-friendly process information from the blockchain.
2313
2557
  * This method fetches raw contract data and transforms it into a user-friendly format
2314
2558
  * that matches the ProcessConfig interface used for creation, plus additional runtime data.
2315
- *
2559
+ *
2316
2560
  * Requires a signer with a provider for blockchain interactions.
2317
- *
2561
+ *
2318
2562
  * @param processId - The process ID to fetch
2319
2563
  * @returns Promise resolving to user-friendly process information
2320
2564
  * @throws Error if signer does not have a provider
2321
- *
2565
+ *
2322
2566
  * @example
2323
2567
  * ```typescript
2324
2568
  * const processInfo = await sdk.getProcess("0x1234567890abcdef...");
2325
- *
2569
+ *
2326
2570
  * // Access the same fields as ProcessConfig
2327
2571
  * console.log("Title:", processInfo.title);
2328
2572
  * console.log("Description:", processInfo.description);
2329
2573
  * console.log("Questions:", processInfo.questions);
2330
2574
  * console.log("Census size:", processInfo.census.size);
2331
2575
  * console.log("Ballot config:", processInfo.ballot);
2332
- *
2576
+ *
2333
2577
  * // Plus additional runtime information
2334
2578
  * console.log("Status:", processInfo.status);
2335
2579
  * console.log("Creator:", processInfo.creator);
@@ -2337,7 +2581,7 @@ class DavinciSDK {
2337
2581
  * console.log("End date:", processInfo.endDate);
2338
2582
  * console.log("Duration:", processInfo.duration, "seconds");
2339
2583
  * console.log("Time remaining:", processInfo.timeRemaining, "seconds");
2340
- *
2584
+ *
2341
2585
  * // Access raw contract data if needed
2342
2586
  * console.log("Raw data:", processInfo.raw);
2343
2587
  * ```
@@ -2353,13 +2597,13 @@ class DavinciSDK {
2353
2597
  * Creates a complete voting process and returns an async generator that yields transaction status events.
2354
2598
  * This method allows you to monitor the transaction progress in real-time, including pending, completed,
2355
2599
  * failed, and reverted states.
2356
- *
2600
+ *
2357
2601
  * Requires a signer with a provider for blockchain interactions.
2358
- *
2602
+ *
2359
2603
  * @param config - Simplified process configuration
2360
2604
  * @returns AsyncGenerator yielding transaction status events
2361
2605
  * @throws Error if signer does not have a provider
2362
- *
2606
+ *
2363
2607
  * @example
2364
2608
  * ```typescript
2365
2609
  * const stream = sdk.createProcessStream({
@@ -2395,7 +2639,7 @@ class DavinciSDK {
2395
2639
  * }
2396
2640
  * ]
2397
2641
  * });
2398
- *
2642
+ *
2399
2643
  * // Monitor transaction progress
2400
2644
  * for await (const event of stream) {
2401
2645
  * switch (event.status) {
@@ -2430,22 +2674,22 @@ class DavinciSDK {
2430
2674
  /**
2431
2675
  * Creates a complete voting process with minimal configuration.
2432
2676
  * This is the ultra-easy method for end users that handles all the complex orchestration internally.
2433
- *
2677
+ *
2434
2678
  * For real-time transaction status updates, use createProcessStream() instead.
2435
- *
2679
+ *
2436
2680
  * Requires a signer with a provider for blockchain interactions.
2437
- *
2681
+ *
2438
2682
  * The method automatically:
2439
2683
  * - Gets encryption keys and initial state root from the sequencer
2440
2684
  * - Handles process creation signatures
2441
2685
  * - Coordinates between sequencer API and on-chain contract calls
2442
2686
  * - Creates and pushes metadata
2443
2687
  * - Submits the on-chain transaction
2444
- *
2688
+ *
2445
2689
  * @param config - Simplified process configuration
2446
2690
  * @returns Promise resolving to the process creation result
2447
2691
  * @throws Error if signer does not have a provider
2448
- *
2692
+ *
2449
2693
  * @example
2450
2694
  * ```typescript
2451
2695
  * // Option 1: Using duration (traditional approach)
@@ -2482,7 +2726,7 @@ class DavinciSDK {
2482
2726
  * }
2483
2727
  * ]
2484
2728
  * });
2485
- *
2729
+ *
2486
2730
  * // Option 2: Using start and end dates
2487
2731
  * const result2 = await sdk.createProcess({
2488
2732
  * title: "Weekend Vote",
@@ -2503,18 +2747,20 @@ class DavinciSDK {
2503
2747
  /**
2504
2748
  * Submit a vote with simplified configuration.
2505
2749
  * This is the ultra-easy method for end users that handles all the complex voting workflow internally.
2506
- *
2750
+ *
2507
2751
  * Does NOT require a provider - can be used with a bare Wallet for signing only.
2508
- *
2752
+ * IMPORTANT: Requires censusUrl to be configured in the SDK for fetching census proofs (unless using custom census providers).
2753
+ *
2509
2754
  * The method automatically:
2510
2755
  * - Fetches process information and validates voting is allowed
2511
2756
  * - Gets census proof (Merkle tree based)
2512
2757
  * - Generates cryptographic proofs and encrypts the vote
2513
2758
  * - Signs and submits the vote to the sequencer
2514
- *
2759
+ *
2515
2760
  * @param config - Simplified vote configuration
2516
2761
  * @returns Promise resolving to vote submission result
2517
- *
2762
+ * @throws Error if censusUrl is not configured (unless using custom census providers)
2763
+ *
2518
2764
  * @example
2519
2765
  * ```typescript
2520
2766
  * // Submit a vote with voter's private key
@@ -2523,14 +2769,14 @@ class DavinciSDK {
2523
2769
  * choices: [1, 0], // Vote for option 1 in question 1, option 0 in question 2
2524
2770
  * voterKey: "0x1234567890abcdef..." // Voter's private key
2525
2771
  * });
2526
- *
2772
+ *
2527
2773
  * console.log("Vote ID:", voteResult.voteId);
2528
2774
  * console.log("Status:", voteResult.status);
2529
- *
2775
+ *
2530
2776
  * // Submit a vote with a Wallet instance
2531
2777
  * import { Wallet } from "ethers";
2532
2778
  * const voterWallet = new Wallet("0x...");
2533
- *
2779
+ *
2534
2780
  * const voteResult2 = await sdk.submitVote({
2535
2781
  * processId: "0x1234567890abcdef...",
2536
2782
  * choices: [2], // Single question vote
@@ -2542,17 +2788,22 @@ class DavinciSDK {
2542
2788
  if (!this.initialized) {
2543
2789
  throw new Error("SDK must be initialized before submitting votes. Call sdk.init() first.");
2544
2790
  }
2791
+ if (!this.config.censusUrl && !this.censusProviders.merkle && !this.censusProviders.csp) {
2792
+ throw new Error(
2793
+ "Census URL is required for voting. Provide censusUrl in the SDK constructor config, or use custom census providers."
2794
+ );
2795
+ }
2545
2796
  return this.voteOrchestrator.submitVote(config);
2546
2797
  }
2547
2798
  /**
2548
2799
  * Get the status of a submitted vote.
2549
- *
2800
+ *
2550
2801
  * Does NOT require a provider - uses API calls only.
2551
- *
2802
+ *
2552
2803
  * @param processId - The process ID
2553
2804
  * @param voteId - The vote ID returned from submitVote()
2554
2805
  * @returns Promise resolving to vote status information
2555
- *
2806
+ *
2556
2807
  * @example
2557
2808
  * ```typescript
2558
2809
  * const statusInfo = await sdk.getVoteStatus(processId, voteId);
@@ -2568,13 +2819,13 @@ class DavinciSDK {
2568
2819
  }
2569
2820
  /**
2570
2821
  * Check if an address has voted in a process.
2571
- *
2822
+ *
2572
2823
  * Does NOT require a provider - uses API calls only.
2573
- *
2824
+ *
2574
2825
  * @param processId - The process ID
2575
2826
  * @param address - The voter's address
2576
2827
  * @returns Promise resolving to boolean indicating if the address has voted
2577
- *
2828
+ *
2578
2829
  * @example
2579
2830
  * ```typescript
2580
2831
  * const hasVoted = await sdk.hasAddressVoted(processId, "0x1234567890abcdef...");
@@ -2585,22 +2836,48 @@ class DavinciSDK {
2585
2836
  */
2586
2837
  async hasAddressVoted(processId, address) {
2587
2838
  if (!this.initialized) {
2588
- throw new Error("SDK must be initialized before checking vote status. Call sdk.init() first.");
2839
+ throw new Error(
2840
+ "SDK must be initialized before checking vote status. Call sdk.init() first."
2841
+ );
2589
2842
  }
2590
2843
  return this.voteOrchestrator.hasAddressVoted(processId, address);
2591
2844
  }
2845
+ /**
2846
+ * Check if an address is able to vote in a process and get participant information.
2847
+ *
2848
+ * Does NOT require a provider - uses API calls only.
2849
+ *
2850
+ * @param processId - The process ID
2851
+ * @param address - The voter's address
2852
+ * @returns Promise resolving to participant information (key and weight)
2853
+ *
2854
+ * @example
2855
+ * ```typescript
2856
+ * const participantInfo = await sdk.isAddressAbleToVote(processId, "0x1234567890abcdef...");
2857
+ * console.log("Address:", participantInfo.key);
2858
+ * console.log("Weight:", participantInfo.weight);
2859
+ * ```
2860
+ */
2861
+ async isAddressAbleToVote(processId, address) {
2862
+ if (!this.initialized) {
2863
+ throw new Error(
2864
+ "SDK must be initialized before checking participant info. Call sdk.init() first."
2865
+ );
2866
+ }
2867
+ return this.apiService.sequencer.isAddressAbleToVote(processId, address);
2868
+ }
2592
2869
  /**
2593
2870
  * Watch vote status changes in real-time using an async generator.
2594
- * This method yields each status change as it happens, perfect for showing
2871
+ * This method yields each status change as it happens, perfect for showing
2595
2872
  * progress indicators in UI applications.
2596
- *
2873
+ *
2597
2874
  * Does NOT require a provider - uses API calls only.
2598
- *
2875
+ *
2599
2876
  * @param processId - The process ID
2600
2877
  * @param voteId - The vote ID
2601
2878
  * @param options - Optional configuration
2602
2879
  * @returns AsyncGenerator yielding vote status updates
2603
- *
2880
+ *
2604
2881
  * @example
2605
2882
  * ```typescript
2606
2883
  * // Submit vote
@@ -2608,11 +2885,11 @@ class DavinciSDK {
2608
2885
  * processId: "0x1234567890abcdef...",
2609
2886
  * choices: [1]
2610
2887
  * });
2611
- *
2888
+ *
2612
2889
  * // Watch status changes in real-time
2613
2890
  * for await (const statusInfo of sdk.watchVoteStatus(voteResult.processId, voteResult.voteId)) {
2614
2891
  * console.log(`Vote status: ${statusInfo.status}`);
2615
- *
2892
+ *
2616
2893
  * switch (statusInfo.status) {
2617
2894
  * case VoteStatus.Pending:
2618
2895
  * console.log("⏳ Processing...");
@@ -2632,7 +2909,9 @@ class DavinciSDK {
2632
2909
  */
2633
2910
  watchVoteStatus(processId, voteId, options) {
2634
2911
  if (!this.initialized) {
2635
- throw new Error("SDK must be initialized before watching vote status. Call sdk.init() first.");
2912
+ throw new Error(
2913
+ "SDK must be initialized before watching vote status. Call sdk.init() first."
2914
+ );
2636
2915
  }
2637
2916
  return this.voteOrchestrator.watchVoteStatus(processId, voteId, options);
2638
2917
  }
@@ -2640,16 +2919,16 @@ class DavinciSDK {
2640
2919
  * Wait for a vote to reach a specific status.
2641
2920
  * This is a simpler alternative to watchVoteStatus() that returns only the final status.
2642
2921
  * Useful for waiting for vote confirmation and processing without needing to handle each intermediate status.
2643
- *
2922
+ *
2644
2923
  * Does NOT require a provider - uses API calls only.
2645
- *
2924
+ *
2646
2925
  * @param processId - The process ID
2647
2926
  * @param voteId - The vote ID
2648
2927
  * @param targetStatus - The target status to wait for (default: "settled")
2649
2928
  * @param timeoutMs - Maximum time to wait in milliseconds (default: 300000 = 5 minutes)
2650
2929
  * @param pollIntervalMs - Polling interval in milliseconds (default: 5000 = 5 seconds)
2651
2930
  * @returns Promise resolving to final vote status
2652
- *
2931
+ *
2653
2932
  * @example
2654
2933
  * ```typescript
2655
2934
  * // Submit vote and wait for it to be settled
@@ -2657,7 +2936,7 @@ class DavinciSDK {
2657
2936
  * processId: "0x1234567890abcdef...",
2658
2937
  * choices: [1]
2659
2938
  * });
2660
- *
2939
+ *
2661
2940
  * // Wait for the vote to be fully processed
2662
2941
  * const finalStatus = await sdk.waitForVoteStatus(
2663
2942
  * voteResult.processId,
@@ -2666,31 +2945,39 @@ class DavinciSDK {
2666
2945
  * 300000, // 5 minute timeout
2667
2946
  * 5000 // Check every 5 seconds
2668
2947
  * );
2669
- *
2948
+ *
2670
2949
  * console.log("Vote final status:", finalStatus.status);
2671
2950
  * ```
2672
2951
  */
2673
2952
  async waitForVoteStatus(processId, voteId, targetStatus = VoteStatus.Settled, timeoutMs = 3e5, pollIntervalMs = 5e3) {
2674
2953
  if (!this.initialized) {
2675
- throw new Error("SDK must be initialized before waiting for vote status. Call sdk.init() first.");
2954
+ throw new Error(
2955
+ "SDK must be initialized before waiting for vote status. Call sdk.init() first."
2956
+ );
2676
2957
  }
2677
- return this.voteOrchestrator.waitForVoteStatus(processId, voteId, targetStatus, timeoutMs, pollIntervalMs);
2958
+ return this.voteOrchestrator.waitForVoteStatus(
2959
+ processId,
2960
+ voteId,
2961
+ targetStatus,
2962
+ timeoutMs,
2963
+ pollIntervalMs
2964
+ );
2678
2965
  }
2679
2966
  /**
2680
- * Ends a voting process by setting its status to ENDED and returns an async generator
2681
- * that yields transaction status events. This method allows you to monitor the
2967
+ * Ends a voting process by setting its status to ENDED and returns an async generator
2968
+ * that yields transaction status events. This method allows you to monitor the
2682
2969
  * transaction progress in real-time.
2683
- *
2970
+ *
2684
2971
  * Requires a signer with a provider for blockchain interactions.
2685
- *
2972
+ *
2686
2973
  * @param processId - The process ID to end
2687
2974
  * @returns AsyncGenerator yielding transaction status events
2688
2975
  * @throws Error if signer does not have a provider
2689
- *
2976
+ *
2690
2977
  * @example
2691
2978
  * ```typescript
2692
2979
  * const stream = sdk.endProcessStream("0x1234567890abcdef...");
2693
- *
2980
+ *
2694
2981
  * for await (const event of stream) {
2695
2982
  * switch (event.status) {
2696
2983
  * case TxStatus.Pending:
@@ -2719,15 +3006,15 @@ class DavinciSDK {
2719
3006
  /**
2720
3007
  * Ends a voting process by setting its status to ENDED.
2721
3008
  * This is the simplified method that waits for transaction completion.
2722
- *
3009
+ *
2723
3010
  * For real-time transaction status updates, use endProcessStream() instead.
2724
- *
3011
+ *
2725
3012
  * Requires a signer with a provider for blockchain interactions.
2726
- *
3013
+ *
2727
3014
  * @param processId - The process ID to end
2728
3015
  * @returns Promise resolving when the process is ended
2729
3016
  * @throws Error if signer does not have a provider
2730
- *
3017
+ *
2731
3018
  * @example
2732
3019
  * ```typescript
2733
3020
  * await sdk.endProcess("0x1234567890abcdef...");
@@ -2742,20 +3029,20 @@ class DavinciSDK {
2742
3029
  return this.processOrchestrator.endProcess(processId);
2743
3030
  }
2744
3031
  /**
2745
- * Pauses a voting process by setting its status to PAUSED and returns an async generator
2746
- * that yields transaction status events. This method allows you to monitor the
3032
+ * Pauses a voting process by setting its status to PAUSED and returns an async generator
3033
+ * that yields transaction status events. This method allows you to monitor the
2747
3034
  * transaction progress in real-time.
2748
- *
3035
+ *
2749
3036
  * Requires a signer with a provider for blockchain interactions.
2750
- *
3037
+ *
2751
3038
  * @param processId - The process ID to pause
2752
3039
  * @returns AsyncGenerator yielding transaction status events
2753
3040
  * @throws Error if signer does not have a provider
2754
- *
3041
+ *
2755
3042
  * @example
2756
3043
  * ```typescript
2757
3044
  * const stream = sdk.pauseProcessStream("0x1234567890abcdef...");
2758
- *
3045
+ *
2759
3046
  * for await (const event of stream) {
2760
3047
  * switch (event.status) {
2761
3048
  * case TxStatus.Pending:
@@ -2784,15 +3071,15 @@ class DavinciSDK {
2784
3071
  /**
2785
3072
  * Pauses a voting process by setting its status to PAUSED.
2786
3073
  * This is the simplified method that waits for transaction completion.
2787
- *
3074
+ *
2788
3075
  * For real-time transaction status updates, use pauseProcessStream() instead.
2789
- *
3076
+ *
2790
3077
  * Requires a signer with a provider for blockchain interactions.
2791
- *
3078
+ *
2792
3079
  * @param processId - The process ID to pause
2793
3080
  * @returns Promise resolving when the process is paused
2794
3081
  * @throws Error if signer does not have a provider
2795
- *
3082
+ *
2796
3083
  * @example
2797
3084
  * ```typescript
2798
3085
  * await sdk.pauseProcess("0x1234567890abcdef...");
@@ -2807,20 +3094,20 @@ class DavinciSDK {
2807
3094
  return this.processOrchestrator.pauseProcess(processId);
2808
3095
  }
2809
3096
  /**
2810
- * Cancels a voting process by setting its status to CANCELED and returns an async generator
2811
- * that yields transaction status events. This method allows you to monitor the
3097
+ * Cancels a voting process by setting its status to CANCELED and returns an async generator
3098
+ * that yields transaction status events. This method allows you to monitor the
2812
3099
  * transaction progress in real-time.
2813
- *
3100
+ *
2814
3101
  * Requires a signer with a provider for blockchain interactions.
2815
- *
3102
+ *
2816
3103
  * @param processId - The process ID to cancel
2817
3104
  * @returns AsyncGenerator yielding transaction status events
2818
3105
  * @throws Error if signer does not have a provider
2819
- *
3106
+ *
2820
3107
  * @example
2821
3108
  * ```typescript
2822
3109
  * const stream = sdk.cancelProcessStream("0x1234567890abcdef...");
2823
- *
3110
+ *
2824
3111
  * for await (const event of stream) {
2825
3112
  * switch (event.status) {
2826
3113
  * case TxStatus.Pending:
@@ -2849,15 +3136,15 @@ class DavinciSDK {
2849
3136
  /**
2850
3137
  * Cancels a voting process by setting its status to CANCELED.
2851
3138
  * This is the simplified method that waits for transaction completion.
2852
- *
3139
+ *
2853
3140
  * For real-time transaction status updates, use cancelProcessStream() instead.
2854
- *
3141
+ *
2855
3142
  * Requires a signer with a provider for blockchain interactions.
2856
- *
3143
+ *
2857
3144
  * @param processId - The process ID to cancel
2858
3145
  * @returns Promise resolving when the process is canceled
2859
3146
  * @throws Error if signer does not have a provider
2860
- *
3147
+ *
2861
3148
  * @example
2862
3149
  * ```typescript
2863
3150
  * await sdk.cancelProcess("0x1234567890abcdef...");
@@ -2872,19 +3159,19 @@ class DavinciSDK {
2872
3159
  return this.processOrchestrator.cancelProcess(processId);
2873
3160
  }
2874
3161
  /**
2875
- * Resumes a voting process by setting its status to READY and returns an async generator
3162
+ * Resumes a voting process by setting its status to READY and returns an async generator
2876
3163
  * that yields transaction status events. This is typically used to resume a paused process.
2877
- *
3164
+ *
2878
3165
  * Requires a signer with a provider for blockchain interactions.
2879
- *
3166
+ *
2880
3167
  * @param processId - The process ID to resume
2881
3168
  * @returns AsyncGenerator yielding transaction status events
2882
3169
  * @throws Error if signer does not have a provider
2883
- *
3170
+ *
2884
3171
  * @example
2885
3172
  * ```typescript
2886
3173
  * const stream = sdk.resumeProcessStream("0x1234567890abcdef...");
2887
- *
3174
+ *
2888
3175
  * for await (const event of stream) {
2889
3176
  * switch (event.status) {
2890
3177
  * case TxStatus.Pending:
@@ -2914,15 +3201,15 @@ class DavinciSDK {
2914
3201
  * Resumes a voting process by setting its status to READY.
2915
3202
  * This is typically used to resume a paused process.
2916
3203
  * This is the simplified method that waits for transaction completion.
2917
- *
3204
+ *
2918
3205
  * For real-time transaction status updates, use resumeProcessStream() instead.
2919
- *
3206
+ *
2920
3207
  * Requires a signer with a provider for blockchain interactions.
2921
- *
3208
+ *
2922
3209
  * @param processId - The process ID to resume
2923
3210
  * @returns Promise resolving when the process is resumed
2924
3211
  * @throws Error if signer does not have a provider
2925
- *
3212
+ *
2926
3213
  * @example
2927
3214
  * ```typescript
2928
3215
  * await sdk.resumeProcess("0x1234567890abcdef...");
@@ -2938,64 +3225,50 @@ class DavinciSDK {
2938
3225
  }
2939
3226
  /**
2940
3227
  * Resolve contract address based on configuration priority:
2941
- * 1. If useSequencerAddresses is true: addresses from sequencer (highest priority)
2942
- * 2. Custom addresses from config (if provided by user)
2943
- * 3. Default deployed addresses from npm package
3228
+ * 1. Custom addresses from user config (if provided)
3229
+ * 2. Addresses from sequencer (fetched during init if no custom addresses provided)
2944
3230
  */
2945
3231
  resolveContractAddress(contractName) {
2946
- if (this.config.useSequencerAddresses) {
2947
- return this.getDefaultContractAddress(contractName);
2948
- }
2949
- const customAddress = this.config.contractAddresses[contractName];
3232
+ const customAddress = this.config.customAddresses[contractName];
2950
3233
  if (customAddress) {
2951
3234
  return customAddress;
2952
3235
  }
2953
- return this.getDefaultContractAddress(contractName);
2954
- }
2955
- /**
2956
- * Get default contract address from deployed addresses
2957
- */
2958
- getDefaultContractAddress(contractName) {
2959
- const chain = this.config.chain;
2960
- switch (contractName) {
2961
- case "processRegistry":
2962
- return deployedAddresses.processRegistry[chain];
2963
- case "organizationRegistry":
2964
- return deployedAddresses.organizationRegistry[chain];
2965
- case "stateTransitionVerifier":
2966
- return deployedAddresses.stateTransitionVerifierGroth16[chain];
2967
- case "resultsVerifier":
2968
- return deployedAddresses.resultsVerifierGroth16[chain];
2969
- case "sequencerRegistry":
2970
- return deployedAddresses.sequencerRegistry[chain];
2971
- default:
2972
- throw new Error(`Unknown contract: ${contractName}`);
3236
+ if (!this.config.customAddresses[contractName]) {
3237
+ throw new Error(
3238
+ `Contract address for '${contractName}' not found. Make sure SDK is initialized with sdk.init() or provide custom addresses in config.`
3239
+ );
2973
3240
  }
3241
+ return this.config.customAddresses[contractName];
2974
3242
  }
2975
3243
  /**
2976
- * Update contract addresses from sequencer info if useSequencerAddresses is enabled
2977
- * Sequencer addresses have priority over user-provided addresses
3244
+ * Fetch contract addresses from sequencer info
3245
+ * This is called during init() if custom addresses are not provided
2978
3246
  */
2979
- async updateContractAddressesFromSequencer() {
3247
+ async fetchContractAddressesFromSequencer() {
2980
3248
  try {
2981
3249
  const info = await this.apiService.sequencer.getInfo();
2982
3250
  const contracts = info.contracts;
2983
3251
  if (contracts.process) {
3252
+ this.config.customAddresses.processRegistry = contracts.process;
2984
3253
  this._processRegistry = new ProcessRegistryService(contracts.process, this.config.signer);
2985
- this.config.contractAddresses.processRegistry = contracts.process;
2986
3254
  }
2987
3255
  if (contracts.organization) {
2988
- this._organizationRegistry = new OrganizationRegistryService(contracts.organization, this.config.signer);
2989
- this.config.contractAddresses.organizationRegistry = contracts.organization;
3256
+ this.config.customAddresses.organizationRegistry = contracts.organization;
3257
+ this._organizationRegistry = new OrganizationRegistryService(
3258
+ contracts.organization,
3259
+ this.config.signer
3260
+ );
2990
3261
  }
2991
3262
  if (contracts.stateTransitionVerifier) {
2992
- this.config.contractAddresses.stateTransitionVerifier = contracts.stateTransitionVerifier;
3263
+ this.config.customAddresses.stateTransitionVerifier = contracts.stateTransitionVerifier;
2993
3264
  }
2994
3265
  if (contracts.resultsVerifier) {
2995
- this.config.contractAddresses.resultsVerifier = contracts.resultsVerifier;
3266
+ this.config.customAddresses.resultsVerifier = contracts.resultsVerifier;
2996
3267
  }
2997
3268
  } catch (error) {
2998
- console.warn("Failed to fetch contract addresses from sequencer, using defaults:", error);
3269
+ throw new Error(
3270
+ `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.`
3271
+ );
2999
3272
  }
3000
3273
  }
3001
3274
  /**
@@ -3024,5 +3297,5 @@ class DavinciSDK {
3024
3297
  }
3025
3298
  }
3026
3299
 
3027
- export { BaseService, CensusOrigin, CircomProof, ContractServiceError, DEFAULT_ENVIRONMENT_URLS, DavinciCrypto, DavinciSDK, ElectionMetadataTemplate, ElectionResultsTypeNames, OrganizationAdministratorError, OrganizationCreateError, OrganizationDeleteError, OrganizationRegistryService, OrganizationUpdateError, ProcessCensusError, ProcessCreateError, ProcessDurationError, ProcessOrchestrationService, ProcessRegistryService, ProcessResultError, ProcessStateTransitionError, ProcessStatus, ProcessStatusError, SmartContractService, TxStatus, VocdoniApiService, VocdoniCensusService, VocdoniSequencerService, VoteOrchestrationService, VoteStatus, assertCSPCensusProof, assertMerkleCensusProof, createProcessSignatureMessage, deployedAddresses, getElectionMetadataTemplate, getEnvironmentChain, getEnvironmentConfig, getEnvironmentUrls, isCSPCensusProof, isMerkleCensusProof, resolveConfiguration, resolveUrls, signProcessCreation, validateProcessId };
3300
+ export { BaseService, Census, CensusOrchestrator, CensusOrigin, CensusType, CircomProof, ContractServiceError, CspCensus, DavinciCrypto, DavinciSDK, ElectionMetadataTemplate, ElectionResultsTypeNames, OrganizationAdministratorError, OrganizationCreateError, OrganizationDeleteError, OrganizationRegistryService, OrganizationUpdateError, PlainCensus, ProcessCensusError, ProcessCreateError, ProcessDurationError, ProcessOrchestrationService, ProcessRegistryService, ProcessResultError, ProcessStateTransitionError, ProcessStatus, ProcessStatusError, PublishedCensus, SmartContractService, TxStatus, VocdoniApiService, VocdoniCensusService, VocdoniSequencerService, VoteOrchestrationService, VoteStatus, WeightedCensus, assertCSPCensusProof, assertMerkleCensusProof, createProcessSignatureMessage, getElectionMetadataTemplate, isCSPCensusProof, isMerkleCensusProof, signProcessCreation, validateProcessId };
3028
3301
  //# sourceMappingURL=index.mjs.map