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