Skip to content

Commit

Permalink
update delegation when slashing (#11287)
Browse files Browse the repository at this point in the history
* Update delegation when slashing

* tests fixed

* PR comments

* lint
  • Loading branch information
pahor167 authored Dec 4, 2024
1 parent 4591aa1 commit 6fde928
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 81 deletions.
3 changes: 3 additions & 0 deletions packages/protocol/contracts/governance/LockedGold.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
182 changes: 101 additions & 81 deletions packages/protocol/test-sol/unit/governance/voting/LockedGold.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 {}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1131,38 +1185,33 @@ 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 {
uint256 penalty = value;
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()
public
{
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);
Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -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()
Expand All @@ -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);
}

Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -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);
}

Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 6fde928

Please sign in to comment.