Skip to content

Commit

Permalink
chore: bump slashing core dependency (#312)
Browse files Browse the repository at this point in the history
* chore: bump to slashing branch

* chore: bump compiler version

* fix: dep interface changes

* fix: compiler errors from interface changes and type changes

* fix: compiler errors

* chore: bump dependencies

* chore: bump core dependency and resolve issues

* chore: bump core dependency and fix compiler errors

* feat: integrate AllocationManager

* feat: add a slashing permission to the service manager

* chore: remove unneeded casting

* feat: implement a slasher permission and forward call to AllocationManager

* feat: add simiple slasher starting point

* chore: bump slashing magnitudes

* chore: bump core slashing-magnitudes branch
  • Loading branch information
stevennevins authored Oct 17, 2024
1 parent e0a79f1 commit eb0d6ad
Show file tree
Hide file tree
Showing 34 changed files with 1,032 additions and 622 deletions.
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ optimizer_runs = 200
# Whether or not to use the Yul intermediate representation compilation pipeline
via_ir = false
# Override the Solidity version (this overrides `auto_detect_solc`)
solc_version = '0.8.12'
solc_version = '0.8.27'

[etherscan]
mainnet = { key = "${ETHERSCAN_API_KEY}" }
Expand Down
2 changes: 1 addition & 1 deletion lib/eigenlayer-contracts
7 changes: 5 additions & 2 deletions script/OperatorSetUpgrade.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {IBLSApkRegistry} from "../src/interfaces/IBLSApkRegistry.sol";
import {IIndexRegistry} from "../src/interfaces/IIndexRegistry.sol";
import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";
import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol";
interface IServiceManagerMigration {
function getOperatorsToMigrate()
Expand Down Expand Up @@ -46,6 +47,7 @@ contract OperatorSetUpgradeScript is Script {
address public delegationManager;
address public blsApkRegistry;
address public indexRegistry;
address public allocationManager;

function setUp() public {
vm.label(DEFAULT_FORGE_SENDER, "DEFAULT FORGE SENDER");
Expand Down Expand Up @@ -145,7 +147,7 @@ contract OperatorSetUpgradeScript is Script {
function _upgradeAvsDirectory() internal {
address proxyAdmin = OperatorSetUpgradeLib.getAdmin(avsDirectory);
address avsDirectoryOwner = Ownable(proxyAdmin).owner();
AVSDirectory avsDirectoryImpl = new AVSDirectory(IDelegationManager(delegationManager));
AVSDirectory avsDirectoryImpl = new AVSDirectory(IDelegationManager(delegationManager), 0); // TODO: config

vm.startPrank(avsDirectoryOwner);
OperatorSetUpgradeLib.upgrade(avsDirectory, address(avsDirectoryImpl));
Expand Down Expand Up @@ -211,7 +213,8 @@ contract OperatorSetUpgradeScript is Script {
IAVSDirectory(avsDirectory),
IRewardsCoordinator(rewardsCoordinator),
IRegistryCoordinator(registryCoordinator),
IStakeRegistry(stakeRegistry)
IStakeRegistry(stakeRegistry),
IAllocationManager(allocationManager)
));
address newRegistryCoordinatorImpl = address(new RegistryCoordinator(
IServiceManager(serviceManager),
Expand Down
8 changes: 5 additions & 3 deletions src/BLSSignatureChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,11 @@ contract BLSSignatureChecker is IBLSSignatureChecker {
*/
{
bool _staleStakesForbidden = staleStakesForbidden;
uint256 withdrawalDelayBlocks = _staleStakesForbidden
? delegation.minWithdrawalDelayBlocks()
: 0;
/// TODO: FIX
uint256 withdrawalDelayBlocks = 0;
// uint256 withdrawalDelayBlocks = _staleStakesForbidden
// ? delegation.minWithdrawalDelayBlocks()
// : 0;

for (uint256 i = 0; i < quorumNumbers.length; i++) {
// If we're disallowing stale stake updates, check that each quorum's last update block
Expand Down
6 changes: 3 additions & 3 deletions src/RegistryCoordinator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.12;

import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol";
import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol";
import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";
import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";
import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol";
import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol";
import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol";
Expand Down Expand Up @@ -676,7 +676,7 @@ contract RegistryCoordinator is
for (uint256 i = 0; i < quorumBytes.length; i++) {
/// We need to track forceDeregistrations so we don't pass an id that was already deregistered on the AVSDirectory
/// but hasnt yet been recorded in the middleware contracts
if (!avsDirectory.isMember(operator, IAVSDirectory.OperatorSet(address(serviceManager), uint8(quorumBytes[i])))){
if (!avsDirectory.isMember(operator, OperatorSet(address(serviceManager), uint8(quorumBytes[i])))){
forceDeregistrationCount++;
}
operatorSetIds[i] = uint8(quorumBytes[i]);
Expand All @@ -687,7 +687,7 @@ contract RegistryCoordinator is
uint32[] memory filteredOperatorSetIds = new uint32[](operatorSetIds.length - forceDeregistrationCount);
uint256 offset;
for (uint256 i; i < operatorSetIds.length; i++){
if (avsDirectory.isMember(operator, IAVSDirectory.OperatorSet(address(serviceManager), operatorSetIds[i]))){
if (avsDirectory.isMember(operator, OperatorSet(address(serviceManager), operatorSetIds[i]))){
filteredOperatorSetIds[i] = operatorSetIds[i+offset];
} else {
offset++;
Expand Down
53 changes: 45 additions & 8 deletions src/ServiceManagerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISi
import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";
import {IRewardsCoordinator} from
"eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";

import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol";
import {IServiceManager} from "./interfaces/IServiceManager.sol";
Expand Down Expand Up @@ -38,36 +39,39 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
_;
}

function _checkRewardsInitiator() internal view {
require(
msg.sender == rewardsInitiator,
"ServiceManagerBase.onlyRewardsInitiator: caller is not the rewards initiator"
);
/// @notice only slasher can call functions with this modifier
modifier onlySlasher() {
_checkSlasher();
_;
}

/// @notice Sets the (immutable) `_registryCoordinator` address
constructor(
IAVSDirectory __avsDirectory,
IRewardsCoordinator __rewardsCoordinator,
IRegistryCoordinator __registryCoordinator,
IStakeRegistry __stakeRegistry
IStakeRegistry __stakeRegistry,
IAllocationManager __allocationManager
)
ServiceManagerBaseStorage(
__avsDirectory,
__rewardsCoordinator,
__registryCoordinator,
__stakeRegistry
__stakeRegistry,
__allocationManager
)
{
_disableInitializers();
}

function __ServiceManagerBase_init(
address initialOwner,
address _rewardsInitiator
address _rewardsInitiator,
address _slasher
) internal virtual onlyInitializing {
_transferOwnership(initialOwner);
_setRewardsInitiator(_rewardsInitiator);
_setSlasher(_slasher);
}

/**
Expand All @@ -79,6 +83,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
_avsDirectory.updateAVSMetadataURI(_metadataURI);
}

function slashOperator(IAllocationManager.SlashingParams memory params) external onlySlasher {
_allocationManager.slashOperator(params);
}

/**
* @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the
* set of stakers delegated to operators who are registered to this `avs`
Expand Down Expand Up @@ -168,6 +176,15 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
_setRewardsInitiator(newRewardsInitiator);
}

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

/**
* @notice Migrates the AVS to use operator sets and creates new operator set IDs.
* @param operatorSetsToCreate An array of operator set IDs to create.
Expand Down Expand Up @@ -325,6 +342,11 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
rewardsInitiator = newRewardsInitiator;
}

function _setSlasher(address newSlasher) internal {
emit SlasherUpdated(slasher, newSlasher);
slasher = newSlasher;
}

/**
* @notice Returns the list of strategies that the AVS supports for restaking
* @dev This function is intended to be called off-chain
Expand Down Expand Up @@ -402,4 +424,19 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
function avsDirectory() external view override returns (address) {
return address(_avsDirectory);
}

function _checkRewardsInitiator() internal view {
require(
msg.sender == rewardsInitiator,
"ServiceManagerBase.onlyRewardsInitiator: caller is not the rewards initiator"
);
}


function _checkSlasher() internal view {
require(
msg.sender == slasher,
"ServiceManagerBase.onlySlasher: caller is not the slasher"
);
}
}
13 changes: 10 additions & 3 deletions src/ServiceManagerBaseStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol";

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

/**
* @title Storage variables for the `ServiceManagerBase` contract.
Expand All @@ -25,6 +26,7 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab
IRewardsCoordinator internal immutable _rewardsCoordinator;
IRegistryCoordinator internal immutable _registryCoordinator;
IStakeRegistry internal immutable _stakeRegistry;
IAllocationManager internal immutable _allocationManager;

/**
*
Expand All @@ -35,21 +37,26 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab
/// @notice The address of the entity that can initiate rewards
address public rewardsInitiator;

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

bool public migrationFinalized;

/// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, and `_stakeRegistry` addresses
/// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, `_stakeRegistry`, and `_allocationManager` addresses
constructor(
IAVSDirectory __avsDirectory,
IRewardsCoordinator __rewardsCoordinator,
IRegistryCoordinator __registryCoordinator,
IStakeRegistry __stakeRegistry
IStakeRegistry __stakeRegistry,
IAllocationManager __allocationManager
) {
_avsDirectory = __avsDirectory;
_rewardsCoordinator = __rewardsCoordinator;
_registryCoordinator = __registryCoordinator;
_stakeRegistry = __stakeRegistry;
_allocationManager = __allocationManager;
}

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

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

import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol";
Expand Down Expand Up @@ -182,7 +182,7 @@ contract StakeRegistry is StakeRegistryStorage {
// Query the AVSDirectory to check if the operator is directly unregistered
operatorRegistered = avsDirectory.isMember(
operator,
IAVSDirectory.OperatorSet(address(serviceManager), operatorSetId)
OperatorSet(address(serviceManager), operatorSetId)
);

if (!hasMinimumStake || (isOperatorSetAVS && !operatorRegistered)) {
Expand Down Expand Up @@ -491,7 +491,8 @@ contract StakeRegistry is StakeRegistryStorage {
uint256 stratsLength = strategyParamsLength(quorumNumber);
StrategyParams memory strategyAndMultiplier;

uint256[] memory strategyShares = delegation.getOperatorShares(operator, strategiesPerQuorum[quorumNumber]);
uint256[] memory strategyShares;
// = delegation.getDelegatableShares(operator, strategiesPerQuorum[quorumNumber]);
for (uint256 i = 0; i < stratsLength; i++) {
// accessing i^th StrategyParams struct for the quorumNumber
strategyAndMultiplier = strategyParams[quorumNumber][i];
Expand Down
6 changes: 5 additions & 1 deletion src/interfaces/IServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity >=0.5.0;
import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
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";

/**
* @title Minimal interface for a ServiceManager-type contract that forms the single point for an AVS to push updates to EigenLayer
Expand All @@ -23,7 +24,7 @@ interface IServiceManager is IServiceManagerUI {
*/
function createAVSRewardsSubmission(IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions) external;

function createOperatorSets(uint32[] memory operatorSetIds) external ;
function createOperatorSets(uint32[] memory operatorSetIds) external;

/**
* @notice Forwards a call to EigenLayer's AVSDirectory contract to register an operator to operator sets
Expand All @@ -44,6 +45,9 @@ interface IServiceManager is IServiceManagerUI {
*/
function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external;

function slashOperator(IAllocationManagerTypes.SlashingParams memory params) external;

// EVENTS
event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator);
event SlasherUpdated(address prevSlasher, address newSlasher);
}
9 changes: 6 additions & 3 deletions src/libraries/SignatureCheckerLib.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import {EIP1271SignatureUtils} from
"eigenlayer-contracts/src/contracts/libraries/EIP1271SignatureUtils.sol";
import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol";

/**
* @title SignatureCheckerLib
Expand All @@ -11,6 +10,8 @@ import {EIP1271SignatureUtils} from
* validation logic to this external library.
*/
library SignatureCheckerLib {
error InvalidSignature();

/**
* @notice Validates a signature using EIP-1271 standard.
* @param signer The address of the signer.
Expand All @@ -22,6 +23,8 @@ library SignatureCheckerLib {
bytes32 digestHash,
bytes memory signature
) external view {
EIP1271SignatureUtils.checkSignature_EIP1271(signer, digestHash, signature);
if (!SignatureCheckerUpgradeable.isValidSignatureNow(signer, digestHash, signature)) {
revert InvalidSignature();
}
}
}
33 changes: 33 additions & 0 deletions src/slashers/SimpleSlasher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {IServiceManager} from "../interfaces/IServiceManager.sol";
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 {
serviceManager = _serviceManager;
}

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

IAllocationManagerTypes.SlashingParams memory params = IAllocationManagerTypes.SlashingParams({
operator: operator,
operatorSetId: operatorSetId,
strategies: strategies,
wadToSlash: wadToSlash,
description: description
});

IServiceManager(serviceManager).slashOperator(params);
}
}
8 changes: 8 additions & 0 deletions src/slashers/SlasherStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.12;

contract SlasherStorage {
address public serviceManager;

uint256[49] private __gap;
}
6 changes: 4 additions & 2 deletions src/unaudited/ECDSAServiceManagerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,10 @@ abstract contract ECDSAServiceManagerBase is
for (uint256 i; i < count; i++) {
strategies[i] = quorum.strategies[i].strategy;
}
uint256[] memory shares = IDelegationManager(delegationManager)
.getOperatorShares(_operator, strategies);
uint256[] memory shares;
// TODO: Fix
// = IDelegationManager(delegationManager)
// .getOperatorShares(_operator, strategies);

uint256 activeCount;
for (uint256 i; i < count; i++) {
Expand Down
Loading

0 comments on commit eb0d6ad

Please sign in to comment.