Skip to content

Commit

Permalink
chore(contracts): update to eigen m2 fixes (#311)
Browse files Browse the repository at this point in the history
Update to eigen dependency to m2-mainnet-fixes branch

- add AVSDirectory
- trim unnused eigenlayer test utils

task: none
  • Loading branch information
kevinhalliday authored Feb 16, 2024
1 parent 507ea5b commit 0f91069
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 1,561 deletions.
4 changes: 2 additions & 2 deletions contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"dependencies": {
"@openzeppelin/contracts": "4.9.3",
"@openzeppelin/contracts-upgradeable": "4.9.3",
"eigenlayer-contracts": "github:Layr-Labs/eigenlayer-contracts",
"eigenlayer-middleware": "github:Layr-Labs/eigenlayer-middleware"
"eigenlayer-contracts": "github:Layr-Labs/eigenlayer-contracts#m2-mainnet-fixes",
"eigenlayer-middleware": "github:Layr-Labs/eigenlayer-middleware#m2-mainnet-fixes"
}
}
18 changes: 9 additions & 9 deletions contracts/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 15 additions & 5 deletions contracts/src/protocol/OmniAVS.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ pragma solidity =0.8.12;
import { OwnableUpgradeable } from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";

import { DelegationManager } from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol";
import { IStrategy } from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import { IDelegationManager } from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol";
import { IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";
import { IStrategy } from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import { ISignatureUtils } from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol";
import { IServiceManager } from "eigenlayer-middleware/src/interfaces/IServiceManager.sol";

Expand All @@ -22,6 +23,9 @@ contract OmniAVS is IOmniAVS, IOmniAVSAdmin, IServiceManager, OwnableUpgradeable
/// @notice EigenLayer core DelegationManager
IDelegationManager public immutable _delegationManager;

/// @notice EigenLayer core AVSDirectory
IAVSDirectory public immutable _avsDirectory;

/// @notice Maximum number of operators that can be registered
uint32 public maxOperatorCount;

Expand All @@ -46,8 +50,9 @@ contract OmniAVS is IOmniAVS, IOmniAVSAdmin, IServiceManager, OwnableUpgradeable
/// @dev OmniPortal.xcall base gas limit in syncWithOmni
uint256 internal xcallBaseGasLimit = 75_000;

constructor(IDelegationManager delegationManager_) {
constructor(IDelegationManager delegationManager_, IAVSDirectory avsDirectory_) {
_delegationManager = delegationManager_;
_avsDirectory = avsDirectory_;
_disableInitializers();
}

Expand Down Expand Up @@ -110,7 +115,7 @@ contract OmniAVS is IOmniAVS, IOmniAVSAdmin, IServiceManager, OwnableUpgradeable
require(_getStaked(operator) >= minimumOperatorStake, "OmniAVS: minimum stake not met");
require(!_isOperator(operator), "OmniAVS: already an operator"); // we could let delegation.regsiterOperatorToAVS handle this, they do check

_delegationManager.registerOperatorToAVS(operator, operatorSignature);
_avsDirectory.registerOperatorToAVS(operator, operatorSignature);
_addOperator(operator);

emit OperatorAdded(operator);
Expand All @@ -121,7 +126,7 @@ contract OmniAVS is IOmniAVS, IOmniAVSAdmin, IServiceManager, OwnableUpgradeable
require(msg.sender == operator, "OmniAVS: only operator");
require(_isOperator(operator), "OmniAVS: not an operator");

_delegationManager.deregisterOperatorFromAVS(operator);
_avsDirectory.deregisterOperatorFromAVS(operator);
_removeOperator(operator);

emit OperatorRemoved(operator);
Expand Down Expand Up @@ -159,7 +164,7 @@ contract OmniAVS is IOmniAVS, IOmniAVSAdmin, IServiceManager, OwnableUpgradeable

/// @inheritdoc IServiceManager
function setMetadataURI(string memory metadataURI) external onlyOwner {
_delegationManager.updateAVSMetadataURI(metadataURI);
_avsDirectory.updateAVSMetadataURI(metadataURI);
}

/// @inheritdoc IOmniAVSAdmin
Expand Down Expand Up @@ -228,6 +233,11 @@ contract OmniAVS is IOmniAVS, IOmniAVSAdmin, IServiceManager, OwnableUpgradeable
return strategies;
}

/// @inheritdoc IServiceManager
function avsDirectory() external view returns (address) {
return address(_avsDirectory);
}

/// @dev Return current list of Validators, including their personal stake and delegated stake
function _getValidators() internal view returns (Validator[] memory) {
Validator[] memory vals = new Validator[](operators.length);
Expand Down
2 changes: 1 addition & 1 deletion contracts/test/avs/AVSBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ contract AVSBase is EigenLayerTestHelper {
vm.startPrank(proxyAdminOwner);
omniAVS =
OmniAVSHarness(address(new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")));
omniAVSImplementation = new OmniAVSHarness(delegation);
omniAVSImplementation = new OmniAVSHarness(delegation, avsDirectory);
proxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(omniAVS))), address(omniAVSImplementation));
vm.stopPrank();

Expand Down
5 changes: 4 additions & 1 deletion contracts/test/avs/OmniAVSHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ pragma solidity =0.8.12;

import { OmniAVS } from "src/protocol/OmniAVS.sol";
import { IDelegationManager } from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol";
import { IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";

/**
* @title OmniAVSHarness
* @dev Wrapper around OmniAVS that exposes internal functions.
*/
contract OmniAVSHarness is OmniAVS {
constructor(IDelegationManager delegationManager) OmniAVS(delegationManager) { }
constructor(IDelegationManager delegationManager, IAVSDirectory avsDirectory)
OmniAVS(delegationManager, avsDirectory)
{ }

function xcallGasLimitFor(uint256 numValidators) external view returns (uint64) {
return _xcallGasLimitFor(numValidators);
Expand Down
191 changes: 191 additions & 0 deletions contracts/test/avs/eigen/AVSDirectoryMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol";

import "eigenlayer-contracts/src/contracts/permissions/Pausable.sol";
import "eigenlayer-contracts/src/contracts/libraries/EIP1271SignatureUtils.sol";
import "eigenlayer-contracts/src/contracts/core/AVSDirectoryStorage.sol";

/**
* @dev Copied from eignlayer-contracts src/contracts/core/AVSDirectory.sol. This contract contains all AVSDirector
* logic, with some checks removed for testing purposes -
* - registerOperatorToAVS signature checks removed
*
* @custom:attribution https://github.com/Layr-Labs/eigenlayer-contracts/blob/m2-mainnet-fixes/src/contracts/core/AVSDirectory.sol
*/
contract AVSDirectoryMock is
Initializable,
OwnableUpgradeable,
Pausable,
AVSDirectoryStorage,
ReentrancyGuardUpgradeable
{
// @dev Index for flag that pauses operator register/deregister to avs when set.
uint8 internal constant PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS = 0;

// @dev Chain ID at the time of contract deployment
uint256 internal immutable ORIGINAL_CHAIN_ID;

/**
*
* INITIALIZING FUNCTIONS
*
*/

/**
* @dev Initializes the immutable addresses of the strategy mananger, delegationManager, slasher,
* and eigenpodManager contracts
*/
constructor(IDelegationManager _delegation) AVSDirectoryStorage(_delegation) {
_disableInitializers();
ORIGINAL_CHAIN_ID = block.chainid;
}

/**
* @dev Initializes the addresses of the initial owner, pauser registry, and paused status.
* minWithdrawalDelayBlocks is set only once here
*/
function initialize(address initialOwner, IPauserRegistry _pauserRegistry, uint256 initialPausedStatus)
external
initializer
{
_initializePauser(_pauserRegistry, initialPausedStatus);
_DOMAIN_SEPARATOR = _calculateDomainSeparator();
_transferOwnership(initialOwner);
}

/**
*
* EXTERNAL FUNCTIONS
*
*/

/**
* @notice Called by the AVS's service manager contract to register an operator with the avs.
* @param operator The address of the operator to register.
* @param operatorSignature The signature, salt, and expiry of the operator's signature.
*/
function registerOperatorToAVS(
address operator,
ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature
) external onlyWhenNotPaused(PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS) {
// require(
// operatorSignature.expiry >= block.timestamp,
// "AVSDirectory.registerOperatorToAVS: operator signature expired"
// );
require(
avsOperatorStatus[msg.sender][operator] != OperatorAVSRegistrationStatus.REGISTERED,
"AVSDirectory.registerOperatorToAVS: operator already registered"
);
require(
!operatorSaltIsSpent[operator][operatorSignature.salt],
"AVSDirectory.registerOperatorToAVS: salt already spent"
);
require(
delegation.isOperator(operator),
"AVSDirectory.registerOperatorToAVS: operator not registered to EigenLayer yet"
);

// // Calculate the digest hash
// bytes32 operatorRegistrationDigestHash = calculateOperatorAVSRegistrationDigestHash({
// operator: operator,
// avs: msg.sender,
// salt: operatorSignature.salt,
// expiry: operatorSignature.expiry
// });

// // Check that the signature is valid
// EIP1271SignatureUtils.checkSignature_EIP1271(
// operator, operatorRegistrationDigestHash, operatorSignature.signature
// );

// Set the operator as registered
avsOperatorStatus[msg.sender][operator] = OperatorAVSRegistrationStatus.REGISTERED;

// Mark the salt as spent
operatorSaltIsSpent[operator][operatorSignature.salt] = true;

emit OperatorAVSRegistrationStatusUpdated(operator, msg.sender, OperatorAVSRegistrationStatus.REGISTERED);
}

/**
* @notice Called by an avs to deregister an operator with the avs.
* @param operator The address of the operator to deregister.
*/
function deregisterOperatorFromAVS(address operator)
external
onlyWhenNotPaused(PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS)
{
require(
avsOperatorStatus[msg.sender][operator] == OperatorAVSRegistrationStatus.REGISTERED,
"AVSDirectory.deregisterOperatorFromAVS: operator not registered"
);

// Set the operator as deregistered
avsOperatorStatus[msg.sender][operator] = OperatorAVSRegistrationStatus.UNREGISTERED;

emit OperatorAVSRegistrationStatusUpdated(operator, msg.sender, OperatorAVSRegistrationStatus.UNREGISTERED);
}

/**
* @notice Called by an avs to emit an `AVSMetadataURIUpdated` event indicating the information has updated.
* @param metadataURI The URI for metadata associated with an avs
*/
function updateAVSMetadataURI(string calldata metadataURI) external {
emit AVSMetadataURIUpdated(msg.sender, metadataURI);
}

/**
* @notice Called by an operator to cancel a salt that has been used to register with an AVS.
* @param salt A unique and single use value associated with the approver signature.
*/
function cancelSalt(bytes32 salt) external {
require(!operatorSaltIsSpent[msg.sender][salt], "AVSDirectory.cancelSalt: cannot cancel spent salt");
operatorSaltIsSpent[msg.sender][salt] = true;
}

/**
*
* VIEW FUNCTIONS
*
*/

/**
* @notice Calculates the digest hash to be signed by an operator to register with an AVS
* @param operator The account registering as an operator
* @param avs The address of the service manager contract for the AVS that the operator is registering to
* @param salt A unique and single use value associated with the approver signature.
* @param expiry Time after which the approver's signature becomes invalid
*/
function calculateOperatorAVSRegistrationDigestHash(address operator, address avs, bytes32 salt, uint256 expiry)
public
view
returns (bytes32)
{
// calculate the struct hash
bytes32 structHash = keccak256(abi.encode(OPERATOR_AVS_REGISTRATION_TYPEHASH, operator, avs, salt, expiry));
// calculate the digest hash
bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator(), structHash));
return digestHash;
}

/**
* @notice Getter function for the current EIP-712 domain separator for this contract.
* @dev The domain separator will change in the event of a fork that changes the ChainID.
*/
function domainSeparator() public view returns (bytes32) {
if (block.chainid == ORIGINAL_CHAIN_ID) {
return _DOMAIN_SEPARATOR;
} else {
return _calculateDomainSeparator();
}
}

// @notice Internal function for calculating the current domain separator of this contract
function _calculateDomainSeparator() internal view returns (bytes32) {
return keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes("EigenLayer")), block.chainid, address(this)));
}
}
Loading

0 comments on commit 0f91069

Please sign in to comment.