Skip to content

Commit

Permalink
Improve StdDaoToken - startVoting/endVoting through the DaoBase #210
Browse files Browse the repository at this point in the history
  • Loading branch information
RostyslavBortman committed Jul 24, 2018
1 parent bc885c3 commit 33fb78e
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 89 deletions.
2 changes: 2 additions & 0 deletions contracts/governance/IVoting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ contract IVoting {
// Can get this stats if voting is NOT finished.
function getVotingStats() public view returns(uint yesResults, uint noResults, uint totalResults);

function setStdDaoTokenVotingID(uint _stdDaoTokenVotingID) public;

// Is voting finished?
//
// 1 - First we check if minutesToVote!=0 and time elapsed
Expand Down
25 changes: 16 additions & 9 deletions contracts/governance/Voting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ contract Voting is IVoting, Ownable {
event CallAction();
event DelegatedTo(address _sender, uint _tokensAmount);
event DelegationRemoved(address _from, address _to);
uint private yesResults;
uint private noResults;
uint private votersTotal;

/*
* @param _dao – DAO where proposal was created.
Expand All @@ -40,12 +43,10 @@ contract Voting is IVoting, Ownable {
}

function setStdDaoTokenVotingID(uint _stdDaoTokenVotingID) public onlyOwner {
if(VotingType.Voting1p1v!=store.votingType){
store.votingID = _stdDaoTokenVotingID;
}
store.votingID = _stdDaoTokenVotingID;
vote(true);
}


function quorumPercent()view returns(uint){
return store.quorumPercent;
}
Expand All @@ -68,9 +69,12 @@ contract Voting is IVoting, Ownable {

function vote(bool _isYes) public{
store.libVote(msg.sender, _isYes);
if(store.isFinished()){
StdDaoToken(store.tokenAddress).finishVoting(store.votingID);
}
}

function finishVoting() public {
require (isFinished());

StdDaoToken(store.tokenAddress).finishVoting(store.votingID);
}

function callActionIfEnded() public {
Expand All @@ -85,7 +89,7 @@ contract Voting is IVoting, Ownable {
return store.isYes();
}

function getVotingStats() public constant returns(uint yesResults, uint noResults, uint votersTotal){
function getVotingStats() public constant returns(uint _yesResults, uint _noResults, uint _votersTotal){
return store.getVotingStats();
}

Expand Down Expand Up @@ -176,7 +180,10 @@ library VotingLib {
store.genesis = now;
store.tokenAddress = _tokenAddress;

libVote(store, _origin, true);
if(VotingType.Voting1p1v==store.votingType){
libVote(store, _origin, true);
}

}

function getNow() public view returns(uint){
Expand Down
2 changes: 1 addition & 1 deletion contracts/tokens/ITokenVotingSupport.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pragma solidity ^0.4.22;
*/
interface ITokenVotingSupport {
// can throw if 20 votings are already started
function startNewVoting() external returns(uint);
function startNewVoting(address _voting) external returns(uint);

function finishVoting(uint _votingID) external;

Expand Down
17 changes: 15 additions & 2 deletions contracts/tokens/StdDaoToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import "zeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol";

import "./CopyOnWriteToken.sol";
import "./ITokenVotingSupport.sol";
import "../DaoBase.sol";

/**
* @title StdDaoToken
Expand All @@ -25,17 +24,25 @@ import "../DaoBase.sol";
* finishVoting()
* getBalanceAtVoting()
*/
contract StdDaoToken is DetailedERC20, PausableToken, CopyOnWriteToken, DaoBase, ITokenVotingSupport {
contract StdDaoToken is DetailedERC20, PausableToken, CopyOnWriteToken, ITokenVotingSupport {
uint256 public cap;
bool isBurnable;
bool isPausable;

address[] public holders;
mapping (address => bool) isHolder;
mapping (uint => address) votingCreated;
mapping (bytes32 => mapping(address => bool)) permissions;

bytes32 public TOKEN_StartNewVoting = keccak256(abi.encodePacked("TOKEN_StartNewVoting"));
bytes32 public allow_actions = keccak256(abi.encodePacked("allow_actions"));
bytes32 public disallow_actions = keccak256(abi.encodePacked("disallow_actions"));

modifier isCanDo(bytes32 _permissionID) {
require (permissions[_permissionID][msg.sender]);
_;
}

modifier isBurnable_() {
require (isBurnable);
_;
Expand All @@ -56,10 +63,16 @@ contract StdDaoToken is DetailedERC20, PausableToken, CopyOnWriteToken, DaoBase,
cap = _cap;
isBurnable = _isBurnable;
isPausable = _isPausable;
permissions[allow_actions][msg.sender] = true;
permissions[TOKEN_StartNewVoting][msg.sender] = true;

holders.push(this);
}

function allowActionByAddress(address _who, bytes32 _action) public isCanDo(allow_actions) {
permissions[_action][_who] = true;
}

// ITokenVotingSupport implementation
// TODO: VULNERABILITY! no onlyOwner!
function startNewVoting(address _voting) public whenNotPaused isCanDo(TOKEN_StartNewVoting) returns(uint) {
Expand Down
13 changes: 7 additions & 6 deletions contracts/utils/GenericCaller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,19 +114,20 @@ contract GenericCaller is DaoClient, Ownable {

function createVoting(bytes32 _permissionIdHash, IProposal _proposal, address _origin)public returns(IVoting){
VotingParams memory vp = votingParams[_permissionIdHash];
StdDaoToken memory token = StdDaoToken(address(vp.param5));
StdDaoToken token = StdDaoToken(address(vp.param5));

IVoting V = new Voting(dao, _proposal, _origin, vp.votingType,
uint(vp.param1),
bytes32ToString(vp.param2),
uint(vp.param3),
uint(vp.param4),
address(vp.param5),
stdDaoTokenVotingID
address(vp.param5)
);

uint stdDaoTokenVotingID = token.startNewVoting(V.address);
V.setStdDaoTokenVotingID(stdDaoTokenVotingID);

if(vp.votingType != VotingLib.VotingType.Voting1p1v){
uint stdDaoTokenVotingID = token.startNewVoting(address(V));
V.setStdDaoTokenVotingID(stdDaoTokenVotingID);
}

return V;
}
Expand Down
3 changes: 2 additions & 1 deletion test/governance/voting_1p1v.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,9 @@ contract('Voting 1P1V', (accounts) => {
var isY = await voting.isYes();
assert.strictEqual(fin,true,'Voting should be finished: 4/6 voted');
assert.strictEqual(isY,true,'Voting is finished: 4/6 voted, all said yes');
await daoBase.removeGroupMember("Employees", employee3, {from:creator});

await daoBase.removeGroupMember("Employees", employee3, {from:creator});

// WARNING:
// if voting is finished -> even if we remove some employees from the group
// the voting results should not be changed!!!
Expand Down
43 changes: 42 additions & 1 deletion test/governance/voting_liquid.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ contract('Voting liquid', (accounts) => {

let r2;
let token;
let voting;
let daoBase;

beforeEach(async() => {
token = await StdDaoToken.new("StdToken","STDT",18, true, true, 1000000000);

await token.mintFor(creator, 1);
await token.mintFor(employee1, 1);
await token.mintFor(employee2, 2);
Expand All @@ -52,13 +52,24 @@ contract('Voting liquid', (accounts) => {
describe('getPowerOf()', function () {
it('Check getPower()',async() => {
const voting = await Voting.new(daoBase.address, creator, creator, VOTING_TYPE_LIQUID, 0, '', 100, 100, token.address);

const tx = await token.startNewVoting(voting.address);
const events = tx.logs.filter(l => l.event == 'VotingStarted');
const votingID = events.filter(e => e.args._address == creator)[0].args._votingID;
await voting.setStdDaoTokenVotingID(votingID);

r2 = await voting.getPowerOf(creator);
assert.equal(r2.toNumber(),1,'yes');
});

it('Check getPower() when voice delegated',async() => {
const voting = await Voting.new(daoBase.address, creator, creator, VOTING_TYPE_LIQUID, 0, '', 100, 100, token.address);

const tx = await token.startNewVoting(voting.address);
const events = tx.logs.filter(l => l.event == 'VotingStarted');
const votingID = events.filter(e => e.args._address == creator)[0].args._votingID;
await voting.setStdDaoTokenVotingID(votingID);

await voting.delegateMyVoiceTo(employee1, 1);

r2 = await voting.getPowerOf(creator);
Expand All @@ -72,6 +83,11 @@ contract('Voting liquid', (accounts) => {
it('Check getPower() when voice delegated and delegation removed',async() => {
const voting = await Voting.new(daoBase.address, creator, creator, VOTING_TYPE_LIQUID, 0, '', 100, 100, token.address);

const tx = await token.startNewVoting(voting.address);
const events = tx.logs.filter(l => l.event == 'VotingStarted');
const votingID = events.filter(e => e.args._address == creator)[0].args._votingID;
await voting.setStdDaoTokenVotingID(votingID);

await voting.delegateMyVoiceTo(employee1, 1);

r2 = await voting.getPowerOf(creator);
Expand All @@ -96,6 +112,11 @@ contract('Voting liquid', (accounts) => {
it('Check getDelegatedPowerOf()',async() => {
const voting = await Voting.new(daoBase.address, creator, creator, VOTING_TYPE_LIQUID, 0, '', 100, 100, token.address);

const tx = await token.startNewVoting(voting.address);
const events = tx.logs.filter(l => l.event == 'VotingStarted');
const votingID = events.filter(e => e.args._address == creator)[0].args._votingID;
await voting.setStdDaoTokenVotingID(votingID);

r2 = await voting.getDelegatedPowerOf(creator);
assert.equal(r2.toNumber(),0,'yes');

Expand All @@ -114,6 +135,11 @@ contract('Voting liquid', (accounts) => {
it('Check getDelegatedPowerByMe()',async() => {
const voting = await Voting.new(daoBase.address, creator, creator, VOTING_TYPE_LIQUID, 0, '', 100, 100, token.address);

const tx = await token.startNewVoting(voting.address);
const events = tx.logs.filter(l => l.event == 'VotingStarted');
const votingID = events.filter(e => e.args._address == creator)[0].args._votingID;
await voting.setStdDaoTokenVotingID(votingID);

r2 = await voting.getDelegatedPowerByMe(creator);
assert.equal(r2.toNumber(),0,'yes');

Expand All @@ -132,6 +158,11 @@ contract('Voting liquid', (accounts) => {
it('Should delegate from A to B',async() => {
const voting = await Voting.new(daoBase.address, creator, creator, VOTING_TYPE_LIQUID, 0, '', 100, 100, token.address);

const tx = await token.startNewVoting(voting.address);
const events = tx.logs.filter(l => l.event == 'VotingStarted');
const votingID = events.filter(e => e.args._address == creator)[0].args._votingID;
await voting.setStdDaoTokenVotingID(votingID);

r2 = await voting.getDelegatedPowerOf(creator);
assert.equal(r2.toNumber(),0);

Expand All @@ -144,6 +175,11 @@ contract('Voting liquid', (accounts) => {
it('Should delegate from A to B then from A to B again with the same amount',async() => {
const voting = await Voting.new(daoBase.address, creator, creator, VOTING_TYPE_LIQUID, 0, '', 100, 100, token.address);

const tx = await token.startNewVoting(voting.address);
const events = tx.logs.filter(l => l.event == 'VotingStarted');
const votingID = events.filter(e => e.args._address == creator)[0].args._votingID;
await voting.setStdDaoTokenVotingID(votingID);

r2 = await voting.getDelegatedPowerOf(creator);
assert.equal(r2.toNumber(),0);

Expand All @@ -163,6 +199,11 @@ contract('Voting liquid', (accounts) => {
it('Check removeDelegation()',async() => {
const voting = await Voting.new(daoBase.address, creator, creator, VOTING_TYPE_LIQUID, 0, '', 100, 100, token.address);

const tx = await token.startNewVoting(voting.address);
const events = tx.logs.filter(l => l.event == 'VotingStarted');
const votingID = events.filter(e => e.args._address == creator)[0].args._votingID;
await voting.setStdDaoTokenVotingID(votingID);

r2 = await voting.getDelegatedPowerOf(creator);
assert.equal(r2.toNumber(),0);

Expand Down
Loading

0 comments on commit 33fb78e

Please sign in to comment.