Skip to content
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

Fix PLCR Proposal inconsistency #713

Merged
merged 5 commits into from
Jun 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions contracts/mocks/SecurityTokenRegistryMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,13 @@ contract SecurityTokenRegistryMock is SecurityTokenRegistry {
/// @notice It is a dummy function
/// Alert! Alert! Do NOT use it for the mainnet release

modifier onlyOwnerOrSelf() {
require(msg.sender == owner() || msg.sender == address(this), "Only owner or self");
_;
}

uint256 public someValue;
function changeTheDeployedAddress(string memory _ticker, address _newSecurityTokenAddress) public {
set(Encoder.getKey("tickerToSecurityToken", _ticker), _newSecurityTokenAddress);

function changeTheFee(uint256 _newFee) public {
set(STLAUNCHFEE, _newFee);
}

function configure(uint256 _someValue) public onlyOwnerOrSelf {
function configure(uint256 _someValue) public {
someValue = _someValue;
}

Expand Down
83 changes: 50 additions & 33 deletions contracts/modules/Checkpoint/Voting/PLCR/PLCRVotingCheckpoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
uint256 _commitDuration,
uint256 _revealDuration,
uint256 _noOfProposals,
uint256 _proposedQuorum
uint256 _quorumPercentage
);
event BallotStatusChanged(uint256 indexed _ballotId, bool _newStatus);
event ChangedBallotExemptedVotersList(uint256 indexed _ballotId, address indexed _voter, bool _exempt);
Expand All @@ -41,85 +41,85 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
* @param _commitDuration Unix time period till the voters commit there vote
* @param _revealDuration Unix time period till the voters reveal there vote starts when commit duration ends
* @param _noOfProposals Total number of proposal used in the ballot. In general it is 2 (For & Against)
* @param _proposedQuorum Minimum number of weight vote requires to win a election.
* @param _quorumPercentage Minimum number of weight vote percentage requires to win a election.
*/
function createBallot(
uint256 _commitDuration,
uint256 _revealDuration,
uint256 _noOfProposals,
uint256 _proposedQuorum
)
uint256 _quorumPercentage
)
external
withPerm(ADMIN)
{
uint256 startTime = now;
uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint();
_createBallotWithCheckpoint(_commitDuration, _revealDuration, _noOfProposals, _proposedQuorum, checkpointId, startTime);
_createBallotWithCheckpoint(_commitDuration, _revealDuration, _noOfProposals, _quorumPercentage, checkpointId, startTime);
}

/**
* @notice Use to create the ballot
* @param _commitDuration Unix time period till the voters commit there vote
* @param _revealDuration Unix time period till the voters reveal there vote starts when commit duration ends
* @param _noOfProposals Total number of proposal used in the ballot. In general it is 2 (For & Against)
* @param _proposedQuorum Minimum number of weight vote requires to win a election.
* @param _quorumPercentage Minimum number of weight vote percentage requires to win a election.
* @param _checkpointId Valid checkpoint Id
* @param _startTime startTime of the ballot
*/
function createCustomBallot(
uint256 _commitDuration,
uint256 _revealDuration,
uint256 _noOfProposals,
uint256 _proposedQuorum,
uint256 _quorumPercentage,
uint256 _checkpointId,
uint256 _startTime
)
external
withPerm(ADMIN)
{
// validate the checkpointId, It should be less than or equal to the current checkpointId of the securityToken
require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId(), "Invalid checkpoint Id");
_createBallotWithCheckpoint(_commitDuration, _revealDuration, _noOfProposals, _proposedQuorum, _checkpointId, _startTime);
_createBallotWithCheckpoint(_commitDuration, _revealDuration, _noOfProposals, _quorumPercentage, _checkpointId, _startTime);
}

function _createBallotWithCheckpoint(
uint256 _commitDuration,
uint256 _revealDuration,
uint256 _totalProposals,
uint256 _proposedQuorum,
uint256 _noOfProposals,
uint256 _quorumPercentage,
uint256 _checkpointId,
uint256 _startTime
)
internal
{
// Sanity checks
_validValueCheck(_commitDuration);
_validValueCheck(_revealDuration);
_validValueCheck(_proposedQuorum);
require(_proposedQuorum <= 100 * 10 ** 16, "Invalid quorum percentage"); // not more than 100 %
_isGreaterThanZero(_commitDuration);
_isGreaterThanZero(_revealDuration);
_isGreaterThanZero(_quorumPercentage);
require(_quorumPercentage <= 100 * 10 ** 16, "Invalid quorum percentage"); // not more than 100 %
// Overflow check
require(
uint64(_commitDuration) == _commitDuration &&
uint64(_revealDuration) == _revealDuration &&
uint64(_startTime) == _startTime &&
uint24(_totalProposals) == _totalProposals,
uint24(_noOfProposals) == _noOfProposals,
"Parameter values get overflowed"
);
require(_startTime >= now, "Invalid start time");
// Total no of proposals always greater than 2 it means minimum valid
// proposal id will be 0 or 1. Proposal Id should be start from 0 instead of 1.
require(_totalProposals > 1, "Invalid number of totalProposals");
// Valid proposal Id range should be 1 to `_noOfProposals`.
require(_noOfProposals > 1, "Invalid number of proposals");
uint256 _ballotId = ballots.length;
ballots.push(Ballot(
_checkpointId,
_proposedQuorum,
_quorumPercentage,
uint64(_commitDuration),
uint64(_revealDuration),
uint64(_startTime),
uint24(_totalProposals),
uint24(_noOfProposals),
uint32(0),
true
));
emit BallotCreated(_ballotId, _checkpointId, _startTime, _commitDuration, _revealDuration, _totalProposals, _proposedQuorum);
emit BallotCreated(_ballotId, _checkpointId, _startTime, _commitDuration, _revealDuration, _noOfProposals, _quorumPercentage);
}

/**
Expand All @@ -128,40 +128,51 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
* @param _secretVote It is secret hash value (hashed offchain)
*/
function commitVote(uint256 _ballotId, bytes32 _secretVote) external {
_validBallotId(_ballotId);
// Check for the ballots array out of bound
_checkIndexOutOfBound(_ballotId);
require(_secretVote != bytes32(0), "Invalid vote");
// Check for the valid stage. Whether that ballot is in the COMMIT state or not.
_checkValidStage(_ballotId, Stage.COMMIT);
// Check whether the msg.sender is allowed to vote for a given ballotId or not.
require(isVoterAllowed(_ballotId, msg.sender), "Invalid voter");
require(getCurrentBallotStage(_ballotId) == Stage.COMMIT, "Not in commit stage");
// validate the storage values
Ballot storage ballot = ballots[_ballotId];
require(ballot.investorToProposal[msg.sender].secretVote == bytes32(0), "Already voted");
require(_secretVote != bytes32(0), "Invalid vote");
require(ballot.isActive, "Inactive ballot");
// Get the balance of the voter (i.e `msg.sender`) at the checkpoint on which ballot was created.
uint256 weight = ISecurityToken(securityToken).balanceOfAt(msg.sender, ballot.checkpointId);
require(weight > 0, "Zero weight is not allowed");
// Update the storage value. Assigned `0` as vote option it will be updated when voter reveals its vote.
ballot.investorToProposal[msg.sender] = Vote(0, _secretVote);
emit VoteCommit(msg.sender, weight, _ballotId, _secretVote);
}

/**
* @notice Used to reveal the vote
* @param _ballotId Given ballot Id
* @param _choiceOfProposal Proposal chossed by the voter. It varies from (0 to totalProposals - 1)
* @param _choiceOfProposal Proposal chossed by the voter. It varies from (1 to totalProposals)
* @param _salt used salt for hashing (unique for each user)
*/
function revealVote(uint256 _ballotId, uint256 _choiceOfProposal, uint256 _salt) external {
_validBallotId(_ballotId);
require(getCurrentBallotStage(_ballotId) == Stage.REVEAL, "Not in reveal stage");
// Check for the ballots array out of bound
_checkIndexOutOfBound(_ballotId);
// Check for the valid stage. Whether that ballot is in the REVEAL state or not.
_checkValidStage(_ballotId, Stage.REVEAL);
Ballot storage ballot = ballots[_ballotId];
// validate the storage values
require(ballot.isActive, "Inactive ballot");
require(ballot.investorToProposal[msg.sender].secretVote != bytes32(0), "Secret vote not available");
require(_choiceOfProposal < ballot.totalProposals && _choiceOfProposal >= 1, "Invalid proposal choice");
require(ballot.totalProposals >= _choiceOfProposal && _choiceOfProposal > 0, "Invalid proposal choice");

// validate the secret vote
require(
bytes32(keccak256(abi.encodePacked(_choiceOfProposal, _salt))) == ballot.investorToProposal[msg.sender].secretVote,
"Invalid vote"
);
// Get the balance of the voter (i.e `msg.sender`) at the checkpoint on which ballot was created.
uint256 weight = ISecurityToken(securityToken).balanceOfAt(msg.sender, ballot.checkpointId);
bytes32 secretVote = ballot.investorToProposal[msg.sender].secretVote;
// update the storage values
ballot.proposalToVotes[_choiceOfProposal] = ballot.proposalToVotes[_choiceOfProposal].add(weight);
ballot.totalVoters = ballot.totalVoters + 1;
ballot.investorToProposal[msg.sender] = Vote(_choiceOfProposal, bytes32(0));
Expand Down Expand Up @@ -192,8 +203,9 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
}

function _changeBallotExemptedVotersList(uint256 _ballotId, address _voter, bool _exempt) internal {
// Check for the ballots array out of bound
_checkIndexOutOfBound(_ballotId);
require(_voter != address(0), "Invalid address");
_validBallotId(_ballotId);
require(ballots[_ballotId].exemptedVoters[_voter] != _exempt, "No change");
ballots[_ballotId].exemptedVoters[_voter] = _exempt;
emit ChangedBallotExemptedVotersList(_ballotId, _voter, _exempt);
Expand All @@ -216,7 +228,8 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
* @param _isActive The bool value of the active stats of the ballot
*/
function changeBallotStatus(uint256 _ballotId, bool _isActive) external withPerm(ADMIN) {
_validBallotId(_ballotId);
// Check for the ballots array out of bound
_checkIndexOutOfBound(_ballotId);
require(
now <= uint256(ballots[_ballotId].startTime)
.add(uint256(ballots[_ballotId].commitDuration)
Expand All @@ -239,7 +252,7 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {

if (now < ballot.startTime)
return Stage.PREP;
else if (now <= commitTimeEnd && now >= ballot.startTime)
else if (now >= ballot.startTime && now <= commitTimeEnd)
return Stage.COMMIT;
else if ( now > commitTimeEnd && now <= revealTimeEnd)
return Stage.REVEAL;
Expand Down Expand Up @@ -367,12 +380,16 @@ contract PLCRVotingCheckpoint is PLCRVotingCheckpointStorage, VotingCheckpoint {
return allPermissions;
}

function _validValueCheck(uint256 _value) internal pure {
function _isGreaterThanZero(uint256 _value) internal pure {
require(_value > 0, "Invalid value");
}

function _validBallotId(uint256 _ballotId) internal view {
function _checkIndexOutOfBound(uint256 _ballotId) internal view {
require(ballots.length > _ballotId, "Index out of bound");
}

function _checkValidStage(uint256 _ballotId, Stage _stage) internal view {
require(getCurrentBallotStage(_ballotId) == _stage, "Not in a valid stage");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ contract WeightedVoteCheckpoint is WeightedVoteCheckpointStorage, VotingCheckpoi
uint256 _startTime,
uint256 _endTime,
uint256 _noOfProposals,
uint256 _proposedQuorum
uint256 _quorumPercentage
);
event VoteCast(address indexed _voter, uint256 _weight, uint256 indexed _ballotId, uint256 indexed _proposalId);
event BallotStatusChanged(uint256 indexed _ballotId, bool _isActive);
Expand Down Expand Up @@ -48,18 +48,18 @@ contract WeightedVoteCheckpoint is WeightedVoteCheckpointStorage, VotingCheckpoi
* @notice Allows the token issuer to create a ballot
* @param _duration The duration of the voting period in seconds
* @param _noOfProposals Number of proposals
* @param _proposedQuorum Minimum Quorum percentage required to make a proposal won
* @param _quorumPercentage Minimum Quorum percentage required to make a proposal won
*/
function createBallot(uint256 _duration, uint256 _noOfProposals, uint256 _proposedQuorum) external withPerm(ADMIN) {
function createBallot(uint256 _duration, uint256 _noOfProposals, uint256 _quorumPercentage) external withPerm(ADMIN) {
require(_duration > 0, "Incorrect ballot duration");
uint256 checkpointId = securityToken.createCheckpoint();
uint256 endTime = now.add(_duration);
_createCustomBallot(checkpointId, _proposedQuorum, now, endTime, _noOfProposals);
_createCustomBallot(checkpointId, _quorumPercentage, now, endTime, _noOfProposals);
}

function _createCustomBallot(
uint256 _checkpointId,
uint256 _proposedQuorum,
uint256 _quorumPercentage,
uint256 _startTime,
uint256 _endTime,
uint256 _noOfProposals
Expand All @@ -68,7 +68,7 @@ contract WeightedVoteCheckpoint is WeightedVoteCheckpointStorage, VotingCheckpoi
{
require(_noOfProposals > 1, "Incorrect proposals no");
require(_endTime > _startTime, "Times are not valid");
require(_proposedQuorum <= 100 * 10 ** 16 && _proposedQuorum > 0, "Invalid quorum percentage"); // not more than 100 %
require(_quorumPercentage <= 100 * 10 ** 16 && _quorumPercentage > 0, "Invalid quorum percentage"); // not more than 100 %
require(
uint64(_startTime) == _startTime &&
uint64(_endTime) == _endTime &&
Expand All @@ -78,24 +78,24 @@ contract WeightedVoteCheckpoint is WeightedVoteCheckpointStorage, VotingCheckpoi
uint256 ballotId = ballots.length;
ballots.push(
Ballot(
_checkpointId, _proposedQuorum, uint64(_startTime), uint64(_endTime), uint64(_noOfProposals), uint56(0), true
_checkpointId, _quorumPercentage, uint64(_startTime), uint64(_endTime), uint64(_noOfProposals), uint56(0), true
)
);
emit BallotCreated(ballotId, _checkpointId, _startTime, _endTime, _noOfProposals, _proposedQuorum);
emit BallotCreated(ballotId, _checkpointId, _startTime, _endTime, _noOfProposals, _quorumPercentage);
}

/**
* @notice Allows the token issuer to create a ballot with custom settings
* @param _checkpointId Index of the checkpoint to use for token balances
* @param _proposedQuorum Minimum Quorum percentage required to make a proposal won
* @param _quorumPercentage Minimum Quorum percentage required to make a proposal won
* @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 _noOfProposals Number of proposals
*/
function createCustomBallot(uint256 _checkpointId, uint256 _proposedQuorum, uint256 _startTime, uint256 _endTime, uint256 _noOfProposals) external withPerm(ADMIN) {
function createCustomBallot(uint256 _checkpointId, uint256 _quorumPercentage, uint256 _startTime, uint256 _endTime, uint256 _noOfProposals) external withPerm(ADMIN) {
require(_checkpointId <= securityToken.currentCheckpointId(), "Invalid checkpoint Id");
require(_startTime >= now, "Invalid startTime");
_createCustomBallot(_checkpointId, _proposedQuorum, _startTime, _endTime, _noOfProposals);
_createCustomBallot(_checkpointId, _quorumPercentage, _startTime, _endTime, _noOfProposals);
}

/**
Expand All @@ -104,16 +104,20 @@ contract WeightedVoteCheckpoint is WeightedVoteCheckpointStorage, VotingCheckpoi
* @param _proposalId Id of the proposal which investor want to vote for proposal
*/
function castVote(uint256 _ballotId, uint256 _proposalId) external {
_validBallotId(_ballotId);
Ballot storage ballot = ballots[_ballotId];
// Check for the ballots array out of bound
_checkIndexOutOfBound(_ballotId);
// Check whether the msg.sender is allowed to vote for a given ballotId or not.
require(isVoterAllowed(_ballotId, msg.sender), "Invalid voter");
Ballot storage ballot = ballots[_ballotId];
// Get the balance of the voter (i.e `msg.sender`) at the checkpoint on which ballot was created.
uint256 weight = securityToken.balanceOfAt(msg.sender, ballot.checkpointId);
require(weight > 0, "weight should be > 0");
// Validate the storage values
require(ballot.totalProposals >= _proposalId && _proposalId > 0, "Incorrect proposals Id");
require(now >= ballot.startTime && now <= ballot.endTime, "Voting period is not active");
require(ballot.investorToProposal[msg.sender] == 0, "Token holder has already voted");
require(ballot.isActive, "Ballot is not active");

// Update the storage
ballot.investorToProposal[msg.sender] = _proposalId;
ballot.totalVoters = ballot.totalVoters + 1;
ballot.proposalToVotes[_proposalId] = ballot.proposalToVotes[_proposalId].add(weight);
Expand Down Expand Up @@ -144,8 +148,9 @@ contract WeightedVoteCheckpoint is WeightedVoteCheckpointStorage, VotingCheckpoi
}

function _changeBallotExemptedVotersList(uint256 _ballotId, address _voter, bool _exempt) internal {
// Check for the ballots array out of bound
_checkIndexOutOfBound(_ballotId);
require(_voter != address(0), "Invalid address");
_validBallotId(_ballotId);
require(ballots[_ballotId].exemptedVoters[_voter] != _exempt, "No change");
ballots[_ballotId].exemptedVoters[_voter] = _exempt;
emit ChangedBallotExemptedVotersList(_ballotId, _voter, _exempt);
Expand Down Expand Up @@ -277,7 +282,7 @@ contract WeightedVoteCheckpoint is WeightedVoteCheckpointStorage, VotingCheckpoi
return allPermissions;
}

function _validBallotId(uint256 _ballotId) internal view {
function _checkIndexOutOfBound(uint256 _ballotId) internal view {
require(ballots.length > _ballotId, "Index out of bound");
}

Expand Down
8 changes: 5 additions & 3 deletions test/t_security_token_registry_proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,11 @@ contract("SecurityTokenRegistryProxy", async (accounts) => {
});

it("Should alter the old storage", async () => {
await I_STRProxied.changeTheDeployedAddress(symbol, account_temp, { from: account_polymath });
let _tokenAddress = await I_Getter.getSecurityTokenAddress.call(symbol);
assert.equal(_tokenAddress, account_temp, "Should match with the changed address");
await I_STRProxied.changeTheFee(0, { from: account_polymath });
let feesToken = await I_STRProxied.getFees.call("0xd677304bb45536bb7fdfa6b9e47a3c58fe413f9e8f01474b0a4b9c6e0275baf2");
console.log(feesToken);
// assert.equal(feesToken[0].toString(), origPriceUSD.toString());
// assert.equal(feesToken[1].toString(), origPricePOLY.toString());
});
});

Expand Down
Loading