Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: unit test slashers #380

Merged
merged 15 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions src/RegistryCoordinator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -237,14 +237,4 @@ contract RegistryCoordinator is RegistryCoordinatorStorage {
) external view returns (bool) {
return _isM2Quorum(quorumNumber);
}

/**
* @notice Returns the message hash that an operator must sign to register their BLS public key.
* @param operator is the address of the operator registering their BLS public key
*/
function calculatePubkeyRegistrationMessageHash(
address operator
) public view returns (bytes32) {
return _hashTypedDataV4(keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator)));
}
}
10 changes: 10 additions & 0 deletions src/SlashingRegistryCoordinator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1066,4 +1066,14 @@ contract SlashingRegistryCoordinator is
_hashTypedDataV4(keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator)))
);
}

/**
* @notice Returns the message hash that an operator must sign to register their BLS public key.
* @param operator is the address of the operator registering their BLS public key
*/
function calculatePubkeyRegistrationMessageHash(
address operator
) public view returns (bytes32) {
return _hashTypedDataV4(keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator)));
}
}
24 changes: 24 additions & 0 deletions src/interfaces/IInstantSlasher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import {IAllocationManager} from
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {ISlasher} from "./ISlasher.sol";

/// @title IInstantSlasher
/// @notice A slashing contract that immediately executes slashing requests without any delay or veto period
/// @dev Extends base interfaces to provide access controlled slashing functionality
interface IInstantSlasher is ISlasher {
/// @notice Initializes the contract with a slasher address
/// @param _slasher Address authorized to create and fulfill slashing requests
function initialize(
address _slasher
) external;

/// @notice Immediately executes a slashing request
/// @param _slashingParams Parameters defining the slashing request including operator and amount
/// @dev Can only be called by the authorized slasher
function fulfillSlashingRequest(
IAllocationManager.SlashingParams memory _slashingParams
) external;
}
74 changes: 9 additions & 65 deletions src/interfaces/ISlasher.sol
Original file line number Diff line number Diff line change
@@ -1,85 +1,24 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

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

interface ISlasherErrors {
/// @notice Thrown when a caller without veto committee privileges attempts a restricted operation.
error OnlyVetoCommittee();
/// @notice Thrown when a caller without slasher privileges attempts a restricted operation.
/// @notice Thrown when a caller without slasher privileges attempts a restricted operation
error OnlySlasher();
/// @notice Thrown when attempting to veto a slashing request after the veto period has expired.
error VetoPeriodPassed();
/// @notice Thrown when attempting to execute a slashing request before the veto period has ended.
error VetoPeriodNotPassed();
/// @notice Thrown when attempting to interact with a slashing request that has been cancelled.
error SlashingRequestIsCancelled();
/// @notice Thrown when attempting to modify a slashing request that does not exist.
error SlashingRequestNotRequested();
}

interface ISlasherTypes {
/**
* @notice Represents the current status of a slashing request.
* @dev The status of a slashing request can be one of the following:
* - Null: Default state, no request exists.
* - Requested: Slashing has been requested but not yet executed.
* - Completed: Slashing has been successfully executed.
* - Cancelled: Slashing request was cancelled by veto committee.
*/
enum SlashingStatus {
Null,
Requested,
Completed,
Cancelled
}

/**
* @notice Contains all information related to a slashing request.
* @param params The slashing parameters from the allocation manager.
* @param requestTimestamp The timestamp when the slashing request was created.
* @param status The current status of the slashing request.
*/
/// @notice Structure containing details about a slashing request
struct SlashingRequest {
IAllocationManager.SlashingParams params;
uint256 requestTimestamp;
SlashingStatus status;
}
}

interface ISlasherEvents is ISlasherTypes {
/**
* @notice Emitted when a new slashing request is created.
* @param requestId The unique identifier for the slashing request (indexed).
* @param operator The address of the operator to be slashed (indexed).
* @param operatorSetId The ID of the operator set involved (indexed).
* @param wadsToSlash The amounts to slash from each strategy.
* @param description A human-readable description of the slashing reason.
*/
event SlashingRequested(
uint256 indexed requestId,
address indexed operator,
uint32 indexed operatorSetId,
uint256[] wadsToSlash,
string description
);

/**
* @notice Emitted when a slashing request is cancelled by the veto committee.
* @param requestId The unique identifier of the cancelled request (indexed).
*/
event SlashingRequestCancelled(uint256 indexed requestId);

/**
* @notice Emitted when an operator is successfully slashed.
* @param slashingRequestId The ID of the executed slashing request (indexed).
* @param operator The address of the slashed operator (indexed).
* @param operatorSetId The ID of the operator set involved (indexed).
* @param wadsToSlash The amounts slashed from each strategy.
* @param description A human-readable description of why the operator was slashed.
*/
/// @notice Emitted when an operator is successfully slashed
event OperatorSlashed(
uint256 indexed slashingRequestId,
address indexed operator,
Expand All @@ -89,4 +28,9 @@ interface ISlasherEvents is ISlasherTypes {
);
}

interface ISlasher is ISlasherErrors, ISlasherEvents {}
/// @title ISlasher
/// @notice Base interface containing shared functionality for all slasher implementations
interface ISlasher is ISlasherErrors, ISlasherEvents {
/// @notice Returns the address authorized to create and fulfill slashing requests
function slasher() external view returns (address);
}
8 changes: 8 additions & 0 deletions src/interfaces/ISlashingRegistryCoordinator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,14 @@ interface ISlashingRegistryCoordinator is

/// VIEW

/**
* @notice Returns the hash of the message that operators must sign with their BLS key to register
* @param operator The operator's Ethereum address
*/
function calculatePubkeyRegistrationMessageHash(
address operator
) external view returns (bytes32);

/**
* @notice Returns the operator set parameters for a given quorum.
* @param quorumNumber The identifier of the quorum to query.
Expand Down
92 changes: 92 additions & 0 deletions src/interfaces/IVetoableSlasher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import {IAllocationManager} from
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {ISlasher} from "./ISlasher.sol";

interface IVetoableSlasherErrors {
/// @notice Thrown when a caller without veto committee privileges attempts a restricted operation
error OnlyVetoCommittee();
/// @notice Thrown when attempting to veto a slashing request after the veto period has expired
error VetoPeriodPassed();
/// @notice Thrown when attempting to execute a slashing request before the veto period has ended
error VetoPeriodNotPassed();
/// @notice Thrown when attempting to interact with a slashing request that has been cancelled
error SlashingRequestIsCancelled();
/// @notice Thrown when attempting to modify a slashing request that does not exist
error SlashingRequestNotRequested();
}

interface IVetoableSlasherTypes {
/// @notice Represents the status of a slashing request
enum SlashingStatus {
Requested,
Cancelled,
Completed
}

/// @notice Structure containing details about a vetoable slashing request
struct VetoableSlashingRequest {
IAllocationManager.SlashingParams params;
uint256 requestTimestamp;
SlashingStatus status;
}
}

interface IVetoableSlasherEvents {
/// @notice Emitted when a new slashing request is created
event SlashingRequested(
uint256 indexed requestId,
address indexed operator,
uint32 operatorSetId,
uint256[] wadsToSlash,
string description
);

/// @notice Emitted when a slashing request is cancelled by the veto committee
event SlashingRequestCancelled(uint256 indexed requestId);
}

/// @title IVetoableSlasher
/// @notice A slashing contract that implements a veto mechanism allowing a designated committee to cancel slashing requests
/// @dev Extends base interfaces and adds a veto period during which slashing requests can be cancelled
interface IVetoableSlasher is
ISlasher,
IVetoableSlasherErrors,
IVetoableSlasherTypes,
IVetoableSlasherEvents
{
/// @notice Duration of the veto period during which the veto committee can cancel slashing requests
/// @dev Set to 3 days (259,200 seconds)
function VETO_PERIOD() external view returns (uint256);

/// @notice Address of the committee that has veto power over slashing requests
function vetoCommittee() external view returns (address);

/// @notice Initializes the contract with a veto committee and slasher address
/// @param _vetoCommittee Address of the committee that can veto slashing requests
/// @param _slasher Address authorized to create and fulfill slashing requests
function initialize(address _vetoCommittee, address _slasher) external;

/// @notice Queues a new slashing request
/// @param params Parameters defining the slashing request including operator and amount
/// @dev Can only be called by the authorized slasher
function queueSlashingRequest(
IAllocationManager.SlashingParams calldata params
) external;

/// @notice Cancels a pending slashing request
/// @param requestId The ID of the slashing request to cancel
/// @dev Can only be called by the veto committee during the veto period
function cancelSlashingRequest(
uint256 requestId
) external;

/// @notice Executes a slashing request after the veto period has passed
/// @param requestId The ID of the slashing request to fulfill
/// @dev Can only be called by the authorized slasher after the veto period
function fulfillSlashingRequest(
uint256 requestId
) external;
}
16 changes: 11 additions & 5 deletions src/slashers/InstantSlasher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,31 @@ pragma solidity ^0.8.27;
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {IAllocationManager} from
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {ISlashingRegistryCoordinator} from "../interfaces/ISlashingRegistryCoordinator.sol";
import {SlasherBase} from "./base/SlasherBase.sol";
import {ISlashingRegistryCoordinator} from "../interfaces/ISlashingRegistryCoordinator.sol";
import {IInstantSlasher} from "../interfaces/IInstantSlasher.sol";

contract InstantSlasher is SlasherBase {
/// @title InstantSlasher
/// @notice A slashing contract that immediately executes slashing requests without any delay or veto period
/// @dev Extends SlasherBase to provide access controlled slashing functionality
contract InstantSlasher is IInstantSlasher, SlasherBase {
constructor(
IAllocationManager _allocationManager,
ISlashingRegistryCoordinator _slashingRegistryCoordinator,
address _slasher
) SlasherBase(_allocationManager, _slashingRegistryCoordinator) {}

/// @inheritdoc IInstantSlasher
function initialize(
address _slasher
) external initializer {
) external override initializer {
__SlasherBase_init(_slasher);
}

/// @inheritdoc IInstantSlasher
function fulfillSlashingRequest(
IAllocationManager.SlashingParams memory _slashingParams
) external virtual onlySlasher {
IAllocationManager.SlashingParams calldata _slashingParams
) external virtual override(IInstantSlasher) onlySlasher {
uint256 requestId = nextRequestId++;
_fulfillSlashingRequest(requestId, _slashingParams);
}
Expand Down
Loading
Loading