Skip to content

Commit

Permalink
feat: requestValidatorsExit()
Browse files Browse the repository at this point in the history
  • Loading branch information
0xvv committed Mar 27, 2023
1 parent 42761e7 commit 757f17d
Show file tree
Hide file tree
Showing 5 changed files with 6,734 additions and 4,607 deletions.
2 changes: 1 addition & 1 deletion lib/forge-std
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,4 @@
"docs": "hardhat compile && sol2uml ./src/contracts -o ./docs/components.svg",
"hh": "hardhat"
}

}
}
17 changes: 17 additions & 0 deletions src/contracts/StakingContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ contract StakingContract {
event DeactivatedOperator(uint256 _operatorIndex);
event ActivatedOperator(uint256 _operatorIndex);
event SetWithdrawerCustomizationStatus(bool _status);
event ExitRequest(address caller, bytes pubkey);

/// @notice Ensures an initialisation call has been called only once per _version value
/// @param _version The current initialisation value
Expand Down Expand Up @@ -570,6 +571,22 @@ contract StakingContract {
_deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());
}

function requestValidatorsExit(bytes calldata _publicKeys) external {
if (_publicKeys.length % PUBLIC_KEY_LENGTH != 0) {
revert InvalidPublicKeys();
}
uint256 keyCount = _publicKeys.length / PUBLIC_KEY_LENGTH;
bytes[] memory keys = new bytes[](keyCount);
for (uint256 i = 0; i < keyCount; i++) {
bytes memory publicKey = BytesLib.slice(_publicKeys, i * PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH);
address withdrawer = _getWithdrawer(_getPubKeyRoot(publicKey));
if (msg.sender != withdrawer) {
revert Unauthorized();
}
emit ExitRequest(withdrawer, publicKey);
}
}

/// ██ ███ ██ ████████ ███████ ██████ ███ ██ █████ ██
/// ██ ████ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██
/// ██ ██ ██ ██ ██ █████ ██████ ██ ██ ██ ███████ ██
Expand Down
75 changes: 72 additions & 3 deletions src/test/StakingContract.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity >=0.8.10;

import "forge-std/Vm.sol";
import "forge-std/Test.sol";
import "./UserFactory.sol";
import "../contracts/Treasury.sol";
import "../contracts/StakingContract.sol";
Expand Down Expand Up @@ -2834,9 +2835,7 @@ contract StakingContractOneValidatorTest is DSTestPlus {
}
}

contract StakingContractBehindProxyTest is DSTestPlus {
Vm internal vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);

contract StakingContractBehindProxyTest is Test {
Treasury internal treasury;
StakingContract internal stakingContract;
DepositContractMock internal depositContract;
Expand All @@ -2851,6 +2850,8 @@ contract StakingContractBehindProxyTest is DSTestPlus {
ConsensusLayerFeeDispatcher internal cld;
FeeRecipient internal feeRecipientImpl;

event ExitRequest(address caller, bytes pubkey);

function setUp() public {
uf = new UserFactory();
depositContract = new DepositContractMock();
Expand Down Expand Up @@ -3482,4 +3483,72 @@ contract StakingContractBehindProxyTest is DSTestPlus {
assert(address(treasury).balance == 0.16 ether);
*/
}

function testRequestValidatorsExits_OneValidator() public {
bytes
memory publicKey = hex"21d2e725aef3a8f9e09d8f4034948bb7f79505fc7c40e7a7ca15734bad4220a594bf0c6257cef7db88d9fc3fd4360759";
vm.deal(bob, 32 ether);
vm.startPrank(bob);
stakingContract.deposit{value: 32 ether}();
assert(stakingContract.getWithdrawer(publicKey) == bob);
vm.stopPrank();
vm.expectEmit(true, true, true, true);
emit ExitRequest(bob, publicKey);
vm.prank(bob);
stakingContract.requestValidatorsExit(publicKey);
}

function testRequestValidatorsExits_TwoValidators() public {
bytes
memory publicKey = hex"21d2e725aef3a8f9e09d8f4034948bb7f79505fc7c40e7a7ca15734bad4220a594bf0c6257cef7db88d9fc3fd4360759";
vm.deal(bob, 32 ether);
vm.startPrank(bob);
stakingContract.deposit{value: 32 ether}();
assert(stakingContract.getWithdrawer(publicKey) == bob);
vm.stopPrank();
bytes
memory publicKey2 = hex"b0ce3fa164aae897adca509ed44429e7b1f91b7c46ddbe199cee848e09b1ccbb9736b78b68aacff1011b7266fe11e060";
vm.deal(bob, 32 ether);
vm.startPrank(bob);
stakingContract.deposit{value: 32 ether}();
assert(stakingContract.getWithdrawer(publicKey2) == bob);
vm.stopPrank();

bytes memory publicKeys = BytesLib.concat(publicKey, publicKey2);

vm.expectEmit(true, true, true, true);
emit ExitRequest(bob, publicKey);
vm.expectEmit(true, true, true, true);
emit ExitRequest(bob, publicKey2);
vm.prank(bob);
stakingContract.requestValidatorsExit(publicKeys);
}

function testRequestValidatorsExits_WrongWithdrawer() public {
bytes
memory publicKey = hex"21d2e725aef3a8f9e09d8f4034948bb7f79505fc7c40e7a7ca15734bad4220a594bf0c6257cef7db88d9fc3fd4360759";
vm.deal(bob, 32 ether);
vm.startPrank(bob);
stakingContract.deposit{value: 32 ether}();
assert(stakingContract.getWithdrawer(publicKey) == bob);
vm.stopPrank();
vm.expectRevert(abi.encodeWithSignature("Unauthorized()"));
vm.prank(address(1337));
stakingContract.requestValidatorsExit(publicKey);
}

function testRequestValidatorsExits_WrongPublicKeys() public {
bytes
memory publicKey = hex"21d2e725aef3a8f9e09d8f4034948bb7f79505fc7c40e7a7ca15734bad4220a594bf0c6257cef7db88d9fc3fd4360759";
vm.deal(bob, 32 ether);
vm.startPrank(bob);
stakingContract.deposit{value: 32 ether}();
assert(stakingContract.getWithdrawer(publicKey) == bob);
vm.stopPrank();
vm.expectRevert(abi.encodeWithSignature("InvalidPublicKeys()"));
vm.prank(bob);
bytes
memory corruptedPublicKey = hex"21d2e725aef3a8f9e09d8f4034948bb7f79505fc7c40e7a7ca15734bad4220a594bf0c6257cef7db88d9fc3fd43607";
stakingContract.requestValidatorsExit(corruptedPublicKey);
}
}
Loading

0 comments on commit 757f17d

Please sign in to comment.