@vocdoni/davinci-sdk 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -87,12 +87,12 @@ class VocdoniCensusService extends BaseService {
87
87
  super(baseURL);
88
88
  }
89
89
  /**
90
- * Constructs the URI for accessing a census by its root
91
- * @param censusRoot - The census root (hex-prefixed)
90
+ * Constructs the URI for accessing a census
91
+ * @param relativePath - The relative path
92
92
  * @returns The constructed URI for the census
93
93
  */
94
- getCensusUri(censusRoot) {
95
- return `${this.axios.defaults.baseURL}/censuses/${censusRoot}`;
94
+ getCensusUri(relativePath) {
95
+ return `${this.axios.defaults.baseURL}${relativePath}`;
96
96
  }
97
97
  createCensus() {
98
98
  return this.request({
@@ -161,10 +161,13 @@ class VocdoniCensusService extends BaseService {
161
161
  return this.request({
162
162
  method: "POST",
163
163
  url: `/censuses/${censusId}/publish`
164
- }).then((response) => ({
165
- ...response,
166
- uri: this.getCensusUri(response.root)
167
- }));
164
+ }).then((apiResponse) => {
165
+ const { censusUri, ...responseWithoutCensusUri } = apiResponse;
166
+ return {
167
+ ...responseWithoutCensusUri,
168
+ uri: this.getCensusUri(censusUri)
169
+ };
170
+ });
168
171
  }
169
172
  // BigQuery endpoints
170
173
  getSnapshots(params) {
@@ -194,13 +197,13 @@ var CensusOrigin = /* @__PURE__ */ ((CensusOrigin2) => {
194
197
  return CensusOrigin2;
195
198
  })(CensusOrigin || {});
196
199
  function isBaseCensusProof(proof) {
197
- return !!proof && typeof proof.root === "string" && typeof proof.address === "string" && typeof proof.weight === "string" && typeof proof.censusOrigin === "number" && Object.values(CensusOrigin).includes(proof.censusOrigin);
200
+ return !!proof && typeof proof.root === "string" && typeof proof.address === "string" && typeof proof.censusOrigin === "number" && Object.values(CensusOrigin).includes(proof.censusOrigin);
198
201
  }
199
202
  function isMerkleCensusProof(proof) {
200
- return isBaseCensusProof(proof) && proof.censusOrigin === 1 /* CensusOriginMerkleTree */ && typeof proof.value === "string" && typeof proof.siblings === "string";
203
+ return isBaseCensusProof(proof) && proof.censusOrigin === 1 /* CensusOriginMerkleTree */ && typeof proof.weight === "string" && typeof proof.value === "string" && typeof proof.siblings === "string";
201
204
  }
202
205
  function isCSPCensusProof(proof) {
203
- return isBaseCensusProof(proof) && proof.censusOrigin === 2 /* CensusOriginCSP */ && typeof proof.processId === "string" && typeof proof.publicKey === "string" && typeof proof.signature === "string";
206
+ return isBaseCensusProof(proof) && proof.censusOrigin === 2 /* CensusOriginCSP */ && typeof proof.weight === "string" && typeof proof.processId === "string" && typeof proof.publicKey === "string" && typeof proof.signature === "string";
204
207
  }
205
208
  function assertMerkleCensusProof(proof) {
206
209
  if (!isMerkleCensusProof(proof)) {
@@ -560,6 +563,27 @@ class VocdoniSequencerService extends BaseService {
560
563
  throw error;
561
564
  }
562
565
  }
566
+ async getAddressWeight(processId, address) {
567
+ const participant = await this.request({
568
+ method: "GET",
569
+ url: `/processes/${processId}/participants/${address}`
570
+ });
571
+ return participant.weight;
572
+ }
573
+ async isAddressAbleToVote(processId, address) {
574
+ try {
575
+ await this.request({
576
+ method: "GET",
577
+ url: `/processes/${processId}/participants/${address}`
578
+ });
579
+ return true;
580
+ } catch (error) {
581
+ if (error?.code === 40001) {
582
+ return false;
583
+ }
584
+ throw error;
585
+ }
586
+ }
563
587
  getInfo() {
564
588
  return this.request({
565
589
  method: "GET",
@@ -983,7 +1007,6 @@ class ProcessRegistryService extends SmartContractService {
983
1007
  newProcess(status, startTime, duration, ballotMode, census, metadata, encryptionKey, initStateRoot) {
984
1008
  const contractCensus = {
985
1009
  censusOrigin: BigInt(census.censusOrigin),
986
- maxVotes: BigInt(census.maxVotes),
987
1010
  censusRoot: census.censusRoot,
988
1011
  censusURI: census.censusURI
989
1012
  };
@@ -1014,7 +1037,6 @@ class ProcessRegistryService extends SmartContractService {
1014
1037
  setProcessCensus(processID, census) {
1015
1038
  const contractCensus = {
1016
1039
  censusOrigin: BigInt(census.censusOrigin),
1017
- maxVotes: BigInt(census.maxVotes),
1018
1040
  censusRoot: census.censusRoot,
1019
1041
  censusURI: census.censusURI
1020
1042
  };
@@ -1183,7 +1205,6 @@ class ProcessOrchestrationService {
1183
1205
  const census = {
1184
1206
  type: Number(rawProcess.census.censusOrigin),
1185
1207
  root: rawProcess.census.censusRoot,
1186
- size: Number(rawProcess.census.maxVotes),
1187
1208
  uri: rawProcess.census.censusURI || ""
1188
1209
  };
1189
1210
  const ballot = {
@@ -1198,11 +1219,11 @@ class ProcessOrchestrationService {
1198
1219
  };
1199
1220
  return {
1200
1221
  processId,
1201
- title,
1222
+ title: title || "",
1202
1223
  description,
1203
1224
  census,
1204
1225
  ballot,
1205
- questions,
1226
+ questions: questions || [],
1206
1227
  status: Number(rawProcess.status),
1207
1228
  creator: rawProcess.organizationId,
1208
1229
  startDate: new Date(startTime * 1e3),
@@ -1210,8 +1231,8 @@ class ProcessOrchestrationService {
1210
1231
  duration,
1211
1232
  timeRemaining,
1212
1233
  result: rawProcess.result,
1213
- voteCount: Number(rawProcess.voteCount),
1214
- voteOverwriteCount: Number(rawProcess.voteOverwriteCount),
1234
+ votersCount: Number(rawProcess.votersCount),
1235
+ overwrittenVotesCount: Number(rawProcess.overwrittenVotesCount),
1215
1236
  metadataURI: rawProcess.metadataURI,
1216
1237
  raw: rawProcess
1217
1238
  };
@@ -1331,20 +1352,27 @@ class ProcessOrchestrationService {
1331
1352
  const censusConfig = await this.handleCensus(config.census);
1332
1353
  const censusRoot = censusConfig.root;
1333
1354
  const ballotMode = config.ballot;
1334
- const metadata = this.createMetadata(config);
1335
- const metadataHash = await this.apiService.sequencer.pushMetadata(metadata);
1336
- const metadataUri = this.apiService.sequencer.getMetadataUrl(metadataHash);
1355
+ let metadataUri;
1356
+ if ("metadataUri" in config) {
1357
+ metadataUri = config.metadataUri;
1358
+ } else {
1359
+ const metadata = this.createMetadata(config);
1360
+ const metadataHash = await this.apiService.sequencer.pushMetadata(metadata);
1361
+ metadataUri = this.apiService.sequencer.getMetadataUrl(metadataHash);
1362
+ }
1337
1363
  const signature = await signProcessCreation(processId, this.signer);
1338
1364
  const sequencerResult = await this.apiService.sequencer.createProcess({
1339
1365
  processId,
1340
- censusRoot,
1366
+ census: {
1367
+ censusOrigin: censusConfig.type,
1368
+ censusRoot,
1369
+ censusURI: censusConfig.uri
1370
+ },
1341
1371
  ballotMode,
1342
- signature,
1343
- censusOrigin: censusConfig.type
1372
+ signature
1344
1373
  });
1345
1374
  const census = {
1346
1375
  censusOrigin: censusConfig.type,
1347
- maxVotes: censusConfig.size.toString(),
1348
1376
  censusRoot,
1349
1377
  censusURI: censusConfig.uri
1350
1378
  };
@@ -1413,15 +1441,13 @@ class ProcessOrchestrationService {
1413
1441
  throw new Error("Invalid date format. Use Date object, ISO string, or Unix timestamp.");
1414
1442
  }
1415
1443
  /**
1416
- * Creates metadata from the simplified configuration
1444
+ * Creates metadata from the configuration with metadata fields
1445
+ * This method should only be called with ProcessConfigWithMetadata
1417
1446
  */
1418
1447
  createMetadata(config) {
1419
1448
  const metadata = getElectionMetadataTemplate();
1420
1449
  metadata.title.default = config.title;
1421
1450
  metadata.description.default = config.description || "";
1422
- if (!config.questions || config.questions.length === 0) {
1423
- throw new Error("Questions are required. Please provide at least one question with choices.");
1424
- }
1425
1451
  metadata.questions = config.questions.map((q) => ({
1426
1452
  title: { default: q.title },
1427
1453
  description: { default: q.description || "" },
@@ -1886,16 +1912,19 @@ class VoteOrchestrationService {
1886
1912
  );
1887
1913
  const { proof } = await this.generateZkProof(circomInputs);
1888
1914
  const signature = await this.signVote(voteId);
1889
- await this.submitVoteRequest({
1915
+ const voteRequest = {
1890
1916
  processId: config.processId,
1891
- censusProof,
1892
1917
  ballot: cryptoOutput.ballot,
1893
1918
  ballotProof: proof,
1894
1919
  ballotInputsHash: cryptoOutput.ballotInputsHash,
1895
1920
  address: voterAddress,
1896
1921
  signature,
1897
1922
  voteId
1898
- });
1923
+ };
1924
+ if (process.census.censusOrigin === CensusOrigin.CensusOriginCSP) {
1925
+ voteRequest.censusProof = censusProof;
1926
+ }
1927
+ await this.submitVoteRequest(voteRequest);
1899
1928
  const status = await this.apiService.sequencer.getVoteStatus(config.processId, voteId);
1900
1929
  return {
1901
1930
  voteId,
@@ -2017,9 +2046,15 @@ class VoteOrchestrationService {
2017
2046
  assertMerkleCensusProof(proof);
2018
2047
  return proof;
2019
2048
  } else {
2020
- const proof = await this.apiService.census.getCensusProof(censusRoot, voterAddress);
2021
- assertMerkleCensusProof(proof);
2022
- return proof;
2049
+ const weight = await this.apiService.sequencer.getAddressWeight(processId, voterAddress);
2050
+ return {
2051
+ root: censusRoot,
2052
+ address: voterAddress,
2053
+ weight,
2054
+ censusOrigin: CensusOrigin.CensusOriginMerkleTree,
2055
+ value: "",
2056
+ siblings: ""
2057
+ };
2023
2058
  }
2024
2059
  }
2025
2060
  if (censusOrigin === CensusOrigin.CensusOriginCSP) {
@@ -2339,14 +2374,15 @@ class DavinciCrypto {
2339
2374
  * @param privKey - The private key in hex format
2340
2375
  * @param processId - The process ID in hex format
2341
2376
  * @param address - The address in hex format
2377
+ * @param weight - The vote weight as a decimal string
2342
2378
  * @returns The CSP proof as a parsed JSON object
2343
2379
  * @throws if called before `await init()`, or if Go returns an error
2344
2380
  */
2345
- async cspSign(censusOrigin, privKey, processId, address) {
2381
+ async cspSign(censusOrigin, privKey, processId, address, weight) {
2346
2382
  if (!this.initialized) {
2347
2383
  throw new Error("DavinciCrypto not initialized \u2014 call `await init()` first");
2348
2384
  }
2349
- const raw = globalThis.DavinciCrypto.cspSign(censusOrigin, privKey, processId, address);
2385
+ const raw = globalThis.DavinciCrypto.cspSign(censusOrigin, privKey, processId, address, weight);
2350
2386
  if (raw.error) {
2351
2387
  throw new Error(`Go/WASM cspSign error: ${raw.error}`);
2352
2388
  }
@@ -2360,13 +2396,14 @@ class DavinciCrypto {
2360
2396
  * @param censusOrigin - The census origin type (e.g., CensusOrigin.CensusOriginCSP)
2361
2397
  * @param root - The census root
2362
2398
  * @param address - The address
2399
+ * @param weight - The vote weight as a decimal string
2363
2400
  * @param processId - The process ID
2364
2401
  * @param publicKey - The public key
2365
2402
  * @param signature - The signature
2366
2403
  * @returns The verification result
2367
2404
  * @throws if called before `await init()`, or if Go returns an error
2368
2405
  */
2369
- async cspVerify(censusOrigin, root, address, processId, publicKey, signature) {
2406
+ async cspVerify(censusOrigin, root, address, weight, processId, publicKey, signature) {
2370
2407
  if (!this.initialized) {
2371
2408
  throw new Error("DavinciCrypto not initialized \u2014 call `await init()` first");
2372
2409
  }
@@ -2374,6 +2411,7 @@ class DavinciCrypto {
2374
2411
  censusOrigin,
2375
2412
  root,
2376
2413
  address,
2414
+ weight,
2377
2415
  processId,
2378
2416
  publicKey,
2379
2417
  signature
@@ -2825,6 +2863,56 @@ class DavinciSDK {
2825
2863
  }
2826
2864
  return this.voteOrchestrator.hasAddressVoted(processId, address);
2827
2865
  }
2866
+ /**
2867
+ * Check if an address is able to vote in a process (i.e., is in the census).
2868
+ *
2869
+ * Does NOT require a provider - uses API calls only.
2870
+ *
2871
+ * @param processId - The process ID
2872
+ * @param address - The voter's address
2873
+ * @returns Promise resolving to boolean indicating if the address can vote
2874
+ *
2875
+ * @example
2876
+ * ```typescript
2877
+ * const canVote = await sdk.isAddressAbleToVote(processId, "0x1234567890abcdef...");
2878
+ * if (canVote) {
2879
+ * console.log("This address can vote");
2880
+ * } else {
2881
+ * console.log("This address is not in the census");
2882
+ * }
2883
+ * ```
2884
+ */
2885
+ async isAddressAbleToVote(processId, address) {
2886
+ if (!this.initialized) {
2887
+ throw new Error(
2888
+ "SDK must be initialized before checking if address can vote. Call sdk.init() first."
2889
+ );
2890
+ }
2891
+ return this.apiService.sequencer.isAddressAbleToVote(processId, address);
2892
+ }
2893
+ /**
2894
+ * Get the voting weight for an address in a process.
2895
+ *
2896
+ * Does NOT require a provider - uses API calls only.
2897
+ *
2898
+ * @param processId - The process ID
2899
+ * @param address - The voter's address
2900
+ * @returns Promise resolving to the address weight as a string
2901
+ *
2902
+ * @example
2903
+ * ```typescript
2904
+ * const weight = await sdk.getAddressWeight(processId, "0x1234567890abcdef...");
2905
+ * console.log("Address weight:", weight);
2906
+ * ```
2907
+ */
2908
+ async getAddressWeight(processId, address) {
2909
+ if (!this.initialized) {
2910
+ throw new Error(
2911
+ "SDK must be initialized before getting address weight. Call sdk.init() first."
2912
+ );
2913
+ }
2914
+ return this.apiService.sequencer.getAddressWeight(processId, address);
2915
+ }
2828
2916
  /**
2829
2917
  * Watch vote status changes in real-time using an async generator.
2830
2918
  * This method yields each status change as it happens, perfect for showing