-
Notifications
You must be signed in to change notification settings - Fork 13
Lurve Voting
A simple Yes/No voting smart contract. Can be used to display the number of likes and dislikes on your web page.
The main bug-fixed Lurve contract is deployed to Ropsten at 0xdcb39e9f4b8347ec08b56a32c0e44b0751e6d421 in block 1673487.
-
Vote Yes by sending a 0 or non-0 Ropsten ETH transaction to the Yes LurveOption contract at 0xb3134f8709b8f5763c0c755517fd0403fc2e1367.
-
Vote No by sending a 0 or non-0 Ropsten ETH transaction to the No LurveOption contract at 0x26742b34ea5885d1f42757b16b10dd3531df2d41.
View the results at https://ethvoter.thedao.fund/lurve/ or http://ethvoter.thedao.fund/lurve/.
You can view the smart contract results at the main Lurve contract at 0xdcb39e9f4b8347ec08b56a32c0e44b0751e6d421.
The Application Binary Interface for the main Lurve contract deployed to Ropsten at 0xdcb39e9f4b8347ec08b56a32c0e44b0751e6d421:
[{"constant":true,"inputs":[],"name":"lurveYes","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"yesCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"seen","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"yesNo","type":"uint256"}],"name":"registerLurve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"noCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lurveNo","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addr","type":"address"},{"indexed":false,"name":"yesNo","type":"uint256"}],"name":"LurveIt","type":"event"}]
The Lurve smart contract will create two addresses.
Users send a transaction to either of the two addresses.
Sending the transaction to the first address will register a vote of No and sending the transaction to the second address will register a vote of Yes.
Each account can only vote once, either a No or Yes.
Any ethers sent with the transaction will be returned back to the user's account. Transactions sending 0 ETH are accepted, and preferred.
- The
yesNo
flag is auint
so you can extend it to multiple states instead of just a Yes/No. Otherwise it can be replaced bybool
.
From Lurve.sol:
pragma solidity ^0.4.16;
// -----------------------------------------------------------------------------
// See https://github.com/bokkypoobah/EthVoter
//
// Version 0.91
//
// The MIT Licence 2017
// -----------------------------------------------------------------------------
contract LurveOption {
Lurve public lurve;
uint public yesNo;
// Constructor - save parameters
function LurveOption(Lurve _lurve, uint _yesNo) {
lurve = _lurve;
yesNo = _yesNo;
}
// User sends a 0 or non-0 ETH transaction to the address
function () payable {
// Call the factory to register the votes
lurve.registerLurve(msg.sender, yesNo);
// Send back any non-0 ETH
if (msg.value > 0) {
msg.sender.transfer(msg.value);
}
}
}
contract Lurve {
// Contract addresses
LurveOption public lurveNo;
LurveOption public lurveYes;
// Count of No votes
uint public noCount;
// Count of Yes votes
uint public yesCount;
// Save addresses that have voted
mapping(address => bool) public seen;
event LurveIt(address indexed addr, uint yesNo);
// Constructor - deploy the yes and no contracts
function Lurve() {
// Deploy a contract to an address that will register a '0' vote
lurveNo = new LurveOption(this, 0);
// Deploy a contract to an address that will register a '1' vote
lurveYes = new LurveOption(this, 1);
}
function registerLurve(address addr, uint yesNo) {
// Only allow lurveNo and lurveYes to call this function
require(msg.sender == address(lurveNo) || msg.sender == address(lurveYes));
// Only allow each address to vote once
require(!seen[addr]);
// Register the address that is voting
seen[addr] = true;
// Register the vote
if (yesNo == 0) {
noCount++;
} else {
yesCount++;
}
// Log the event
LurveIt(addr, yesNo);
}
}
I created /home/bokky/Lurve/getLurve.sh
with the following contents:
#!/bin/sh
geth attach rpc:http://localhost:8545 << EOF | grep "RESULT: " | sed "s/RESULT: //"
var lurveAddress="0xdcb39e9f4b8347ec08b56a32c0e44b0751e6d421";
var lurveAbi=[{"constant":true,"inputs":[],"name":"lurveYes","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"yesCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"seen","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"yesNo","type":"uint256"}],"name":"registerLurve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"noCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lurveNo","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addr","type":"address"},{"indexed":false,"name":"yesNo","type":"uint256"}],"name":"LurveIt","type":"event"}];
var lurveBlockNumber=1673487;
var lurve=web3.eth.contract(lurveAbi).at(lurveAddress);
console.log("RESULT: noCount=" + lurve.noCount());
console.log("RESULT: yesCount=" + lurve.yesCount());
var lurveEvents = lurve.LurveIt({}, { fromBlock: lurveBlockNumber, toBlock: "latest" });
var i = 0;
lurveEvents.watch(function (error, result) {
console.log("RESULT: LurveIt " + i++ + " #" + result.blockNumber + ": addr=" + result.args.addr + " yesNo=" + result.args.yesNo);
});
lurveEvents.stopWatching();
EOF
I set the executable permission for this script using the command:
chmod 700 /home/bokky/Lurve/getLurve.sh
Sample output:
$ ./getLurve.sh
noCount=1
yesCount=2
LurveIt 0 #1673566: addr=0x0052d07bb447273181412197b1057d9a805edca4 yesNo=0
LurveIt 1 #1674428: addr=0xd9d72d466637e8408bb3b17d3ff6db02e8bebf27 yesNo=1
LurveIt 2 #1675069: addr=0x4aac1b2a1c2fee71a896e4b32b8fb3ab5a37562f yesNo=1
I created /home/bokky/Lurve/genLurveHTML.sh
with the following contents:
#!/bin/sh
HTMLFILE=/var/www/html/lurve/index.html
geth attach rpc:http://localhost:8545 << EOF | grep "RESULT: " | sed "s/RESULT: //" > $HTMLFILE
console.log("RESULT: <html>");
console.log("RESULT: <head>");
console.log("RESULT: <title>The Lurve Page</title>");
console.log("RESULT: </head>");
console.log("RESULT: <body>");
console.log("RESULT: <h2>The Lurve Page</h2>");
console.log("RESULT: <p>Send a 0 (or non-0) Ropsten Testnet ETH transaction to <a href='https://ropsten.etherscan.io/address/0xb3134f8709b8f5763c0c755517fd0403fc2e1367'>0xb3134f8709b8f5763c0c755517fd0403fc2e1367</a
> if you lurve this page</p>");
console.log("RESULT: <p>Send a 0 (or non-0) Ropsten Testnet ETH transaction to <a href='https://ropsten.etherscan.io/address/0x26742b34ea5885d1f42757b16b10dd3531df2d41'>0x26742b34ea5885d1f42757b16b10dd3531df2d41</a
> if you don't lurve this page</p>");
console.log("RESULT: <br />");
console.log("RESULT: <h2>Statistics</h2>");
var lurveAddress="0xdcb39e9f4b8347ec08b56a32c0e44b0751e6d421";
var lurveAbi=[{"constant":true,"inputs":[],"name":"lurveYes","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"yesCount","outputs"
:[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"seen","outputs":[{"name":"","type":"bool"}],"payable":false,"
stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"yesNo","type":"uint256"}],"name":"registerLurve","outputs":[],"payable":false,"stateMutability":"nonpayab
le","type":"function"},{"constant":true,"inputs":[],"name":"noCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lurveNo","o
utputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexe
d":true,"name":"addr","type":"address"},{"indexed":false,"name":"yesNo","type":"uint256"}],"name":"LurveIt","type":"event"}];
var lurveBlockNumber=1673487;
var lurve=web3.eth.contract(lurveAbi).at(lurveAddress);
var total=lurve.noCount().add(lurve.yesCount());
console.log("RESULT: <p>Total votes=" + total + "</p>");
console.log("RESULT: <p>Yes votes=" + lurve.yesCount() + " (" + lurve.yesCount()/total*100 + "%)</p>");
console.log("RESULT: <p>No votes=" + lurve.noCount() + " (" + lurve.noCount()/total*100 + "%)</p>");
console.log("RESULT: <br />");
console.log("RESULT: <h2>Votes</h2>");
console.log("RESULT: <p>Statistics collected at <a href='https://ropsten.etherscan.io/address/0xdcb39e9f4b8347ec08b56a32c0e44b0751e6d421#readContract'>0xdcb39e9f4b8347ec08b56a32c0e44b0751e6d421</a></p>");
var lurveEvents = lurve.LurveIt({}, { fromBlock: lurveBlockNumber, toBlock: "latest" });
var i = 0;
lurveEvents.watch(function (error, result) {
console.log("RESULT: <p>LurveIt " + i++ + " #" + result.blockNumber + ": addr=" + result.args.addr + " yesNo=" + result.args.yesNo +
" hash=<a href='https://ropsten.etherscan.io/tx/" + result.transactionHash + "'>" + result.transactionHash + "</a></p>");
});
lurveEvents.stopWatching();
console.log("RESULT: <br />");
console.log("RESULT: <p>Further information at <a href='https://github.com/bokkypoobah/EthVoter/wiki/Lurve-Voting'>https://github.com/bokkypoobah/EthVoter/wiki/Lurve-Voting</a></p>");
console.log("RESULT: <br />");
console.log("RESULT: <p>Page generated " + new Date().toUTCString() + "</p>");
console.log("RESULT: <br />");
console.log("RESULT: Enjoy. BokkyPooBah 2017");
console.log("RESULT: </body>");
console.log("RESULT: </html>");
EOF
I set the executable permission for this script using the command:
chmod 700 /home/bokky/Lurve/genLurveHTML.sh
I created the HTML directory using the command:
sudo mkdir /var/www/html/lurve
I set the ownership of the HTML directory using the command:
sudo chown bokky:bokky /var/www/html/lurve
The script is scheduled to run every minute by adding the following entry to crontab -e
:
# m h dom mon dow command
* * * * * /home/bokky/Lurve/genLurveHTML.sh
Some existing voting systems to consider:
Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd and other contributors - 2018. The MIT Licence.