@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/README.md +21 -0
- package/dist/contracts.d.ts +5 -6
- package/dist/index.d.ts +112 -60
- package/dist/index.js +126 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +126 -38
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +126 -38
- package/dist/sequencer.d.ts +24 -39
- package/package.json +2 -2
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
|
|
93
|
-
* @param
|
|
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(
|
|
97
|
-
return `${this.axios.defaults.baseURL}
|
|
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((
|
|
167
|
-
...
|
|
168
|
-
|
|
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.
|
|
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
|
-
|
|
1216
|
-
|
|
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
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
2023
|
-
|
|
2024
|
-
|
|
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
|