Skip to content

Commit 7aedea4

Browse files
feat(redistribution): update slashers (#492)
**Motivation:** We want our slasher examples to support the redistribution release. **Modifications:** - Bumped `eigenlayer-contracts` -> `v1.7.0-rc.3`. - Bumped `forge-std` -> `v1.9.7`. - Added `fulfillSlashingRequestAndBurnOrRedistribute` to `InstantSlasher` + `VetoableSlasher`. - Deprecated `requestId` (we now track this in core as `slashId`). **Result:** MW supports redistribution.
1 parent 677ef5b commit 7aedea4

18 files changed

+167
-111
lines changed

docs/slashing/VetoableSlasher.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Creates and queues a new slashing request that will be executable after the veto
4444
#### `cancelSlashingRequest`
4545
```solidity
4646
function cancelSlashingRequest(
47-
uint256 requestId
47+
uint256 slashId
4848
)
4949
external
5050
virtual
@@ -68,7 +68,7 @@ Allows the veto committee to cancel a pending slashing request within the veto w
6868
#### `fulfillSlashingRequest`
6969
```solidity
7070
function fulfillSlashingRequest(
71-
uint256 requestId
71+
uint256 slashId
7272
)
7373
external
7474
virtual

src/interfaces/IInstantSlasher.sol

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,18 @@ import {ISlasher} from "./ISlasher.sol";
1010
/// @dev Extends base interfaces to provide access controlled slashing functionality
1111
interface IInstantSlasher is ISlasher {
1212
/// @notice Immediately executes a slashing request
13-
/// @param _slashingParams Parameters defining the slashing request including operator and amount
13+
/// @param params Parameters defining the slashing request including operator and amount
1414
/// @dev Can only be called by the authorized slasher
15+
/// @return slashId The ID of the slashing request
1516
function fulfillSlashingRequest(
16-
IAllocationManager.SlashingParams memory _slashingParams
17-
) external;
17+
IAllocationManager.SlashingParams memory params
18+
) external returns (uint256 slashId);
19+
20+
/// @notice Immediately executes a slashing request and burns or redistributes shares
21+
/// @param params Parameters defining the slashing request including operator and amount
22+
/// @dev Can only be called by the authorized slasher
23+
/// @return slashId The ID of the slashing request
24+
function fulfillSlashingRequestAndBurnOrRedistribute(
25+
IAllocationManager.SlashingParams memory params
26+
) external returns (uint256 slashId);
1827
}

src/interfaces/ISlasher.sol

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ interface ISlasherTypes {
2020
interface ISlasherEvents is ISlasherTypes {
2121
/// @notice Emitted when an operator is successfully slashed
2222
event OperatorSlashed(
23-
uint256 indexed slashingRequestId,
23+
uint256 indexed slashId,
2424
address indexed operator,
2525
uint32 indexed operatorSetId,
2626
uint256[] wadsToSlash,
@@ -33,7 +33,4 @@ interface ISlasherEvents is ISlasherTypes {
3333
interface ISlasher is ISlasherErrors, ISlasherEvents {
3434
/// @notice Returns the address authorized to create and fulfill slashing requests
3535
function slasher() external view returns (address);
36-
37-
/// @notice Returns the next slashing request ID
38-
function nextRequestId() external view returns (uint256);
3936
}

src/interfaces/IVetoableSlasher.sol

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ interface IVetoableSlasherTypes {
3737
interface IVetoableSlasherEvents {
3838
/// @notice Emitted when a new slashing request is created
3939
event SlashingRequested(
40-
uint256 indexed requestId,
40+
uint256 indexed slashId,
4141
address indexed operator,
4242
uint32 operatorSetId,
4343
uint256[] wadsToSlash,
4444
string description
4545
);
4646

4747
/// @notice Emitted when a slashing request is cancelled by the veto committee
48-
event SlashingRequestCancelled(uint256 indexed requestId);
48+
event SlashingRequestCancelled(uint256 indexed slashId);
4949
}
5050

5151
/// @title IVetoableSlasher
@@ -71,16 +71,23 @@ interface IVetoableSlasher is
7171
) external;
7272

7373
/// @notice Cancels a pending slashing request
74-
/// @param requestId The ID of the slashing request to cancel
74+
/// @param slashId The ID of the slashing request to cancel
7575
/// @dev Can only be called by the veto committee during the veto period
7676
function cancelSlashingRequest(
77-
uint256 requestId
77+
uint256 slashId
7878
) external;
7979

8080
/// @notice Executes a slashing request after the veto period has passed
81-
/// @param requestId The ID of the slashing request to fulfill
81+
/// @param slashId The ID of the slashing request to fulfill
8282
/// @dev Can only be called by the authorized slasher after the veto period
8383
function fulfillSlashingRequest(
84-
uint256 requestId
84+
uint256 slashId
85+
) external;
86+
87+
/// @notice Executes a slashing request after the veto period has passed and burns or redistributes shares
88+
/// @param slashId The ID of the slashing request to fulfill
89+
/// @dev Can only be called by the authorized slasher after the veto period
90+
function fulfillSlashingRequestAndBurnOrRedistribute(
91+
uint256 slashId
8592
) external;
8693
}

src/slashers/InstantSlasher.sol

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity ^0.8.27;
44
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
55
import {IAllocationManager} from
66
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
7+
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
78
import {SlasherBase} from "./base/SlasherBase.sol";
89
import {ISlashingRegistryCoordinator} from "../interfaces/ISlashingRegistryCoordinator.sol";
910
import {IInstantSlasher} from "../interfaces/IInstantSlasher.sol";
@@ -14,19 +15,22 @@ import {IInstantSlasher} from "../interfaces/IInstantSlasher.sol";
1415
contract InstantSlasher is IInstantSlasher, SlasherBase {
1516
constructor(
1617
IAllocationManager _allocationManager,
18+
IStrategyManager _strategyManager,
1719
ISlashingRegistryCoordinator _slashingRegistryCoordinator,
1820
address _slasher
19-
) SlasherBase(_allocationManager, _slashingRegistryCoordinator, _slasher) {}
21+
) SlasherBase(_allocationManager, _strategyManager, _slashingRegistryCoordinator, _slasher) {}
2022

2123
/// @inheritdoc IInstantSlasher
2224
function fulfillSlashingRequest(
23-
IAllocationManager.SlashingParams calldata _slashingParams
24-
) external virtual override(IInstantSlasher) onlySlasher {
25-
uint256 requestId = nextRequestId++;
26-
_fulfillSlashingRequest(requestId, _slashingParams);
25+
IAllocationManager.SlashingParams calldata params
26+
) external virtual override(IInstantSlasher) onlySlasher returns (uint256 slashId) {
27+
slashId = _fulfillSlashingRequest(params);
28+
}
2729

28-
address[] memory operators = new address[](1);
29-
operators[0] = _slashingParams.operator;
30-
slashingRegistryCoordinator.updateOperators(operators);
30+
/// @inheritdoc IInstantSlasher
31+
function fulfillSlashingRequestAndBurnOrRedistribute(
32+
IAllocationManager.SlashingParams calldata params
33+
) external virtual override onlySlasher returns (uint256 slashId) {
34+
slashId = _fulfillSlashingRequestAndBurnOrRedistribute(params);
3135
}
3236
}

src/slashers/VetoableSlasher.sol

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
pragma solidity ^0.8.27;
33

44
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
5-
import {IAllocationManager} from
6-
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
5+
import {
6+
IAllocationManager,
7+
OperatorSet
8+
} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
9+
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
710
import {SlasherBase} from "./base/SlasherBase.sol";
811
import {ISlashingRegistryCoordinator} from "../interfaces/ISlashingRegistryCoordinator.sol";
912
import {IVetoableSlasher, IVetoableSlasherTypes} from "../interfaces/IVetoableSlasher.sol";
@@ -29,11 +32,12 @@ contract VetoableSlasher is IVetoableSlasher, SlasherBase {
2932

3033
constructor(
3134
IAllocationManager _allocationManager,
35+
IStrategyManager _strategyManager,
3236
ISlashingRegistryCoordinator _slashingRegistryCoordinator,
3337
address _slasher,
3438
address _vetoCommittee,
3539
uint32 _vetoWindowBlocks
36-
) SlasherBase(_allocationManager, _slashingRegistryCoordinator, _slasher) {
40+
) SlasherBase(_allocationManager, _strategyManager, _slashingRegistryCoordinator, _slasher) {
3741
vetoWindowBlocks = _vetoWindowBlocks;
3842
vetoCommittee = _vetoCommittee;
3943
}
@@ -47,72 +51,82 @@ contract VetoableSlasher is IVetoableSlasher, SlasherBase {
4751

4852
/// @inheritdoc IVetoableSlasher
4953
function cancelSlashingRequest(
50-
uint256 requestId
54+
uint256 slashId
5155
) external virtual override onlyVetoCommittee {
52-
_cancelSlashingRequest(requestId);
56+
_cancelSlashingRequest(slashId);
5357
}
5458

5559
/// @inheritdoc IVetoableSlasher
5660
function fulfillSlashingRequest(
57-
uint256 requestId
61+
uint256 slashId
5862
) external virtual override onlySlasher {
59-
_fulfillSlashingRequestAndMarkAsCompleted(requestId);
63+
IVetoableSlasherTypes.VetoableSlashingRequest storage request = slashingRequests[slashId];
64+
_markAsCompleted(request);
65+
_fulfillSlashingRequest(request.params);
66+
}
67+
68+
/// @inheritdoc IVetoableSlasher
69+
function fulfillSlashingRequestAndBurnOrRedistribute(
70+
uint256 slashId
71+
) external virtual override onlySlasher {
72+
IVetoableSlasherTypes.VetoableSlashingRequest storage request = slashingRequests[slashId];
73+
_markAsCompleted(request);
74+
_fulfillSlashingRequestAndBurnOrRedistribute(request.params);
6075
}
6176

6277
/// @notice Internal function to create and store a new slashing request
6378
/// @param params Parameters defining the slashing request
6479
function _queueSlashingRequest(
6580
IAllocationManager.SlashingParams memory params
6681
) internal virtual {
67-
uint256 requestId = nextRequestId++;
68-
slashingRequests[requestId] = IVetoableSlasherTypes.VetoableSlashingRequest({
82+
uint256 nextSlashId = allocationManager.getSlashCount(
83+
OperatorSet({avs: slashingRegistryCoordinator.avs(), id: params.operatorSetId})
84+
);
85+
slashingRequests[nextSlashId] = IVetoableSlasherTypes.VetoableSlashingRequest({
6986
params: params,
7087
requestBlock: block.number,
7188
status: IVetoableSlasherTypes.SlashingStatus.Requested
7289
});
7390

7491
emit SlashingRequested(
75-
requestId, params.operator, params.operatorSetId, params.wadsToSlash, params.description
92+
nextSlashId,
93+
params.operator,
94+
params.operatorSetId,
95+
params.wadsToSlash,
96+
params.description
7697
);
7798
}
7899

79100
/// @notice Internal function to mark a slashing request as cancelled
80-
/// @param requestId The ID of the slashing request to cancel
101+
/// @param slashId The ID of the slashing request to cancel
81102
function _cancelSlashingRequest(
82-
uint256 requestId
103+
uint256 slashId
83104
) internal virtual {
84105
require(
85-
block.number < slashingRequests[requestId].requestBlock + vetoWindowBlocks,
106+
block.number < slashingRequests[slashId].requestBlock + vetoWindowBlocks,
86107
VetoPeriodPassed()
87108
);
88109
require(
89-
slashingRequests[requestId].status == IVetoableSlasherTypes.SlashingStatus.Requested,
110+
slashingRequests[slashId].status == IVetoableSlasherTypes.SlashingStatus.Requested,
90111
SlashingRequestNotRequested()
91112
);
92113

93-
slashingRequests[requestId].status = IVetoableSlasherTypes.SlashingStatus.Cancelled;
94-
emit SlashingRequestCancelled(requestId);
114+
slashingRequests[slashId].status = IVetoableSlasherTypes.SlashingStatus.Cancelled;
115+
emit SlashingRequestCancelled(slashId);
95116
}
96117

97-
/// @notice Internal function to fulfill a slashing request and mark it as completed
98-
/// @param requestId The ID of the slashing request to fulfill
99-
function _fulfillSlashingRequestAndMarkAsCompleted(
100-
uint256 requestId
118+
/// @notice Internal function to mark a slashing request as completed
119+
/// @param request The request to mark as completed
120+
function _markAsCompleted(
121+
IVetoableSlasherTypes.VetoableSlashingRequest storage request
101122
) internal virtual {
102-
IVetoableSlasherTypes.VetoableSlashingRequest storage request = slashingRequests[requestId];
103123
require(block.number >= request.requestBlock + vetoWindowBlocks, VetoPeriodNotPassed());
104124
require(
105125
request.status == IVetoableSlasherTypes.SlashingStatus.Requested,
106126
SlashingRequestIsCancelled()
107127
);
108128

109129
request.status = IVetoableSlasherTypes.SlashingStatus.Completed;
110-
111-
_fulfillSlashingRequest(requestId, request.params);
112-
113-
address[] memory operators = new address[](1);
114-
operators[0] = request.params.operator;
115-
slashingRegistryCoordinator.updateOperators(operators);
116130
}
117131

118132
/// @notice Internal function to verify if an account is the veto committee

src/slashers/base/SlasherBase.sol

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ pragma solidity ^0.8.27;
33

44
import {SlasherStorage, ISlashingRegistryCoordinator} from "./SlasherStorage.sol";
55
import {
6+
OperatorSet,
67
IAllocationManagerTypes,
78
IAllocationManager
89
} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
10+
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
911
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
1012

1113
/// @title SlasherBase
@@ -24,26 +26,45 @@ abstract contract SlasherBase is SlasherStorage {
2426
/// @param _slasher The address of the slasher
2527
constructor(
2628
IAllocationManager _allocationManager,
29+
IStrategyManager _strategyManager,
2730
ISlashingRegistryCoordinator _registryCoordinator,
2831
address _slasher
29-
) SlasherStorage(_allocationManager, _registryCoordinator, _slasher) {}
32+
) SlasherStorage(_allocationManager, _strategyManager, _registryCoordinator, _slasher) {}
3033

3134
/// @notice Internal function to execute a slashing request
32-
/// @param _requestId The ID of the slashing request to fulfill
33-
/// @param _params Parameters defining the slashing request including operator, strategies, and amounts
35+
/// @param params Parameters defining the slashing request including operator, strategies, and amounts
3436
/// @dev Calls AllocationManager.slashOperator to perform the actual slashing
3537
function _fulfillSlashingRequest(
36-
uint256 _requestId,
37-
IAllocationManager.SlashingParams memory _params
38-
) internal virtual {
39-
allocationManager.slashOperator({avs: slashingRegistryCoordinator.avs(), params: _params});
38+
IAllocationManager.SlashingParams memory params
39+
) internal virtual returns (uint256 slashId) {
40+
(slashId,) = allocationManager.slashOperator({
41+
avs: slashingRegistryCoordinator.avs(),
42+
params: params
43+
});
4044
emit OperatorSlashed(
41-
_requestId,
42-
_params.operator,
43-
_params.operatorSetId,
44-
_params.wadsToSlash,
45-
_params.description
45+
slashId, params.operator, params.operatorSetId, params.wadsToSlash, params.description
4646
);
47+
48+
// Update operator stake weights
49+
address[] memory operators = new address[](1);
50+
operators[0] = params.operator;
51+
slashingRegistryCoordinator.updateOperators(operators);
52+
}
53+
54+
/// @notice Internal function to optionally fulfill burn or redistribution instead of waiting for cron job
55+
function _fulfillBurnOrRedistribution(uint32 operatorSetId, uint256 slashId) internal virtual {
56+
strategyManager.clearBurnOrRedistributableShares({
57+
operatorSet: OperatorSet({avs: slashingRegistryCoordinator.avs(), id: operatorSetId}),
58+
slashId: slashId
59+
});
60+
}
61+
62+
/// @notice Internal function to fulfill a slashing request and burn or redistribute shares
63+
function _fulfillSlashingRequestAndBurnOrRedistribute(
64+
IAllocationManager.SlashingParams memory params
65+
) internal virtual returns (uint256 slashId) {
66+
slashId = _fulfillSlashingRequest(params);
67+
_fulfillBurnOrRedistribution(params.operatorSetId, slashId);
4768
}
4869

4970
/// @notice Internal function to verify if an account is the authorized slasher

src/slashers/base/SlasherStorage.sol

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pragma solidity ^0.8.27;
33

44
import {IAllocationManager} from
55
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
6+
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
67
import {ISlashingRegistryCoordinator} from "../../interfaces/ISlashingRegistryCoordinator.sol";
78
import {ISlasher} from "../../interfaces/ISlasher.sol";
89

@@ -16,21 +17,27 @@ abstract contract SlasherStorage is ISlasher {
1617
*
1718
*/
1819

19-
/// @notice the AllocationManager that tracks OperatorSets and Slashing in EigenLayer
20+
/// @notice The `AllocationManager` tracks operator sets, operator set allocations, and slashing in EigenLayer.
2021
IAllocationManager public immutable allocationManager;
21-
/// @notice the SlashingRegistryCoordinator for this AVS
22+
/// @notice The `StrategyManager` handles strategy inflows/outflows.
23+
IStrategyManager public immutable strategyManager;
24+
/// @notice The `SlashingRegistryCoordinator` for this AVS.
2225
ISlashingRegistryCoordinator public immutable slashingRegistryCoordinator;
26+
2327
/// @notice the address of the slasher
2428
address public immutable slasher;
2529

26-
uint256 public nextRequestId;
30+
/// @dev DEPRECATED -- `AllocationManager` now tracks monotonically increasing `slashId`.
31+
uint256 private __deprecated_nextRequestId;
2732

2833
constructor(
2934
IAllocationManager _allocationManager,
35+
IStrategyManager _strategyManager,
3036
ISlashingRegistryCoordinator _slashingRegistryCoordinator,
3137
address _slasher
3238
) {
3339
allocationManager = _allocationManager;
40+
strategyManager = _strategyManager;
3441
slashingRegistryCoordinator = _slashingRegistryCoordinator;
3542
slasher = _slasher;
3643
}

0 commit comments

Comments
 (0)