Skip to content

Commit

Permalink
feat(contracts): implement IServiceManager
Browse files Browse the repository at this point in the history
  • Loading branch information
mempirate committed Oct 23, 2024
1 parent 71c787c commit 333d8dd
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 22 deletions.
1 change: 1 addition & 0 deletions bolt-contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ remappings = [
"@relic/=lib/relic-sdk/packages/contracts",
"@symbiotic/=lib/core/src/",
"@eigenlayer/=lib/eigenlayer-contracts/",
"@eigenlayer-middleware/=lib/eigenlayer-middleware/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/",
Expand Down
87 changes: 65 additions & 22 deletions bolt-contracts/src/contracts/BoltEigenLayerMiddlewareV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {IBoltValidatorsV1} from "../interfaces/IBoltValidatorsV1.sol";
import {IBoltMiddlewareV1} from "../interfaces/IBoltMiddlewareV1.sol";
import {IBoltManagerV1} from "../interfaces/IBoltManagerV1.sol";

import {IServiceManager} from "@eigenlayer-middleware/src/interfaces/IServiceManager.sol";
import {IStrategyManager} from "@eigenlayer/src/contracts/interfaces/IStrategyManager.sol";
import {IServiceManager} from "@eigenlayer/src/contracts/interfaces/IServiceManager.sol";
import {IAVSDirectory} from "@eigenlayer/src/contracts/interfaces/IAVSDirectory.sol";
import {IDelegationManager} from "@eigenlayer/src/contracts/interfaces/IDelegationManager.sol";
import {ISignatureUtils} from "@eigenlayer/src/contracts/interfaces/ISignatureUtils.sol";
Expand All @@ -31,7 +31,7 @@ import {StrategyManagerStorage} from "@eigenlayer/src/contracts/core/StrategyMan
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
/// To validate the storage layout, use the Openzeppelin Foundry Upgrades toolkit.
/// You can also validate manually with forge: forge inspect <contract> storage-layout --pretty
contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, OwnableUpgradeable, UUPSUpgradeable {
contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, IServiceManager, OwnableUpgradeable, UUPSUpgradeable {
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableMap for EnumerableMap.AddressToUintMap;
using MapWithTimeData for EnumerableMap.AddressToUintMap;
Expand Down Expand Up @@ -184,8 +184,7 @@ contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, OwnableUpgradeable, UU
revert NotOperator();
}

// Register the operator to the AVS directory for this AVS
AVS_DIRECTORY.registerOperatorToAVS(msg.sender, operatorSignature);
registerOperatorToAVS(msg.sender, operatorSignature);

// Register the operator in the manager
manager.registerOperator(msg.sender, rpc);
Expand All @@ -199,7 +198,7 @@ contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, OwnableUpgradeable, UU
revert NotRegistered();
}

AVS_DIRECTORY.deregisterOperatorFromAVS(msg.sender);
deregisterOperatorFromAVS(msg.sender);

manager.deregisterOperator(msg.sender);
}
Expand Down Expand Up @@ -257,8 +256,6 @@ contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, OwnableUpgradeable, UU

uint48 epochStartTs = getEpochStartTs(getEpochAtTs(Time.timestamp()));

IStrategy[] memory strategyImpls = new IStrategy[](strategies.length());

for (uint256 i = 0; i < strategies.length(); ++i) {
(address strategy, uint48 enabledTime, uint48 disabledTime) = strategies.atWithTimes(i);

Expand All @@ -271,14 +268,8 @@ contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, OwnableUpgradeable, UU
address collateral = address(strategyImpl.underlyingToken());
collateralTokens[i] = collateral;

strategyImpls[i] = strategyImpl;
}

// NOTE: order is preserved, which is why we can use the same index for both arrays below
uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares(operator, strategyImpls);

for (uint256 i = 0; i < strategyImpls.length; ++i) {
amounts[i] = strategyImpls[i].sharesToUnderlyingView(shares[i]);
uint256 shares = DELEGATION_MANAGER.operatorShares(operator, strategyImpl);
amounts[i] = strategyImpl.sharesToUnderlyingView(shares);
}

return (collateralTokens, amounts);
Expand Down Expand Up @@ -309,9 +300,6 @@ contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, OwnableUpgradeable, UU

uint48 epochStartTs = getEpochStartTs(getEpochAtTs(timestamp));

// NOTE: Can this be done more gas-efficiently?
IStrategy[] memory strategyMem = new IStrategy[](1);

for (uint256 i = 0; i < strategies.length(); i++) {
(address strategy, uint48 enabledTime, uint48 disabledTime) = strategies.atWithTimes(i);

Expand All @@ -323,10 +311,8 @@ contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, OwnableUpgradeable, UU
continue;
}

strategyMem[0] = IStrategy(strategy);
// NOTE: order is preserved i.e., shares[i] corresponds to strategies[i]
uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares(operator, strategyMem);
amount += IStrategy(strategy).sharesToUnderlyingView(shares[0]);
uint256 shares = DELEGATION_MANAGER.operatorShares(operator, IStrategy(strategy));
amount += IStrategy(strategy).sharesToUnderlyingView(shares);
}

return amount;
Expand All @@ -352,4 +338,61 @@ contract BoltEigenLayerMiddlewareV1 is IBoltMiddlewareV1, OwnableUpgradeable, UU
function _wasEnabledAt(uint48 enabledTime, uint48 disabledTime, uint48 timestamp) private pure returns (bool) {
return enabledTime != 0 && enabledTime <= timestamp && (disabledTime == 0 || disabledTime >= timestamp);
}

// ============== EIGENLAYER SERVICE MANAGER ================= //
// Cfr. https://docs.eigenlayer.xyz/developers/avs-dashboard-onboarding
// getOperatorRestakedStrategies and getRestakeableStrategies have reference implementations
// that read from RegistryCoordinator & StakeRegistry. These are middleware contracts that
// are not used in the EigenLayer operator CLI as of today (23 Oct 2024): https://github.com/Layr-Labs/eigensdk-go/blob/0042b1a0dd502bb03c6bf1da85fc096c5c8e8f1b/chainio/clients/elcontracts/writer.go#L158
//
// So we'll just get that information from our own system for now.

function registerOperatorToAVS(
address operator,
ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature
) public override {
// Register the operator to the AVS directory for this AVS
AVS_DIRECTORY.registerOperatorToAVS(operator, operatorSignature);
}

function deregisterOperatorFromAVS(
address operator
) public override {
// NOTE: need to do this check because these functions have to be public
if (msg.sender != operator) {
revert NotAllowed();
}

AVS_DIRECTORY.deregisterOperatorFromAVS(operator);
}

function getOperatorRestakedStrategies(
address operator
) external view override returns (address[] memory) {
address[] memory restakedStrategies = new address[](strategies.length());

uint48 epochStartTs = getEpochStartTs(getEpochAtTs(Time.timestamp()));

for (uint256 i = 0; i < strategies.length(); ++i) {
(address strategy, uint48 enabledTime, uint48 disabledTime) = strategies.atWithTimes(i);

if (!_wasEnabledAt(enabledTime, disabledTime, epochStartTs)) {
continue;
}

if (DELEGATION_MANAGER.operatorShares(operator, IStrategy(strategy)) > 0) {
restakedStrategies[restakedStrategies.length] = strategy;
}
}

return restakedStrategies;
}

function getRestakeableStrategies() external view override returns (address[] memory) {
return strategies.keys();
}

function avsDirectory() external view override returns (address) {
return address(AVS_DIRECTORY);
}
}

0 comments on commit 333d8dd

Please sign in to comment.