-
Notifications
You must be signed in to change notification settings - Fork 152
Voting module #329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Voting module #329
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
5976c9a
copy files over based on dev 1.5.0
comeonbuddy 627a4e3
debugging test
comeonbuddy 865af7a
new test file from scratch
comeonbuddy e7c04b2
factory debug
comeonbuddy df02a68
rebased branch on dev 1.5.0 and rewrite a new test
comeonbuddy d2f048b
finished refacting module / added new function to allow active/deacti…
comeonbuddy 5c0c3ba
update test file name
comeonbuddy 019ad67
Merge branch 'development-1.5.0' into voting-module-oct
adamdossa 3f4f6db
fixed pull comments
comeonbuddy 60d2514
Merge branch 'voting-module-oct' of https://github.com/PolymathNetwor…
comeonbuddy b94c068
fixed pull request comments
comeonbuddy 22dab87
Merge branch 'development-1.5.0' into voting-module-oct
comeonbuddy 14acb4e
fixed permission manager test causing fail
comeonbuddy 72fe74a
Merge branch 'development-1.5.0' into voting-module-oct
comeonbuddy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
141 changes: 141 additions & 0 deletions
141
contracts/modules/Checkpoint/WeightedVoteCheckpoint.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
pragma solidity ^0.4.24; | ||
|
||
import "./ICheckpoint.sol"; | ||
import "../Module.sol"; | ||
import "openzeppelin-solidity/contracts/math/SafeMath.sol"; | ||
|
||
/** | ||
* @title Checkpoint module for token weighted vote | ||
* @notice This voting system uses public votes | ||
*/ | ||
contract WeightedVoteCheckpoint is ICheckpoint, Module { | ||
using SafeMath for uint256; | ||
|
||
struct Ballot { | ||
uint256 checkpointId; | ||
uint256 totalSupply; | ||
uint256 startTime; | ||
uint256 endTime; | ||
uint256 cumulativeYes; | ||
uint256 cumulativeNo; | ||
uint256 numVotes; | ||
mapping(address => Vote) voteByAddress; | ||
bool isActive; | ||
} | ||
|
||
Ballot[] public ballots; | ||
|
||
struct Vote { | ||
uint256 time; | ||
uint256 weight; | ||
bool vote; | ||
} | ||
|
||
event BallotCreated(uint256 _startTime, uint256 _endTime, uint256 _ballotId, uint256 _checkpointId); | ||
event VoteCasted(uint256 _ballotId, uint256 _time, address indexed _investor, uint256 _weight, bool _vote); | ||
event BallotActiveStatsChanged(uint256 _ballotId, bool _isActive); | ||
|
||
/** | ||
* @notice Constructor | ||
* @param _securityToken Address of the security token | ||
* @param _polyAddress Address of the polytoken | ||
*/ | ||
constructor(address _securityToken, address _polyAddress) public Module(_securityToken, _polyAddress) { | ||
|
||
} | ||
|
||
/** | ||
* @notice Queries the result of a given ballot | ||
* @param _ballotId Id of the target ballot | ||
* @return uint256 cummulativeYes | ||
* @return uint256 cummulativeNo | ||
* @return uint256 totalAbstain | ||
* @return uint256 remainingTime | ||
*/ | ||
function getResults(uint256 _ballotId) public view returns (uint256 cummulativeYes, uint256 cummulativeNo, uint256 totalAbstain, uint256 remainingTime) { | ||
uint256 abstain = (ballots[_ballotId].totalSupply.sub(ballots[_ballotId].cumulativeYes)).sub(ballots[_ballotId].cumulativeNo); | ||
uint256 time = (ballots[_ballotId].endTime > now) ? ballots[_ballotId].endTime.sub(now) : 0; | ||
return (ballots[_ballotId].cumulativeYes, ballots[_ballotId].cumulativeNo, abstain, time); | ||
} | ||
|
||
/** | ||
* @notice Allows a token holder to cast their vote on a specific ballot | ||
* @param _vote The vote (true/false) in favor or against the proposal | ||
* @param _ballotId The index of the target ballot | ||
* @return bool success | ||
*/ | ||
function castVote(bool _vote, uint256 _ballotId) public returns (bool) { | ||
require(now > ballots[_ballotId].startTime && now < ballots[_ballotId].endTime, "Voting period is not active."); | ||
require(ballots[_ballotId].voteByAddress[msg.sender].time == 0, "Token holder has already voted."); | ||
require(ballots[_ballotId].isActive == true, "This ballot is deactiveated."); | ||
uint256 checkpointId = ballots[_ballotId].checkpointId; | ||
uint256 weight = ISecurityToken(securityToken).balanceOfAt(msg.sender,checkpointId); | ||
require(weight > 0, "Token Holder balance is zero."); | ||
ballots[_ballotId].voteByAddress[msg.sender].time = now; | ||
ballots[_ballotId].voteByAddress[msg.sender].weight = weight; | ||
ballots[_ballotId].voteByAddress[msg.sender].vote = _vote; | ||
ballots[_ballotId].numVotes = ballots[_ballotId].numVotes.add(1); | ||
if (_vote == true) { | ||
ballots[_ballotId].cumulativeYes = ballots[_ballotId].cumulativeYes.add(weight); | ||
} else { | ||
ballots[_ballotId].cumulativeNo = ballots[_ballotId].cumulativeNo.add(weight); | ||
} | ||
emit VoteCasted(_ballotId, now, msg.sender, weight, _vote); | ||
return true; | ||
} | ||
|
||
/** | ||
* @notice Allows the token issuer to create a ballot | ||
* @param _duration The duration of the voting period in seconds | ||
* @return bool success | ||
*/ | ||
function createBallot(uint256 _duration) public onlyOwner { | ||
require(_duration > 0, "Incorrect ballot duration."); | ||
uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); | ||
uint256 endTime = now.add(_duration); | ||
createCustomBallot(now, endTime, checkpointId); | ||
} | ||
|
||
/** | ||
* @notice Allows the token issuer to create a ballot with custom settings | ||
* @param _startTime Start time of the voting period in Unix Epoch time | ||
* @param _endTime End time of the voting period in Unix Epoch time | ||
* @param _checkpointId Index of the checkpoint to use for token balances | ||
* @return bool success | ||
*/ | ||
function createCustomBallot(uint256 _startTime, uint256 _endTime, uint256 _checkpointId) public onlyOwner { | ||
require(_endTime > _startTime, "Ballot end time must be later than start time."); | ||
uint256 ballotId = ballots.length; | ||
uint256 supplyAtCheckpoint = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); | ||
ballots.push(Ballot(_checkpointId,supplyAtCheckpoint,_startTime,_endTime,0,0,0, true)); | ||
emit BallotCreated(_startTime, _endTime, ballotId, _checkpointId); | ||
} | ||
|
||
/** | ||
* @notice Allows the token issuer to set the active stats of a ballot | ||
* @param _ballotId The index of the target ballot | ||
* @param _isActive The bool value of the active stats of the ballot | ||
* @return bool success | ||
*/ | ||
function setActiveStatsBallot(uint256 _ballotId, bool _isActive) public onlyOwner { | ||
require(now < ballots[_ballotId].endTime, "This ballot has already ended."); | ||
require(ballots[_ballotId].isActive != _isActive, "Active state unchanged"); | ||
ballots[_ballotId].isActive = _isActive; | ||
emit BallotActiveStatsChanged(_ballotId, _isActive); | ||
} | ||
|
||
|
||
function getInitFunction() public returns(bytes4) { | ||
return bytes4(0); | ||
} | ||
|
||
/** | ||
* @notice Return the permissions flag that are associated with STO | ||
* @return bytes32 array | ||
*/ | ||
function getPermissions() public view returns(bytes32[]) { | ||
bytes32[] memory allPermissions = new bytes32[](0); | ||
return allPermissions; | ||
} | ||
|
||
} |
98 changes: 98 additions & 0 deletions
98
contracts/modules/Checkpoint/WeightedVoteCheckpointFactory.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
pragma solidity ^0.4.24; | ||
|
||
import "./WeightedVoteCheckpoint.sol"; | ||
import "../ModuleFactory.sol"; | ||
|
||
/** | ||
* @title Factory for deploying WeightedVoteCheckpoint module | ||
*/ | ||
contract WeightedVoteCheckpointFactory is ModuleFactory { | ||
|
||
/** | ||
* @notice Constructor | ||
* @param _polyAddress Address of the polytoken | ||
* @param _setupCost Setup cost of the module | ||
* @param _usageCost Usage cost of the module | ||
* @param _subscriptionCost Subscription cost of the module | ||
*/ | ||
constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public | ||
ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) | ||
{ | ||
version = "1.0.0"; | ||
name = "WeightedVoteCheckpoint"; | ||
title = "Weighted Vote Checkpoint"; | ||
description = "Weighted votes based on token amount"; | ||
compatibleSTVersionRange["lowerBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); | ||
compatibleSTVersionRange["upperBound"] = VersionUtils.pack(uint8(0), uint8(0), uint8(0)); | ||
|
||
} | ||
|
||
/** | ||
* @notice used to launch the Module with the help of factory | ||
* @return address Contract address of the Module | ||
*/ | ||
function deploy(bytes /* _data */) external returns(address) { | ||
if (setupCost > 0) | ||
require(polyToken.transferFrom(msg.sender, owner, setupCost), "Failed transferFrom because of sufficent Allowance is not provided"); | ||
return address(new WeightedVoteCheckpoint(msg.sender, address(polyToken))); | ||
} | ||
|
||
/** | ||
* @notice Type of the Module factory | ||
*/ | ||
function getTypes() external view returns(uint8[]) { | ||
uint8[] memory res = new uint8[](1); | ||
res[0] = 4; | ||
return res; | ||
} | ||
|
||
/** | ||
* @notice Get the name of the Module | ||
*/ | ||
function getName() public view returns(bytes32) { | ||
return name; | ||
} | ||
|
||
/** | ||
* @notice Get the description of the Module | ||
*/ | ||
function getDescription() external view returns(string) { | ||
return description; | ||
} | ||
|
||
/** | ||
* @notice Get the title of the Module | ||
*/ | ||
function getTitle() external view returns(string) { | ||
return title; | ||
} | ||
|
||
/** | ||
* @notice Get the version of the Module | ||
*/ | ||
function getVersion() external view returns(string) { | ||
return version; | ||
} | ||
|
||
/** | ||
* @notice Get the setup cost of the module | ||
*/ | ||
function getSetupCost() external view returns (uint256) { | ||
return setupCost; | ||
} | ||
|
||
/** | ||
* @notice Get the Instructions that helped to used the module | ||
*/ | ||
function getInstructions() external view returns(string) { | ||
return "Create a vote which allows token holders to vote on an issue with a weight proportional to their balances at the point the vote is created."; | ||
} | ||
|
||
/** | ||
* @notice Get the tags related to the module factory | ||
*/ | ||
function getTags() external view returns(bytes32[]) { | ||
bytes32[] memory availableTags = new bytes32[](0); | ||
return availableTags; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.