@vocdoni/davinci-sdk 0.0.1 → 0.0.2

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
@@ -400,29 +400,34 @@ function resolveUrls(options = {}) {
400
400
  }
401
401
 
402
402
  var processRegistry = {
403
- sepolia: "0x40939Ec9FD872eb79A1723B559572dfD71a05d11",
403
+ sepolia: "0x50CA6A350f3A9C7B8a82eE7a4D5F0f21C54D68e3",
404
404
  uzh: "0x69B16f67Bd2fB18bD720379E9C1Ef5EaD3872d67",
405
- mainnet: "0x0"
405
+ mainnet: "0x0",
406
+ celo: "0xDda6c75d32c375946C8ae9be41B2F3539dB1118A"
406
407
  };
407
408
  var organizationRegistry = {
408
- sepolia: "0xe7136ED5a7b0e995A8fe35d8B1B815E4160cB491",
409
+ sepolia: "0xF30678f579Fd89b86295503dC179d5d3aed47a98",
409
410
  uzh: "0xf7BCE4546805547bE526Ca864d6722Ed193E51Aa",
410
- mainnet: "0x0"
411
+ mainnet: "0x0",
412
+ celo: "0xE17D701EA8f34022F97fC2Ec68c73D42bF99D0BD"
411
413
  };
412
414
  var stateTransitionVerifierGroth16 = {
413
- sepolia: "0xb7A142D24b9220eCBC4f7fcB89Ee952a6C7E332a",
415
+ sepolia: "0x96EcBbD6aB5fDC063E0fC426F2700290DeeAFE4E",
414
416
  uzh: "0x5e4673CD378F05cc3Ae25804539c91E711548741",
415
- mainnet: "0x0"
417
+ mainnet: "0x0",
418
+ celo: "0x2DaF913D423128258b2F378E320F9D9D3Be5eCf5"
416
419
  };
417
420
  var resultsVerifierGroth16 = {
418
- sepolia: "0x1188cEbB56ecc90e2bAe5c914274C81Fe1a22e67",
421
+ sepolia: "0x3ab37C40f7d0649f7a15BA3230f14AB29B51eDCC",
419
422
  uzh: "0x00c7F87731346F592197E49A90Ad6EC236Ad9985",
420
- mainnet: "0x0"
423
+ mainnet: "0x0",
424
+ celo: "0x808276962217AD1ED3af7D51bFc791903CAd9389"
421
425
  };
422
426
  var sequencerRegistry = {
423
427
  sepolia: "0x0",
424
428
  uzh: "0x0",
425
- mainnet: "0x0"
429
+ mainnet: "0x0",
430
+ celo: "0x0"
426
431
  };
427
432
  var addressesJson = {
428
433
  processRegistry: processRegistry,
@@ -441,6 +446,12 @@ var TxStatus = /* @__PURE__ */ ((TxStatus2) => {
441
446
  return TxStatus2;
442
447
  })(TxStatus || {});
443
448
  class SmartContractService {
449
+ constructor() {
450
+ /** Active polling intervals for event listeners using fallback mode */
451
+ this.pollingIntervals = [];
452
+ /** Default polling interval in milliseconds for event listener fallback */
453
+ this.eventPollingInterval = 5e3;
454
+ }
444
455
  /**
445
456
  * Sends a transaction and yields status events during its lifecycle.
446
457
  * This method handles the complete transaction flow from submission to completion,
@@ -552,6 +563,141 @@ class SmartContractService {
552
563
  callback(...args);
553
564
  };
554
565
  }
566
+ /**
567
+ * Sets up an event listener with automatic fallback for RPCs that don't support eth_newFilter.
568
+ * First attempts to use contract.on() which relies on eth_newFilter. If the RPC doesn't support
569
+ * this method (error code -32601), automatically falls back to polling with queryFilter.
570
+ *
571
+ * @template Args - Tuple type representing the event arguments
572
+ * @param contract - The contract instance to listen to
573
+ * @param eventFilter - The event filter to listen for
574
+ * @param callback - The callback function to invoke when the event occurs
575
+ *
576
+ * @example
577
+ * ```typescript
578
+ * this.setupEventListener(
579
+ * this.contract,
580
+ * this.contract.filters.Transfer(),
581
+ * (from: string, to: string, amount: bigint) => {
582
+ * console.log(`Transfer: ${from} -> ${to}: ${amount}`);
583
+ * }
584
+ * );
585
+ * ```
586
+ */
587
+ async setupEventListener(contract, eventFilter, callback) {
588
+ const normalizedCallback = this.normalizeListener(callback);
589
+ const provider = contract.runner?.provider;
590
+ if (!provider) {
591
+ console.warn("No provider available for event listeners");
592
+ return;
593
+ }
594
+ try {
595
+ const testFilter = {
596
+ address: await contract.getAddress(),
597
+ topics: []
598
+ };
599
+ if ("send" in provider && typeof provider.send === "function") {
600
+ try {
601
+ await provider.send("eth_newFilter", [testFilter]);
602
+ contract.on(eventFilter, normalizedCallback);
603
+ return;
604
+ } catch (error) {
605
+ if (this.isUnsupportedMethodError(error)) {
606
+ console.warn(
607
+ "RPC does not support eth_newFilter, falling back to polling for events. This may result in delayed event notifications."
608
+ );
609
+ this.setupPollingListener(contract, eventFilter, callback);
610
+ return;
611
+ }
612
+ }
613
+ }
614
+ const errorHandler = (error) => {
615
+ if (this.isUnsupportedMethodError(error)) {
616
+ contract.off(eventFilter, normalizedCallback);
617
+ contract.off("error", errorHandler);
618
+ console.warn(
619
+ "RPC does not support eth_newFilter, falling back to polling for events. This may result in delayed event notifications."
620
+ );
621
+ this.setupPollingListener(contract, eventFilter, callback);
622
+ }
623
+ };
624
+ contract.once("error", errorHandler);
625
+ contract.on(eventFilter, normalizedCallback);
626
+ } catch (error) {
627
+ console.warn("Error setting up event listener, falling back to polling:", error.message);
628
+ this.setupPollingListener(contract, eventFilter, callback);
629
+ }
630
+ }
631
+ /**
632
+ * Checks if an error indicates that the RPC method is unsupported (eth_newFilter).
633
+ *
634
+ * @param error - The error to check
635
+ * @returns true if the error indicates unsupported method
636
+ */
637
+ isUnsupportedMethodError(error) {
638
+ return error?.code === -32601 || error?.error?.code === -32601 || error?.data?.code === -32601 || typeof error?.message === "string" && error.message.includes("unsupported method");
639
+ }
640
+ /**
641
+ * Sets up a polling-based event listener as fallback when eth_newFilter is not supported.
642
+ * Periodically queries for new events and invokes the callback for each new event found.
643
+ *
644
+ * @template Args - Tuple type representing the event arguments
645
+ * @param contract - The contract instance to poll
646
+ * @param eventFilter - The event filter to poll for
647
+ * @param callback - The callback function to invoke for each event
648
+ */
649
+ setupPollingListener(contract, eventFilter, callback) {
650
+ let lastProcessedBlock = 0;
651
+ const poll = async () => {
652
+ try {
653
+ const provider = contract.runner?.provider;
654
+ if (!provider) {
655
+ console.warn("No provider available for polling events");
656
+ return;
657
+ }
658
+ const currentBlock = await provider.getBlockNumber();
659
+ if (lastProcessedBlock === 0) {
660
+ lastProcessedBlock = currentBlock - 1;
661
+ }
662
+ if (currentBlock > lastProcessedBlock) {
663
+ const events = await contract.queryFilter(
664
+ eventFilter,
665
+ lastProcessedBlock + 1,
666
+ currentBlock
667
+ );
668
+ for (const event of events) {
669
+ if ("args" in event && event.args) {
670
+ callback(...event.args);
671
+ }
672
+ }
673
+ lastProcessedBlock = currentBlock;
674
+ }
675
+ } catch (error) {
676
+ console.error("Error polling for events:", error);
677
+ }
678
+ };
679
+ const intervalId = setInterval(poll, this.eventPollingInterval);
680
+ this.pollingIntervals.push(intervalId);
681
+ poll();
682
+ }
683
+ /**
684
+ * Clears all active polling intervals.
685
+ * Should be called when removing all listeners or cleaning up the service.
686
+ */
687
+ clearPollingIntervals() {
688
+ for (const intervalId of this.pollingIntervals) {
689
+ clearInterval(intervalId);
690
+ }
691
+ this.pollingIntervals = [];
692
+ }
693
+ /**
694
+ * Sets the polling interval for event listeners using the fallback mechanism.
695
+ *
696
+ * @param intervalMs - Polling interval in milliseconds
697
+ */
698
+ setEventPollingInterval(intervalMs) {
699
+ this.eventPollingInterval = intervalMs;
700
+ }
555
701
  }
556
702
 
557
703
  class ContractServiceError extends Error {
@@ -730,43 +876,50 @@ class ProcessRegistryService extends SmartContractService {
730
876
  }
731
877
  // ─── EVENT LISTENERS ───────────────────────────────────────────────────────
732
878
  onProcessCreated(cb) {
733
- this.contract.on(
879
+ this.setupEventListener(
880
+ this.contract,
734
881
  this.contract.filters.ProcessCreated(),
735
- this.normalizeListener(cb)
736
- );
882
+ cb
883
+ ).catch((err) => console.error("Error setting up ProcessCreated listener:", err));
737
884
  }
738
885
  onProcessStatusChanged(cb) {
739
- this.contract.on(
886
+ this.setupEventListener(
887
+ this.contract,
740
888
  this.contract.filters.ProcessStatusChanged(),
741
- this.normalizeListener(cb)
742
- );
889
+ cb
890
+ ).catch((err) => console.error("Error setting up ProcessStatusChanged listener:", err));
743
891
  }
744
892
  onCensusUpdated(cb) {
745
- this.contract.on(
893
+ this.setupEventListener(
894
+ this.contract,
746
895
  this.contract.filters.CensusUpdated(),
747
- this.normalizeListener(cb)
748
- );
896
+ cb
897
+ ).catch((err) => console.error("Error setting up CensusUpdated listener:", err));
749
898
  }
750
899
  onProcessDurationChanged(cb) {
751
- this.contract.on(
900
+ this.setupEventListener(
901
+ this.contract,
752
902
  this.contract.filters.ProcessDurationChanged(),
753
- this.normalizeListener(cb)
754
- );
903
+ cb
904
+ ).catch((err) => console.error("Error setting up ProcessDurationChanged listener:", err));
755
905
  }
756
906
  onStateRootUpdated(cb) {
757
- this.contract.on(
907
+ this.setupEventListener(
908
+ this.contract,
758
909
  this.contract.filters.ProcessStateRootUpdated(),
759
- this.normalizeListener(cb)
760
- );
910
+ cb
911
+ ).catch((err) => console.error("Error setting up StateRootUpdated listener:", err));
761
912
  }
762
913
  onProcessResultsSet(cb) {
763
- this.contract.on(
914
+ this.setupEventListener(
915
+ this.contract,
764
916
  this.contract.filters.ProcessResultsSet(),
765
- this.normalizeListener(cb)
766
- );
917
+ cb
918
+ ).catch((err) => console.error("Error setting up ProcessResultsSet listener:", err));
767
919
  }
768
920
  removeAllListeners() {
769
921
  this.contract.removeAllListeners();
922
+ this.clearPollingIntervals();
770
923
  }
771
924
  }
772
925
 
@@ -850,10 +1003,114 @@ class ProcessOrchestrationService {
850
1003
  };
851
1004
  }
852
1005
  /**
853
- * Creates a complete voting process with minimal configuration
854
- * This method handles all the complex orchestration internally
1006
+ * Creates a complete voting process and returns an async generator that yields transaction status events.
1007
+ * This method allows you to monitor the transaction progress in real-time.
1008
+ *
1009
+ * @param config - Process configuration
1010
+ * @returns AsyncGenerator yielding transaction status events with ProcessCreationResult
1011
+ *
1012
+ * @example
1013
+ * ```typescript
1014
+ * const stream = sdk.createProcessStream({
1015
+ * title: "My Election",
1016
+ * description: "A simple election",
1017
+ * census: { ... },
1018
+ * ballot: { ... },
1019
+ * timing: { ... },
1020
+ * questions: [ ... ]
1021
+ * });
1022
+ *
1023
+ * for await (const event of stream) {
1024
+ * switch (event.status) {
1025
+ * case "pending":
1026
+ * console.log("Transaction pending:", event.hash);
1027
+ * break;
1028
+ * case "completed":
1029
+ * console.log("Process created:", event.response.processId);
1030
+ * console.log("Transaction hash:", event.response.transactionHash);
1031
+ * break;
1032
+ * case "failed":
1033
+ * console.error("Transaction failed:", event.error);
1034
+ * break;
1035
+ * case "reverted":
1036
+ * console.error("Transaction reverted:", event.reason);
1037
+ * break;
1038
+ * }
1039
+ * }
1040
+ * ```
1041
+ */
1042
+ async *createProcessStream(config) {
1043
+ const data = await this.prepareProcessCreation(config);
1044
+ const encryptionKey = {
1045
+ x: data.sequencerResult.encryptionPubKey[0],
1046
+ y: data.sequencerResult.encryptionPubKey[1]
1047
+ };
1048
+ const txStream = this.processRegistry.newProcess(
1049
+ ProcessStatus.READY,
1050
+ data.startTime,
1051
+ data.duration,
1052
+ data.ballotMode,
1053
+ data.census,
1054
+ data.metadataUri,
1055
+ encryptionKey,
1056
+ BigInt(data.sequencerResult.stateRoot)
1057
+ );
1058
+ let transactionHash = "unknown";
1059
+ for await (const event of txStream) {
1060
+ if (event.status === TxStatus.Pending) {
1061
+ transactionHash = event.hash;
1062
+ yield { status: TxStatus.Pending, hash: event.hash };
1063
+ } else if (event.status === TxStatus.Completed) {
1064
+ yield {
1065
+ status: TxStatus.Completed,
1066
+ response: {
1067
+ processId: data.processId,
1068
+ transactionHash
1069
+ }
1070
+ };
1071
+ break;
1072
+ } else if (event.status === TxStatus.Failed) {
1073
+ yield { status: TxStatus.Failed, error: event.error };
1074
+ break;
1075
+ } else if (event.status === TxStatus.Reverted) {
1076
+ yield { status: TxStatus.Reverted, reason: event.reason };
1077
+ break;
1078
+ }
1079
+ }
1080
+ }
1081
+ /**
1082
+ * Creates a complete voting process with minimal configuration.
1083
+ * This is the ultra-easy method for end users that handles all the complex orchestration internally.
1084
+ *
1085
+ * For real-time transaction status updates, use createProcessStream() instead.
1086
+ *
1087
+ * The method automatically:
1088
+ * - Gets encryption keys and initial state root from the sequencer
1089
+ * - Handles process creation signatures
1090
+ * - Coordinates between sequencer API and on-chain contract calls
1091
+ * - Creates and pushes metadata
1092
+ * - Submits the on-chain transaction
1093
+ *
1094
+ * @param config - Simplified process configuration
1095
+ * @returns Promise resolving to the process creation result
855
1096
  */
856
1097
  async createProcess(config) {
1098
+ for await (const event of this.createProcessStream(config)) {
1099
+ if (event.status === "completed") {
1100
+ return event.response;
1101
+ } else if (event.status === "failed") {
1102
+ throw event.error;
1103
+ } else if (event.status === "reverted") {
1104
+ throw new Error(`Transaction reverted: ${event.reason || "unknown reason"}`);
1105
+ }
1106
+ }
1107
+ throw new Error("Process creation stream ended unexpectedly");
1108
+ }
1109
+ /**
1110
+ * Prepares all data needed for process creation
1111
+ * @private
1112
+ */
1113
+ async prepareProcessCreation(config) {
857
1114
  const { startTime, duration } = this.calculateTiming(config.timing);
858
1115
  const signerAddress = await this.signer.getAddress();
859
1116
  const processId = await this.processRegistry.getNextProcessId(signerAddress);
@@ -876,35 +1133,15 @@ class ProcessOrchestrationService {
876
1133
  censusRoot,
877
1134
  censusURI: config.census.uri
878
1135
  };
879
- const encryptionKey = {
880
- x: sequencerResult.encryptionPubKey[0],
881
- y: sequencerResult.encryptionPubKey[1]
882
- };
883
- const txStream = this.processRegistry.newProcess(
884
- ProcessStatus.READY,
1136
+ return {
1137
+ processId,
885
1138
  startTime,
886
1139
  duration,
1140
+ censusRoot,
887
1141
  ballotMode,
888
- census,
889
1142
  metadataUri,
890
- encryptionKey,
891
- BigInt(sequencerResult.stateRoot)
892
- );
893
- let transactionHash = "unknown";
894
- for await (const event of txStream) {
895
- if (event.status === "pending") {
896
- transactionHash = event.hash;
897
- } else if (event.status === "completed") {
898
- break;
899
- } else if (event.status === "failed") {
900
- throw event.error;
901
- } else if (event.status === "reverted") {
902
- throw new Error(`Transaction reverted: ${event.reason || "unknown reason"}`);
903
- }
904
- }
905
- return {
906
- processId,
907
- transactionHash
1143
+ sequencerResult,
1144
+ census
908
1145
  };
909
1146
  }
910
1147
  /**
@@ -982,6 +1219,312 @@ class ProcessOrchestrationService {
982
1219
  }));
983
1220
  return metadata;
984
1221
  }
1222
+ /**
1223
+ * Ends a voting process by setting its status to ENDED.
1224
+ * Returns an async generator that yields transaction status events.
1225
+ *
1226
+ * @param processId - The process ID to end
1227
+ * @returns AsyncGenerator yielding transaction status events
1228
+ *
1229
+ * @example
1230
+ * ```typescript
1231
+ * const stream = sdk.endProcessStream("0x1234567890abcdef...");
1232
+ *
1233
+ * for await (const event of stream) {
1234
+ * switch (event.status) {
1235
+ * case "pending":
1236
+ * console.log("Transaction pending:", event.hash);
1237
+ * break;
1238
+ * case "completed":
1239
+ * console.log("Process ended successfully");
1240
+ * break;
1241
+ * case "failed":
1242
+ * console.error("Transaction failed:", event.error);
1243
+ * break;
1244
+ * case "reverted":
1245
+ * console.error("Transaction reverted:", event.reason);
1246
+ * break;
1247
+ * }
1248
+ * }
1249
+ * ```
1250
+ */
1251
+ async *endProcessStream(processId) {
1252
+ const txStream = this.processRegistry.setProcessStatus(processId, ProcessStatus.ENDED);
1253
+ for await (const event of txStream) {
1254
+ if (event.status === TxStatus.Pending) {
1255
+ yield { status: TxStatus.Pending, hash: event.hash };
1256
+ } else if (event.status === TxStatus.Completed) {
1257
+ yield {
1258
+ status: TxStatus.Completed,
1259
+ response: { success: true }
1260
+ };
1261
+ break;
1262
+ } else if (event.status === TxStatus.Failed) {
1263
+ yield { status: TxStatus.Failed, error: event.error };
1264
+ break;
1265
+ } else if (event.status === TxStatus.Reverted) {
1266
+ yield { status: TxStatus.Reverted, reason: event.reason };
1267
+ break;
1268
+ }
1269
+ }
1270
+ }
1271
+ /**
1272
+ * Ends a voting process by setting its status to ENDED.
1273
+ * This is a simplified method that waits for transaction completion.
1274
+ *
1275
+ * For real-time transaction status updates, use endProcessStream() instead.
1276
+ *
1277
+ * @param processId - The process ID to end
1278
+ * @returns Promise resolving when the process is ended
1279
+ *
1280
+ * @example
1281
+ * ```typescript
1282
+ * await sdk.endProcess("0x1234567890abcdef...");
1283
+ * console.log("Process ended successfully");
1284
+ * ```
1285
+ */
1286
+ async endProcess(processId) {
1287
+ for await (const event of this.endProcessStream(processId)) {
1288
+ if (event.status === "completed") {
1289
+ return;
1290
+ } else if (event.status === "failed") {
1291
+ throw event.error;
1292
+ } else if (event.status === "reverted") {
1293
+ throw new Error(`Transaction reverted: ${event.reason || "unknown reason"}`);
1294
+ }
1295
+ }
1296
+ throw new Error("End process stream ended unexpectedly");
1297
+ }
1298
+ /**
1299
+ * Pauses a voting process by setting its status to PAUSED.
1300
+ * Returns an async generator that yields transaction status events.
1301
+ *
1302
+ * @param processId - The process ID to pause
1303
+ * @returns AsyncGenerator yielding transaction status events
1304
+ *
1305
+ * @example
1306
+ * ```typescript
1307
+ * const stream = sdk.pauseProcessStream("0x1234567890abcdef...");
1308
+ *
1309
+ * for await (const event of stream) {
1310
+ * switch (event.status) {
1311
+ * case "pending":
1312
+ * console.log("Transaction pending:", event.hash);
1313
+ * break;
1314
+ * case "completed":
1315
+ * console.log("Process paused successfully");
1316
+ * break;
1317
+ * case "failed":
1318
+ * console.error("Transaction failed:", event.error);
1319
+ * break;
1320
+ * case "reverted":
1321
+ * console.error("Transaction reverted:", event.reason);
1322
+ * break;
1323
+ * }
1324
+ * }
1325
+ * ```
1326
+ */
1327
+ async *pauseProcessStream(processId) {
1328
+ const txStream = this.processRegistry.setProcessStatus(processId, ProcessStatus.PAUSED);
1329
+ for await (const event of txStream) {
1330
+ if (event.status === TxStatus.Pending) {
1331
+ yield { status: TxStatus.Pending, hash: event.hash };
1332
+ } else if (event.status === TxStatus.Completed) {
1333
+ yield {
1334
+ status: TxStatus.Completed,
1335
+ response: { success: true }
1336
+ };
1337
+ break;
1338
+ } else if (event.status === TxStatus.Failed) {
1339
+ yield { status: TxStatus.Failed, error: event.error };
1340
+ break;
1341
+ } else if (event.status === TxStatus.Reverted) {
1342
+ yield { status: TxStatus.Reverted, reason: event.reason };
1343
+ break;
1344
+ }
1345
+ }
1346
+ }
1347
+ /**
1348
+ * Pauses a voting process by setting its status to PAUSED.
1349
+ * This is a simplified method that waits for transaction completion.
1350
+ *
1351
+ * For real-time transaction status updates, use pauseProcessStream() instead.
1352
+ *
1353
+ * @param processId - The process ID to pause
1354
+ * @returns Promise resolving when the process is paused
1355
+ *
1356
+ * @example
1357
+ * ```typescript
1358
+ * await sdk.pauseProcess("0x1234567890abcdef...");
1359
+ * console.log("Process paused successfully");
1360
+ * ```
1361
+ */
1362
+ async pauseProcess(processId) {
1363
+ for await (const event of this.pauseProcessStream(processId)) {
1364
+ if (event.status === "completed") {
1365
+ return;
1366
+ } else if (event.status === "failed") {
1367
+ throw event.error;
1368
+ } else if (event.status === "reverted") {
1369
+ throw new Error(`Transaction reverted: ${event.reason || "unknown reason"}`);
1370
+ }
1371
+ }
1372
+ throw new Error("Pause process stream ended unexpectedly");
1373
+ }
1374
+ /**
1375
+ * Cancels a voting process by setting its status to CANCELED.
1376
+ * Returns an async generator that yields transaction status events.
1377
+ *
1378
+ * @param processId - The process ID to cancel
1379
+ * @returns AsyncGenerator yielding transaction status events
1380
+ *
1381
+ * @example
1382
+ * ```typescript
1383
+ * const stream = sdk.cancelProcessStream("0x1234567890abcdef...");
1384
+ *
1385
+ * for await (const event of stream) {
1386
+ * switch (event.status) {
1387
+ * case "pending":
1388
+ * console.log("Transaction pending:", event.hash);
1389
+ * break;
1390
+ * case "completed":
1391
+ * console.log("Process canceled successfully");
1392
+ * break;
1393
+ * case "failed":
1394
+ * console.error("Transaction failed:", event.error);
1395
+ * break;
1396
+ * case "reverted":
1397
+ * console.error("Transaction reverted:", event.reason);
1398
+ * break;
1399
+ * }
1400
+ * }
1401
+ * ```
1402
+ */
1403
+ async *cancelProcessStream(processId) {
1404
+ const txStream = this.processRegistry.setProcessStatus(processId, ProcessStatus.CANCELED);
1405
+ for await (const event of txStream) {
1406
+ if (event.status === TxStatus.Pending) {
1407
+ yield { status: TxStatus.Pending, hash: event.hash };
1408
+ } else if (event.status === TxStatus.Completed) {
1409
+ yield {
1410
+ status: TxStatus.Completed,
1411
+ response: { success: true }
1412
+ };
1413
+ break;
1414
+ } else if (event.status === TxStatus.Failed) {
1415
+ yield { status: TxStatus.Failed, error: event.error };
1416
+ break;
1417
+ } else if (event.status === TxStatus.Reverted) {
1418
+ yield { status: TxStatus.Reverted, reason: event.reason };
1419
+ break;
1420
+ }
1421
+ }
1422
+ }
1423
+ /**
1424
+ * Cancels a voting process by setting its status to CANCELED.
1425
+ * This is a simplified method that waits for transaction completion.
1426
+ *
1427
+ * For real-time transaction status updates, use cancelProcessStream() instead.
1428
+ *
1429
+ * @param processId - The process ID to cancel
1430
+ * @returns Promise resolving when the process is canceled
1431
+ *
1432
+ * @example
1433
+ * ```typescript
1434
+ * await sdk.cancelProcess("0x1234567890abcdef...");
1435
+ * console.log("Process canceled successfully");
1436
+ * ```
1437
+ */
1438
+ async cancelProcess(processId) {
1439
+ for await (const event of this.cancelProcessStream(processId)) {
1440
+ if (event.status === "completed") {
1441
+ return;
1442
+ } else if (event.status === "failed") {
1443
+ throw event.error;
1444
+ } else if (event.status === "reverted") {
1445
+ throw new Error(`Transaction reverted: ${event.reason || "unknown reason"}`);
1446
+ }
1447
+ }
1448
+ throw new Error("Cancel process stream ended unexpectedly");
1449
+ }
1450
+ /**
1451
+ * Resumes a voting process by setting its status to READY.
1452
+ * This is typically used to resume a paused process.
1453
+ * Returns an async generator that yields transaction status events.
1454
+ *
1455
+ * @param processId - The process ID to resume
1456
+ * @returns AsyncGenerator yielding transaction status events
1457
+ *
1458
+ * @example
1459
+ * ```typescript
1460
+ * const stream = sdk.resumeProcessStream("0x1234567890abcdef...");
1461
+ *
1462
+ * for await (const event of stream) {
1463
+ * switch (event.status) {
1464
+ * case "pending":
1465
+ * console.log("Transaction pending:", event.hash);
1466
+ * break;
1467
+ * case "completed":
1468
+ * console.log("Process resumed successfully");
1469
+ * break;
1470
+ * case "failed":
1471
+ * console.error("Transaction failed:", event.error);
1472
+ * break;
1473
+ * case "reverted":
1474
+ * console.error("Transaction reverted:", event.reason);
1475
+ * break;
1476
+ * }
1477
+ * }
1478
+ * ```
1479
+ */
1480
+ async *resumeProcessStream(processId) {
1481
+ const txStream = this.processRegistry.setProcessStatus(processId, ProcessStatus.READY);
1482
+ for await (const event of txStream) {
1483
+ if (event.status === TxStatus.Pending) {
1484
+ yield { status: TxStatus.Pending, hash: event.hash };
1485
+ } else if (event.status === TxStatus.Completed) {
1486
+ yield {
1487
+ status: TxStatus.Completed,
1488
+ response: { success: true }
1489
+ };
1490
+ break;
1491
+ } else if (event.status === TxStatus.Failed) {
1492
+ yield { status: TxStatus.Failed, error: event.error };
1493
+ break;
1494
+ } else if (event.status === TxStatus.Reverted) {
1495
+ yield { status: TxStatus.Reverted, reason: event.reason };
1496
+ break;
1497
+ }
1498
+ }
1499
+ }
1500
+ /**
1501
+ * Resumes a voting process by setting its status to READY.
1502
+ * This is typically used to resume a paused process.
1503
+ * This is a simplified method that waits for transaction completion.
1504
+ *
1505
+ * For real-time transaction status updates, use resumeProcessStream() instead.
1506
+ *
1507
+ * @param processId - The process ID to resume
1508
+ * @returns Promise resolving when the process is resumed
1509
+ *
1510
+ * @example
1511
+ * ```typescript
1512
+ * await sdk.resumeProcess("0x1234567890abcdef...");
1513
+ * console.log("Process resumed successfully");
1514
+ * ```
1515
+ */
1516
+ async resumeProcess(processId) {
1517
+ for await (const event of this.resumeProcessStream(processId)) {
1518
+ if (event.status === "completed") {
1519
+ return;
1520
+ } else if (event.status === "failed") {
1521
+ throw event.error;
1522
+ } else if (event.status === "reverted") {
1523
+ throw new Error(`Transaction reverted: ${event.reason || "unknown reason"}`);
1524
+ }
1525
+ }
1526
+ throw new Error("Resume process stream ended unexpectedly");
1527
+ }
985
1528
  }
986
1529
 
987
1530
  class CircomProof {
@@ -1171,11 +1714,61 @@ class VoteOrchestrationService {
1171
1714
  * @param address - The voter's address
1172
1715
  * @returns Promise resolving to boolean indicating if the address has voted
1173
1716
  */
1174
- async hasAddressVoted(processId, address) {
1175
- return this.apiService.sequencer.hasAddressVoted(processId, address);
1717
+ async hasAddressVoted(processId, address) {
1718
+ return this.apiService.sequencer.hasAddressVoted(processId, address);
1719
+ }
1720
+ /**
1721
+ * Watch vote status changes in real-time using an async generator.
1722
+ * Yields each status change as it happens, allowing for reactive UI updates.
1723
+ *
1724
+ * @param processId - The process ID
1725
+ * @param voteId - The vote ID
1726
+ * @param options - Optional configuration
1727
+ * @returns AsyncGenerator yielding vote status updates
1728
+ *
1729
+ * @example
1730
+ * ```typescript
1731
+ * const vote = await sdk.submitVote({ processId, choices: [1] });
1732
+ *
1733
+ * for await (const statusInfo of sdk.watchVoteStatus(vote.processId, vote.voteId)) {
1734
+ * console.log(`Vote status: ${statusInfo.status}`);
1735
+ *
1736
+ * switch (statusInfo.status) {
1737
+ * case VoteStatus.Pending:
1738
+ * console.log("⏳ Processing...");
1739
+ * break;
1740
+ * case VoteStatus.Verified:
1741
+ * console.log("✓ Verified");
1742
+ * break;
1743
+ * case VoteStatus.Settled:
1744
+ * console.log("✅ Settled");
1745
+ * break;
1746
+ * }
1747
+ * }
1748
+ * ```
1749
+ */
1750
+ async *watchVoteStatus(processId, voteId, options) {
1751
+ const targetStatus = options?.targetStatus ?? VoteStatus.Settled;
1752
+ const timeoutMs = options?.timeoutMs ?? 3e5;
1753
+ const pollIntervalMs = options?.pollIntervalMs ?? 5e3;
1754
+ const startTime = Date.now();
1755
+ let previousStatus = null;
1756
+ while (Date.now() - startTime < timeoutMs) {
1757
+ const statusInfo = await this.getVoteStatus(processId, voteId);
1758
+ if (statusInfo.status !== previousStatus) {
1759
+ previousStatus = statusInfo.status;
1760
+ yield statusInfo;
1761
+ if (statusInfo.status === targetStatus || statusInfo.status === VoteStatus.Error) {
1762
+ return;
1763
+ }
1764
+ }
1765
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
1766
+ }
1767
+ throw new Error(`Vote did not reach status ${targetStatus} within ${timeoutMs}ms`);
1176
1768
  }
1177
1769
  /**
1178
- * Wait for a vote to reach a specific status
1770
+ * Wait for a vote to reach a specific status.
1771
+ * This is a simpler alternative to watchVoteStatus() that returns only the final status.
1179
1772
  *
1180
1773
  * @param processId - The process ID
1181
1774
  * @param voteId - The vote ID
@@ -1185,15 +1778,18 @@ class VoteOrchestrationService {
1185
1778
  * @returns Promise resolving to final vote status
1186
1779
  */
1187
1780
  async waitForVoteStatus(processId, voteId, targetStatus = VoteStatus.Settled, timeoutMs = 3e5, pollIntervalMs = 5e3) {
1188
- const startTime = Date.now();
1189
- while (Date.now() - startTime < timeoutMs) {
1190
- const statusInfo = await this.getVoteStatus(processId, voteId);
1191
- if (statusInfo.status === targetStatus || statusInfo.status === VoteStatus.Error) {
1192
- return statusInfo;
1193
- }
1194
- await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
1781
+ let finalStatus = null;
1782
+ for await (const statusInfo of this.watchVoteStatus(processId, voteId, {
1783
+ targetStatus,
1784
+ timeoutMs,
1785
+ pollIntervalMs
1786
+ })) {
1787
+ finalStatus = statusInfo;
1195
1788
  }
1196
- throw new Error(`Vote did not reach status ${targetStatus} within ${timeoutMs}ms`);
1789
+ if (!finalStatus) {
1790
+ throw new Error(`Vote did not reach status ${targetStatus} within ${timeoutMs}ms`);
1791
+ }
1792
+ return finalStatus;
1197
1793
  }
1198
1794
  /**
1199
1795
  * Get census proof based on census origin type
@@ -1382,31 +1978,36 @@ class OrganizationRegistryService extends SmartContractService {
1382
1978
  }
1383
1979
  // ─── EVENT LISTENERS ───────────────────────────────────────────────────────
1384
1980
  onOrganizationCreated(cb) {
1385
- this.contract.on(
1981
+ this.setupEventListener(
1982
+ this.contract,
1386
1983
  this.contract.filters.OrganizationCreated(),
1387
- this.normalizeListener(cb)
1388
- );
1984
+ cb
1985
+ ).catch((err) => console.error("Error setting up OrganizationCreated listener:", err));
1389
1986
  }
1390
1987
  onOrganizationUpdated(cb) {
1391
- this.contract.on(
1988
+ this.setupEventListener(
1989
+ this.contract,
1392
1990
  this.contract.filters.OrganizationUpdated(),
1393
- this.normalizeListener(cb)
1394
- );
1991
+ cb
1992
+ ).catch((err) => console.error("Error setting up OrganizationUpdated listener:", err));
1395
1993
  }
1396
1994
  onAdministratorAdded(cb) {
1397
- this.contract.on(
1995
+ this.setupEventListener(
1996
+ this.contract,
1398
1997
  this.contract.filters.AdministratorAdded(),
1399
- this.normalizeListener(cb)
1400
- );
1998
+ cb
1999
+ ).catch((err) => console.error("Error setting up AdministratorAdded listener:", err));
1401
2000
  }
1402
2001
  onAdministratorRemoved(cb) {
1403
- this.contract.on(
2002
+ this.setupEventListener(
2003
+ this.contract,
1404
2004
  this.contract.filters.AdministratorRemoved(),
1405
- this.normalizeListener(cb)
1406
- );
2005
+ cb
2006
+ ).catch((err) => console.error("Error setting up AdministratorRemoved listener:", err));
1407
2007
  }
1408
2008
  removeAllListeners() {
1409
2009
  this.contract.removeAllListeners();
2010
+ this.clearPollingIntervals();
1410
2011
  }
1411
2012
  }
1412
2013
 
@@ -1633,9 +2234,13 @@ class DavinciSDK {
1633
2234
  return this.apiService;
1634
2235
  }
1635
2236
  /**
1636
- * Get the process registry service for process management
2237
+ * Get the process registry service for process management.
2238
+ * Requires a signer with a provider for blockchain interactions.
2239
+ *
2240
+ * @throws Error if signer does not have a provider
1637
2241
  */
1638
2242
  get processes() {
2243
+ this.ensureProvider();
1639
2244
  if (!this._processRegistry) {
1640
2245
  const processRegistryAddress = this.resolveContractAddress("processRegistry");
1641
2246
  this._processRegistry = new ProcessRegistryService(processRegistryAddress, this.config.signer);
@@ -1643,9 +2248,13 @@ class DavinciSDK {
1643
2248
  return this._processRegistry;
1644
2249
  }
1645
2250
  /**
1646
- * Get the organization registry service for organization management
2251
+ * Get the organization registry service for organization management.
2252
+ * Requires a signer with a provider for blockchain interactions.
2253
+ *
2254
+ * @throws Error if signer does not have a provider
1647
2255
  */
1648
2256
  get organizations() {
2257
+ this.ensureProvider();
1649
2258
  if (!this._organizationRegistry) {
1650
2259
  const organizationRegistryAddress = this.resolveContractAddress("organizationRegistry");
1651
2260
  this._organizationRegistry = new OrganizationRegistryService(organizationRegistryAddress, this.config.signer);
@@ -1667,9 +2276,13 @@ class DavinciSDK {
1667
2276
  return this.davinciCrypto;
1668
2277
  }
1669
2278
  /**
1670
- * Get the process orchestration service for simplified process creation
2279
+ * Get the process orchestration service for simplified process creation.
2280
+ * Requires a signer with a provider for blockchain interactions.
2281
+ *
2282
+ * @throws Error if signer does not have a provider
1671
2283
  */
1672
2284
  get processOrchestrator() {
2285
+ this.ensureProvider();
1673
2286
  if (!this._processOrchestrator) {
1674
2287
  this._processOrchestrator = new ProcessOrchestrationService(
1675
2288
  this.processes,
@@ -1700,8 +2313,11 @@ class DavinciSDK {
1700
2313
  * This method fetches raw contract data and transforms it into a user-friendly format
1701
2314
  * that matches the ProcessConfig interface used for creation, plus additional runtime data.
1702
2315
  *
2316
+ * Requires a signer with a provider for blockchain interactions.
2317
+ *
1703
2318
  * @param processId - The process ID to fetch
1704
2319
  * @returns Promise resolving to user-friendly process information
2320
+ * @throws Error if signer does not have a provider
1705
2321
  *
1706
2322
  * @example
1707
2323
  * ```typescript
@@ -1730,12 +2346,95 @@ class DavinciSDK {
1730
2346
  if (!this.initialized) {
1731
2347
  throw new Error("SDK must be initialized before getting processes. Call sdk.init() first.");
1732
2348
  }
2349
+ this.ensureProvider();
1733
2350
  return this.processOrchestrator.getProcess(processId);
1734
2351
  }
2352
+ /**
2353
+ * Creates a complete voting process and returns an async generator that yields transaction status events.
2354
+ * This method allows you to monitor the transaction progress in real-time, including pending, completed,
2355
+ * failed, and reverted states.
2356
+ *
2357
+ * Requires a signer with a provider for blockchain interactions.
2358
+ *
2359
+ * @param config - Simplified process configuration
2360
+ * @returns AsyncGenerator yielding transaction status events
2361
+ * @throws Error if signer does not have a provider
2362
+ *
2363
+ * @example
2364
+ * ```typescript
2365
+ * const stream = sdk.createProcessStream({
2366
+ * title: "My Election",
2367
+ * description: "A simple election",
2368
+ * census: {
2369
+ * type: CensusOrigin.CensusOriginMerkleTree,
2370
+ * root: "0x1234...",
2371
+ * size: 100,
2372
+ * uri: "ipfs://..."
2373
+ * },
2374
+ * ballot: {
2375
+ * numFields: 2,
2376
+ * maxValue: "3",
2377
+ * minValue: "0",
2378
+ * uniqueValues: false,
2379
+ * costFromWeight: false,
2380
+ * costExponent: 10000,
2381
+ * maxValueSum: "6",
2382
+ * minValueSum: "0"
2383
+ * },
2384
+ * timing: {
2385
+ * startDate: new Date("2024-12-01T10:00:00Z"),
2386
+ * duration: 3600 * 24
2387
+ * },
2388
+ * questions: [
2389
+ * {
2390
+ * title: "What is your favorite color?",
2391
+ * choices: [
2392
+ * { title: "Red", value: 0 },
2393
+ * { title: "Blue", value: 1 }
2394
+ * ]
2395
+ * }
2396
+ * ]
2397
+ * });
2398
+ *
2399
+ * // Monitor transaction progress
2400
+ * for await (const event of stream) {
2401
+ * switch (event.status) {
2402
+ * case TxStatus.Pending:
2403
+ * console.log("Transaction pending:", event.hash);
2404
+ * // Update UI to show pending state
2405
+ * break;
2406
+ * case TxStatus.Completed:
2407
+ * console.log("Process created:", event.response.processId);
2408
+ * console.log("Transaction hash:", event.response.transactionHash);
2409
+ * // Update UI to show success
2410
+ * break;
2411
+ * case TxStatus.Failed:
2412
+ * console.error("Transaction failed:", event.error);
2413
+ * // Update UI to show error
2414
+ * break;
2415
+ * case TxStatus.Reverted:
2416
+ * console.error("Transaction reverted:", event.reason);
2417
+ * // Update UI to show revert reason
2418
+ * break;
2419
+ * }
2420
+ * }
2421
+ * ```
2422
+ */
2423
+ createProcessStream(config) {
2424
+ if (!this.initialized) {
2425
+ throw new Error("SDK must be initialized before creating processes. Call sdk.init() first.");
2426
+ }
2427
+ this.ensureProvider();
2428
+ return this.processOrchestrator.createProcessStream(config);
2429
+ }
1735
2430
  /**
1736
2431
  * Creates a complete voting process with minimal configuration.
1737
2432
  * This is the ultra-easy method for end users that handles all the complex orchestration internally.
1738
2433
  *
2434
+ * For real-time transaction status updates, use createProcessStream() instead.
2435
+ *
2436
+ * Requires a signer with a provider for blockchain interactions.
2437
+ *
1739
2438
  * The method automatically:
1740
2439
  * - Gets encryption keys and initial state root from the sequencer
1741
2440
  * - Handles process creation signatures
@@ -1745,6 +2444,7 @@ class DavinciSDK {
1745
2444
  *
1746
2445
  * @param config - Simplified process configuration
1747
2446
  * @returns Promise resolving to the process creation result
2447
+ * @throws Error if signer does not have a provider
1748
2448
  *
1749
2449
  * @example
1750
2450
  * ```typescript
@@ -1797,12 +2497,15 @@ class DavinciSDK {
1797
2497
  if (!this.initialized) {
1798
2498
  throw new Error("SDK must be initialized before creating processes. Call sdk.init() first.");
1799
2499
  }
2500
+ this.ensureProvider();
1800
2501
  return this.processOrchestrator.createProcess(config);
1801
2502
  }
1802
2503
  /**
1803
2504
  * Submit a vote with simplified configuration.
1804
2505
  * This is the ultra-easy method for end users that handles all the complex voting workflow internally.
1805
2506
  *
2507
+ * Does NOT require a provider - can be used with a bare Wallet for signing only.
2508
+ *
1806
2509
  * The method automatically:
1807
2510
  * - Fetches process information and validates voting is allowed
1808
2511
  * - Gets census proof (Merkle tree based)
@@ -1844,6 +2547,8 @@ class DavinciSDK {
1844
2547
  /**
1845
2548
  * Get the status of a submitted vote.
1846
2549
  *
2550
+ * Does NOT require a provider - uses API calls only.
2551
+ *
1847
2552
  * @param processId - The process ID
1848
2553
  * @param voteId - The vote ID returned from submitVote()
1849
2554
  * @returns Promise resolving to vote status information
@@ -1864,6 +2569,8 @@ class DavinciSDK {
1864
2569
  /**
1865
2570
  * Check if an address has voted in a process.
1866
2571
  *
2572
+ * Does NOT require a provider - uses API calls only.
2573
+ *
1867
2574
  * @param processId - The process ID
1868
2575
  * @param address - The voter's address
1869
2576
  * @returns Promise resolving to boolean indicating if the address has voted
@@ -1882,9 +2589,59 @@ class DavinciSDK {
1882
2589
  }
1883
2590
  return this.voteOrchestrator.hasAddressVoted(processId, address);
1884
2591
  }
2592
+ /**
2593
+ * Watch vote status changes in real-time using an async generator.
2594
+ * This method yields each status change as it happens, perfect for showing
2595
+ * progress indicators in UI applications.
2596
+ *
2597
+ * Does NOT require a provider - uses API calls only.
2598
+ *
2599
+ * @param processId - The process ID
2600
+ * @param voteId - The vote ID
2601
+ * @param options - Optional configuration
2602
+ * @returns AsyncGenerator yielding vote status updates
2603
+ *
2604
+ * @example
2605
+ * ```typescript
2606
+ * // Submit vote
2607
+ * const voteResult = await sdk.submitVote({
2608
+ * processId: "0x1234567890abcdef...",
2609
+ * choices: [1]
2610
+ * });
2611
+ *
2612
+ * // Watch status changes in real-time
2613
+ * for await (const statusInfo of sdk.watchVoteStatus(voteResult.processId, voteResult.voteId)) {
2614
+ * console.log(`Vote status: ${statusInfo.status}`);
2615
+ *
2616
+ * switch (statusInfo.status) {
2617
+ * case VoteStatus.Pending:
2618
+ * console.log("⏳ Processing...");
2619
+ * break;
2620
+ * case VoteStatus.Verified:
2621
+ * console.log("✓ Vote verified");
2622
+ * break;
2623
+ * case VoteStatus.Aggregated:
2624
+ * console.log("📊 Vote aggregated");
2625
+ * break;
2626
+ * case VoteStatus.Settled:
2627
+ * console.log("✅ Vote settled");
2628
+ * break;
2629
+ * }
2630
+ * }
2631
+ * ```
2632
+ */
2633
+ watchVoteStatus(processId, voteId, options) {
2634
+ if (!this.initialized) {
2635
+ throw new Error("SDK must be initialized before watching vote status. Call sdk.init() first.");
2636
+ }
2637
+ return this.voteOrchestrator.watchVoteStatus(processId, voteId, options);
2638
+ }
1885
2639
  /**
1886
2640
  * Wait for a vote to reach a specific status.
1887
- * Useful for waiting for vote confirmation and processing.
2641
+ * This is a simpler alternative to watchVoteStatus() that returns only the final status.
2642
+ * Useful for waiting for vote confirmation and processing without needing to handle each intermediate status.
2643
+ *
2644
+ * Does NOT require a provider - uses API calls only.
1888
2645
  *
1889
2646
  * @param processId - The process ID
1890
2647
  * @param voteId - The vote ID
@@ -1898,15 +2655,14 @@ class DavinciSDK {
1898
2655
  * // Submit vote and wait for it to be settled
1899
2656
  * const voteResult = await sdk.submitVote({
1900
2657
  * processId: "0x1234567890abcdef...",
1901
- * choices: [1],
1902
- * voterKey: "0x..."
2658
+ * choices: [1]
1903
2659
  * });
1904
2660
  *
1905
2661
  * // Wait for the vote to be fully processed
1906
2662
  * const finalStatus = await sdk.waitForVoteStatus(
1907
2663
  * voteResult.processId,
1908
2664
  * voteResult.voteId,
1909
- * "settled", // Wait until vote is settled
2665
+ * VoteStatus.Settled, // Wait until vote is settled
1910
2666
  * 300000, // 5 minute timeout
1911
2667
  * 5000 // Check every 5 seconds
1912
2668
  * );
@@ -1920,6 +2676,266 @@ class DavinciSDK {
1920
2676
  }
1921
2677
  return this.voteOrchestrator.waitForVoteStatus(processId, voteId, targetStatus, timeoutMs, pollIntervalMs);
1922
2678
  }
2679
+ /**
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
2682
+ * transaction progress in real-time.
2683
+ *
2684
+ * Requires a signer with a provider for blockchain interactions.
2685
+ *
2686
+ * @param processId - The process ID to end
2687
+ * @returns AsyncGenerator yielding transaction status events
2688
+ * @throws Error if signer does not have a provider
2689
+ *
2690
+ * @example
2691
+ * ```typescript
2692
+ * const stream = sdk.endProcessStream("0x1234567890abcdef...");
2693
+ *
2694
+ * for await (const event of stream) {
2695
+ * switch (event.status) {
2696
+ * case TxStatus.Pending:
2697
+ * console.log("Transaction pending:", event.hash);
2698
+ * break;
2699
+ * case TxStatus.Completed:
2700
+ * console.log("Process ended successfully");
2701
+ * break;
2702
+ * case TxStatus.Failed:
2703
+ * console.error("Transaction failed:", event.error);
2704
+ * break;
2705
+ * case TxStatus.Reverted:
2706
+ * console.error("Transaction reverted:", event.reason);
2707
+ * break;
2708
+ * }
2709
+ * }
2710
+ * ```
2711
+ */
2712
+ endProcessStream(processId) {
2713
+ if (!this.initialized) {
2714
+ throw new Error("SDK must be initialized before ending processes. Call sdk.init() first.");
2715
+ }
2716
+ this.ensureProvider();
2717
+ return this.processOrchestrator.endProcessStream(processId);
2718
+ }
2719
+ /**
2720
+ * Ends a voting process by setting its status to ENDED.
2721
+ * This is the simplified method that waits for transaction completion.
2722
+ *
2723
+ * For real-time transaction status updates, use endProcessStream() instead.
2724
+ *
2725
+ * Requires a signer with a provider for blockchain interactions.
2726
+ *
2727
+ * @param processId - The process ID to end
2728
+ * @returns Promise resolving when the process is ended
2729
+ * @throws Error if signer does not have a provider
2730
+ *
2731
+ * @example
2732
+ * ```typescript
2733
+ * await sdk.endProcess("0x1234567890abcdef...");
2734
+ * console.log("Process ended successfully");
2735
+ * ```
2736
+ */
2737
+ async endProcess(processId) {
2738
+ if (!this.initialized) {
2739
+ throw new Error("SDK must be initialized before ending processes. Call sdk.init() first.");
2740
+ }
2741
+ this.ensureProvider();
2742
+ return this.processOrchestrator.endProcess(processId);
2743
+ }
2744
+ /**
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
2747
+ * transaction progress in real-time.
2748
+ *
2749
+ * Requires a signer with a provider for blockchain interactions.
2750
+ *
2751
+ * @param processId - The process ID to pause
2752
+ * @returns AsyncGenerator yielding transaction status events
2753
+ * @throws Error if signer does not have a provider
2754
+ *
2755
+ * @example
2756
+ * ```typescript
2757
+ * const stream = sdk.pauseProcessStream("0x1234567890abcdef...");
2758
+ *
2759
+ * for await (const event of stream) {
2760
+ * switch (event.status) {
2761
+ * case TxStatus.Pending:
2762
+ * console.log("Transaction pending:", event.hash);
2763
+ * break;
2764
+ * case TxStatus.Completed:
2765
+ * console.log("Process paused successfully");
2766
+ * break;
2767
+ * case TxStatus.Failed:
2768
+ * console.error("Transaction failed:", event.error);
2769
+ * break;
2770
+ * case TxStatus.Reverted:
2771
+ * console.error("Transaction reverted:", event.reason);
2772
+ * break;
2773
+ * }
2774
+ * }
2775
+ * ```
2776
+ */
2777
+ pauseProcessStream(processId) {
2778
+ if (!this.initialized) {
2779
+ throw new Error("SDK must be initialized before pausing processes. Call sdk.init() first.");
2780
+ }
2781
+ this.ensureProvider();
2782
+ return this.processOrchestrator.pauseProcessStream(processId);
2783
+ }
2784
+ /**
2785
+ * Pauses a voting process by setting its status to PAUSED.
2786
+ * This is the simplified method that waits for transaction completion.
2787
+ *
2788
+ * For real-time transaction status updates, use pauseProcessStream() instead.
2789
+ *
2790
+ * Requires a signer with a provider for blockchain interactions.
2791
+ *
2792
+ * @param processId - The process ID to pause
2793
+ * @returns Promise resolving when the process is paused
2794
+ * @throws Error if signer does not have a provider
2795
+ *
2796
+ * @example
2797
+ * ```typescript
2798
+ * await sdk.pauseProcess("0x1234567890abcdef...");
2799
+ * console.log("Process paused successfully");
2800
+ * ```
2801
+ */
2802
+ async pauseProcess(processId) {
2803
+ if (!this.initialized) {
2804
+ throw new Error("SDK must be initialized before pausing processes. Call sdk.init() first.");
2805
+ }
2806
+ this.ensureProvider();
2807
+ return this.processOrchestrator.pauseProcess(processId);
2808
+ }
2809
+ /**
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
2812
+ * transaction progress in real-time.
2813
+ *
2814
+ * Requires a signer with a provider for blockchain interactions.
2815
+ *
2816
+ * @param processId - The process ID to cancel
2817
+ * @returns AsyncGenerator yielding transaction status events
2818
+ * @throws Error if signer does not have a provider
2819
+ *
2820
+ * @example
2821
+ * ```typescript
2822
+ * const stream = sdk.cancelProcessStream("0x1234567890abcdef...");
2823
+ *
2824
+ * for await (const event of stream) {
2825
+ * switch (event.status) {
2826
+ * case TxStatus.Pending:
2827
+ * console.log("Transaction pending:", event.hash);
2828
+ * break;
2829
+ * case TxStatus.Completed:
2830
+ * console.log("Process canceled successfully");
2831
+ * break;
2832
+ * case TxStatus.Failed:
2833
+ * console.error("Transaction failed:", event.error);
2834
+ * break;
2835
+ * case TxStatus.Reverted:
2836
+ * console.error("Transaction reverted:", event.reason);
2837
+ * break;
2838
+ * }
2839
+ * }
2840
+ * ```
2841
+ */
2842
+ cancelProcessStream(processId) {
2843
+ if (!this.initialized) {
2844
+ throw new Error("SDK must be initialized before canceling processes. Call sdk.init() first.");
2845
+ }
2846
+ this.ensureProvider();
2847
+ return this.processOrchestrator.cancelProcessStream(processId);
2848
+ }
2849
+ /**
2850
+ * Cancels a voting process by setting its status to CANCELED.
2851
+ * This is the simplified method that waits for transaction completion.
2852
+ *
2853
+ * For real-time transaction status updates, use cancelProcessStream() instead.
2854
+ *
2855
+ * Requires a signer with a provider for blockchain interactions.
2856
+ *
2857
+ * @param processId - The process ID to cancel
2858
+ * @returns Promise resolving when the process is canceled
2859
+ * @throws Error if signer does not have a provider
2860
+ *
2861
+ * @example
2862
+ * ```typescript
2863
+ * await sdk.cancelProcess("0x1234567890abcdef...");
2864
+ * console.log("Process canceled successfully");
2865
+ * ```
2866
+ */
2867
+ async cancelProcess(processId) {
2868
+ if (!this.initialized) {
2869
+ throw new Error("SDK must be initialized before canceling processes. Call sdk.init() first.");
2870
+ }
2871
+ this.ensureProvider();
2872
+ return this.processOrchestrator.cancelProcess(processId);
2873
+ }
2874
+ /**
2875
+ * Resumes a voting process by setting its status to READY and returns an async generator
2876
+ * that yields transaction status events. This is typically used to resume a paused process.
2877
+ *
2878
+ * Requires a signer with a provider for blockchain interactions.
2879
+ *
2880
+ * @param processId - The process ID to resume
2881
+ * @returns AsyncGenerator yielding transaction status events
2882
+ * @throws Error if signer does not have a provider
2883
+ *
2884
+ * @example
2885
+ * ```typescript
2886
+ * const stream = sdk.resumeProcessStream("0x1234567890abcdef...");
2887
+ *
2888
+ * for await (const event of stream) {
2889
+ * switch (event.status) {
2890
+ * case TxStatus.Pending:
2891
+ * console.log("Transaction pending:", event.hash);
2892
+ * break;
2893
+ * case TxStatus.Completed:
2894
+ * console.log("Process resumed successfully");
2895
+ * break;
2896
+ * case TxStatus.Failed:
2897
+ * console.error("Transaction failed:", event.error);
2898
+ * break;
2899
+ * case TxStatus.Reverted:
2900
+ * console.error("Transaction reverted:", event.reason);
2901
+ * break;
2902
+ * }
2903
+ * }
2904
+ * ```
2905
+ */
2906
+ resumeProcessStream(processId) {
2907
+ if (!this.initialized) {
2908
+ throw new Error("SDK must be initialized before resuming processes. Call sdk.init() first.");
2909
+ }
2910
+ this.ensureProvider();
2911
+ return this.processOrchestrator.resumeProcessStream(processId);
2912
+ }
2913
+ /**
2914
+ * Resumes a voting process by setting its status to READY.
2915
+ * This is typically used to resume a paused process.
2916
+ * This is the simplified method that waits for transaction completion.
2917
+ *
2918
+ * For real-time transaction status updates, use resumeProcessStream() instead.
2919
+ *
2920
+ * Requires a signer with a provider for blockchain interactions.
2921
+ *
2922
+ * @param processId - The process ID to resume
2923
+ * @returns Promise resolving when the process is resumed
2924
+ * @throws Error if signer does not have a provider
2925
+ *
2926
+ * @example
2927
+ * ```typescript
2928
+ * await sdk.resumeProcess("0x1234567890abcdef...");
2929
+ * console.log("Process resumed successfully");
2930
+ * ```
2931
+ */
2932
+ async resumeProcess(processId) {
2933
+ if (!this.initialized) {
2934
+ throw new Error("SDK must be initialized before resuming processes. Call sdk.init() first.");
2935
+ }
2936
+ this.ensureProvider();
2937
+ return this.processOrchestrator.resumeProcess(processId);
2938
+ }
1923
2939
  /**
1924
2940
  * Resolve contract address based on configuration priority:
1925
2941
  * 1. If useSequencerAddresses is true: addresses from sequencer (highest priority)
@@ -1994,6 +3010,18 @@ class DavinciSDK {
1994
3010
  isInitialized() {
1995
3011
  return this.initialized;
1996
3012
  }
3013
+ /**
3014
+ * Ensures that the signer has a provider for blockchain operations.
3015
+ * @throws Error if the signer does not have a provider
3016
+ * @private
3017
+ */
3018
+ ensureProvider() {
3019
+ if (!this.config.signer.provider) {
3020
+ throw new Error(
3021
+ "Provider required for blockchain operations (process/organization management). The signer must be connected to a provider. Use wallet.connect(provider) or a browser signer like MetaMask. Note: Voting operations do not require a provider."
3022
+ );
3023
+ }
3024
+ }
1997
3025
  }
1998
3026
 
1999
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 };