Merge branch '000-snt-voting-dapp' of https://github.com/status-im/contracts into 000-snt-voting-dapp
This commit is contained in:
commit
00957320b1
|
@ -48,10 +48,6 @@
|
||||||
"TestToken": {
|
"TestToken": {
|
||||||
"deploy": true
|
"deploy": true
|
||||||
},
|
},
|
||||||
"MultiOptionPollManager": {
|
|
||||||
"deploy": false
|
|
||||||
},
|
|
||||||
|
|
||||||
"SNT": {
|
"SNT": {
|
||||||
"instanceOf": "MiniMeToken",
|
"instanceOf": "MiniMeToken",
|
||||||
"deploy": true,
|
"deploy": true,
|
||||||
|
@ -83,6 +79,9 @@
|
||||||
],
|
],
|
||||||
"gasLimit": 5000000
|
"gasLimit": 5000000
|
||||||
},
|
},
|
||||||
|
"SingleChoiceFactory": {
|
||||||
|
"deploy": false
|
||||||
|
},
|
||||||
"PollManager": {
|
"PollManager": {
|
||||||
"deploy": true,
|
"deploy": true,
|
||||||
"args": ["$MiniMeTokenFactory", "$SNT"]
|
"args": ["$MiniMeTokenFactory", "$SNT"]
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
pragma solidity ^0.4.21;
|
|
||||||
|
|
||||||
import "../common/Controlled.sol";
|
|
||||||
import "../token/MiniMeTokenInterface.sol";
|
|
||||||
import "../token/MiniMeTokenFactory.sol";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @title PollManager
|
|
||||||
* @author Richard Ramos (Status Research & Development GmbH)
|
|
||||||
*/
|
|
||||||
contract MultiOptionPollManager is Controlled {
|
|
||||||
event PollCreated(uint256 pollId, uint8 numOptions);
|
|
||||||
event PollCanceled(uint256 pollId);
|
|
||||||
event Voted(address voter, uint8[] votes);
|
|
||||||
|
|
||||||
MiniMeTokenFactory public tokenFactory;
|
|
||||||
MiniMeTokenInterface public token;
|
|
||||||
|
|
||||||
Poll[] public polls;
|
|
||||||
|
|
||||||
struct Vote {
|
|
||||||
mapping(uint8 => uint8) distribution;
|
|
||||||
bool voted;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Poll {
|
|
||||||
uint start;
|
|
||||||
uint end;
|
|
||||||
uint8 numOptions;
|
|
||||||
address[] voters;
|
|
||||||
mapping(address => Vote) voteMap;
|
|
||||||
uint256[] results;
|
|
||||||
address token;
|
|
||||||
bool cancelled;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(address _tokenFactory, address _token)
|
|
||||||
public
|
|
||||||
{
|
|
||||||
tokenFactory = MiniMeTokenFactory(_tokenFactory);
|
|
||||||
token = MiniMeTokenInterface(_token);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createPoll(
|
|
||||||
uint _blocksUntilVotingStart,
|
|
||||||
uint _voteDuration,
|
|
||||||
uint8 _numOptions
|
|
||||||
)
|
|
||||||
public
|
|
||||||
onlyController
|
|
||||||
returns (uint pollId)
|
|
||||||
{
|
|
||||||
pollId = polls.length++;
|
|
||||||
|
|
||||||
Poll storage p = polls[pollId];
|
|
||||||
|
|
||||||
p.cancelled = false;
|
|
||||||
p.start = block.number + _blocksUntilVotingStart;
|
|
||||||
p.end = p.start + _voteDuration;
|
|
||||||
p.numOptions = _numOptions;
|
|
||||||
p.token = tokenFactory.createCloneToken(
|
|
||||||
token,
|
|
||||||
p.start - 1,
|
|
||||||
"VotingToken",
|
|
||||||
MiniMeToken(token).decimals(),
|
|
||||||
"VTN",
|
|
||||||
true);
|
|
||||||
|
|
||||||
|
|
||||||
emit PollCreated(pollId, _numOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
function vote(uint _pollId, uint8[] _vote)
|
|
||||||
public
|
|
||||||
{
|
|
||||||
Poll storage poll = polls[_pollId];
|
|
||||||
|
|
||||||
require(block.number >= poll.start);
|
|
||||||
require(block.number <= poll.end);
|
|
||||||
require(_vote.length == poll.numOptions);
|
|
||||||
require(!poll.voteMap[msg.sender].voted);
|
|
||||||
require(!poll.cancelled);
|
|
||||||
|
|
||||||
uint8 percentage = 0;
|
|
||||||
|
|
||||||
for(uint8 i = 0; i < poll.numOptions; i++){
|
|
||||||
poll.results[i] = (MiniMeTokenInterface(poll.token).balanceOf(msg.sender) * _vote[i]) / 100;
|
|
||||||
percentage += _vote[i];
|
|
||||||
poll.voteMap[msg.sender].distribution[i] = _vote[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
require(percentage == 100);
|
|
||||||
|
|
||||||
poll.voteMap[msg.sender].voted = true;
|
|
||||||
poll.voters.push(msg.sender);
|
|
||||||
|
|
||||||
emit Voted(msg.sender, _vote);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPollCount()
|
|
||||||
public
|
|
||||||
view
|
|
||||||
returns (uint256)
|
|
||||||
{
|
|
||||||
return polls.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function exists(uint _pollId)
|
|
||||||
public
|
|
||||||
view
|
|
||||||
returns (bool) {
|
|
||||||
return polls.length != 0 && polls[_pollId].start != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPollResults(uint _pollId)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256[]){
|
|
||||||
return polls[_pollId].results;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasVotesRecorded(uint256 _pollId)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (bool)
|
|
||||||
{
|
|
||||||
return polls[_pollId].voters.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isVotingAvailable(uint _pollId) public view returns (bool){
|
|
||||||
Poll memory p = polls[_pollId];
|
|
||||||
return p.end > block.number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancel(uint _pollId) onlyController {
|
|
||||||
require(polls[_pollId].start > 0);
|
|
||||||
require(polls[_pollId].end < block.number);
|
|
||||||
|
|
||||||
Poll storage p = polls[_pollId];
|
|
||||||
p.cancelled = true;
|
|
||||||
|
|
||||||
emit PollCanceled(_pollId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
pragma solidity ^0.4.23;
|
||||||
|
|
||||||
|
contract IPollFactory {
|
||||||
|
function create(bytes _description) public returns(address);
|
||||||
|
}
|
|
@ -65,7 +65,7 @@ contract LowLevelStringManipulator {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTokenNameSymbol(address tokenAddr) internal returns (string name, string symbol) {
|
function getTokenNameSymbol(address tokenAddr) internal returns (string name, string symbol) {
|
||||||
return (getString(tokenAddr, bytes4(sha3("name()"))),getString(tokenAddr, bytes4(sha3("symbol()"))));
|
return (getString(tokenAddr, bytes4(keccak256("name()"))),getString(tokenAddr, bytes4(keccak256("symbol()"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getString(address _dst, bytes4 sig) internal returns(string) {
|
function getString(address _dst, bytes4 sig) internal returns(string) {
|
||||||
|
|
|
@ -3,16 +3,17 @@ pragma solidity ^0.4.23;
|
||||||
import "../common/Controlled.sol";
|
import "../common/Controlled.sol";
|
||||||
import "./LowLevelStringManipulator.sol";
|
import "./LowLevelStringManipulator.sol";
|
||||||
import "../token/MiniMeToken.sol";
|
import "../token/MiniMeToken.sol";
|
||||||
|
import "./IPollFactory.sol";
|
||||||
|
import "./SingleChoiceFactory.sol";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
contract IPollContract {
|
contract IPollContract {
|
||||||
function deltaVote(int _amount, bytes32 _ballot) returns (bool _succes);
|
function deltaVote(int _amount, bytes32 _ballot) public returns (bool _succes);
|
||||||
function pollType() constant returns (bytes32);
|
function pollType() public constant returns (bytes32);
|
||||||
function question() constant returns (string);
|
function question() public constant returns (string);
|
||||||
}
|
}
|
||||||
|
|
||||||
contract IPollFactory {
|
|
||||||
function create(bytes _description) returns(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
contract PollManager is LowLevelStringManipulator, Controlled {
|
contract PollManager is LowLevelStringManipulator, Controlled {
|
||||||
|
|
||||||
|
@ -33,14 +34,16 @@ contract PollManager is LowLevelStringManipulator, Controlled {
|
||||||
}
|
}
|
||||||
|
|
||||||
Poll[] _polls;
|
Poll[] _polls;
|
||||||
|
IPollFactory pollFactory;
|
||||||
|
|
||||||
MiniMeTokenFactory public tokenFactory;
|
MiniMeTokenFactory public tokenFactory;
|
||||||
MiniMeToken public token;
|
MiniMeToken public token;
|
||||||
|
|
||||||
function PollManager(address _tokenFactory, address _token)
|
constructor(address _tokenFactory, address _token)
|
||||||
public {
|
public {
|
||||||
tokenFactory = MiniMeTokenFactory(_tokenFactory);
|
tokenFactory = MiniMeTokenFactory(_tokenFactory);
|
||||||
token = MiniMeToken(_token);
|
token = MiniMeToken(_token);
|
||||||
|
pollFactory = IPollFactory(new SingleChoiceFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
modifier onlySNTHolder {
|
modifier onlySNTHolder {
|
||||||
|
@ -52,21 +55,24 @@ contract PollManager is LowLevelStringManipulator, Controlled {
|
||||||
function addPoll(
|
function addPoll(
|
||||||
uint _startBlock,
|
uint _startBlock,
|
||||||
uint _endBlock,
|
uint _endBlock,
|
||||||
address _pollFactory,
|
|
||||||
bytes _description)
|
bytes _description)
|
||||||
|
public
|
||||||
onlySNTHolder
|
onlySNTHolder
|
||||||
returns (uint _idPoll)
|
returns (uint _idPoll)
|
||||||
{
|
{
|
||||||
if (_endBlock <= _startBlock) throw;
|
require(_endBlock > _startBlock && _endBlock > block.number);
|
||||||
if (_endBlock <= getBlockNumber()) throw;
|
|
||||||
_idPoll = _polls.length;
|
_idPoll = _polls.length;
|
||||||
_polls.length ++;
|
_polls.length ++;
|
||||||
Poll p = _polls[ _idPoll ];
|
Poll storage p = _polls[ _idPoll ];
|
||||||
p.startBlock = _startBlock;
|
p.startBlock = _startBlock;
|
||||||
p.endBlock = _endBlock;
|
p.endBlock = _endBlock;
|
||||||
p.voters = 0;
|
p.voters = 0;
|
||||||
|
|
||||||
var (name, symbol) = getTokenNameSymbol(address(token));
|
string memory name;
|
||||||
|
string memory symbol;
|
||||||
|
(name, symbol) = getTokenNameSymbol(address(token));
|
||||||
|
|
||||||
string memory proposalName = strConcat(name, "_", uint2str(_idPoll));
|
string memory proposalName = strConcat(name, "_", uint2str(_idPoll));
|
||||||
string memory proposalSymbol = strConcat(symbol, "_", uint2str(_idPoll));
|
string memory proposalSymbol = strConcat(symbol, "_", uint2str(_idPoll));
|
||||||
|
|
||||||
|
@ -78,23 +84,32 @@ contract PollManager is LowLevelStringManipulator, Controlled {
|
||||||
proposalSymbol,
|
proposalSymbol,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
p.pollContract = pollFactory.create(_description);
|
||||||
|
|
||||||
p.pollContract = IPollFactory(_pollFactory).create(_description);
|
require(p.pollContract != 0);
|
||||||
|
|
||||||
if (p.pollContract == 0) throw;
|
|
||||||
|
|
||||||
emit PollCreated(_idPoll);
|
emit PollCreated(_idPoll);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelPoll(uint _idPoll) onlyController {
|
function cancelPoll(uint _idPoll)
|
||||||
if (_idPoll >= _polls.length) throw;
|
onlyController
|
||||||
Poll p = _polls[_idPoll];
|
public
|
||||||
if (getBlockNumber() >= p.endBlock) throw;
|
{
|
||||||
|
require(_idPoll < _polls.length);
|
||||||
|
|
||||||
|
Poll storage p = _polls[_idPoll];
|
||||||
|
|
||||||
|
require(p.endBlock < block.number);
|
||||||
|
|
||||||
p.canceled = true;
|
p.canceled = true;
|
||||||
PollCanceled(_idPoll);
|
emit PollCanceled(_idPoll);
|
||||||
}
|
}
|
||||||
|
|
||||||
function canVote(uint _idPoll) public view returns(bool) {
|
function canVote(uint _idPoll)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns(bool)
|
||||||
|
{
|
||||||
if(_idPoll >= _polls.length) return false;
|
if(_idPoll >= _polls.length) return false;
|
||||||
|
|
||||||
Poll storage p = _polls[_idPoll];
|
Poll storage p = _polls[_idPoll];
|
||||||
|
@ -106,23 +121,19 @@ contract PollManager is LowLevelStringManipulator, Controlled {
|
||||||
balance != 0;
|
balance != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function vote(uint _idPoll, bytes32 _ballot) {
|
function vote(uint _idPoll, bytes32 _ballot) public {
|
||||||
if (_idPoll >= _polls.length) throw;
|
require(_idPoll < _polls.length);
|
||||||
Poll p = _polls[_idPoll];
|
|
||||||
if (getBlockNumber() < p.startBlock) throw;
|
Poll storage p = _polls[_idPoll];
|
||||||
if (getBlockNumber() >= p.endBlock) throw;
|
|
||||||
if (p.canceled) throw;
|
require(block.number >= p.startBlock && block.number < p.endBlock && !p.canceled);
|
||||||
|
|
||||||
unvote(_idPoll);
|
unvote(_idPoll);
|
||||||
|
|
||||||
uint amount = MiniMeToken(p.token).balanceOf(msg.sender);
|
uint amount = MiniMeToken(p.token).balanceOf(msg.sender);
|
||||||
|
|
||||||
if (amount == 0) throw;
|
require(amount != 0);
|
||||||
|
require(MiniMeToken(p.token).transferFrom(msg.sender, address(this), amount));
|
||||||
|
|
||||||
// enableTransfers = true;
|
|
||||||
if (!MiniMeToken(p.token).transferFrom(msg.sender, address(this), amount)) throw;
|
|
||||||
// enableTransfers = false;
|
|
||||||
|
|
||||||
p.votes[msg.sender].ballot = _ballot;
|
p.votes[msg.sender].ballot = _ballot;
|
||||||
p.votes[msg.sender].amount = amount;
|
p.votes[msg.sender].amount = amount;
|
||||||
|
@ -131,44 +142,48 @@ contract PollManager is LowLevelStringManipulator, Controlled {
|
||||||
|
|
||||||
p.votersPerBallot[_ballot]++;
|
p.votersPerBallot[_ballot]++;
|
||||||
|
|
||||||
if (!IPollContract(p.pollContract).deltaVote(int(amount), _ballot)) throw;
|
require(IPollContract(p.pollContract).deltaVote(int(amount), _ballot));
|
||||||
|
|
||||||
Vote(_idPoll, msg.sender, _ballot, amount);
|
emit Vote(_idPoll, msg.sender, _ballot, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unvote(uint _idPoll) {
|
function unvote(uint _idPoll) public {
|
||||||
if (_idPoll >= _polls.length) throw;
|
require(_idPoll < _polls.length);
|
||||||
Poll p = _polls[_idPoll];
|
Poll storage p = _polls[_idPoll];
|
||||||
if (getBlockNumber() < p.startBlock) throw;
|
|
||||||
if (getBlockNumber() >= p.endBlock) throw;
|
require(block.number >= p.startBlock && block.number < p.endBlock && !p.canceled);
|
||||||
if (p.canceled) throw;
|
|
||||||
|
|
||||||
uint amount = p.votes[msg.sender].amount;
|
uint amount = p.votes[msg.sender].amount;
|
||||||
bytes32 ballot = p.votes[msg.sender].ballot;
|
bytes32 ballot = p.votes[msg.sender].ballot;
|
||||||
if (amount == 0) return;
|
if (amount == 0) return;
|
||||||
|
|
||||||
if (!IPollContract(p.pollContract).deltaVote(-int(amount), ballot)) throw;
|
require(IPollContract(p.pollContract).deltaVote(-int(amount), ballot));
|
||||||
|
|
||||||
p.votes[msg.sender].ballot = 0;
|
p.votes[msg.sender].ballot = 0x00;
|
||||||
p.votes[msg.sender].amount = 0;
|
p.votes[msg.sender].amount = 0;
|
||||||
p.votersPerBallot[ballot]--;
|
p.votersPerBallot[ballot]--;
|
||||||
|
|
||||||
p.voters--;
|
p.voters--;
|
||||||
|
|
||||||
// enableTransfers = true;
|
require(MiniMeToken(p.token).transferFrom(address(this), msg.sender, amount));
|
||||||
if (!MiniMeToken(p.token).transferFrom(address(this), msg.sender, amount)) throw;
|
|
||||||
// enableTransfers = false;
|
|
||||||
|
|
||||||
Unvote(_idPoll, msg.sender, ballot, amount);
|
emit Unvote(_idPoll, msg.sender, ballot, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constant Helper Function
|
// Constant Helper Function
|
||||||
|
|
||||||
function nPolls() constant returns(uint) {
|
function nPolls()
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns(uint)
|
||||||
|
{
|
||||||
return _polls.length;
|
return _polls.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function poll(uint _idPoll) constant returns(
|
function poll(uint _idPoll)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns(
|
||||||
uint _startBlock,
|
uint _startBlock,
|
||||||
uint _endBlock,
|
uint _endBlock,
|
||||||
address _token,
|
address _token,
|
||||||
|
@ -179,32 +194,44 @@ contract PollManager is LowLevelStringManipulator, Controlled {
|
||||||
bool _finalized,
|
bool _finalized,
|
||||||
uint _totalCensus,
|
uint _totalCensus,
|
||||||
uint _voters
|
uint _voters
|
||||||
) {
|
)
|
||||||
if (_idPoll >= _polls.length) throw;
|
{
|
||||||
Poll p = _polls[_idPoll];
|
require(_idPoll < _polls.length);
|
||||||
|
|
||||||
|
Poll storage p = _polls[_idPoll];
|
||||||
|
|
||||||
_startBlock = p.startBlock;
|
_startBlock = p.startBlock;
|
||||||
_endBlock = p.endBlock;
|
_endBlock = p.endBlock;
|
||||||
_token = p.token;
|
_token = p.token;
|
||||||
_pollContract = p.pollContract;
|
_pollContract = p.pollContract;
|
||||||
_canceled = p.canceled;
|
_canceled = p.canceled;
|
||||||
_pollType = IPollContract(p.pollContract).pollType();
|
_pollType = IPollContract(p.pollContract).pollType();
|
||||||
_question = getString(p.pollContract, bytes4(sha3("question()")));
|
_question = getString(p.pollContract, bytes4(keccak256("question()")));
|
||||||
_finalized = (!p.canceled) && (getBlockNumber() >= _endBlock);
|
_finalized = (!p.canceled) && (block.number >= _endBlock);
|
||||||
_totalCensus = MiniMeToken(p.token).totalSupply();
|
_totalCensus = MiniMeToken(p.token).totalSupply();
|
||||||
_voters = p.voters;
|
_voters = p.voters;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVote(uint _idPoll, address _voter) constant returns (bytes32 _ballot, uint _amount) {
|
function getVote(uint _idPoll, address _voter)
|
||||||
if (_idPoll >= _polls.length) throw;
|
public
|
||||||
Poll p = _polls[_idPoll];
|
view
|
||||||
|
returns (bytes32 _ballot, uint _amount)
|
||||||
|
{
|
||||||
|
require(_idPoll < _polls.length);
|
||||||
|
|
||||||
|
Poll storage p = _polls[_idPoll];
|
||||||
|
|
||||||
_ballot = p.votes[_voter].ballot;
|
_ballot = p.votes[_voter].ballot;
|
||||||
_amount = p.votes[_voter].amount;
|
_amount = p.votes[_voter].amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVotesByBallot(uint _idPoll, bytes32 _ballot)
|
function getVotesByBallot(uint _idPoll, bytes32 _ballot)
|
||||||
public view returns(uint voters, uint votes) {
|
public
|
||||||
if (_idPoll >= _polls.length) throw;
|
view
|
||||||
|
returns(uint voters, uint votes)
|
||||||
|
{
|
||||||
|
require(_idPoll < _polls.length);
|
||||||
|
|
||||||
Poll storage p = _polls[_idPoll];
|
Poll storage p = _polls[_idPoll];
|
||||||
|
|
||||||
voters = p.votersPerBallot[_ballot];
|
voters = p.votersPerBallot[_ballot];
|
||||||
|
@ -212,29 +239,30 @@ contract PollManager is LowLevelStringManipulator, Controlled {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function proxyPayment(address ) payable returns(bool) {
|
function proxyPayment(address )
|
||||||
|
payable
|
||||||
|
returns(bool) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function onTransfer(address , address , uint ) returns(bool) {
|
function onTransfer(address , address , uint )
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns(bool)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onApprove(address , address , uint ) returns(bool) {
|
function onApprove(address , address , uint )
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns(bool) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getBlockNumber() internal constant returns (uint) {
|
|
||||||
return block.number;
|
|
||||||
}
|
|
||||||
|
|
||||||
event Vote(uint indexed idPoll, address indexed _voter, bytes32 ballot, uint amount);
|
event Vote(uint indexed idPoll, address indexed _voter, bytes32 ballot, uint amount);
|
||||||
event Unvote(uint indexed idPoll, address indexed _voter, bytes32 ballot, uint amount);
|
event Unvote(uint indexed idPoll, address indexed _voter, bytes32 ballot, uint amount);
|
||||||
event PollCanceled(uint indexed idPoll);
|
event PollCanceled(uint indexed idPoll);
|
||||||
event PollCreated(uint indexed idPoll);
|
event PollCreated(uint indexed idPoll);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,15 @@ contract SingleChoice is Controlled {
|
||||||
|
|
||||||
string public question;
|
string public question;
|
||||||
string[] public choices;
|
string[] public choices;
|
||||||
|
|
||||||
int[] public result;
|
int[] public result;
|
||||||
|
int[] public qvResult;
|
||||||
|
|
||||||
bytes32 uid;
|
bytes32 uid;
|
||||||
|
|
||||||
function SingleChoice(address _controller, bytes _rlpDefinition, uint salt) {
|
function SingleChoice(address _controller, bytes _rlpDefinition, uint salt) {
|
||||||
|
|
||||||
uid = sha3(block.blockhash(block.number-1), salt);
|
uid = keccak256(block.blockhash(block.number-1), salt);
|
||||||
controller = _controller;
|
controller = _controller;
|
||||||
|
|
||||||
var itmPoll = _rlpDefinition.toRLPItem(true);
|
var itmPoll = _rlpDefinition.toRLPItem(true);
|
||||||
|
@ -55,9 +58,10 @@ contract SingleChoice is Controlled {
|
||||||
}
|
}
|
||||||
|
|
||||||
result.length = choices.length;
|
result.length = choices.length;
|
||||||
|
qvResult.length = choices.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pollType() constant returns (bytes32) {
|
function pollType() public constant returns (bytes32) {
|
||||||
return bytes32("SINGLE_CHOICE");
|
return bytes32("SINGLE_CHOICE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +75,18 @@ contract SingleChoice is Controlled {
|
||||||
function deltaVote(int _amount, bytes32 _ballot) onlyController returns (bool _succes) {
|
function deltaVote(int _amount, bytes32 _ballot) onlyController returns (bool _succes) {
|
||||||
if (!isValid(_ballot)) return false;
|
if (!isValid(_ballot)) return false;
|
||||||
uint v = uint(_ballot) / (2**248);
|
uint v = uint(_ballot) / (2**248);
|
||||||
|
|
||||||
result[v] += _amount;
|
result[v] += _amount;
|
||||||
|
|
||||||
|
int qv;
|
||||||
|
if (_amount < 0) {
|
||||||
|
qv = -sqrt(-_amount);
|
||||||
|
} else {
|
||||||
|
qv = sqrt(_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
qvResult[v] += qv;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +95,16 @@ contract SingleChoice is Controlled {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBallot(uint _option) constant returns(bytes32) {
|
function getBallot(uint _option) constant returns(bytes32) {
|
||||||
return bytes32((_option * (2**248)) + (uint(sha3(uid, _option)) & (2**248 -1)));
|
return bytes32((_option * (2**248)) + (uint(keccak256(uid, _option)) & (2**248 -1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function sqrt(int256 x) public pure returns (int256 y) {
|
||||||
|
int256 z = (x + 1) / 2;
|
||||||
|
y = x;
|
||||||
|
while (z < y) {
|
||||||
|
y = z;
|
||||||
|
z = (x / z + z) / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
pragma solidity ^0.4.6;
|
pragma solidity ^0.4.6;
|
||||||
|
|
||||||
import "./SingleChoice.sol";
|
import "./SingleChoice.sol";
|
||||||
import "./PollManager.sol";
|
import "./IPollFactory.sol";
|
||||||
|
|
||||||
|
|
||||||
contract SingleChoiceFactory is IPollFactory {
|
contract SingleChoiceFactory is IPollFactory {
|
||||||
uint salt;
|
uint salt;
|
||||||
function create(bytes _description) returns(address) {
|
function create(bytes _description) public returns(address) {
|
||||||
salt++;
|
salt++;
|
||||||
SingleChoice sc = new SingleChoice(msg.sender, _description, salt);
|
SingleChoice sc = new SingleChoice(msg.sender, _description, salt);
|
||||||
SingleChoiceCreated(address(sc));
|
emit SingleChoiceCreated(address(sc));
|
||||||
return address(sc);
|
return address(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,12 @@ config({
|
||||||
],
|
],
|
||||||
"gasLimit": 4000000
|
"gasLimit": 4000000
|
||||||
},
|
},
|
||||||
|
"SingleChoiceFactory": {
|
||||||
|
"deploy": false
|
||||||
|
},
|
||||||
"PollManager": {
|
"PollManager": {
|
||||||
"deploy": true,
|
"deploy": true,
|
||||||
"args": ["$MiniMeTokenFactory", "$SNT"]
|
"args": ["$MiniMeTokenFactory", "$SNT"]
|
||||||
},
|
|
||||||
"SingleChoiceFactory": {
|
|
||||||
"deploy": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -59,13 +59,13 @@ describe("VotingDapp", function () {
|
||||||
|
|
||||||
web3.eth.getAccounts().then((acc) => {
|
web3.eth.getAccounts().then((acc) => {
|
||||||
accounts = acc;
|
accounts = acc;
|
||||||
return SNT.methods.generateTokens(accounts[0], 123456).send()
|
return SNT.methods.generateTokens(accounts[0], 6).send()
|
||||||
}).then((receipt) => {
|
}).then((receipt) => {
|
||||||
return SNT.methods.generateTokens(accounts[1], 789012).send()
|
return SNT.methods.generateTokens(accounts[1], 12).send()
|
||||||
}).then((receipt) => {
|
}).then((receipt) => {
|
||||||
return SNT.methods.generateTokens(accounts[2], 345678).send()
|
return SNT.methods.generateTokens(accounts[2], 10).send()
|
||||||
}).then((receipt) => {
|
}).then((receipt) => {
|
||||||
return SNT.methods.generateTokens(accounts[3], 901234).send()
|
return SNT.methods.generateTokens(accounts[3], 7).send()
|
||||||
}).then((receipt) => {
|
}).then((receipt) => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -84,7 +84,6 @@ describe("VotingDapp", function () {
|
||||||
receipt = await PollManager.methods.addPoll(
|
receipt = await PollManager.methods.addPoll(
|
||||||
blockNumber,
|
blockNumber,
|
||||||
blockNumber + 10,
|
blockNumber + 10,
|
||||||
SingleChoiceFactory.options.address,
|
|
||||||
question)
|
question)
|
||||||
.send({from: accounts[8]});
|
.send({from: accounts[8]});
|
||||||
assert.fail('should have reverted before');
|
assert.fail('should have reverted before');
|
||||||
|
@ -99,7 +98,6 @@ describe("VotingDapp", function () {
|
||||||
receipt = await PollManager.methods.addPoll(
|
receipt = await PollManager.methods.addPoll(
|
||||||
blockNumber,
|
blockNumber,
|
||||||
blockNumber + 10,
|
blockNumber + 10,
|
||||||
SingleChoiceFactory.options.address,
|
|
||||||
question)
|
question)
|
||||||
.send({from: accounts[0]});
|
.send({from: accounts[0]});
|
||||||
|
|
||||||
|
@ -150,18 +148,25 @@ describe("VotingDapp", function () {
|
||||||
poll = await PollManager.methods.poll(pollId).call();
|
poll = await PollManager.methods.poll(pollId).call();
|
||||||
let votersByBallotYES = await PollManager.methods.getVotesByBallot(pollId, Yes).call();
|
let votersByBallotYES = await PollManager.methods.getVotesByBallot(pollId, Yes).call();
|
||||||
let tokenVotesByBallotYES = await pollContract.methods.result(0).call(); // 0 == Yes (because it is the initial option )
|
let tokenVotesByBallotYES = await pollContract.methods.result(0).call(); // 0 == Yes (because it is the initial option )
|
||||||
|
let quadraticVotesByBallotYES = await pollContract.methods.qvResult(0).call(); // 0 == Yes (because it is the initial option )
|
||||||
|
|
||||||
// console.dir(poll); // Will contain state of the poll
|
// Will contain state of the poll
|
||||||
// console.log(tokenVotesByBallotYES); // Contains how many votes has a ballot
|
// console.dir(poll);
|
||||||
// console.log(votersByBallotYES); // Contains how many voters voted for that option
|
|
||||||
|
|
||||||
|
// Contains how many votes has a ballot
|
||||||
|
// console.log(tokenVotesByBallotYES);
|
||||||
|
|
||||||
|
// Contains how many votes has a ballot using quadratic voting
|
||||||
|
//console.log(quadraticVotesByBallotYES);
|
||||||
|
|
||||||
|
// Contains how many voters voted for that option
|
||||||
|
// console.log(votersByBallotYES);
|
||||||
|
|
||||||
// ===================================================
|
// ===================================================
|
||||||
// Unvote
|
// Unvote
|
||||||
receipt = await PollManager.methods.unvote(pollId).send({from: accounts[0]});
|
receipt = await PollManager.methods.unvote(pollId).send({from: accounts[0]});
|
||||||
assert.equal(!!receipt.events.Unvote, true, "Unvote not triggered");
|
assert.equal(!!receipt.events.Unvote, true, "Unvote not triggered");
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue