Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add CSP census example #373

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions examples/csp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "csp-tutorial",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@ethersproject/wallet": "^5.7.0",
"@vocdoni/sdk": "https://github.com/vocdoni/vocdoni-sdk.git#main"
},
"scripts": {
"start": "ts-node src/index.ts"
},
"devDependencies": {
"@types/node": "^20.11.25",
"ts-node": "^10.9.1",
"typescript": "^4.9.4"
}
}
16 changes: 16 additions & 0 deletions examples/csp/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Vocdoni SDK Tutorial example
==============================

This example is a tutorial to guide you through the most basic possible integration of the Vocdoni SDK in a Typescript project.

It was created to serve as a tutorial for implementing token-based censuses for voting with Vocdoni. The complete tutorial is available [here](https://developer.vocdoni.io/sdk/tutorial).

To execute this example, use the following steps:

~~~bash
git clone [email protected]:vocdoni/vocdoni-sdk.git
cd vocdoni-sdk/examples/tutorial
yarn
yarn start
~~~

16 changes: 16 additions & 0 deletions examples/csp/src/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Account, VocdoniSDKClient } from '@vocdoni/sdk';

export const createAccount = (client: VocdoniSDKClient) => {
return client
.createAccount({
account: new Account({
languages: ['en'],
name: {
default: 'Account name',
},
description: 'Description of the account',
logo: 'https://logo.io',
}),
})
.then(() => client.fetchAccountInfo().then((info) => console.log(info)));
};
12 changes: 12 additions & 0 deletions examples/csp/src/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { EnvOptions, VocdoniSDKClient } from '@vocdoni/sdk';
import { Wallet } from '@ethersproject/wallet';

export const getDefaultClient = () => {
const wallet = Wallet.createRandom();
const client = new VocdoniSDKClient({
env: EnvOptions.STG,
wallet: wallet,
});

return { wallet, client };
};
46 changes: 46 additions & 0 deletions examples/csp/src/election.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Census, Election, ElectionStatus, UnpublishedElection, VocdoniSDKClient } from '@vocdoni/sdk';

export const createElection = (census: Census): UnpublishedElection => {
const election: UnpublishedElection = Election.from({
title: 'Election title',
description: 'Election description',
header: 'https://source.unsplash.com/random',
endDate: new Date().getTime() + 100000000,
maxCensusSize: 2000,
census: census,
});

election.addQuestion('This is a title', 'This is a description', [
{
title: 'Option 1',
value: 0,
},
{
title: 'Option 2',
value: 1,
},
]);

return election;
};

const waitForElectionReady = (client: VocdoniSDKClient, electionId: string): Promise<string> => {
return new Promise((f) => setTimeout(f, 5000))
.then(() => client.fetchElection(electionId))
.then((election) => {
if (election.status !== ElectionStatus.ONGOING) {
return waitForElectionReady(client, electionId);
}
return Promise.resolve(electionId);
});
};

export const publishElection = (client: VocdoniSDKClient, election: UnpublishedElection): Promise<string> => {
return client.createElection(election).then((electionId) => {
client.setElectionId(electionId);
console.log('Election created!', electionId);
console.log('View this election at ' + client.explorerUrl + '/processes/show/#/' + electionId);
console.log('Waiting for election to be published...');
return waitForElectionReady(client, electionId);
});
};
25 changes: 25 additions & 0 deletions examples/csp/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { getDefaultClient } from './client';
import { createElection, publishElection } from './election';
import { castVotes, countVotes } from './vote';
import { CspCensus } from '@vocdoni/sdk';
import { createAccount } from './account';

// Testing CSP
const CSP_URL = 'https://csp-dev-simplemath.vocdoni.net/v1';
const CSP_PUBKEY = '025de8cb8de1005aa939c1403e37e1fa165ebc758da49cb37215c6237d01591104';

async function main() {
console.log('Initializing client...');
const { client } = getDefaultClient();
console.log('Creating account...');
await createAccount(client);
console.log('Creating election...');
const election = createElection(new CspCensus(CSP_PUBKEY, CSP_URL));
const electionId = await publishElection(client, election);
console.log('Voting...');
await castVotes(electionId);
console.log('Getting results...');
await countVotes(client);
}

main();
41 changes: 41 additions & 0 deletions examples/csp/src/vote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Wallet } from '@ethersproject/wallet';
import { EnvOptions, ICspFinalStepResponse, ICspIntermediateStepResponse, VocdoniSDKClient, Vote } from '@vocdoni/sdk';

export const castVotes = (electionId: string) => {
var votePromises = [];
for (let i = 0; i < 10; i++) {
const voter = Wallet.createRandom();
const client = new VocdoniSDKClient({ env: EnvOptions.STG, wallet: voter, electionId: electionId });
votePromises.push(
new Promise<void>(async (resolve) => {
// Auth steps for the CSP (can vary of the type of the CSP)
const step0 = (await client.cspStep(0, ['Name test'])) as ICspIntermediateStepResponse;
// Auth step 1: for this CSP, add the two values and return the result
const challenge = step0.response.reduce((accumulator, value) => +accumulator + +value, 0).toString();
const step1 = (await client.cspStep(1, [challenge], step0.authToken)) as ICspFinalStepResponse;

// Request a CSP signature of the voter's address, proven by the token
const signature = await client.cspSign(voter.address, step1.token);

// Create a random vote alongside the CSP signature
const vote = client.cspVote(new Vote([Math.round(Math.random())]), signature);

// Submit the vote as usual
await client.submitVote(vote);
resolve();
})
);
}
return Promise.all(votePromises);
};

export const countVotes = (client: VocdoniSDKClient) => {
return client.fetchElection().then((election) => {
console.log('Election results: ');
election.questions.forEach((question) => {
question.choices.forEach((choice) => {
console.log(choice.title.default + ': ' + choice.results);
});
});
});
};
6 changes: 6 additions & 0 deletions examples/csp/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"include": ["src"],
"compilerOptions": {
"rootDir": "./src",
}
}
Loading
Loading