Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
91c5a53
chore: bump to slashing branch
stevennevins Sep 30, 2024
9eb3446
chore: bump compiler version
stevennevins Sep 30, 2024
e579e21
fix: dep interface changes
stevennevins Sep 30, 2024
9e5e15f
fix: compiler errors from interface changes and type changes
stevennevins Oct 3, 2024
6068036
fix: compiler errors
stevennevins Oct 8, 2024
eea938a
chore: bump dependencies
stevennevins Oct 8, 2024
221b4fe
chore: bump core dependency and resolve issues
stevennevins Oct 8, 2024
b70945a
chore: bump core dependency and fix compiler errors
stevennevins Oct 10, 2024
2c80944
feat: integrate AllocationManager
stevennevins Oct 10, 2024
860faa8
feat: add a slashing permission to the service manager
stevennevins Oct 10, 2024
dad3d4d
chore: remove unneeded casting
stevennevins Oct 10, 2024
c8a8e16
feat: implement a slasher permission and forward call to AllocationMa…
stevennevins Oct 10, 2024
9d5c200
feat: add simiple slasher starting point
stevennevins Oct 10, 2024
ac12473
feat: slashers
stevennevins Oct 16, 2024
8caf960
chore: change around slashed event
stevennevins Oct 16, 2024
dd31230
fix: call dm
stevennevins Oct 21, 2024
e08cc44
fix: resolve merge conflict in dep
stevennevins Oct 21, 2024
fc2a1ba
feat: add proposal mechanism for updating slasher
stevennevins Oct 21, 2024
0fcee61
fix: set to completed instead of delete
stevennevins Oct 21, 2024
337d561
chore: use struct instead of params directly
stevennevins Oct 21, 2024
eb22245
chore: clean up params more
stevennevins Oct 21, 2024
4c60219
chore: simplify and organize files
stevennevins Oct 23, 2024
fcff338
chore: cleanup logic and couple event with internal func
stevennevins Oct 23, 2024
7213174
fix: pass correct params
stevennevins Oct 23, 2024
38dca52
chore: organize and add interface
stevennevins Oct 23, 2024
0847612
chore: nits
stevennevins Oct 23, 2024
825b82b
chore: cleanup more nits
stevennevins Oct 23, 2024
31dd3f3
fix: storage gap
stevennevins Oct 23, 2024
c287af6
chore: nits refactor
stevennevins Oct 23, 2024
999b2c0
chore: go back to fulfill being onlySlasher
stevennevins Oct 23, 2024
7ce35e1
test: fixes from core updates
stevennevins Oct 29, 2024
fdff6f2
fix: use delegated stake per operator set instead of per AVS
stevennevins Oct 30, 2024
a102f9f
fix: update to 14 days
stevennevins Nov 1, 2024
9af73b9
feat: configurable lookahead and stake type
stevennevins Nov 1, 2024
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
32 changes: 28 additions & 4 deletions src/ServiceManagerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol";
import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol";
import {BitmapUtils} from "./libraries/BitmapUtils.sol";
import {LibMergeSort} from "./libraries/LibMergeSort.sol";
import {console} from "forge-std/Test.sol";

/**
* @title Minimal implementation of a ServiceManager-type contract.
Expand All @@ -24,6 +23,8 @@ import {console} from "forge-std/Test.sol";
abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
using BitmapUtils for *;

uint256 public constant SLASHER_PROPOSAL_DELAY = 7 days;

/// @notice when applied to a function, only allows the RegistryCoordinator to call it
modifier onlyRegistryCoordinator() {
require(
Expand Down Expand Up @@ -177,12 +178,25 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
}

/**
* @notice Sets the slasher address
* @notice Proposes a new slasher address
* @param newSlasher The new slasher address
* @dev only callable by the owner
*/
function setSlasher(address newSlasher) external onlyOwner {
_setSlasher(newSlasher);
function proposeNewSlasher(address newSlasher) external onlyOwner {
_proposeNewSlasher(newSlasher);
}

/**
* @notice Accepts the proposed slasher address after the delay period
* @dev only callable by the owner
*/
function acceptProposedSlasher() external onlyOwner {
require(
block.timestamp >= slasherProposalTimestamp + SLASHER_PROPOSAL_DELAY,
"ServiceManager: Slasher proposal delay not met"
);
_setSlasher(proposedSlasher);
delete proposedSlasher;
}

/**
Expand Down Expand Up @@ -342,6 +356,12 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
rewardsInitiator = newRewardsInitiator;
}

function _proposeNewSlasher(address newSlasher) internal {
proposedSlasher = newSlasher;
slasherProposalTimestamp = block.timestamp;
emit SlasherProposed(newSlasher, slasherProposalTimestamp);
}

function _setSlasher(address newSlasher) internal {
emit SlasherUpdated(slasher, newSlasher);
slasher = newSlasher;
Expand Down Expand Up @@ -425,6 +445,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
return address(_avsDirectory);
}

function allocationManager() external view override returns (address) {
return address(_allocationManager);
}

function _checkRewardsInitiator() internal view {
require(
msg.sender == rewardsInitiator,
Expand Down
9 changes: 8 additions & 1 deletion src/ServiceManagerBaseStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab
/// @notice The address of the slasher account
address public slasher;

/// @notice The address of the proposed slasher account
address public proposedSlasher;

/// @notice The timestamp when the slasher was proposed
uint256 public slasherProposalTimestamp;

/// @notice Boolean indicating if the migration has been finalized
bool public migrationFinalized;

/// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, `_stakeRegistry`, and `_allocationManager` addresses
Expand All @@ -58,5 +65,5 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab
}

// storage gap for upgradeability
uint256[48] private __GAP;
uint256[46] private __GAP;
}
44 changes: 40 additions & 4 deletions src/StakeRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.12;

import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol";
import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";
import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IServiceManager} from "./interfaces/IServiceManager.sol";

import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol";
Expand Down Expand Up @@ -229,6 +230,18 @@ contract StakeRegistry is StakeRegistryStorage {
_setMinimumStakeForQuorum(quorumNumber, minimumStake);
}

/**
* @notice Sets the stake type for the registry
* @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH)
*/
function setStakeType(StakeType _stakeType) external onlyCoordinatorOwner {
_setStakeType(_stakeType);
}


function setSlashableStakeLookahead(uint32 _lookAheadPeriod) external onlyCoordinatorOwner {
_setLookAheadPeriod(_lookAheadPeriod);
}
/**
* @notice Adds strategies and weights to the quorum
* @dev Checks to make sure that the *same* strategy cannot be added multiple times (checks against both against existing and new strategies).
Expand Down Expand Up @@ -491,15 +504,17 @@ contract StakeRegistry is StakeRegistryStorage {
uint256 stratsLength = strategyParamsLength(quorumNumber);
StrategyParams memory strategyAndMultiplier;

uint256[] memory strategyShares;
// = delegation.getDelegatableShares(operator, strategiesPerQuorum[quorumNumber]);
address[] memory operators = new address[](1);
operators[0] = operator;
uint32 beforeTimestamp = uint32(block.timestamp + slashableStakeLookAhead);
(uint256[][] memory strategyShares, ) = IAllocationManager(serviceManager.allocationManager()).getMinDelegatedAndSlashableOperatorShares(OperatorSet(address(serviceManager), quorumNumber), operators ,strategiesPerQuorum[quorumNumber], beforeTimestamp);
for (uint256 i = 0; i < stratsLength; i++) {
// accessing i^th StrategyParams struct for the quorumNumber
strategyAndMultiplier = strategyParams[quorumNumber][i];

// add the weight from the shares for this strategy to the total weight
if (strategyShares[i] > 0) {
weight += uint96(strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR);
if (strategyShares[i][0] > 0) {
weight += uint96(strategyShares[i][0] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR);
}
}

Expand Down Expand Up @@ -731,6 +746,27 @@ contract StakeRegistry is StakeRegistryStorage {
return indices;
}

/**
* @notice Sets the stake type for the registry
* @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH)
*/
function _setStakeType(StakeType _stakeType) internal {
StakeType oldStakeType = stakeType;
stakeType = _stakeType;
emit StakeTypeSet(oldStakeType, _stakeType);
}

/**
* @notice Sets the look ahead time for checking operator shares
* @param _lookAheadDays The number of days to look ahead when checking shares
*/
function _setLookAheadPeriod(uint32 _lookAheadDays) internal {
uint32 oldLookAheadDays = slashableStakeLookAhead;
slashableStakeLookAhead = _lookAheadDays;
emit LookAheadPeriodChanged(oldLookAheadDays, _lookAheadDays);
}


function _checkRegistryCoordinator() internal view {
require(
msg.sender == address(registryCoordinator),
Expand Down
5 changes: 4 additions & 1 deletion src/StakeRegistryStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ abstract contract StakeRegistryStorage is IStakeRegistry {
mapping(uint8 => StrategyParams[]) public strategyParams;
mapping(uint8 => IStrategy[]) public strategiesPerQuorum;

StakeType public stakeType;

uint32 public slashableStakeLookAhead;

constructor(
IRegistryCoordinator _registryCoordinator,
Expand All @@ -67,5 +70,5 @@ abstract contract StakeRegistryStorage is IStakeRegistry {

// storage gap for upgradeability
// slither-disable-next-line shadowing-state
uint256[45] private __GAP;
uint256[44] private __GAP;
}
2 changes: 2 additions & 0 deletions src/interfaces/IServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces
import {IServiceManagerUI} from "./IServiceManagerUI.sol";
import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol";
import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";

/**
* @title Minimal interface for a ServiceManager-type contract that forms the single point for an AVS to push updates to EigenLayer
Expand Down Expand Up @@ -50,4 +51,5 @@ interface IServiceManager is IServiceManagerUI {
// EVENTS
event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator);
event SlasherUpdated(address prevSlasher, address newSlasher);
event SlasherProposed(address newSlasher, uint256 slasherProposalTimestamp);
}
3 changes: 3 additions & 0 deletions src/interfaces/IServiceManagerUI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,7 @@ interface IServiceManagerUI {

/// @notice Returns the EigenLayer AVSDirectory contract.
function avsDirectory() external view returns (address);

/// @notice Returns the EigenLayer AllocationManager contract.
function allocationManager() external view returns (address);
}
45 changes: 45 additions & 0 deletions src/interfaces/ISlasher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

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

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

event SlashingRequestCancelled(uint256 indexed requestId);

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

interface ISlasherTypes {
enum SlashingStatus {
Null,
Requested,
Completed,
Cancelled
}

struct SlashingRequest {
IAllocationManager.SlashingParams params;
uint256 requestTimestamp;
SlashingStatus status;
}

}

interface ISlasher is ISlasherEvents, ISlasherTypes{}
13 changes: 13 additions & 0 deletions src/interfaces/IStakeRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import {IRegistry} from "./IRegistry.sol";
* @author Layr Labs, Inc.
*/
interface IStakeRegistry is IRegistry {

enum StakeType {
TOTAL_DELEGATED,
TOTAL_SLASHABLE,
BOTH
}

// DATA STRUCTURES

Expand Down Expand Up @@ -42,6 +48,13 @@ interface IStakeRegistry is IRegistry {
uint8 quorumNumber,
uint96 stake
);


/// @notice emitted when the look ahead time for checking operator shares is updated
event LookAheadPeriodChanged(uint32 oldLookAheadDays, uint32 newLookAheadDays);

/// @notice emitted when the stake type is updated
event StakeTypeSet(StakeType previousStakeType, StakeType newStakeType);
/// @notice emitted when the minimum stake for a quorum is updated
event MinimumStakeForQuorumUpdated(uint8 indexed quorumNumber, uint96 minimumStake);
/// @notice emitted when a new quorum is created
Expand Down
22 changes: 22 additions & 0 deletions src/slashers/InstantSlasher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

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

contract InstantSlasher is SlasherBase {

function initialize(address _serviceManager, address _slasher) external initializer {
__SlasherBase_init(_serviceManager, _slasher);
}

function fulfillSlashingRequest(
IAllocationManager.SlashingParams memory _slashingParams
) external virtual onlySlasher {
uint256 requestId = nextRequestId++;
_fulfillSlashingRequest(requestId, _slashingParams);
}


}
33 changes: 0 additions & 33 deletions src/slashers/SimpleSlasher.sol

This file was deleted.

8 changes: 0 additions & 8 deletions src/slashers/SlasherStorage.sol

This file was deleted.

Loading
Loading