diff --git a/packages/protocol/contracts/governance/LockedGold.sol b/packages/protocol/contracts/governance/LockedGold.sol index 6b2b5f223e..fd9390bc41 100755 --- a/packages/protocol/contracts/governance/LockedGold.sol +++ b/packages/protocol/contracts/governance/LockedGold.sol @@ -505,6 +505,9 @@ contract LockedGold is _decrementNonvotingAccountBalance(account, maxSlash.sub(difference)); _incrementNonvotingAccountBalance(reporter, reward); } + + _updateDelegatedAmount(account); + address communityFund = registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID); address payable communityFundPayable = address(uint160(communityFund)); require(maxSlash.sub(reward) <= address(this).balance, "Inconsistent balance"); diff --git a/packages/protocol/test-sol/unit/governance/voting/LockedGold.t.sol b/packages/protocol/test-sol/unit/governance/voting/LockedGold.t.sol index dfa4d45e99..d0a6cb8f57 100644 --- a/packages/protocol/test-sol/unit/governance/voting/LockedGold.t.sol +++ b/packages/protocol/test-sol/unit/governance/voting/LockedGold.t.sol @@ -38,6 +38,23 @@ contract LockedGoldTest is TestWithUtils { address caller = address(this); TestBlocker blocker; + address delegatee1 = actor("delegatee1"); + address delegatee2 = actor("delegatee2"); + address delegatee3 = actor("delegatee3"); + address delegator = actor("delegator"); + address delegator2 = actor("delegator2"); + address reporter = actor("reporter"); + string slasherName = "DowntimeSlasher"; + address downtimeSlasher = actor(slasherName); + address delegatorSigner; + uint256 delegatorSignerPK; + address delegatorSigner2; + uint256 delegatorSigner2PK; + address delegateeSigner1; + uint256 delegateeSigner1PK; + address delegateeSigner2; + uint256 delegateeSigner2PK; + event UnlockingPeriodSet(uint256 period); event GoldLocked(address indexed account, uint256 value); event GoldUnlocked(address indexed account, uint256 value, uint256 available); @@ -88,6 +105,13 @@ contract LockedGoldTest is TestWithUtils { blocker = new TestBlocker(); lockedGold.setBlockedByContract(address(blocker)); + + (delegatorSigner, delegatorSignerPK) = actorWithPK("delegatorSigner"); + (delegatorSigner2, delegatorSigner2PK) = actorWithPK("delegatorSigner2"); + (delegateeSigner1, delegateeSigner1PK) = actorWithPK("delegateeSigner1"); + (delegateeSigner2, delegateeSigner2PK) = actorWithPK("delegateeSigner2"); + vm.deal(delegator, 10 ether); + vm.deal(delegator2, 10 ether); } function getParsedSignatureOfAddress( @@ -211,6 +235,39 @@ contract LockedGoldTest is TestWithUtils { vm.prank(celoOwner); lockedGold.lock.value(value)(); } + + function whenVoteSigner_LockedGoldDelegateGovernanceVotes() public { + helper_WhenVoteSigners( + WhenVoteSignerStruct( + delegator, + delegator2, + delegatee1, + delegatee2, + delegatorSignerPK, + delegateeSigner1PK, + delegatorSigner2PK, + delegateeSigner2PK, + true + ) + ); + } + + function helper_WhenAccountIsSlashedForAllOfItsLockedGold( + uint256 penalty, + uint256 reward, + address accountToSlash + ) public { + address[] memory lessers = new address[](1); + lessers[0] = address(0); + address[] memory greaters = new address[](1); + greaters[0] = address(0); + + uint256[] memory indices = new uint256[](1); + indices[0] = 0; + + vm.prank(downtimeSlasher); + lockedGold.slash(accountToSlash, penalty, reporter, reward, lessers, greaters, indices); + } } contract LockedGoldTest_L2 is WhenL2, LockedGoldTest {} @@ -1094,12 +1151,9 @@ contract LockedGoldTest_removeSlasher is LockedGoldTest { contract LockedGoldTest_removeSlasher_L2 is LockedGoldTest_L2, LockedGoldTest_removeSlasher {} contract LockedGoldTest_slash is LockedGoldTest { - string slasherName = "DowntimeSlasher"; uint256 value = 1000; address group = actor("group"); address groupMember = actor("groupMember"); - address reporter = actor("reporter"); - address downtimeSlasher = actor(slasherName); address delegatee = actor("delegatee"); Election electionSlashTest; @@ -1131,22 +1185,17 @@ contract LockedGoldTest_slash is LockedGoldTest { vm.prank(reporter); accounts.createAccount(); - } - function helper_WhenAccountIsSlashedForAllOfItsLockedGold( - uint256 penalty, - uint256 reward - ) public { - address[] memory lessers = new address[](1); - lessers[0] = address(0); - address[] memory greaters = new address[](1); - greaters[0] = address(0); - - uint256[] memory indices = new uint256[](1); - indices[0] = 0; - - vm.prank(downtimeSlasher); - lockedGold.slash(caller, penalty, reporter, reward, lessers, greaters, indices); + vm.prank(delegatee1); + accounts.createAccount(); + vm.prank(delegatee2); + accounts.createAccount(); + vm.prank(delegatee3); + accounts.createAccount(); + vm.prank(delegator); + accounts.createAccount(); + vm.prank(delegator2); + accounts.createAccount(); } function test_Reverts_WhenBlocked() public { @@ -1154,7 +1203,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 reward = value / 2; blocker.mockSetBlocked(true); vm.expectRevert("Contract is blocked from performing this action"); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); } function test_ShouldReduceAccountsLockedGoldBalance_WhenAccountIsSlashedForAllOfItsLockedGold() @@ -1162,7 +1211,7 @@ contract LockedGoldTest_slash is LockedGoldTest { { uint256 penalty = value; uint256 reward = value / 2; - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(caller), value - penalty); assertEq(lockedGold.getAccountTotalLockedGold(caller), value - penalty); @@ -1173,7 +1222,7 @@ contract LockedGoldTest_slash is LockedGoldTest { { uint256 penalty = value; uint256 reward = value / 2; - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(reporter), reward); assertEq(lockedGold.getAccountTotalLockedGold(reporter), reward); @@ -1184,7 +1233,7 @@ contract LockedGoldTest_slash is LockedGoldTest { { uint256 penalty = value; uint256 reward = value / 2; - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(address(governance).balance, penalty - reward); } @@ -1196,7 +1245,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 reward = value / 2; lockedGold.removeSlasher(slasherName, 0); vm.expectRevert("Caller is not a whitelisted slasher."); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); } function test_ShouldReduceAccountsNonVotingLockedGoldBalance_WhenAccountIsSlashedForOnlyItsNonvotingBalance_WhenTheAccountHasHalfVotingAndHalfNonVotingGold() @@ -1208,7 +1257,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(caller), nonVoting - penalty); } @@ -1220,7 +1269,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = nonVoting; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountTotalLockedGold(caller), value - penalty); assertEq(electionSlashTest.getTotalVotesByAccount(caller), voting); @@ -1234,7 +1283,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = nonVoting; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(reporter), reward); assertEq(lockedGold.getAccountTotalLockedGold(reporter), reward); @@ -1248,7 +1297,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = nonVoting; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(address(governance).balance, penalty - reward); } @@ -1261,7 +1310,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(caller), 0); } @@ -1272,7 +1321,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = value; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountTotalLockedGold(caller), 0); assertEq(electionSlashTest.getTotalVotesByAccount(caller), 0); @@ -1285,7 +1334,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = value; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(reporter), reward); assertEq(lockedGold.getAccountTotalLockedGold(reporter), reward); @@ -1298,7 +1347,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = value; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(address(governance).balance, penalty - reward); } @@ -1310,7 +1359,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = value * 2; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(caller), 0); assertEq(lockedGold.getAccountTotalLockedGold(caller), 0); @@ -1324,7 +1373,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = value * 2; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(reporter), reward); assertEq(lockedGold.getAccountTotalLockedGold(reporter), reward); @@ -1337,7 +1386,7 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 penalty = value * 2; uint256 reward = penalty / 2; electionSlashTest.vote(group, voting, address(0), address(0)); - helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, caller); assertEq(address(governance).balance, value - reward); } @@ -1366,30 +1415,32 @@ contract LockedGoldTest_slash is LockedGoldTest { uint256 reward = value / 2; - helper_WhenAccountIsSlashedForAllOfItsLockedGold(value, reward); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(value, reward, caller); assertEq(lockedGold.getAccountNonvotingLockedGold(reporter), reward); assertEq(lockedGold.getAccountTotalLockedGold(reporter), reward); } + + function test_ShouldReduceAccountsLockedGoldBalance_WhenAccountIsSlashedForAllOfItsLockedGoldAndIsDelegating() + public + { + uint256 penalty = value; + uint256 reward = value / 2; + whenVoteSigner_LockedGoldDelegateGovernanceVotes(); + vm.prank(delegator); + lockedGold.delegateGovernanceVotes(delegatee1, FixidityLib.newFixedFraction(30, 100).unwrap()); + assertEq(lockedGold.getAccountNonvotingLockedGold(delegator), 1000); + assertEq(lockedGold.getAccountTotalLockedGold(delegator), 1000); + assertEq(lockedGold.getAccountTotalGovernanceVotingPower(delegatee1), 300); + helper_WhenAccountIsSlashedForAllOfItsLockedGold(penalty, reward, delegator); + assertEq(lockedGold.getAccountNonvotingLockedGold(delegator), 0); + assertEq(lockedGold.getAccountTotalLockedGold(delegator), 0); + assertEq(lockedGold.getAccountTotalGovernanceVotingPower(delegatee1), 0); + } } contract LockedGoldTest_slash_L2 is LockedGoldTest_L2, LockedGoldTest_slash {} contract LockedGoldTest_delegateGovernanceVotes is LockedGoldTest { - address delegatee1 = actor("delegatee1"); - address delegatee2 = actor("delegatee2"); - address delegatee3 = actor("delegatee3"); - address delegator = actor("delegator"); - address delegator2 = actor("delegator2"); - - address delegatorSigner; - uint256 delegatorSignerPK; - address delegatorSigner2; - uint256 delegatorSigner2PK; - address delegateeSigner1; - uint256 delegateeSigner1PK; - address delegateeSigner2; - uint256 delegateeSigner2PK; - uint256 value = 1000; uint256 percentToDelegate = 30; uint256 delegatedAmount = (value * percentToDelegate) / 100; @@ -1424,22 +1475,6 @@ contract LockedGoldTest_delegateGovernanceVotes is LockedGoldTest { vm.deal(delegator2, 10 ether); } - function whenVoteSigner_LockedGoldDelegateGovernanceVotes() public { - helper_WhenVoteSigners( - WhenVoteSignerStruct( - delegator, - delegator2, - delegatee1, - delegatee2, - delegatorSignerPK, - delegateeSigner1PK, - delegatorSigner2PK, - delegateeSigner2PK, - true - ) - ); - } - function test_ShouldRevertWhenDelegateeIsNotAccount() public { vm.expectRevert("Must first register address with Account.createAccount"); lockedGold.delegateGovernanceVotes(randomAddress, FixidityLib.newFixedFraction(1, 1).unwrap()); @@ -1794,21 +1829,6 @@ contract LockedGoldTest_delegateGovernanceVotes_L2 is {} contract LockedGoldTest_revokeDelegatedGovernanceVotes is LockedGoldTest { - address delegatee1 = actor("delegatee1"); - address delegatee2 = actor("delegatee2"); - address delegatee3 = actor("delegatee3"); - address delegator = actor("delegator"); - address delegator2 = actor("delegator2"); - - address delegatorSigner; - uint256 delegatorSignerPK; - address delegatorSigner2; - uint256 delegatorSigner2PK; - address delegateeSigner1; - uint256 delegateeSigner1PK; - address delegateeSigner2; - uint256 delegateeSigner2PK; - uint256 value = 1000; uint256 percentageToRevoke = 2; uint256 percentageToDelegate = 10;