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