@@ -19,11 +19,12 @@ pragma solidity 0.7.3;
1919pragma experimental ABIEncoderV2;
2020
2121import "./../colonyNetwork/IColonyNetwork.sol " ;
22+ import "./../patriciaTree/PatriciaTreeProofs.sol " ;
2223import "./../tokenLocking/ITokenLocking.sol " ;
2324import "./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