votepeerjs - VotePeer Javascript Library
Javascript library with support, or partial support for VotePeer contracts. This library was developed for use with the VotePeer web interface, VotePeer API backend and for research.
The following vote contracts support is added to this library.
Vote contract | Tally votes | Validate votes | Casting vote |
---|---|---|---|
two-option-vote | ✅ | ✅ | ✅ |
multi-option-vote | ✅ | ✅ | ❌ |
ring-signature-vote | ✅ | ✅ | ❌ |
The non-vote contract input payload contract
is also implemented in this library. See VotePeer documentation to learn about the contracts.
Features
Transparent Voting
A Bitcoin Cash smart contract and protocol for transparent on-chain voting.
"Two option vote" is a minimalistic and transparent voting protocol on top of Bitcoin Cash and similar blockchains. Participating, verifying and tallying does not require a full node, but is fully SPV client compatible. Votes are non-transferable.
This repository hosts the protocol/smart contract specification and a reference implementation in javascript.
Example
See this and more examples in the examples directory.
import {
TwoOptionVote, TwoOptionVoteContract, tallyTwoOptionVotes, Blockchain,
DEFAULT_CAST_TX_FEE, derivePublicKey, getPublicKeyHash,
DEFAULT_DUST_THRESHOLD, createSalt, generatePrivateKey
} from '@bitcoinunlimited/votepeerjs';
const alice = generatePrivateKey();
const bob = generatePrivateKey();
// Initialize an election
const votersPKH = [
await getPublicKeyHash(await derivePublicKey(alice)),
await getPublicKeyHash(await derivePublicKey(bob)),
];
const election: TwoOptionVote = {
network: 'mainnet',
salt: createSalt(),
description: 'Pizza for lunch?',
optionA: 'Yes',
optionB: 'No',
endHeight: 1_000_000,
votersPKH,
};
// Setup contracts
const aliceContract = await TwoOptionVoteContract.make(election, alice);
const bobContract = await TwoOptionVoteContract.make(election, bob);
const electrum = new Blockchain();
await electrum.connect();
for (const contract of [aliceContract, bobContract]) {
const contractAddress = await contract.getContractAddress();
await contract.waitForBalance(electrum, DEFAULT_CAST_TX_FEE + DEFAULT_DUST_THRESHOLD, (balance) => {
console.log(`Too low balance (${balance} sats) in contract ${contractAddress}`);
});
}
// Alice casts vote for option A ("Yes") and bob for B ("No")
const aliceTxID = await aliceContract.castVote(electrum, await aliceContract.optionAHash());
const bobTxID = await bobContract.castVote(electrum, await bobContract.optionBHash());
console.log(`Alice voted in tx ${aliceTxID}`);
console.log(`Bob voted in tx ${bobTxID}`);
const tally = await tallyTwoOptionVotes(electrum, election, true);
console.log(`Results: ${JSON.stringify(tally, null, 4)}`);
Developers
Tests vectors
See files with *.test.ts
suffix.
Build project
npm run build
npm run test
Run the above example: node build/examples/readme-example.js
Building Fujisaki Ring signature dependency
For building the fujisaki ring signature dependency, you'll need to install wasm-pack and Rust.
When these dependencies are installed, run:
npm run build-ringsig
To use your new build, rm -rf node_modules/fujisaki-ringsig-wasm && npm install
.