@vocdoni/davinci-sdk 0.0.1
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/LICENSE +661 -0
- package/README.md +635 -0
- package/dist/contracts.d.ts +512 -0
- package/dist/index.d.ts +1388 -0
- package/dist/index.js +2045 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2000 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +2045 -0
- package/dist/sequencer.d.ts +538 -0
- package/package.json +103 -0
package/README.md
ADDED
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
# Vocdoni DaVinci SDK
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/%40vocdoni%2Fdavinci-sdk)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](#)
|
|
7
|
+
|
|
8
|
+
A powerful, easy-to-use TypeScript SDK for building decentralized voting applications on the Vocdoni DaVinci protocol. Create secure, private, and verifiable elections with just a few lines of code.
|
|
9
|
+
|
|
10
|
+
## ๐ Quick Start
|
|
11
|
+
|
|
12
|
+
### Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @vocdoni/davinci-sdk
|
|
16
|
+
# or
|
|
17
|
+
yarn add @vocdoni/davinci-sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Basic Usage
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { DavinciSDK, CensusOrigin } from '@vocdoni/davinci-sdk';
|
|
24
|
+
import { Wallet } from 'ethers';
|
|
25
|
+
|
|
26
|
+
// Initialize the SDK
|
|
27
|
+
const wallet = new Wallet('your-private-key');
|
|
28
|
+
const sdk = new DavinciSDK({
|
|
29
|
+
signer: wallet,
|
|
30
|
+
environment: 'dev' // or 'stg', 'prod'
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await sdk.init();
|
|
34
|
+
|
|
35
|
+
// 1. Create a census with eligible voters
|
|
36
|
+
const censusId = await sdk.api.census.createCensus();
|
|
37
|
+
|
|
38
|
+
// Add participants to the census
|
|
39
|
+
const participants = [
|
|
40
|
+
{ key: "0x1234567890123456789012345678901234567890", weight: "1" },
|
|
41
|
+
{ key: "0x2345678901234567890123456789012345678901", weight: "1" },
|
|
42
|
+
{ key: "0x3456789012345678901234567890123456789012", weight: "2" } // Higher weight
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
await sdk.api.census.addParticipants(censusId, participants);
|
|
46
|
+
|
|
47
|
+
// Publish the census to get the root
|
|
48
|
+
const publishResult = await sdk.api.census.publishCensus(censusId);
|
|
49
|
+
const censusSize = await sdk.api.census.getCensusSize(publishResult.root);
|
|
50
|
+
|
|
51
|
+
// 2. Create a voting process
|
|
52
|
+
const process = await sdk.createProcess({
|
|
53
|
+
title: "Community Decision",
|
|
54
|
+
description: "Vote on our next community initiative",
|
|
55
|
+
census: {
|
|
56
|
+
type: CensusOrigin.CensusOriginMerkleTree,
|
|
57
|
+
root: publishResult.root,
|
|
58
|
+
size: censusSize,
|
|
59
|
+
uri: publishResult.uri
|
|
60
|
+
},
|
|
61
|
+
timing: {
|
|
62
|
+
startDate: new Date("2024-12-01T10:00:00Z"),
|
|
63
|
+
duration: 86400 // 24 hours in seconds
|
|
64
|
+
},
|
|
65
|
+
questions: [{
|
|
66
|
+
title: "Which initiative should we prioritize?",
|
|
67
|
+
choices: [
|
|
68
|
+
{ title: "Community Garden", value: 0 },
|
|
69
|
+
{ title: "Tech Workshop", value: 1 },
|
|
70
|
+
{ title: "Art Exhibition", value: 2 }
|
|
71
|
+
]
|
|
72
|
+
}]
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// 3. Submit a vote (using one of the census participants)
|
|
76
|
+
const voterWallet = new Wallet('voter-private-key'); // Must be one of the census participants
|
|
77
|
+
const voterSdk = new DavinciSDK({
|
|
78
|
+
signer: voterWallet,
|
|
79
|
+
environment: 'dev'
|
|
80
|
+
});
|
|
81
|
+
await voterSdk.init();
|
|
82
|
+
|
|
83
|
+
const vote = await voterSdk.submitVote({
|
|
84
|
+
processId: process.processId,
|
|
85
|
+
choices: [1] // Vote for "Tech Workshop"
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// 4. Wait for vote confirmation
|
|
89
|
+
const finalStatus = await voterSdk.waitForVoteStatus(
|
|
90
|
+
vote.processId,
|
|
91
|
+
vote.voteId,
|
|
92
|
+
VoteStatus.Settled
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
console.log('Vote confirmed!', finalStatus);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## ๐ Table of Contents
|
|
99
|
+
|
|
100
|
+
- [Features](#-features)
|
|
101
|
+
- [Installation](#-installation)
|
|
102
|
+
- [Core Concepts](#-core-concepts)
|
|
103
|
+
- [API Reference](#-api-reference)
|
|
104
|
+
- [SDK Initialization](#sdk-initialization)
|
|
105
|
+
- [Process Management](#process-management)
|
|
106
|
+
- [Voting Operations](#voting-operations)
|
|
107
|
+
- [Examples](#-examples)
|
|
108
|
+
- [Advanced Configuration](#-advanced-configuration)
|
|
109
|
+
- [Error Handling](#-error-handling)
|
|
110
|
+
- [Testing](#-testing)
|
|
111
|
+
- [Contributing](#-contributing)
|
|
112
|
+
- [Support](#-support)
|
|
113
|
+
|
|
114
|
+
## โจ Features
|
|
115
|
+
|
|
116
|
+
- **๐ Privacy-First**: Homomorphic encryption ensures vote privacy
|
|
117
|
+
- **๐ก๏ธ Secure**: Built on battle-tested cryptographic primitives
|
|
118
|
+
- **โก Easy Integration**: Simple, intuitive API for developers
|
|
119
|
+
- **๐ Decentralized**: No central authority controls the voting process
|
|
120
|
+
- **๐ฑ Cross-Platform**: Works in browsers, Node.js, and mobile apps
|
|
121
|
+
- **๐ง TypeScript**: Full type safety and excellent developer experience
|
|
122
|
+
- **๐ฏ Flexible**: Support for multiple question types and voting modes
|
|
123
|
+
|
|
124
|
+
## ๐ Installation
|
|
125
|
+
|
|
126
|
+
### Prerequisites
|
|
127
|
+
|
|
128
|
+
- Node.js 16+ or modern browser environment
|
|
129
|
+
- An Ethereum wallet/signer (MetaMask, WalletConnect, etc.)
|
|
130
|
+
|
|
131
|
+
### Package Installation
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Using npm
|
|
135
|
+
npm install @vocdoni/davinci-sdk ethers
|
|
136
|
+
|
|
137
|
+
# Using yarn
|
|
138
|
+
yarn add @vocdoni/davinci-sdk ethers
|
|
139
|
+
|
|
140
|
+
# Using pnpm
|
|
141
|
+
pnpm add @vocdoni/davinci-sdk ethers
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## ๐ง Core Concepts
|
|
145
|
+
|
|
146
|
+
### Voting Process Lifecycle
|
|
147
|
+
|
|
148
|
+
1. **Process Creation**: Define voting parameters, questions, and census
|
|
149
|
+
2. **Vote Submission**: Voters submit encrypted, anonymous votes
|
|
150
|
+
3. **Vote Processing**: Votes are verified and aggregated using zk-SNARKs
|
|
151
|
+
4. **Results**: Final results are computed and made available
|
|
152
|
+
|
|
153
|
+
### Key Components
|
|
154
|
+
|
|
155
|
+
- **Census**: List of eligible voters (Merkle tree or CSP-based)
|
|
156
|
+
- **Ballot**: Vote structure defining questions and possible answers
|
|
157
|
+
- **Process**: Container for all voting parameters and metadata
|
|
158
|
+
- **Proof**: Cryptographic evidence that a vote is valid
|
|
159
|
+
|
|
160
|
+
## ๐ API Reference
|
|
161
|
+
|
|
162
|
+
### SDK Initialization
|
|
163
|
+
|
|
164
|
+
#### Constructor Options
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
interface DavinciSDKConfig {
|
|
168
|
+
signer: Signer; // Ethereum signer (required)
|
|
169
|
+
environment?: 'dev' | 'stg' | 'prod'; // Environment (default: 'prod')
|
|
170
|
+
sequencerUrl?: string; // Custom sequencer URL
|
|
171
|
+
censusUrl?: string; // Custom census API URL
|
|
172
|
+
chain?: 'sepolia' | 'mainnet'; // Blockchain network
|
|
173
|
+
contractAddresses?: { // Custom contract addresses
|
|
174
|
+
processRegistry?: string;
|
|
175
|
+
organizationRegistry?: string;
|
|
176
|
+
// ... other contracts
|
|
177
|
+
};
|
|
178
|
+
useSequencerAddresses?: boolean; // Use addresses from sequencer
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Basic Initialization
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { DavinciSDK } from '@vocdoni/davinci-sdk';
|
|
186
|
+
import { Wallet } from 'ethers';
|
|
187
|
+
|
|
188
|
+
const sdk = new DavinciSDK({
|
|
189
|
+
signer: new Wallet('your-private-key'),
|
|
190
|
+
environment: 'dev'
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await sdk.init();
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Process Management
|
|
197
|
+
|
|
198
|
+
#### Creating a Process
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const processResult = await sdk.createProcess({
|
|
202
|
+
title: "Election Title",
|
|
203
|
+
description: "Detailed description of the election",
|
|
204
|
+
|
|
205
|
+
// Census configuration
|
|
206
|
+
census: {
|
|
207
|
+
type: CensusOrigin.CensusOriginMerkleTree,
|
|
208
|
+
root: "0x...",
|
|
209
|
+
size: 1000,
|
|
210
|
+
uri: "ipfs://..."
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
// Timing configuration
|
|
214
|
+
timing: {
|
|
215
|
+
startDate: new Date("2024-12-01T10:00:00Z"),
|
|
216
|
+
duration: 86400 // 24 hours
|
|
217
|
+
// Alternative: endDate: new Date("2024-12-02T10:00:00Z")
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
// Ballot configuration
|
|
221
|
+
ballot: {
|
|
222
|
+
numFields: 1,
|
|
223
|
+
maxValue: "2",
|
|
224
|
+
minValue: "0",
|
|
225
|
+
uniqueValues: false,
|
|
226
|
+
costFromWeight: false,
|
|
227
|
+
costExponent: 1,
|
|
228
|
+
maxValueSum: "2",
|
|
229
|
+
minValueSum: "0"
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
// Questions
|
|
233
|
+
questions: [{
|
|
234
|
+
title: "What is your preferred option?",
|
|
235
|
+
description: "Choose the option that best represents your view",
|
|
236
|
+
choices: [
|
|
237
|
+
{ title: "Option A", value: 0 },
|
|
238
|
+
{ title: "Option B", value: 1 },
|
|
239
|
+
{ title: "Option C", value: 2 }
|
|
240
|
+
]
|
|
241
|
+
}]
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
console.log('Process created:', processResult.processId);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### Retrieving Process Information
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
const processInfo = await sdk.getProcess(processId);
|
|
251
|
+
|
|
252
|
+
console.log('Title:', processInfo.title);
|
|
253
|
+
console.log('Status:', processInfo.status);
|
|
254
|
+
console.log('Start date:', processInfo.startDate);
|
|
255
|
+
console.log('End date:', processInfo.endDate);
|
|
256
|
+
console.log('Questions:', processInfo.questions);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Voting Operations
|
|
260
|
+
|
|
261
|
+
#### Submitting a Vote
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
const voteResult = await sdk.submitVote({
|
|
265
|
+
processId: "0x...",
|
|
266
|
+
choices: [1, 0], // Answers for each question
|
|
267
|
+
randomness: "optional-custom-randomness" // Optional
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
console.log('Vote ID:', voteResult.voteId);
|
|
271
|
+
console.log('Status:', voteResult.status);
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
#### Checking Vote Status
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
const status = await sdk.getVoteStatus(processId, voteId);
|
|
278
|
+
console.log('Current status:', status.status);
|
|
279
|
+
// Possible statuses: pending, verified, aggregated, processed, settled, error
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### Waiting for Vote Confirmation
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { VoteStatus } from '@vocdoni/davinci-sdk';
|
|
286
|
+
|
|
287
|
+
const finalStatus = await sdk.waitForVoteStatus(
|
|
288
|
+
processId,
|
|
289
|
+
voteId,
|
|
290
|
+
VoteStatus.Settled, // Target status
|
|
291
|
+
300000, // 5 minute timeout
|
|
292
|
+
5000 // Check every 5 seconds
|
|
293
|
+
);
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### Checking if Address Has Voted
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
const hasVoted = await sdk.hasAddressVoted(processId, voterAddress);
|
|
300
|
+
if (hasVoted) {
|
|
301
|
+
console.log('This address has already voted');
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## ๐ก Examples
|
|
306
|
+
|
|
307
|
+
### Complete Voting Flow
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import { DavinciSDK, CensusOrigin, VoteStatus } from '@vocdoni/davinci-sdk';
|
|
311
|
+
import { Wallet } from 'ethers';
|
|
312
|
+
|
|
313
|
+
async function completeVotingExample() {
|
|
314
|
+
// 1. Initialize SDK
|
|
315
|
+
const organizerWallet = new Wallet('organizer-private-key');
|
|
316
|
+
const sdk = new DavinciSDK({
|
|
317
|
+
signer: organizerWallet,
|
|
318
|
+
environment: 'dev'
|
|
319
|
+
});
|
|
320
|
+
await sdk.init();
|
|
321
|
+
|
|
322
|
+
// 2. Create census with eligible voters
|
|
323
|
+
const censusId = await sdk.api.census.createCensus();
|
|
324
|
+
|
|
325
|
+
// Create voter wallets and add them to census
|
|
326
|
+
const voters = [];
|
|
327
|
+
for (let i = 0; i < 5; i++) {
|
|
328
|
+
const voterWallet = Wallet.createRandom();
|
|
329
|
+
voters.push(voterWallet);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const participants = voters.map(voter => ({
|
|
333
|
+
key: voter.address,
|
|
334
|
+
weight: "1"
|
|
335
|
+
}));
|
|
336
|
+
|
|
337
|
+
await sdk.api.census.addParticipants(censusId, participants);
|
|
338
|
+
|
|
339
|
+
// Publish the census
|
|
340
|
+
const publishResult = await sdk.api.census.publishCensus(censusId);
|
|
341
|
+
const censusSize = await sdk.api.census.getCensusSize(publishResult.root);
|
|
342
|
+
|
|
343
|
+
// 3. Create voting process
|
|
344
|
+
const process = await sdk.createProcess({
|
|
345
|
+
title: "Community Budget Allocation",
|
|
346
|
+
description: "Decide how to allocate our community budget",
|
|
347
|
+
census: {
|
|
348
|
+
type: CensusOrigin.CensusOriginMerkleTree,
|
|
349
|
+
root: publishResult.root,
|
|
350
|
+
size: censusSize,
|
|
351
|
+
uri: publishResult.uri
|
|
352
|
+
},
|
|
353
|
+
timing: {
|
|
354
|
+
startDate: new Date(Date.now() + 60000), // Start in 1 minute
|
|
355
|
+
duration: 3600 // 1 hour
|
|
356
|
+
},
|
|
357
|
+
questions: [{
|
|
358
|
+
title: "Which project should receive funding?",
|
|
359
|
+
choices: [
|
|
360
|
+
{ title: "Community Garden", value: 0 },
|
|
361
|
+
{ title: "Tech Education Program", value: 1 },
|
|
362
|
+
{ title: "Local Art Initiative", value: 2 }
|
|
363
|
+
]
|
|
364
|
+
}]
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
console.log(`Process created: ${process.processId}`);
|
|
368
|
+
|
|
369
|
+
// 4. Vote using one of the census participants
|
|
370
|
+
const voterWallet = voters[0]; // Use first voter from census
|
|
371
|
+
const voterSdk = new DavinciSDK({
|
|
372
|
+
signer: voterWallet,
|
|
373
|
+
environment: 'dev'
|
|
374
|
+
});
|
|
375
|
+
await voterSdk.init();
|
|
376
|
+
|
|
377
|
+
// Wait for process to start accepting votes
|
|
378
|
+
await new Promise(resolve => setTimeout(resolve, 65000));
|
|
379
|
+
|
|
380
|
+
const vote = await voterSdk.submitVote({
|
|
381
|
+
processId: process.processId,
|
|
382
|
+
choices: [1] // Vote for Tech Education Program
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
console.log(`Vote submitted: ${vote.voteId}`);
|
|
386
|
+
|
|
387
|
+
// 5. Wait for vote confirmation
|
|
388
|
+
const finalStatus = await voterSdk.waitForVoteStatus(
|
|
389
|
+
vote.processId,
|
|
390
|
+
vote.voteId,
|
|
391
|
+
VoteStatus.Settled
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
console.log('Vote confirmed with status:', finalStatus.status);
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Browser Integration with MetaMask
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
import { DavinciSDK } from '@vocdoni/davinci-sdk';
|
|
402
|
+
import { BrowserProvider } from 'ethers';
|
|
403
|
+
|
|
404
|
+
async function browserVotingExample() {
|
|
405
|
+
// Connect to MetaMask
|
|
406
|
+
if (!window.ethereum) {
|
|
407
|
+
throw new Error('MetaMask not found');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const provider = new BrowserProvider(window.ethereum);
|
|
411
|
+
await provider.send("eth_requestAccounts", []);
|
|
412
|
+
const signer = await provider.getSigner();
|
|
413
|
+
|
|
414
|
+
// Initialize SDK
|
|
415
|
+
const sdk = new DavinciSDK({
|
|
416
|
+
signer,
|
|
417
|
+
environment: 'prod'
|
|
418
|
+
});
|
|
419
|
+
await sdk.init();
|
|
420
|
+
|
|
421
|
+
// Submit vote
|
|
422
|
+
const vote = await sdk.submitVote({
|
|
423
|
+
processId: "0x...",
|
|
424
|
+
choices: [2]
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
console.log('Vote submitted from browser:', vote.voteId);
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## โ๏ธ Advanced Configuration
|
|
432
|
+
|
|
433
|
+
<details>
|
|
434
|
+
<summary>Click to expand advanced configuration options</summary>
|
|
435
|
+
|
|
436
|
+
### Custom Network Configuration
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
const sdk = new DavinciSDK({
|
|
440
|
+
signer: wallet,
|
|
441
|
+
chain: 'sepolia',
|
|
442
|
+
sequencerUrl: 'https://your-custom-sequencer.com',
|
|
443
|
+
censusUrl: 'https://your-custom-census.com',
|
|
444
|
+
contractAddresses: {
|
|
445
|
+
processRegistry: '0x...',
|
|
446
|
+
organizationRegistry: '0x...',
|
|
447
|
+
stateTransitionVerifier: '0x...',
|
|
448
|
+
resultsVerifier: '0x...'
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Using Sequencer-Provided Addresses
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
const sdk = new DavinciSDK({
|
|
457
|
+
signer: wallet,
|
|
458
|
+
environment: 'dev',
|
|
459
|
+
useSequencerAddresses: true // Fetch contract addresses from sequencer
|
|
460
|
+
});
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Custom Vote Randomness
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
const vote = await sdk.submitVote({
|
|
467
|
+
processId: "0x...",
|
|
468
|
+
choices: [1],
|
|
469
|
+
randomness: "your-custom-randomness-hex" // For deterministic testing
|
|
470
|
+
});
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Advanced Process Configuration
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
const process = await sdk.createProcess({
|
|
477
|
+
title: "Advanced Election",
|
|
478
|
+
// ... basic config
|
|
479
|
+
|
|
480
|
+
ballot: {
|
|
481
|
+
numFields: 3, // Number of questions
|
|
482
|
+
maxValue: "5", // Maximum choice value
|
|
483
|
+
minValue: "0", // Minimum choice value
|
|
484
|
+
uniqueValues: true, // Require unique choices
|
|
485
|
+
costFromWeight: false, // Use weight for vote cost
|
|
486
|
+
costExponent: 1, // Cost calculation exponent
|
|
487
|
+
maxValueSum: "10", // Maximum sum of all choices
|
|
488
|
+
minValueSum: "3" // Minimum sum of all choices
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Direct Service Access
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
// Access underlying services for advanced operations
|
|
497
|
+
const processRegistry = sdk.processes;
|
|
498
|
+
const organizationRegistry = sdk.organizations;
|
|
499
|
+
const apiService = sdk.api;
|
|
500
|
+
const crypto = await sdk.getCrypto();
|
|
501
|
+
|
|
502
|
+
// Direct API calls
|
|
503
|
+
const processInfo = await sdk.api.sequencer.getProcess(processId);
|
|
504
|
+
const censusProof = await sdk.api.census.getCensusProof(root, address);
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
</details>
|
|
508
|
+
|
|
509
|
+
## ๐จ Error Handling
|
|
510
|
+
|
|
511
|
+
The SDK provides detailed error messages for common scenarios:
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
try {
|
|
515
|
+
const vote = await sdk.submitVote({
|
|
516
|
+
processId: "0x...",
|
|
517
|
+
choices: [1, 2, 3]
|
|
518
|
+
});
|
|
519
|
+
} catch (error) {
|
|
520
|
+
if (error.message.includes('already voted')) {
|
|
521
|
+
console.log('User has already voted in this process');
|
|
522
|
+
} else if (error.message.includes('not accepting votes')) {
|
|
523
|
+
console.log('Voting period has not started or has ended');
|
|
524
|
+
} else if (error.message.includes('out of range')) {
|
|
525
|
+
console.log('Invalid choice values provided');
|
|
526
|
+
} else {
|
|
527
|
+
console.error('Unexpected error:', error.message);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Common Error Types
|
|
533
|
+
|
|
534
|
+
- **Process Errors**: Process not found, not accepting votes, invalid configuration
|
|
535
|
+
- **Vote Errors**: Already voted, invalid choices, proof generation failed
|
|
536
|
+
- **Network Errors**: Connection issues, transaction failures
|
|
537
|
+
- **Validation Errors**: Invalid parameters, out-of-range values
|
|
538
|
+
|
|
539
|
+
## ๐งช Testing
|
|
540
|
+
|
|
541
|
+
### Running Tests
|
|
542
|
+
|
|
543
|
+
```bash
|
|
544
|
+
# Run all tests
|
|
545
|
+
npm test
|
|
546
|
+
|
|
547
|
+
# Run unit tests only
|
|
548
|
+
npm run test:unit
|
|
549
|
+
|
|
550
|
+
# Run integration tests only
|
|
551
|
+
npm run test:integration
|
|
552
|
+
|
|
553
|
+
# Run specific test suites
|
|
554
|
+
npm run test:contracts
|
|
555
|
+
npm run test:sequencer
|
|
556
|
+
npm run test:census
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Test Environment Setup
|
|
560
|
+
|
|
561
|
+
Create a `.env` file in the test directory:
|
|
562
|
+
|
|
563
|
+
```env
|
|
564
|
+
SEPOLIA_RPC=https://sepolia.infura.io/v3/your-key
|
|
565
|
+
PRIVATE_KEY=0x...
|
|
566
|
+
TIME_OUT=600000
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## ๐ค Contributing
|
|
570
|
+
|
|
571
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
572
|
+
|
|
573
|
+
### Development Setup
|
|
574
|
+
|
|
575
|
+
```bash
|
|
576
|
+
# Clone the repository
|
|
577
|
+
git clone https://github.com/vocdoni/davinci-sdk.git
|
|
578
|
+
cd davinci-sdk
|
|
579
|
+
|
|
580
|
+
# Install dependencies
|
|
581
|
+
yarn install
|
|
582
|
+
|
|
583
|
+
# Run development build
|
|
584
|
+
yarn dev
|
|
585
|
+
|
|
586
|
+
# Run linting
|
|
587
|
+
yarn lint
|
|
588
|
+
|
|
589
|
+
# Format code
|
|
590
|
+
yarn format
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Code Quality
|
|
594
|
+
|
|
595
|
+
- **TypeScript**: Full type safety
|
|
596
|
+
- **ESLint**: Code linting and style enforcement
|
|
597
|
+
- **Prettier**: Code formatting
|
|
598
|
+
- **Jest**: Comprehensive testing suite
|
|
599
|
+
- **Husky**: Pre-commit hooks
|
|
600
|
+
|
|
601
|
+
## ๐ License
|
|
602
|
+
|
|
603
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
604
|
+
|
|
605
|
+
## ๐ Support
|
|
606
|
+
|
|
607
|
+
### Documentation
|
|
608
|
+
|
|
609
|
+
- [API Documentation](https://github.com/vocdoni/davinci-node/tree/main/api)
|
|
610
|
+
- [Protocol Documentation](https://whitepaper.vocdoni.io)
|
|
611
|
+
- [Examples Repository](https://github.com/vocdoni/davinci-sdk/tree/main/examples)
|
|
612
|
+
|
|
613
|
+
### Community
|
|
614
|
+
|
|
615
|
+
- [Discord](https://chat.vocdoni.io)
|
|
616
|
+
- [Telegram](https://t.me/vocdoni_community)
|
|
617
|
+
- [Twitter](https://twitter.com/vocdoni)
|
|
618
|
+
|
|
619
|
+
### Issues and Bugs
|
|
620
|
+
|
|
621
|
+
Please report issues on our [GitHub Issues](https://github.com/vocdoni/davinci-sdk/issues) page.
|
|
622
|
+
|
|
623
|
+
### Professional Support
|
|
624
|
+
|
|
625
|
+
For enterprise support and custom integrations, contact us at [info@vocdoni.io](mailto:info@vocdoni.io).
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
<div align="center">
|
|
630
|
+
|
|
631
|
+
**Built with โค๏ธ by the [Vocdoni](https://vocdoni.io) team**
|
|
632
|
+
|
|
633
|
+
[Website](https://vocdoni.io) โข [Documentation](https://docs.vocdoni.io) โข [GitHub](https://github.com/vocdoni) โข [Twitter](https://twitter.com/vocdoni)
|
|
634
|
+
|
|
635
|
+
</div>
|