From bfad0ae88e2cac53fe0180c93124eaef1a5d8afb Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Wed, 27 Jun 2018 17:23:27 -0400 Subject: [PATCH] Simplified contract to only gather votes without requiring options --- app/components/simple-voting/AddPoll.js | 18 +- app/dapp.js | 10 - contracts/polls/IPollFactory.sol | 5 - contracts/polls/LowLevelStringManipulator.sol | 115 ----- contracts/polls/PollManager.sol | 132 ++---- contracts/polls/RLP.sol | 416 ------------------ contracts/polls/SingleChoice.sol | 112 ----- contracts/polls/SingleChoiceFactory.sol | 17 - test/votingdapp.js | 56 +-- 9 files changed, 62 insertions(+), 819 deletions(-) delete mode 100644 contracts/polls/IPollFactory.sol delete mode 100644 contracts/polls/LowLevelStringManipulator.sol delete mode 100644 contracts/polls/RLP.sol delete mode 100644 contracts/polls/SingleChoice.sol delete mode 100644 contracts/polls/SingleChoiceFactory.sol diff --git a/app/components/simple-voting/AddPoll.js b/app/components/simple-voting/AddPoll.js index 81e48b8..1c5ff00 100644 --- a/app/components/simple-voting/AddPoll.js +++ b/app/components/simple-voting/AddPoll.js @@ -5,28 +5,12 @@ import CardContent from '@material-ui/core/CardContent'; import PollManager from 'Embark/contracts/PollManager'; import TextField from '@material-ui/core/TextField'; import Button from '@material-ui/core/Button'; -import { map } from 'lodash'; -import rlp from 'rlp'; import LinearProgress from '@material-ui/core/LinearProgress'; import { withStyles } from '@material-ui/core/styles'; import { withFormik } from 'formik'; const oneDayinBlocks = 5760; -const singleChoiceDef = (question, options) => { - const d = [ - new Buffer(question), - map(options, function(o) { - return new Buffer(o); - }) - ]; - - const b = rlp.encode(d); - const rlpDefinition = '0x' + b.toString('hex'); - - return rlpDefinition; -} - const styles = theme => ({ button: { margin: theme.spacing.unit, @@ -108,7 +92,7 @@ const AddPoll = withFormik({ const { addPoll } = PollManager.methods; const currentBlock = await getBlockNumber(); const endTime = currentBlock + (oneDayinBlocks * 90); - const toSend = addPoll(endTime, singleChoiceDef(description, ['YES'])); + const toSend = addPoll(endTime, description); setSubmitting(true); diff --git a/app/dapp.js b/app/dapp.js index 4d9c603..2cbe450 100644 --- a/app/dapp.js +++ b/app/dapp.js @@ -2,7 +2,6 @@ import React, { Fragment } from 'react'; import ReactDOM from 'react-dom'; import EmbarkJS from 'Embark/EmbarkJS'; import PollManager from 'Embark/contracts/PollManager'; -import SingleChoice from 'Embark/contracts/SingleChoice'; import AdminView from './components/AdminView'; import Voting from './components/Voting'; import SNT from 'Embark/contracts/SNT'; @@ -41,18 +40,9 @@ class App extends React.Component { const { nPolls, poll } = PollManager.methods; const polls = await nPolls.call(); const total = await polls.call(); - if (total) this._setVotingOptions(); getPolls(total, poll).then(rawPolls => { this.setState({ rawPolls })}); } - async _setVotingOptions(){ - const poll = await PollManager.methods.poll(0).call(); - SingleChoice.options.address = poll._pollContract; - const yes = await SingleChoice.methods.getBallot(0).call(); - const no = await SingleChoice.methods.getBallot(1).call(); - this.setState({ votingOptions: { yes, no } }) - } - _renderStatus(title, available) { let className = available ? 'pull-right status-online' : 'pull-right status-offline'; return diff --git a/contracts/polls/IPollFactory.sol b/contracts/polls/IPollFactory.sol deleted file mode 100644 index e4679bd..0000000 --- a/contracts/polls/IPollFactory.sol +++ /dev/null @@ -1,5 +0,0 @@ -pragma solidity ^0.4.23; - -contract IPollFactory { - function create(bytes _description) public returns(address); -} diff --git a/contracts/polls/LowLevelStringManipulator.sol b/contracts/polls/LowLevelStringManipulator.sol deleted file mode 100644 index 2de012c..0000000 --- a/contracts/polls/LowLevelStringManipulator.sol +++ /dev/null @@ -1,115 +0,0 @@ -pragma solidity ^0.4.11; - -contract LowLevelStringManipulator { - -//////////////////// -// Internal helper functions to manipulate strings -///////////////// - - function strConcat(string _a, string _b, string _c, string _d, string _e) internal returns (string){ - bytes memory _ba = bytes(_a); - bytes memory _bb = bytes(_b); - bytes memory _bc = bytes(_c); - bytes memory _bd = bytes(_d); - bytes memory _be = bytes(_e); - string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length); - bytes memory babcde = bytes(abcde); - uint k = 0; - for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i]; - for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i]; - for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i]; - for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i]; - for (i = 0; i < _be.length; i++) babcde[k++] = _be[i]; - return string(babcde); - } - - function strConcat(string _a, string _b, string _c, string _d) internal returns (string) { - return strConcat(_a, _b, _c, _d, ""); - } - - function strConcat(string _a, string _b, string _c) internal returns (string) { - return strConcat(_a, _b, _c, "", ""); - } - - function strConcat(string _a, string _b) internal returns (string) { - return strConcat(_a, _b, "", "", ""); - } - - function uint2str(uint a) internal returns (string) { - return bytes32ToString(uintToBytes(a)); - } - - function uintToBytes(uint v) internal constant returns (bytes32 ret) { - if (v == 0) { - ret = '0'; - } - else { - while (v > 0) { - ret = bytes32(uint(ret) / (2 ** 8)); - ret |= bytes32(((v % 10) + 48) * 2 ** (8 * 31)); - v /= 10; - } - } - return ret; - } - - function bytes32ToString (bytes32 data) internal constant returns (string) { - bytes memory bytesString = new bytes(32); - for (uint j=0; j<32; j++) { - byte char = byte(bytes32(uint(data) * 2 ** (8 * j))); - if (char != 0) { - bytesString[j] = char; - } - } - return string(bytesString); - } - - function getTokenNameSymbol(address tokenAddr) internal returns (string name, string symbol) { - return (getString(tokenAddr, bytes4(keccak256("name()"))),getString(tokenAddr, bytes4(keccak256("symbol()")))); - } - - function getString(address _dst, bytes4 sig) internal returns(string) { - string memory s; - bool success1; - bool success2; - assembly { - let x := mload(0x40) //Find empty storage location using "free memory pointer" - mstore(x,sig) //Place signature at begining of empty storage - - success1 := call( //This is the critical change (Pop the top stack value) - 5000, //5k gas - _dst, //To addr - 0, //No value - x, //Inputs are stored at location x - 0x04, //Inputs are 36 byes long - x, //Store output over input (saves space) - 0x80) //Outputs are 32 bytes long - - let strL := mload(add(x, 0x20)) // Load the length of the sring - - jumpi(ask_more, gt(strL, 64)) - - mstore(0x40,add(x,add(strL, 0x40))) - - s := add(x,0x20) - ask_more: - mstore(x,sig) //Place signature at begining of empty storage - - success2 := call( //This is the critical change (Pop the top stack value) - 5000, //5k gas - _dst, //To addr - 0, //No value - x, //Inputs are stored at location x - 0x04, //Inputs are 36 byes long - x, //Store output over input (saves space) - add(0x40, strL)) //Outputs are 32 bytes long - - mstore(0x40,add(x,add(strL, 0x40))) - s := add(x,0x20) - - } - if ((!success1)||(!success2)) throw; - return s; - } - -} diff --git a/contracts/polls/PollManager.sol b/contracts/polls/PollManager.sol index ed9b56b..1de98c7 100644 --- a/contracts/polls/PollManager.sol +++ b/contracts/polls/PollManager.sol @@ -1,40 +1,25 @@ pragma solidity ^0.4.23; import "../common/Controlled.sol"; -import "./LowLevelStringManipulator.sol"; import "../token/MiniMeToken.sol"; -import "./IPollFactory.sol"; -import "./SingleChoiceFactory.sol"; -contract IPollContract { - function deltaVote(int _amount, bytes32 _ballot) public returns (bool _succes); - function pollType() public constant returns (bytes32); - function question() public constant returns (string); -} - - -contract PollManager is LowLevelStringManipulator, Controlled { - - struct VoteLog { - bytes32 ballot; - uint amount; - } +contract PollManager is Controlled { struct Poll { uint startBlock; uint endBlock; address token; - address pollContract; bool canceled; uint voters; - mapping(bytes32 => uint) votersPerBallot; - mapping(address => VoteLog) votes; + string description; + mapping(address => uint) votes; + uint results; + uint qvResults; } Poll[] _polls; - IPollFactory pollFactory; MiniMeTokenFactory public tokenFactory; MiniMeToken public token; @@ -43,7 +28,6 @@ contract PollManager is LowLevelStringManipulator, Controlled { public { tokenFactory = MiniMeTokenFactory(_tokenFactory); token = MiniMeToken(_token); - pollFactory = IPollFactory(new SingleChoiceFactory()); } modifier onlySNTHolder { @@ -54,7 +38,7 @@ contract PollManager is LowLevelStringManipulator, Controlled { function addPoll( uint _endBlock, - bytes _description) + string _description) public onlySNTHolder returns (uint _idPoll) @@ -67,26 +51,16 @@ contract PollManager is LowLevelStringManipulator, Controlled { p.startBlock = block.number; p.endBlock = _endBlock; p.voters = 0; - - string memory name; - string memory symbol; - (name, symbol) = getTokenNameSymbol(address(token)); - - string memory proposalName = strConcat(name, "_", uint2str(_idPoll)); - string memory proposalSymbol = strConcat(symbol, "_", uint2str(_idPoll)); + p.description = _description; p.token = tokenFactory.createCloneToken( address(token), block.number - 1, - proposalName, + "SNT Voting Token", token.decimals(), - proposalSymbol, + "SVT", true); - p.pollContract = pollFactory.create(_description); - - require(p.pollContract != 0); - emit PollCreated(_idPoll); } @@ -120,7 +94,16 @@ contract PollManager is LowLevelStringManipulator, Controlled { balance != 0; } - function vote(uint _idPoll, bytes32 _ballot) public { + function sqrt(uint256 x) public pure returns (uint256 y) { + uint256 z = (x + 1) / 2; + y = x; + while (z < y) { + y = z; + z = (x / z + z) / 2; + } + } + + function vote(uint _idPoll) public { require(_idPoll < _polls.length); Poll storage p = _polls[_idPoll]; @@ -134,19 +117,16 @@ contract PollManager is LowLevelStringManipulator, Controlled { require(amount != 0); require(MiniMeToken(p.token).transferFrom(msg.sender, address(this), amount)); - p.votes[msg.sender].ballot = _ballot; - p.votes[msg.sender].amount = amount; - + p.votes[msg.sender] = amount; p.voters++; + + p.results += amount; + p.qvResults += sqrt(amount); - p.votersPerBallot[_ballot]++; - - require(IPollContract(p.pollContract).deltaVote(int(amount), _ballot)); - - emit Vote(_idPoll, msg.sender, _ballot, amount); + emit Vote(_idPoll, msg.sender, amount); } - function customVote(uint _idPoll, bytes32 _ballot, uint _amount) public { + function customVote(uint _idPoll, uint _amount) public { require(_idPoll < _polls.length); Poll storage p = _polls[_idPoll]; @@ -160,16 +140,13 @@ contract PollManager is LowLevelStringManipulator, Controlled { require(balance != 0 && balance >= _amount); require(MiniMeToken(p.token).transferFrom(msg.sender, address(this), _amount)); - p.votes[msg.sender].ballot = _ballot; - p.votes[msg.sender].amount = _amount; - + p.votes[msg.sender] = _amount; p.voters++; - p.votersPerBallot[_ballot]++; + p.results += _amount; + p.qvResults += sqrt(_amount); - require(IPollContract(p.pollContract).deltaVote(int(_amount), _ballot)); - - emit Vote(_idPoll, msg.sender, _ballot, _amount); + emit Vote(_idPoll, msg.sender, _amount); } function unvote(uint _idPoll) public { @@ -178,21 +155,18 @@ contract PollManager is LowLevelStringManipulator, Controlled { require(block.number >= p.startBlock && block.number < p.endBlock && !p.canceled); - uint amount = p.votes[msg.sender].amount; - bytes32 ballot = p.votes[msg.sender].ballot; + uint amount = p.votes[msg.sender]; if (amount == 0) return; - require(IPollContract(p.pollContract).deltaVote(-int(amount), ballot)); - - p.votes[msg.sender].ballot = 0x00; - p.votes[msg.sender].amount = 0; - p.votersPerBallot[ballot]--; + p.votes[msg.sender] = 0; p.voters--; + p.results -= amount; + p.qvResults -= sqrt(amount); require(MiniMeToken(p.token).transferFrom(address(this), msg.sender, amount)); - emit Unvote(_idPoll, msg.sender, ballot, amount); + emit Unvote(_idPoll, msg.sender, amount); } // Constant Helper Function @@ -212,13 +186,13 @@ contract PollManager is LowLevelStringManipulator, Controlled { uint _startBlock, uint _endBlock, address _token, - address _pollContract, bool _canceled, - bytes32 _pollType, - string _question, + string _description, bool _finalized, uint _totalCensus, - uint _voters + uint _voters, + uint _results, + uint _qvResults ) { require(_idPoll < _polls.length); @@ -228,40 +202,24 @@ contract PollManager is LowLevelStringManipulator, Controlled { _startBlock = p.startBlock; _endBlock = p.endBlock; _token = p.token; - _pollContract = p.pollContract; _canceled = p.canceled; - _pollType = IPollContract(p.pollContract).pollType(); - _question = getString(p.pollContract, bytes4(keccak256("question()"))); + _description = p.description; _finalized = (!p.canceled) && (block.number >= _endBlock); _totalCensus = MiniMeToken(p.token).totalSupply(); _voters = p.voters; + _results = p.results; + _qvResults = p.qvResults; } function getVote(uint _idPoll, address _voter) public view - returns (bytes32 _ballot, uint _amount) + returns (uint) { require(_idPoll < _polls.length); Poll storage p = _polls[_idPoll]; - - _ballot = p.votes[_voter].ballot; - _amount = p.votes[_voter].amount; - } - - function getVotesByBallot(uint _idPoll, bytes32 _ballot) - public - view - returns(uint voters, uint votes) - { - require(_idPoll < _polls.length); - - Poll storage p = _polls[_idPoll]; - - voters = p.votersPerBallot[_ballot]; - votes = p.votersPerBallot[_ballot]; - + return p.votes[_voter]; } function proxyPayment(address ) @@ -286,8 +244,8 @@ contract PollManager is LowLevelStringManipulator, Controlled { return true; } - 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 Vote(uint indexed idPoll, address indexed _voter, uint amount); + event Unvote(uint indexed idPoll, address indexed _voter, uint amount); event PollCanceled(uint indexed idPoll); event PollCreated(uint indexed idPoll); } diff --git a/contracts/polls/RLP.sol b/contracts/polls/RLP.sol deleted file mode 100644 index 5bb27bb..0000000 --- a/contracts/polls/RLP.sol +++ /dev/null @@ -1,416 +0,0 @@ -pragma solidity ^0.4.6; - -/** -* @title RLPReader -* -* RLPReader is used to read and parse RLP encoded data in memory. -* -* @author Andreas Olofsson (androlo1980@gmail.com) -*/ -library RLP { - - uint constant DATA_SHORT_START = 0x80; - uint constant DATA_LONG_START = 0xB8; - uint constant LIST_SHORT_START = 0xC0; - uint constant LIST_LONG_START = 0xF8; - - uint constant DATA_LONG_OFFSET = 0xB7; - uint constant LIST_LONG_OFFSET = 0xF7; - - - struct RLPItem { - uint _unsafe_memPtr; // Pointer to the RLP-encoded bytes. - uint _unsafe_length; // Number of bytes. This is the full length of the string. - } - - struct Iterator { - RLPItem _unsafe_item; // Item that's being iterated over. - uint _unsafe_nextPtr; // Position of the next item in the list. - } - - /* Iterator */ - - function next(Iterator memory self) internal constant returns (RLPItem memory subItem) { - if(hasNext(self)) { - var ptr = self._unsafe_nextPtr; - var itemLength = _itemLength(ptr); - subItem._unsafe_memPtr = ptr; - subItem._unsafe_length = itemLength; - self._unsafe_nextPtr = ptr + itemLength; - } - else - throw; - } - - function next(Iterator memory self, bool strict) internal constant returns (RLPItem memory subItem) { - subItem = next(self); - if(strict && !_validate(subItem)) - throw; - return; - } - - function hasNext(Iterator memory self) internal constant returns (bool) { - var item = self._unsafe_item; - return self._unsafe_nextPtr < item._unsafe_memPtr + item._unsafe_length; - } - - /* RLPItem */ - - /// @dev Creates an RLPItem from an array of RLP encoded bytes. - /// @param self The RLP encoded bytes. - /// @return An RLPItem - function toRLPItem(bytes memory self) internal constant returns (RLPItem memory) { - uint len = self.length; - if (len == 0) { - return RLPItem(0, 0); - } - uint memPtr; - assembly { - memPtr := add(self, 0x20) - } - return RLPItem(memPtr, len); - } - - /// @dev Creates an RLPItem from an array of RLP encoded bytes. - /// @param self The RLP encoded bytes. - /// @param strict Will throw if the data is not RLP encoded. - /// @return An RLPItem - function toRLPItem(bytes memory self, bool strict) internal constant returns (RLPItem memory) { - var item = toRLPItem(self); - if(strict) { - uint len = self.length; - if(_payloadOffset(item) > len) - throw; - if(_itemLength(item._unsafe_memPtr) != len) - throw; - if(!_validate(item)) - throw; - } - return item; - } - - /// @dev Check if the RLP item is null. - /// @param self The RLP item. - /// @return 'true' if the item is null. - function isNull(RLPItem memory self) internal constant returns (bool ret) { - return self._unsafe_length == 0; - } - - /// @dev Check if the RLP item is a list. - /// @param self The RLP item. - /// @return 'true' if the item is a list. - function isList(RLPItem memory self) internal constant returns (bool ret) { - if (self._unsafe_length == 0) - return false; - uint memPtr = self._unsafe_memPtr; - assembly { - ret := iszero(lt(byte(0, mload(memPtr)), 0xC0)) - } - } - - /// @dev Check if the RLP item is data. - /// @param self The RLP item. - /// @return 'true' if the item is data. - function isData(RLPItem memory self) internal constant returns (bool ret) { - if (self._unsafe_length == 0) - return false; - uint memPtr = self._unsafe_memPtr; - assembly { - ret := lt(byte(0, mload(memPtr)), 0xC0) - } - } - - /// @dev Check if the RLP item is empty (string or list). - /// @param self The RLP item. - /// @return 'true' if the item is null. - function isEmpty(RLPItem memory self) internal constant returns (bool ret) { - if(isNull(self)) - return false; - uint b0; - uint memPtr = self._unsafe_memPtr; - assembly { - b0 := byte(0, mload(memPtr)) - } - return (b0 == DATA_SHORT_START || b0 == LIST_SHORT_START); - } - - /// @dev Get the number of items in an RLP encoded list. - /// @param self The RLP item. - /// @return The number of items. - function items(RLPItem memory self) internal constant returns (uint) { - if (!isList(self)) - return 0; - uint b0; - uint memPtr = self._unsafe_memPtr; - assembly { - b0 := byte(0, mload(memPtr)) - } - uint pos = memPtr + _payloadOffset(self); - uint last = memPtr + self._unsafe_length - 1; - uint itms; - while(pos <= last) { - pos += _itemLength(pos); - itms++; - } - return itms; - } - - /// @dev Create an iterator. - /// @param self The RLP item. - /// @return An 'Iterator' over the item. - function iterator(RLPItem memory self) internal constant returns (Iterator memory it) { - if (!isList(self)) - throw; - uint ptr = self._unsafe_memPtr + _payloadOffset(self); - it._unsafe_item = self; - it._unsafe_nextPtr = ptr; - } - - /// @dev Return the RLP encoded bytes. - /// @param self The RLPItem. - /// @return The bytes. - function toBytes(RLPItem memory self) internal constant returns (bytes memory bts) { - var len = self._unsafe_length; - if (len == 0) - return; - bts = new bytes(len); - _copyToBytes(self._unsafe_memPtr, bts, len); - } - - /// @dev Decode an RLPItem into bytes. This will not work if the - /// RLPItem is a list. - /// @param self The RLPItem. - /// @return The decoded string. - function toData(RLPItem memory self) internal constant returns (bytes memory bts) { - if(!isData(self)) - throw; - var (rStartPos, len) = _decode(self); - bts = new bytes(len); - _copyToBytes(rStartPos, bts, len); - } - - /// @dev Get the list of sub-items from an RLP encoded list. - /// Warning: This is inefficient, as it requires that the list is read twice. - /// @param self The RLP item. - /// @return Array of RLPItems. - function toList(RLPItem memory self) internal constant returns (RLPItem[] memory list) { - if(!isList(self)) - throw; - var numItems = items(self); - list = new RLPItem[](numItems); - var it = iterator(self); - uint idx; - while(hasNext(it)) { - list[idx] = next(it); - idx++; - } - } - - /// @dev Decode an RLPItem into an ascii string. This will not work if the - /// RLPItem is a list. - /// @param self The RLPItem. - /// @return The decoded string. - function toAscii(RLPItem memory self) internal constant returns (string memory str) { - if(!isData(self)) - throw; - var (rStartPos, len) = _decode(self); - bytes memory bts = new bytes(len); - _copyToBytes(rStartPos, bts, len); - str = string(bts); - } - - /// @dev Decode an RLPItem into a uint. This will not work if the - /// RLPItem is a list. - /// @param self The RLPItem. - /// @return The decoded string. - function toUint(RLPItem memory self) internal constant returns (uint data) { - if(!isData(self)) - throw; - var (rStartPos, len) = _decode(self); - if (len > 32 || len == 0) - throw; - assembly { - data := div(mload(rStartPos), exp(256, sub(32, len))) - } - } - - /// @dev Decode an RLPItem into a boolean. This will not work if the - /// RLPItem is a list. - /// @param self The RLPItem. - /// @return The decoded string. - function toBool(RLPItem memory self) internal constant returns (bool data) { - if(!isData(self)) - throw; - var (rStartPos, len) = _decode(self); - if (len != 1) - throw; - uint temp; - assembly { - temp := byte(0, mload(rStartPos)) - } - if (temp > 1) - throw; - return temp == 1 ? true : false; - } - - /// @dev Decode an RLPItem into a byte. This will not work if the - /// RLPItem is a list. - /// @param self The RLPItem. - /// @return The decoded string. - function toByte(RLPItem memory self) internal constant returns (byte data) { - if(!isData(self)) - throw; - var (rStartPos, len) = _decode(self); - if (len != 1) - throw; - uint temp; - assembly { - temp := byte(0, mload(rStartPos)) - } - return byte(temp); - } - - /// @dev Decode an RLPItem into an int. This will not work if the - /// RLPItem is a list. - /// @param self The RLPItem. - /// @return The decoded string. - function toInt(RLPItem memory self) internal constant returns (int data) { - return int(toUint(self)); - } - - /// @dev Decode an RLPItem into a bytes32. This will not work if the - /// RLPItem is a list. - /// @param self The RLPItem. - /// @return The decoded string. - function toBytes32(RLPItem memory self) internal constant returns (bytes32 data) { - return bytes32(toUint(self)); - } - - /// @dev Decode an RLPItem into an address. This will not work if the - /// RLPItem is a list. - /// @param self The RLPItem. - /// @return The decoded string. - function toAddress(RLPItem memory self) internal constant returns (address data) { - if(!isData(self)) - throw; - var (rStartPos, len) = _decode(self); - if (len != 20) - throw; - assembly { - data := div(mload(rStartPos), exp(256, 12)) - } - } - - // Get the payload offset. - function _payloadOffset(RLPItem memory self) private constant returns (uint) { - if(self._unsafe_length == 0) - return 0; - uint b0; - uint memPtr = self._unsafe_memPtr; - assembly { - b0 := byte(0, mload(memPtr)) - } - if(b0 < DATA_SHORT_START) - return 0; - if(b0 < DATA_LONG_START || (b0 >= LIST_SHORT_START && b0 < LIST_LONG_START)) - return 1; - if(b0 < LIST_SHORT_START) - return b0 - DATA_LONG_OFFSET + 1; - return b0 - LIST_LONG_OFFSET + 1; - } - - // Get the full length of an RLP item. - function _itemLength(uint memPtr) private constant returns (uint len) { - uint b0; - assembly { - b0 := byte(0, mload(memPtr)) - } - if (b0 < DATA_SHORT_START) - len = 1; - else if (b0 < DATA_LONG_START) - len = b0 - DATA_SHORT_START + 1; - else if (b0 < LIST_SHORT_START) { - assembly { - let bLen := sub(b0, 0xB7) // bytes length (DATA_LONG_OFFSET) - let dLen := div(mload(add(memPtr, 1)), exp(256, sub(32, bLen))) // data length - len := add(1, add(bLen, dLen)) // total length - } - } - else if (b0 < LIST_LONG_START) - len = b0 - LIST_SHORT_START + 1; - else { - assembly { - let bLen := sub(b0, 0xF7) // bytes length (LIST_LONG_OFFSET) - let dLen := div(mload(add(memPtr, 1)), exp(256, sub(32, bLen))) // data length - len := add(1, add(bLen, dLen)) // total length - } - } - } - - // Get start position and length of the data. - function _decode(RLPItem memory self) private constant returns (uint memPtr, uint len) { - if(!isData(self)) - throw; - uint b0; - uint start = self._unsafe_memPtr; - assembly { - b0 := byte(0, mload(start)) - } - if (b0 < DATA_SHORT_START) { - memPtr = start; - len = 1; - return; - } - if (b0 < DATA_LONG_START) { - len = self._unsafe_length - 1; - memPtr = start + 1; - } else { - uint bLen; - assembly { - bLen := sub(b0, 0xB7) // DATA_LONG_OFFSET - } - len = self._unsafe_length - 1 - bLen; - memPtr = start + bLen + 1; - } - return; - } - - // Assumes that enough memory has been allocated to store in target. - function _copyToBytes(uint btsPtr, bytes memory tgt, uint btsLen) private constant { - // Exploiting the fact that 'tgt' was the last thing to be allocated, - // we can write entire words, and just overwrite any excess. - assembly { - { - let i := 0 // Start at arr + 0x20 - let words := div(add(btsLen, 31), 32) - let rOffset := btsPtr - let wOffset := add(tgt, 0x20) - tag_loop: - jumpi(end, eq(i, words)) - { - let offset := mul(i, 0x20) - mstore(add(wOffset, offset), mload(add(rOffset, offset))) - i := add(i, 1) - } - jump(tag_loop) - end: - mstore(add(tgt, add(0x20, mload(tgt))), 0) - } - } - } - - // Check that an RLP item is valid. - function _validate(RLPItem memory self) private constant returns (bool ret) { - // Check that RLP is well-formed. - uint b0; - uint b1; - uint memPtr = self._unsafe_memPtr; - assembly { - b0 := byte(0, mload(memPtr)) - b1 := byte(1, mload(memPtr)) - } - if(b0 == DATA_SHORT_START + 1 && b1 < DATA_SHORT_START) - return false; - return true; - } -} diff --git a/contracts/polls/SingleChoice.sol b/contracts/polls/SingleChoice.sol deleted file mode 100644 index 3ba2230..0000000 --- a/contracts/polls/SingleChoice.sol +++ /dev/null @@ -1,112 +0,0 @@ -pragma solidity ^0.4.6; - -/* - Copyright 2016, Jordi Baylina - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -import "../common/Controlled.sol"; -import "./RLP.sol"; - -contract SingleChoice is Controlled { - using RLP for RLP.RLPItem; - using RLP for RLP.Iterator; - using RLP for bytes; - - string public question; - string[] public choices; - - int[] public result; - int[] public qvResult; - - bytes32 uid; - - function SingleChoice(address _controller, bytes _rlpDefinition, uint salt) { - - uid = keccak256(block.blockhash(block.number-1), salt); - controller = _controller; - - var itmPoll = _rlpDefinition.toRLPItem(true); - - if (!itmPoll.isList()) throw; - - var itrPoll = itmPoll.iterator(); - - question = itrPoll.next().toAscii(); - - var itmOptions = itrPoll.next(); - - if (!itmOptions.isList()) throw; - - var itrOptions = itmOptions.iterator(); - - while(itrOptions.hasNext()) { - choices.length++; - choices[choices.length-1] = itrOptions.next().toAscii(); - } - - result.length = choices.length; - qvResult.length = choices.length; - } - - function pollType() public constant returns (bytes32) { - return bytes32("SINGLE_CHOICE"); - } - - function isValid(bytes32 _ballot) constant returns(bool) { - uint v = uint(_ballot) / (2**248); - if (v>=choices.length) return false; - if (getBallot(v) != _ballot) return false; - return true; - } - - function deltaVote(int _amount, bytes32 _ballot) onlyController returns (bool _succes) { - if (!isValid(_ballot)) return false; - uint v = uint(_ballot) / (2**248); - - result[v] += _amount; - - int qv; - if (_amount < 0) { - qv = -sqrt(-_amount); - } else { - qv = sqrt(_amount); - } - - qvResult[v] += qv; - - return true; - } - - function nOptions() constant returns(uint) { - return choices.length; - } - - function getBallot(uint _option) constant returns(bytes32) { - 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; - } - } -} - - - diff --git a/contracts/polls/SingleChoiceFactory.sol b/contracts/polls/SingleChoiceFactory.sol deleted file mode 100644 index 34e19a6..0000000 --- a/contracts/polls/SingleChoiceFactory.sol +++ /dev/null @@ -1,17 +0,0 @@ -pragma solidity ^0.4.6; - -import "./SingleChoice.sol"; -import "./IPollFactory.sol"; - - -contract SingleChoiceFactory is IPollFactory { - uint salt; - function create(bytes _description) public returns(address) { - salt++; - SingleChoice sc = new SingleChoice(msg.sender, _description, salt); - emit SingleChoiceCreated(address(sc)); - return address(sc); - } - - event SingleChoiceCreated(address indexed addr); -} diff --git a/test/votingdapp.js b/test/votingdapp.js index c7089be..72830ba 100644 --- a/test/votingdapp.js +++ b/test/votingdapp.js @@ -1,6 +1,5 @@ const utils = require('../utils/testUtils') const assert = require('assert'); -const SingleChoice = require('Embark/contracts/SingleChoice'); const BN = web3.utils.BN; var _ = require('lodash'); var rlp = require('rlp'); @@ -26,9 +25,6 @@ config({ ], "gasLimit": 4000000 }, - "SingleChoiceFactory": { - "deploy": false - }, "PollManager": { "deploy": true, "args": ["$MiniMeTokenFactory", "$SNT"] @@ -36,20 +32,6 @@ config({ } }); -singleChoiceDef = (question, options) => { - var d = [ - new Buffer(question), - _.map(options, function(o) { - return new Buffer(o); - }) - ]; - - var b= rlp.encode(d); - var rlpDefinition = '0x' + b.toString('hex'); - - return rlpDefinition; -} - describe("VotingDapp", function () { this.timeout(0); @@ -74,7 +56,7 @@ describe("VotingDapp", function () { it("Test", async () => { const blockNumber = await web3.eth.getBlockNumber(); - const question = singleChoiceDef("Move from Slack to Status Desktop", [ "Yes", "No" ]); + const question = "Move from Slack to Status Desktop"; let receipt; @@ -103,14 +85,7 @@ describe("VotingDapp", function () { const pollId = receipt.events.PollCreated.returnValues.idPoll; let poll = await PollManager.methods.poll(pollId).call(); - - SingleChoice.options.address = poll._pollContract; - const pollContract = SingleChoice; - - // Options are represented as a hex value - const Yes = await SingleChoice.methods.getBallot(0).call(); - const No = await SingleChoice.methods.getBallot(1).call(); - + // =================================================== // Determining if I can vote por a proposal @@ -120,23 +95,24 @@ describe("VotingDapp", function () { // =================================================== // Voting - receipt = await PollManager.methods.vote(pollId, Yes).send({from: accounts[0]}); + receipt = await PollManager.methods.vote(pollId).send({from: accounts[0]}); assert.equal(!!receipt.events.Vote, true, "Vote not triggered"); - receipt = await PollManager.methods.customVote(pollId, Yes, 12).send({from: accounts[1]}); + receipt = await PollManager.methods.customVote(pollId, 12).send({from: accounts[1]}); assert.equal(!!receipt.events.Vote, true, "Vote not triggered"); // =================================================== // Getting what option the voter selected let myVote = await PollManager.methods.getVote(pollId, accounts[0]).call(); - assert.equal(myVote._ballot, Yes, "Vote is different from selected"); + const balance = await SNT.methods.balanceOf(accounts[0]).call(); + assert.equal(myVote, balance, "Vote is different from selected"); // =================================================== // Voting when you're not a SNT holder SHOULD FAIL! try { - receipt = await PollManager.methods.vote(pollId, Yes) + receipt = await PollManager.methods.vote(pollId) .send({from: accounts[8]}); assert.fail('should have reverted before'); } catch(error) { @@ -147,21 +123,21 @@ describe("VotingDapp", function () { // =================================================== // Getting proposal information poll = await PollManager.methods.poll(pollId).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 quadraticVotesByBallotYES = await pollContract.methods.qvResult(0).call(); // 0 == Yes (because it is the initial option ) + let tokenVotes = poll._results; + let quadraticVotes = poll._qvResults; + let voters = poll._voters; // Will contain state of the poll // console.dir(poll); - // Contains how many votes has a ballot - //console.log(tokenVotesByBallotYES); + // Contains how many voters + // console.log(voters); - // Contains how many votes has a ballot using quadratic voting - //console.log(quadraticVotesByBallotYES); + // Contains how many votes using quadratic voting + // console.log(quadraticVotes); - // Contains how many voters voted for that option - // console.log(votersByBallotYES); + // Contains how many votes + // console.log(tokenVotes); // =================================================== // Unvote