From e07d9ce94a755c8056c8b39e3a71758e462e7634 Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Wed, 20 Jan 2021 18:47:39 -0800 Subject: [PATCH] Use totalInfluence to determine voting rewards --- contracts/extensions/VotingBase.sol | 11 +++++++---- contracts/extensions/VotingReputation.sol | 14 ++++++++++++++ contracts/extensions/VotingToken.sol | 13 +++++++++++++ test/extensions/voting-rep.js | 9 ++++++--- test/extensions/voting-token.js | 2 +- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/contracts/extensions/VotingBase.sol b/contracts/extensions/VotingBase.sol index e2b7b99f4d..9527c4e629 100644 --- a/contracts/extensions/VotingBase.sol +++ b/contracts/extensions/VotingBase.sol @@ -203,6 +203,8 @@ abstract contract VotingBase is ColonyExtension, PatriciaTreeProofs { function getInfluence(uint256 _motionId, address _user) public view virtual returns (uint256); + function getTotalInfluence(uint256 _motionId) public view virtual returns (uint256); + function postReveal(uint256 _motionId, address _user) internal virtual; function postClaim(uint256 _motionId, address _user) internal virtual; @@ -588,13 +590,14 @@ abstract contract VotingBase is ColonyExtension, PatriciaTreeProofs { /// @notice Get the voter reward /// @param _motionId The id of the motion - /// @param _voterRep The reputation the voter has in the domain + /// @param _voterInfluence The influence the voter has in the domain /// @return The voter reward - function getVoterReward(uint256 _motionId, uint256 _voterRep) public view returns (uint256) { + function getVoterReward(uint256 _motionId, uint256 _voterInfluence) public view returns (uint256) { Motion storage motion = motions[_motionId]; - uint256 fractionUserReputation = wdiv(_voterRep, motion.maxVotes); + uint256 totalInfluence = getTotalInfluence(_motionId); + uint256 fractionUserInfluence = wdiv(_voterInfluence, totalInfluence); uint256 totalStake = add(motion.stakes[YAY], motion.stakes[NAY]); - return wmul(wmul(fractionUserReputation, totalStake), voterRewardFraction); + return wmul(wmul(fractionUserInfluence, totalStake), voterRewardFraction); } /// @notice Get the staker reward diff --git a/contracts/extensions/VotingReputation.sol b/contracts/extensions/VotingReputation.sol index ac647c29bc..cdc0553d90 100644 --- a/contracts/extensions/VotingReputation.sol +++ b/contracts/extensions/VotingReputation.sol @@ -36,6 +36,8 @@ contract VotingReputation is VotingBase { // [rootHash][skillId][user] => reputationBalance mapping (bytes32 => mapping (uint256 => mapping (address => uint256))) influences; + // [rootHash][skillId] => reputationBalance + mapping (bytes32 => mapping (uint256 => uint256)) totalInfluences; // Public @@ -53,15 +55,27 @@ contract VotingReputation is VotingBase { ) public { Motion storage motion = motions[_motionId]; uint256 userRep = getReputationFromProof(_motionId, msg.sender, _key, _value, _branchMask, _siblings); + + if (influences[motion.rootHash][motion.skillId][msg.sender] == 0) { + totalInfluences[motion.rootHash][motion.skillId] = add(totalInfluences[motion.rootHash][motion.skillId], userRep); + } + influences[motion.rootHash][motion.skillId][msg.sender] = userRep; } /// @param _motionId The id of the motion + /// @param _user The user in question function getInfluence(uint256 _motionId, address _user) public view override returns (uint256) { Motion storage motion = motions[_motionId]; return influences[motion.rootHash][motion.skillId][_user]; } + /// @param _motionId The id of the motion + function getTotalInfluence(uint256 _motionId) public view override returns (uint256) { + Motion storage motion = motions[_motionId]; + return totalInfluences[motion.rootHash][motion.skillId]; + } + function postReveal(uint256 _motionId, address _user) internal override {} function postClaim(uint256 _motionId, address _user) internal override {} diff --git a/contracts/extensions/VotingToken.sol b/contracts/extensions/VotingToken.sol index 63eeacfca5..39bf05b977 100644 --- a/contracts/extensions/VotingToken.sol +++ b/contracts/extensions/VotingToken.sol @@ -37,6 +37,8 @@ contract VotingToken is VotingBase { // [motionId][user] => tokenBalance mapping (uint256 => mapping (address => uint256)) influences; + // [motionId] => tokenBalance + mapping (uint256 => uint256) totalInfluences; // [motionId] => lockId mapping (uint256 => uint256) locks; @@ -51,14 +53,25 @@ contract VotingToken is VotingBase { ); uint256 balance = tokenLocking.getUserLock(token, msg.sender).balance; + + if (influences[_motionId][msg.sender] == 0) { + totalInfluences[_motionId] = add(totalInfluences[_motionId], balance); + } + influences[_motionId][msg.sender] = balance; } /// @param _motionId The id of the motion + /// @param _user The user in question function getInfluence(uint256 _motionId, address _user) public view override returns (uint256) { return influences[_motionId][_user]; } + /// @param _motionId The id of the motion + function getTotalInfluence(uint256 _motionId) public view override returns (uint256) { + return totalInfluences[_motionId]; + } + function postReveal(uint256 _motionId, address _user) internal override { colony.unlockTokenForUser(_user, locks[_motionId]); } diff --git a/test/extensions/voting-rep.js b/test/extensions/voting-rep.js index 1f5ddd2e8e..c869543136 100644 --- a/test/extensions/voting-rep.js +++ b/test/extensions/voting-rep.js @@ -1361,7 +1361,8 @@ contract("Voting Reputation", (accounts) => { const user0LockPost = await tokenLocking.getUserLock(token.address, USER0); const user1LockPost = await tokenLocking.getUserLock(token.address, USER1); - const loserStake = REQUIRED_STAKE.divn(10).muln(8); // Take out voter comp + const motion = await voting.getMotion(motionId); + const loserStake = REQUIRED_STAKE.sub(new BN(motion.paidVoterComp)); const expectedReward0 = loserStake.divn(3).muln(2); // (stake * .8) * (winPct = 1/3 * 2) const expectedReward1 = REQUIRED_STAKE.add(loserStake.divn(3)); // stake + ((stake * .8) * (1 - (winPct = 2/3 * 2)) @@ -1410,7 +1411,8 @@ contract("Voting Reputation", (accounts) => { const user1LockPost = await tokenLocking.getUserLock(token.address, USER1); const user2LockPost = await tokenLocking.getUserLock(token.address, USER2); - const loserStake = REQUIRED_STAKE.divn(10).muln(8); // Take out voter comp + const motion = await voting.getMotion(motionId); + const loserStake = REQUIRED_STAKE.sub(new BN(motion.paidVoterComp)); const expectedReward0 = loserStake.divn(3).muln(2); // (stake * .8) * (winPct = 1/3 * 2) const expectedReward1 = REQUIRED_STAKE.add(loserStake.divn(3)).divn(3).muln(2); // stake + ((stake * .8) * (1 - (winPct = 2/3 * 2)) const expectedReward2 = REQUIRED_STAKE.add(loserStake.divn(3)).divn(3); // stake + ((stake * .8) * (1 - (winPct = 2/3 * 2)) @@ -1453,7 +1455,8 @@ contract("Voting Reputation", (accounts) => { const user1LockPost = await tokenLocking.getUserLock(token.address, USER1); const user2LockPost = await tokenLocking.getUserLock(token.address, USER2); - const loserStake = REQUIRED_STAKE.divn(10).muln(8); // Take out voter comp + const motion = await voting.getMotion(motionId); + const loserStake = REQUIRED_STAKE.sub(new BN(motion.paidVoterComp)); const expectedReward0 = loserStake.divn(3).muln(2).divn(3).muln(2); // (stake * .8) * (winPct = 1/3 * 2) const expectedReward1 = REQUIRED_STAKE.add(loserStake.divn(3)); // stake + ((stake * .8) * (1 - (winPct = 2/3 * 2)) const expectedReward2 = loserStake.divn(3).muln(2).divn(3); // (stake * .8) * (winPct = 1/3 * 2) diff --git a/test/extensions/voting-token.js b/test/extensions/voting-token.js index 00af4f5395..09c89d5124 100644 --- a/test/extensions/voting-token.js +++ b/test/extensions/voting-token.js @@ -1152,7 +1152,7 @@ contract("Voting Token", (accounts) => { const motion = await voting.getMotion(motionId); const loserStake = requiredStake.sub(new BN(motion.paidVoterComp)); const expectedReward0 = loserStake.divn(3).muln(2).addn(1); // (stake * .8) * (winPct = 1/3 * 2) + dust - const expectedReward1 = requiredStake.add(loserStake.divn(3)); // stake + ((stake * .8) * (1 - (winPct = 2/3 * 2)) + const expectedReward1 = requiredStake.add(loserStake.divn(3)).addn(1); // stake + ((stake * .8) * (1 - (winPct = 2/3 * 2)) + dust expect(new BN(user0LockPost.balance).sub(new BN(user0LockPre.balance))).to.eq.BN(expectedReward0); expect(new BN(user1LockPost.balance).sub(new BN(user1LockPre.balance))).to.eq.BN(expectedReward1);