@@ -9,10 +9,11 @@ import {RocketNetworkSnapshotsInterface} from "../../interface/network/RocketNet
99import {RocketMegapoolDelegateInterface} from "../../interface/megapool/RocketMegapoolDelegateInterface.sol " ;
1010import {RocketMegapoolPenaltiesInterface} from "../../interface/megapool/RocketMegapoolPenaltiesInterface.sol " ;
1111
12- /// @notice Performs deterministic deployment of megapool delegate contracts and handles deprecation of old ones
12+ /// @notice Applies penalties to megapools for MEV theft
1313contract RocketMegapoolPenalties is RocketBase , RocketMegapoolPenaltiesInterface {
1414 // Constants
1515 uint256 constant internal penaltyMaximumPeriod = 50400 ;
16+ bytes32 constant internal penaltyKey = keccak256 (abi.encodePacked ("megapool.running.penalty " ));
1617
1718 constructor (RocketStorageInterface _rocketStorageAddress ) RocketBase (_rocketStorageAddress) {
1819 }
@@ -30,7 +31,9 @@ contract RocketMegapoolPenalties is RocketBase, RocketMegapoolPenaltiesInterface
3031 /// @param _megapool Address of the accused megapool
3132 /// @param _block Block that the theft occurred (used for uniqueness)
3233 /// @param _amount Amount in ETH of the penalty
33- function penalise (address _megapool , uint256 _block , uint256 _amount ) override external onlyTrustedNode (msg .sender ) {
34+ function penalise (address _megapool , uint256 _block , uint256 _amount ) override external onlyTrustedNode (msg .sender ) onlyRegisteredMegapool (_megapool) {
35+ require (_amount > 0 , "Invalid penalty amount " );
36+ require (_block < block .number , "Invalid block number " );
3437 // Check this penalty hasn't already reach majority and been applied
3538 bytes32 penaltyAppliedKey = keccak256 (abi.encodePacked ("megapool.penalty.submission.applied " , _megapool, _block, _amount));
3639 require (! getBool (penaltyAppliedKey), "Penalty already applied " );
@@ -52,41 +55,54 @@ contract RocketMegapoolPenalties is RocketBase, RocketMegapoolPenaltiesInterface
5255 }
5356 }
5457
55- function getPenaltyRunningTotalAtBlock (address _megapool , uint32 _block ) override external view returns (uint256 ) {
58+ /// @dev Manually execute a penalty that has hit majority vote
59+ /// @param _megapool Address of the accused megapool
60+ /// @param _block Block that the theft occurred (used for uniqueness)
61+ /// @param _amount Amount in ETH of the penalty
62+ function executePenalty (address _megapool , uint256 _block , uint256 _amount ) override external {
63+ // Check this penalty hasn't already reach majority and been applied
64+ bytes32 penaltyAppliedKey = keccak256 (abi.encodePacked ("megapool.penalty.submission.applied " , _megapool, _block, _amount));
65+ require (! getBool (penaltyAppliedKey), "Penalty already applied " );
66+ // Get submission keys
67+ bytes32 submissionCountKey = keccak256 (abi.encodePacked ("megapool.penalty.submission " , _megapool, _block, _amount));
68+ // Increment submission count
69+ uint256 submissionCount = getUint (submissionCountKey);
70+ // Check for majority
71+ RocketDAONodeTrustedInterface rocketDAONodeTrusted = RocketDAONodeTrustedInterface (getContractAddress ("rocketDAONodeTrusted " ));
72+ if (calcBase * submissionCount / rocketDAONodeTrusted.getMemberCount () > 0.5 ether) {
73+ // Apply penalty and mark as applied
74+ applyPenalty (_megapool, _amount);
75+ setBool (penaltyAppliedKey, true );
76+ }
77+ }
78+
79+ function getPenaltyRunningTotalAtBlock (uint32 _block ) override external view returns (uint256 ) {
5680 RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface (getContractAddress ("rocketNetworkSnapshots " ));
57- bytes32 penaltyKey = keccak256 (abi.encodePacked ("megapool.running.penalty " , _megapool));
5881 return rocketNetworkSnapshots.lookup (penaltyKey, _block);
5982 }
6083
61- function getCurrentPenaltyRunningTotal (address _megapool ) override external view returns (uint256 ) {
84+ function getCurrentPenaltyRunningTotal () override external view returns (uint256 ) {
6285 RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface (getContractAddress ("rocketNetworkSnapshots " ));
63- bytes32 penaltyKey = keccak256 (abi.encodePacked ("megapool.running.penalty " , _megapool));
6486 (,,uint224 value ) = rocketNetworkSnapshots.latest (penaltyKey);
6587 return uint256 (value);
6688 }
6789
68- function getCurrentMaxPenalty (address _megapool ) override external view returns (uint256 ) {
90+ function getCurrentMaxPenalty () override external view returns (uint256 ) {
6991 // Get contracts
7092 RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface (getContractAddress ("rocketNetworkSnapshots " ));
7193 RocketDAOProtocolSettingsMegapoolInterface rocketDAOProtocolSettingsMegapool = RocketDAOProtocolSettingsMegapoolInterface (getContractAddress ("rocketDAOProtocolSettingsMegapool " ));
7294 // Grab max weekly penalty
7395 uint256 maxPenalty = rocketDAOProtocolSettingsMegapool.getMaximumEthPenalty ();
74- // Precompute storage key
75- bytes32 penaltyKey = keccak256 (abi.encodePacked ("megapool.running.penalty " , _megapool));
7696 // Get running total from 50400 slots ago
7797 uint256 earlierBlock = 0 ;
7898 if (block .number > penaltyMaximumPeriod) {
7999 earlierBlock = block .number - penaltyMaximumPeriod;
80100 }
81- uint256 earlierRunningTotal = rocketNetworkSnapshots.lookupRecent (penaltyKey, uint32 (earlierBlock), 5 );
101+ uint256 earlierRunningTotal = uint256 ( rocketNetworkSnapshots.lookup (penaltyKey, uint32 (earlierBlock)) );
82102 // Get current running total
83- (bool exists , uint32 slot , uint224 value ) = rocketNetworkSnapshots.latest (penaltyKey);
84- uint256 currentTotal = 0 ;
85- if (exists) {
86- currentTotal = value;
87- }
103+ (bool exists ,, uint224 currentTotal ) = rocketNetworkSnapshots.latest (penaltyKey);
88104 // Cap the penalty at the maximum amount based on past 50400 blocks
89- return maxPenalty - (currentTotal - earlierRunningTotal);
105+ return maxPenalty - (uint256 ( currentTotal) - earlierRunningTotal);
90106 }
91107
92108 /// @dev Applies a penalty up to given amount, honouring the max penalty parameter
@@ -96,29 +112,19 @@ contract RocketMegapoolPenalties is RocketBase, RocketMegapoolPenaltiesInterface
96112 RocketDAOProtocolSettingsMegapoolInterface rocketDAOProtocolSettingsMegapool = RocketDAOProtocolSettingsMegapoolInterface (getContractAddress ("rocketDAOProtocolSettingsMegapool " ));
97113 // Grab max weekly penalty
98114 uint256 maxPenalty = rocketDAOProtocolSettingsMegapool.getMaximumEthPenalty ();
99- // Precompute storage key
100- bytes32 penaltyKey = keccak256 (abi.encodePacked ("megapool.running.penalty " , _megapool));
101115 // Get running total from 50400 slots ago
102116 uint256 earlierBlock = 0 ;
103117 if (block .number > penaltyMaximumPeriod) {
104118 earlierBlock = block .number - penaltyMaximumPeriod;
105119 }
106- uint256 earlierRunningTotal = rocketNetworkSnapshots.lookupRecent (penaltyKey, uint32 (earlierBlock), 5 );
120+ uint256 earlierRunningTotal = rocketNetworkSnapshots.lookup (penaltyKey, uint32 (earlierBlock));
107121 // Get current running total
108- (bool exists , uint32 slot , uint224 value ) = rocketNetworkSnapshots.latest (penaltyKey);
109- uint256 currentTotal = 0 ;
110- if (exists) {
111- currentTotal = value;
112- }
122+ (,, uint224 currentTotal ) = rocketNetworkSnapshots.latest (penaltyKey);
113123 // Cap the penalty at the maximum amount based on past 50400 blocks
114- uint256 maxCurrentPenalty = maxPenalty - (currentTotal - earlierRunningTotal);
115- if (_amount > maxCurrentPenalty) {
116- _amount = maxCurrentPenalty;
117- }
118- // Prevent useless penalty
119- require (_amount > 0 , "No penalty to apply " );
124+ uint256 maxCurrentPenalty = maxPenalty - (uint256 (currentTotal) - earlierRunningTotal);
125+ require (_amount <= maxCurrentPenalty, "Max penalty exceeded " );
120126 // Insert new running total
121- rocketNetworkSnapshots.push (penaltyKey, uint224 ( currentTotal + _amount));
127+ rocketNetworkSnapshots.push (penaltyKey, currentTotal + uint224 ( _amount));
122128 // Call megapool to increase debt
123129 RocketMegapoolDelegateInterface (_megapool).applyPenalty (_amount);
124130 }
0 commit comments