Skip to content

Commit

Permalink
feat: slashers
Browse files Browse the repository at this point in the history
  • Loading branch information
stevennevins committed Oct 16, 2024
1 parent 9d5c200 commit ac12473
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 4 deletions.
39 changes: 39 additions & 0 deletions src/slashers/Slasher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {SlasherBase} from "./SlasherBase.sol";

contract Slasher is SlasherBase {
uint256 public nextRequestId;

event Slashed(
uint256 indexed requestId,
address indexed operator,
uint32 indexed operatorSetId,
uint256 wadToSlash,
string description
);

function initialize(address _serviceManager) public initializer {
__SlasherBase_init(_serviceManager);
}

function fulfillSlashingRequest(
address operator,
uint32 operatorSetId,
IStrategy[] memory strategies,
uint256 wadToSlash,
string memory description
) external virtual {
uint256 requestId = nextRequestId++;
_fulfillSlashingRequest(
operator,
operatorSetId,
strategies,
wadToSlash,
description
);
emit Slashed(requestId, operator, operatorSetId, wadToSlash, description);
}
}
29 changes: 25 additions & 4 deletions src/slashers/SimpleSlasher.sol → src/slashers/SlasherBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,33 @@ import {SlasherStorage} from "./SlasherStorage.sol";
import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";

contract SimpleSlasher is Initializable, SlasherStorage {
function initialize(address _serviceManager) public initializer {
abstract contract SlasherBase is Initializable, SlasherStorage {
enum SlashingStatus {
Null,
Requested,
Completed,
Cancelled
}

event OperatorSlashed(
address indexed operator,
uint32 indexed operatorSetId,
IStrategy[] strategies,
uint256 wadToSlash,
string description
);

function __SlasherBase_init(address _serviceManager) internal onlyInitializing {
serviceManager = _serviceManager;
}

function slashOperator(
function _fulfillSlashingRequest(
address operator,
uint32 operatorSetId,
IStrategy[] memory strategies,
uint256 wadToSlash,
string memory description
) external {
) internal virtual {

IAllocationManagerTypes.SlashingParams memory params = IAllocationManagerTypes.SlashingParams({
operator: operator,
Expand All @@ -28,6 +43,12 @@ contract SimpleSlasher is Initializable, SlasherStorage {
description: description
});

emit OperatorSlashed(operator, operatorSetId, strategies, wadToSlash, description);

IServiceManager(serviceManager).slashOperator(params);
}
}




107 changes: 107 additions & 0 deletions src/slashers/VetoableSlasher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {SlasherBase} from "./SlasherBase.sol";

contract VetoableSlashing is SlasherBase {
struct SlashingRequest {
address operator;
uint32 operatorSetId;
IStrategy[] strategies;
uint256 wadToSlash;
string description;
uint256 requestTimestamp;
SlashingStatus status;
}

uint256 public constant VETO_PERIOD = 3 days;
address public vetoCommittee;
uint256 public nextRequestId;
mapping(uint256 => SlashingRequest) public slashingRequests;

event SlashingRequested(
uint256 indexed requestId,
address indexed operator,
uint32 indexed operatorSetId,
uint256 wadToSlash,
string description
);

event SlashingRequestCancelled(uint256 indexed requestId);

modifier onlyVetoCommittee() {
require(msg.sender == vetoCommittee, "VetoableSlashing: caller is not the veto committee");
_;
}

function initialize(address _serviceManager, address _vetoCommittee) external virtual initializer {
__SlasherBase_init(_serviceManager);
vetoCommittee = _vetoCommittee;
}

function queueSlashingRequest(
address operator,
uint32 operatorSetId,
IStrategy[] memory strategies,
uint256 wadToSlash,
string memory description
) external virtual {
_queueSlashingRequest(operator, operatorSetId, strategies, wadToSlash, description);
}

function cancelSlashingRequest(uint256 requestId) external virtual onlyVetoCommittee {
require(
block.timestamp < slashingRequests[requestId].requestTimestamp + VETO_PERIOD,
"VetoableSlashing: veto period has passed"
);
require(slashingRequests[requestId].status == SlashingStatus.Requested, "VetoableSlashing: request is not in Requested status");

_cancelSlashingRequest(requestId);
}

function fulfillSlashingRequest(uint256 requestId) external virtual {
SlashingRequest storage request = slashingRequests[requestId];
require(
block.timestamp >= request.requestTimestamp + VETO_PERIOD,
"VetoableSlashing: veto period has not passed"
);
require(request.status == SlashingStatus.Requested, "VetoableSlashing: request has been cancelled");

_fulfillSlashingRequest(
request.operator,
request.operatorSetId,
request.strategies,
request.wadToSlash,
request.description
);

delete slashingRequests[requestId];
}

function _queueSlashingRequest(
address operator,
uint32 operatorSetId,
IStrategy[] memory strategies,
uint256 wadToSlash,
string memory description
) internal virtual {
uint256 requestId = nextRequestId++;
slashingRequests[requestId] = SlashingRequest({
operator: operator,
operatorSetId: operatorSetId,
strategies: strategies,
wadToSlash: wadToSlash,
description: description,
requestTimestamp: block.timestamp,
status: SlashingStatus.Requested
});

emit SlashingRequested(requestId, operator, operatorSetId, wadToSlash, description);
}

function _cancelSlashingRequest(uint256 requestId) internal virtual {
slashingRequests[requestId].status = SlashingStatus.Cancelled;
emit SlashingRequestCancelled(requestId);
}
}

0 comments on commit ac12473

Please sign in to comment.