Skip to content

Commit 593483a

Browse files
committed
Redesign VotingHybrid to have single lifecycle WIP
1 parent 69bdf98 commit 593483a

File tree

7 files changed

+1316
-359
lines changed

7 files changed

+1316
-359
lines changed

contracts/extensions/VotingBase.sol

Lines changed: 95 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ pragma solidity 0.7.3;
1919
pragma experimental ABIEncoderV2;
2020

2121
import "./../colonyNetwork/IColonyNetwork.sol";
22+
import "./../patriciaTree/PatriciaTreeProofs.sol";
2223
import "./../tokenLocking/ITokenLocking.sol";
2324
import "./ColonyExtension.sol";
2425

2526

26-
abstract contract VotingBase is ColonyExtension {
27+
abstract contract VotingBase is ColonyExtension, PatriciaTreeProofs {
2728

2829
// Events
2930
event MotionCreated(uint256 indexed motionId, address creator, uint256 indexed domainId);
@@ -172,17 +173,22 @@ abstract contract VotingBase is ColonyExtension {
172173
// Data structures
173174
enum MotionState { Null, Staking, Submit, Reveal, Closed, Finalizable, Finalized, Failed }
174175

176+
struct Influence {
177+
uint256 reputation;
178+
uint256 token;
179+
}
180+
175181
struct Motion {
176182
uint64[3] events; // For recording motion lifecycle timestamps (STAKE, SUBMIT, REVEAL)
177183
bytes32 rootHash;
178184
uint256 domainId;
179185
uint256 skillId;
180-
uint256 maxVotes;
181-
uint256 totalVotes;
182186
uint256 paidVoterComp;
183187
uint256[2] pastVoterComp; // [nay, yay]
184188
uint256[2] stakes; // [nay, yay]
185-
uint256[2] votes; // [nay, yay]
189+
Influence[2] votes; // [nay, yay]
190+
Influence totalVotes;
191+
Influence maxVotes;
186192
bool escalated;
187193
bool finalized;
188194
address altTarget;
@@ -200,9 +206,9 @@ abstract contract VotingBase is ColonyExtension {
200206

201207
// Virtual functions
202208

203-
function getInfluence(uint256 _motionId, address _user) public view virtual returns (uint256);
209+
function getInfluence(uint256 _motionId, address _user) public view virtual returns (Influence memory);
204210

205-
function getTotalInfluence(uint256 _motionId) public view virtual returns (uint256);
211+
function getTotalInfluence(uint256 _motionId) public view virtual returns (Influence memory);
206212

207213
function postReveal(uint256 _motionId, address _user) internal virtual;
208214

@@ -219,8 +225,9 @@ abstract contract VotingBase is ColonyExtension {
219225
require(getMotionState(_motionId) == MotionState.Reveal, "voting-base-motion-not-reveal");
220226
require(_vote <= 1, "voting-base-bad-vote");
221227

222-
uint256 influence = getInfluence(_motionId, msg.sender);
223-
motion.votes[_vote] = add(motion.votes[_vote], influence);
228+
Influence memory influence = getInfluence(_motionId, msg.sender);
229+
motion.votes[_vote].reputation = add(motion.votes[_vote].reputation, influence.reputation);
230+
motion.votes[_vote].token = add(motion.votes[_vote].token, influence.token);
224231

225232
bytes32 voteSecret = voteSecrets[_motionId][msg.sender];
226233
require(voteSecret == getVoteSecret(_salt, _vote), "voting-base-secret-no-match");
@@ -232,7 +239,10 @@ abstract contract VotingBase is ColonyExtension {
232239
emit MotionVoteRevealed(_motionId, msg.sender, _vote);
233240

234241
// See if reputation revealed matches reputation submitted
235-
if (add(motion.votes[NAY], motion.votes[YAY]) == motion.totalVotes) {
242+
if (
243+
add(motion.votes[NAY].reputation, motion.votes[YAY].reputation) == motion.totalVotes.reputation &&
244+
add(motion.votes[NAY].token, motion.votes[YAY].token) == motion.totalVotes.token
245+
) {
236246
motion.events[REVEAL_END] = uint64(block.timestamp);
237247

238248
emit MotionEventSet(_motionId, REVEAL_END);
@@ -249,14 +259,20 @@ abstract contract VotingBase is ColonyExtension {
249259

250260
assert(
251261
motion.stakes[YAY] == getRequiredStake(_motionId) ||
252-
add(motion.votes[NAY], motion.votes[YAY]) > 0
262+
add(
263+
add(motion.votes[NAY].reputation, motion.votes[YAY].reputation),
264+
add(motion.votes[NAY].token, motion.votes[YAY].token)
265+
) > 0
253266
);
254267

255268
motion.finalized = true;
256269

257270
bool canExecute = (
258271
motion.stakes[NAY] < motion.stakes[YAY] ||
259-
motion.votes[NAY] < motion.votes[YAY]
272+
(
273+
motion.votes[NAY].reputation <= motion.votes[YAY].reputation &&
274+
motion.votes[NAY].token <= motion.votes[YAY].token
275+
)
260276
);
261277

262278
if (getSig(motion.action) == CHANGE_FUNCTION && motion.altTarget == address(0x0)) {
@@ -271,8 +287,10 @@ abstract contract VotingBase is ColonyExtension {
271287
}
272288

273289
bytes32 actionHash = hashExpenditureAction(motion.action);
274-
uint256 votePower = (add(motion.votes[NAY], motion.votes[YAY]) > 0) ?
275-
motion.votes[YAY] : motion.stakes[YAY];
290+
uint256 votePower = (add(
291+
add(motion.votes[NAY].reputation, motion.votes[YAY].reputation),
292+
add(motion.votes[NAY].token, motion.votes[YAY].token)
293+
) > 0) ? add(motion.votes[YAY].reputation, motion.votes[YAY].token) : motion.stakes[YAY];
276294

277295
if (expenditurePastVotes[actionHash] < votePower) {
278296
expenditurePastVotes[actionHash] = votePower;
@@ -449,8 +467,8 @@ abstract contract VotingBase is ColonyExtension {
449467
// If not, did the YAY side stake?
450468
} else if (motion.stakes[YAY] == requiredStake) {
451469
return MotionState.Finalizable;
452-
// If not, was there a prior vote we can fall back on?
453-
} else if (add(motion.votes[NAY], motion.votes[YAY]) > 0) {
470+
// If not, was there a prior (reputation) vote we can fall back on?
471+
} else if (add(motion.votes[NAY].reputation, motion.votes[YAY].reputation) > 0) {
454472
return MotionState.Finalizable;
455473
// Otherwise, the motion failed
456474
} else {
@@ -478,12 +496,17 @@ abstract contract VotingBase is ColonyExtension {
478496

479497
/// @notice Get the voter reward
480498
/// @param _motionId The id of the motion
481-
/// @param _voterInfluence The influence the voter has in the domain
499+
/// @param _influence The influence the voter has in the domain
482500
/// @return The voter reward
483-
function getVoterReward(uint256 _motionId, uint256 _voterInfluence) public view returns (uint256) {
501+
function getVoterReward(uint256 _motionId, Influence memory _influence) public view returns (uint256) {
484502
Motion storage motion = motions[_motionId];
485-
uint256 totalInfluence = getTotalInfluence(_motionId);
486-
uint256 fractionUserInfluence = wdiv(_voterInfluence, totalInfluence);
503+
Influence memory totalInfluence = getTotalInfluence(_motionId);
504+
505+
uint256 fractionUserInfluence = wdiv(
506+
add(_influence.reputation, _influence.token),
507+
add(totalInfluence.reputation, totalInfluence.token)
508+
);
509+
487510
uint256 totalStake = add(motion.stakes[YAY], motion.stakes[NAY]);
488511
return wmul(wmul(fractionUserInfluence, totalStake), voterRewardFraction);
489512
}
@@ -508,11 +531,14 @@ abstract contract VotingBase is ColonyExtension {
508531
uint256 repPenalty;
509532

510533
// Went to a vote, use vote to determine reward or penalty
511-
if (add(motion.votes[NAY], motion.votes[YAY]) > 0) {
534+
if (add(
535+
add(motion.votes[NAY].reputation, motion.votes[YAY].reputation),
536+
add(motion.votes[NAY].token, motion.votes[YAY].token)
537+
) > 0) {
512538

513539
uint256 loserStake = sub(requiredStake, motion.paidVoterComp);
514-
uint256 totalVotes = add(motion.votes[NAY], motion.votes[YAY]);
515-
uint256 winFraction = wdiv(motion.votes[_vote], totalVotes);
540+
uint256 totalVotes = add(add(motion.votes[NAY].reputation, motion.votes[YAY].reputation), add(motion.votes[NAY].token, motion.votes[YAY].token));
541+
uint256 winFraction = wdiv(add(motion.votes[_vote].reputation, motion.votes[_vote].token), totalVotes);
516542
uint256 winShare = wmul(winFraction, 2 * WAD); // On a scale of 0-2 WAD
517543

518544
if (winShare > WAD || (winShare == WAD && _vote == NAY)) {
@@ -612,9 +638,10 @@ abstract contract VotingBase is ColonyExtension {
612638
require(amount > 0, "voting-base-bad-amount");
613639

614640
uint256 stakerTotalAmount = add(stakes[_motionId][msg.sender][_vote], amount);
641+
Influence memory influence = getInfluence(_motionId, msg.sender);
615642

616643
require(
617-
stakerTotalAmount <= getInfluence(_motionId, msg.sender),
644+
stakerTotalAmount <= max(influence.reputation, influence.token),
618645
"voting-base-insufficient-influence"
619646
);
620647
require(
@@ -682,18 +709,25 @@ abstract contract VotingBase is ColonyExtension {
682709
require(getMotionState(_motionId) == MotionState.Submit, "voting-base-motion-not-open");
683710
require(_voteSecret != bytes32(0), "voting-base-invalid-secret");
684711

685-
uint256 influence = getInfluence(_motionId, msg.sender);
712+
Influence memory influence = getInfluence(_motionId, msg.sender);
686713

687714
// Count reputation if first submission
688715
if (voteSecrets[_motionId][msg.sender] == bytes32(0)) {
689-
motion.totalVotes = add(motion.totalVotes, influence);
716+
motion.totalVotes.reputation = add(motion.totalVotes.reputation, influence.reputation);
717+
motion.totalVotes.token = add(motion.totalVotes.token, influence.token);
690718
}
691719

692720
voteSecrets[_motionId][msg.sender] = _voteSecret;
693721

694722
emit MotionVoteSubmitted(_motionId, msg.sender);
695723

696-
if (motion.totalVotes >= wmul(motion.maxVotes, maxVoteFraction)) {
724+
if ((
725+
motion.totalVotes.reputation == 0 ||
726+
motion.totalVotes.reputation >= wmul(motion.maxVotes.reputation, maxVoteFraction)
727+
) && (
728+
motion.totalVotes.token == 0 ||
729+
motion.totalVotes.token >= wmul(motion.maxVotes.token, maxVoteFraction)
730+
)) {
697731
motion.events[SUBMIT_END] = uint64(block.timestamp);
698732
motion.events[REVEAL_END] = uint64(block.timestamp + revealPeriod);
699733

@@ -706,7 +740,8 @@ abstract contract VotingBase is ColonyExtension {
706740
}
707741

708742
function getRequiredStake(uint256 _motionId) public view returns (uint256) {
709-
return wmul(motions[_motionId].maxVotes, totalStakeFraction);
743+
Motion storage motion = motions[_motionId];
744+
return wmul(add(motion.maxVotes.reputation, motion.maxVotes.token), totalStakeFraction);
710745
}
711746

712747
function flip(uint256 _vote) internal pure returns (uint256) {
@@ -858,4 +893,37 @@ abstract contract VotingBase is ColonyExtension {
858893

859894
}
860895
}
896+
897+
function getReputationFromProof(
898+
uint256 _motionId,
899+
address _who,
900+
bytes memory _key,
901+
bytes memory _value,
902+
uint256 _branchMask,
903+
bytes32[] memory _siblings
904+
)
905+
internal view returns (uint256)
906+
{
907+
bytes32 impliedRoot = getImpliedRootHashKey(_key, _value, _branchMask, _siblings);
908+
require(motions[_motionId].rootHash == impliedRoot, "voting-base-invalid-root-hash");
909+
910+
uint256 reputationValue;
911+
address keyColonyAddress;
912+
uint256 keySkill;
913+
address keyUserAddress;
914+
915+
assembly {
916+
reputationValue := mload(add(_value, 32))
917+
keyColonyAddress := mload(add(_key, 20))
918+
keySkill := mload(add(_key, 52))
919+
keyUserAddress := mload(add(_key, 72))
920+
}
921+
922+
require(keyColonyAddress == address(colony), "voting-base-invalid-colony-address");
923+
require(keySkill == motions[_motionId].skillId, "voting-base-invalid-skill-id");
924+
require(keyUserAddress == _who, "voting-base-invalid-user-address");
925+
926+
return reputationValue;
927+
}
928+
861929
}

0 commit comments

Comments
 (0)