Skip to main content

EigenLayerVerifier

Overview​

EigenLayerVerifier is a custom ICustomVerifier implementation tailored to securely authorize calls to EigenLayer contracts like DelegationManager, StrategyManager, and RewardsCoordinator. It uses strict role-based gating, exact calldata matching, and entity specific validation to ensure that only authorized vaults and bots can interact with EigenLayer staking, delegation, withdrawal, and rewards workflows.

This verifier protects EigenLayer operations by:

  • Ensuring only whitelisted entities (vaults, strategies, operators) can execute actions.
  • Verifying target contracts and function selectors precisely.
  • Enforcing exact calldata encoding to eliminate any ambiguity or abuse.

Roles and Permissions​

Role Definitions​

Role ConstantDescription
CALLER_ROLEAddress allowed to initiate EigenLayer calls (typically curators)
ASSET_ROLEWhitelisted ERC20 token allowed in strategy deposits or withdrawals
STRATEGY_ROLEWhitelisted EigenLayer strategy contracts
OPERATOR_ROLEApproved EigenLayer operator address for delegation
MELLOW_VAULT_ROLEWhitelisted vaults acting as stakers or earners (usually Subvault)
RECEIVER_ROLEAuthorized receivers for claimed rewards

Configuration and State​

Constructor​

constructor(address delegationManager_, address strategyManager_, address rewardsCoordinator_, string memory name_, uint256 version_)

Initializes the verifier by:

  • Setting immutable references to EigenLayer's DelegationManager, StrategyManager, and RewardsCoordinator.
  • Inheriting access control via OwnedCustomVerifier.

Behavior​

General Preconditions​

  • who must have CALLER_ROLE.
  • value must be 0 (no ETH allowed).
  • callData.length >= 4 (valid selector).

Validated Targets & Selectors​

StrategyManager – depositIntoStrategy​

depositIntoStrategy(IStrategy, address asset, uint256 amount)

  • Strategy must have STRATEGY_ROLE.
  • Asset must have ASSET_ROLE.
  • The deposit token amount must be non-zero; this argument is not a number of strategy shares.
  • Calldata must match.

DelegationManager​

delegateTo(address operator, SignatureWithExpiry signature, bytes32 salt)

  • Operator must have OPERATOR_ROLE.
  • Calldata must match.

queueWithdrawals(QueuedWithdrawalParams[] params)

  • Only one params.length == 1 allowed.
  • Param must include one strategy with STRATEGY_ROLE and one deposit share > 0.
  • Calldata must match.

completeQueuedWithdrawal(Withdrawal, address[] tokens, bool receiveAsTokens)

  • receiveAsTokens must be true.
  • Withdrawal must have only one strategy with STRATEGY_ROLE and staker with MELLOW_VAULT_ROLE.
  • tokens.length == 1 and token must have ASSET_ROLE.
  • Calldata must match.

RewardsCoordinator – processClaim​

Selector: processClaim(RewardsMerkleClaim claimData, address receiver)

  • claimData.earnerLeaf.earner must have MELLOW_VAULT_ROLE.
  • receiver must have RECEIVER_ROLE.
  • Calldata must match.

Functions​

verifyCall​

function verifyCall(
address who,
address where,
uint256 value,
bytes calldata callData,
bytes calldata /* verificationData */
) external view override returns (bool)

Invariants and Limitations​

Security Properties​

  • Role enforcement: Prevents unauthorized usage of EigenLayer functions.
  • Exact calldata match: Avoids incorrect encoding or maliciously crafted data.
  • Zero ETH transfers: Disallows unexpected native token usage.
  • Single param enforcement (withdrawals): Minimizes complexity and risk surface.