-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a57f682
commit 7cf2e2c
Showing
8 changed files
with
707 additions
and
3 deletions.
There are no files selected for viewing
This file contains 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,74 @@ | ||
/* | ||
This file is part of The Colony Network. | ||
The Colony Network 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. | ||
The Colony Network 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 The Colony Network. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
pragma solidity 0.5.8; | ||
pragma experimental ABIEncoderV2; | ||
|
||
import "../../lib/dappsys/math.sol"; | ||
import "../IColony.sol"; | ||
import "../IColonyNetwork.sol"; | ||
|
||
|
||
contract VotingBase is DSMath { | ||
|
||
// Constants | ||
uint256 constant REVEAL_PERIOD = 2 days; | ||
|
||
// Initialization data | ||
IColony colony; | ||
IColonyNetwork colonyNetwork; | ||
|
||
constructor(address _colony) public { | ||
colony = IColony(_colony); | ||
colonyNetwork = IColonyNetwork(colony.getColonyNetwork()); | ||
} | ||
|
||
// Data structures | ||
enum PollState { Open, Reveal, Closed } | ||
|
||
struct Poll { | ||
uint256 pollCloses; | ||
uint256[] voteCounts; | ||
} | ||
|
||
// Storage | ||
uint256 pollCount; | ||
mapping (uint256 => Poll) polls; | ||
|
||
// Functions | ||
function getPollCount() public view returns (uint256) { | ||
return pollCount; | ||
} | ||
|
||
function getPollInfo(uint256 _pollId) public view returns (Poll memory poll) { | ||
poll = polls[_pollId]; | ||
} | ||
|
||
function getPollState(uint256 _pollId) internal view returns (PollState) { | ||
if (now < polls[_pollId].pollCloses) { | ||
return PollState.Open; | ||
} else if (now < add(polls[_pollId].pollCloses, REVEAL_PERIOD)) { | ||
return PollState.Reveal; | ||
} else { | ||
return PollState.Closed; | ||
} | ||
} | ||
|
||
function getVoteSecret(bytes32 _salt, uint256 _vote) internal pure returns (bytes32) { | ||
return keccak256(abi.encodePacked(_salt, _vote)); | ||
} | ||
} |
This file contains 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,122 @@ | ||
/* | ||
This file is part of The Colony Network. | ||
The Colony Network 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. | ||
The Colony Network 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 The Colony Network. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
pragma solidity 0.5.8; | ||
pragma experimental ABIEncoderV2; | ||
|
||
import "../PatriciaTree/PatriciaTreeProofs.sol"; | ||
import "./VotingBase.sol"; | ||
|
||
|
||
contract VotingReputation is VotingBase, PatriciaTreeProofs { | ||
|
||
constructor(address _colony) public VotingBase(_colony) {} | ||
|
||
struct RepDatum { | ||
bytes32 rootHash; | ||
uint256 skillId; | ||
} | ||
|
||
mapping (uint256 => RepDatum) repData; | ||
|
||
// The UserVote type here is just the bytes32 voteSecret | ||
|
||
mapping (address => mapping (uint256 => bytes32)) userVotes; | ||
|
||
function createPoll(uint256 _numOutcomes, uint256 _duration, uint256 _skillId) public { | ||
pollCount += 1; | ||
|
||
polls[pollCount] = Poll({ | ||
pollCloses: add(now, _duration), | ||
voteCounts: new uint256[](_numOutcomes) | ||
}); | ||
|
||
repData[pollCount] = RepDatum({ | ||
rootHash: colonyNetwork.getReputationRootHash(), | ||
skillId: _skillId | ||
}); | ||
} | ||
|
||
function submitVote(uint256 _pollId, bytes32 _voteSecret) public { | ||
require(getPollState(_pollId) == PollState.Open, "colony-rep-voting-poll-not-open"); | ||
|
||
userVotes[msg.sender][_pollId] = _voteSecret; | ||
} | ||
|
||
function revealVote( | ||
uint256 _pollId, | ||
bytes32 _salt, | ||
uint256 _vote, | ||
bytes memory _key, | ||
bytes memory _value, | ||
uint256 _branchMask, | ||
bytes32[] memory _siblings | ||
) | ||
public | ||
{ | ||
uint256 pollCloses = polls[_pollId].pollCloses; | ||
require(getPollState(_pollId) != PollState.Open, "colony-rep-voting-poll-still-open"); | ||
|
||
bytes32 voteSecret = userVotes[msg.sender][_pollId]; | ||
require(voteSecret == getVoteSecret(_salt, _vote), "colony-rep-voting-secret-no-match"); | ||
require(_vote < polls[_pollId].voteCounts.length, "colony-rep-voting-invalid-vote"); | ||
|
||
// Validate proof and get reputation value | ||
uint256 userReputation = checkReputation(_pollId, _key, _value, _branchMask, _siblings); | ||
|
||
// Remove the secret | ||
delete userVotes[msg.sender][_pollId]; | ||
|
||
// Increment the vote if poll in reveal, otherwise skip | ||
// NOTE: since there's no locking, we could just `require` PollState.Reveal | ||
if (getPollState(_pollId) == PollState.Reveal) { | ||
polls[_pollId].voteCounts[_vote] += userReputation; | ||
} | ||
} | ||
|
||
function checkReputation( | ||
uint256 _pollId, | ||
bytes memory _key, | ||
bytes memory _value, | ||
uint256 _branchMask, | ||
bytes32[] memory _siblings | ||
) | ||
internal view returns (uint256) | ||
{ | ||
bytes32 impliedRoot = getImpliedRootHashKey(_key, _value, _branchMask, _siblings); | ||
require(repData[_pollId].rootHash == impliedRoot, "colony-rep-voting-invalid-root-hash"); | ||
|
||
uint256 reputationValue; | ||
address keyColonyAddress; | ||
uint256 keySkill; | ||
address keyUserAddress; | ||
|
||
assembly { | ||
reputationValue := mload(add(_value, 32)) | ||
keyColonyAddress := mload(add(_key, 20)) | ||
keySkill := mload(add(_key, 52)) | ||
keyUserAddress := mload(add(_key, 72)) | ||
} | ||
|
||
require(keyColonyAddress == address(colony), "colony-rep-voting-invalid-colony-address"); | ||
require(keySkill == repData[_pollId].skillId, "colony-rep-voting-invalid-skill-id"); | ||
require(keyUserAddress == msg.sender, "colony-rep-voting-invalid-user-address"); | ||
|
||
return reputationValue; | ||
} | ||
|
||
} |
This file contains 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,110 @@ | ||
/* | ||
This file is part of The Colony Network. | ||
The Colony Network 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. | ||
The Colony Network 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 The Colony Network. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
pragma solidity 0.5.8; | ||
pragma experimental ABIEncoderV2; | ||
|
||
import "../ITokenLocking.sol"; | ||
import "./VotingBase.sol"; | ||
|
||
|
||
contract VotingToken is VotingBase { | ||
|
||
constructor(address _colony) public VotingBase(_colony) {} | ||
|
||
struct UserVote { | ||
uint256 pollId; | ||
bytes32 voteSecret; | ||
uint256 prevPollCloses; | ||
uint256 nextPollCloses; | ||
} | ||
|
||
mapping (address => mapping (uint256 => UserVote)) userVotes; | ||
|
||
function createPoll(uint256 _numOutcomes, uint256 _duration) public { | ||
pollCount += 1; | ||
|
||
polls[pollCount] = Poll({ | ||
pollCloses: add(now, _duration), | ||
voteCounts: new uint256[](_numOutcomes) | ||
}); | ||
} | ||
|
||
// TODO: Implement inner linked list | ||
function submitVote(uint256 _pollId, bytes32 _voteSecret, uint256 _prevPollCloses) public { | ||
require(getPollState(_pollId) == PollState.Open, "colony-token-voting-poll-not-open"); | ||
|
||
UserVote storage prev = userVotes[msg.sender][_prevPollCloses]; | ||
UserVote storage next = userVotes[msg.sender][prev.nextPollCloses]; | ||
|
||
// Check we are inserting at the correct location | ||
uint256 pollCloses = polls[_pollId].pollCloses; | ||
require(pollCloses > _prevPollCloses, "colony-token-voting-insert-too-soon"); | ||
require(pollCloses < prev.nextPollCloses || prev.nextPollCloses == 0, "colony-token-voting-insert-too-late"); | ||
|
||
userVotes[msg.sender][pollCloses] = UserVote({ | ||
pollId: _pollId, | ||
voteSecret: _voteSecret, | ||
prevPollCloses: _prevPollCloses, | ||
nextPollCloses: prev.nextPollCloses | ||
}); | ||
|
||
prev.nextPollCloses = pollCloses; | ||
next.prevPollCloses = pollCloses; | ||
} | ||
|
||
function revealVote(uint256 _pollId, bytes32 _salt, uint256 _vote) public { | ||
require(getPollState(_pollId) != PollState.Open, "colony-token-voting-poll-still-open"); | ||
|
||
uint256 pollCloses = polls[_pollId].pollCloses; | ||
UserVote storage curr = userVotes[msg.sender][pollCloses]; | ||
UserVote storage prev = userVotes[msg.sender][curr.prevPollCloses]; | ||
UserVote storage next = userVotes[msg.sender][curr.nextPollCloses]; | ||
|
||
require(curr.voteSecret == getVoteSecret(_salt, _vote), "colony-token-voting-secret-no-match"); | ||
require(_vote < polls[_pollId].voteCounts.length, "colony-token-voting-invalid-vote"); | ||
|
||
// Remove the secret | ||
prev.nextPollCloses = curr.nextPollCloses; | ||
next.prevPollCloses = curr.prevPollCloses; | ||
delete userVotes[msg.sender][pollCloses]; | ||
|
||
// Increment the vote if poll in reveal | ||
if (getPollState(_pollId) == PollState.Reveal) { | ||
address token = colony.getToken(); | ||
address tokenLocking = colonyNetwork.getTokenLocking(); | ||
uint256 userBalance = ITokenLocking(tokenLocking).getUserLock(token, msg.sender).balance; | ||
polls[_pollId].voteCounts[_vote] += userBalance; | ||
} | ||
} | ||
|
||
function isAddressLocked(address _address) public view returns (bool) { | ||
uint256 nextPollCloses = userVotes[_address][0].nextPollCloses; | ||
if (nextPollCloses == 0) { | ||
// The list is empty, no unrevealed votes for this address | ||
return false; | ||
} else if (now < nextPollCloses) { | ||
// The poll is still open for voting and tokens transfer | ||
return false; | ||
} else { | ||
// The poll is closed for voting and is in the reveal period, during which all votes' tokens are locked until reveal | ||
// Note: even after the poll is resolved, tokens remain locked until reveal | ||
return true; | ||
} | ||
} | ||
|
||
} |
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.