1. EigenLayer Architecture
EigenLayer is a middleware protocol on Ethereum that introduces the concept of restaking: taking already-staked ETH (either native or via liquid staking tokens) and using that same cryptoeconomic security to bootstrap trust for additional protocols and applications.
The design elegantly solves the "cold-start problem" for new protocols that need a secure validator set — instead of bootstrapping their own token and validator set, they lease security from Ethereum's existing $100B+ stake through EigenLayer.
Core Contracts
Agents interacting with EigenLayer must understand three primary smart contract interfaces:
- StrategyManager: Entry point for LST (liquid staking token) deposits. Agents deposit tokens like wstETH, cbETH, rETH here to receive "shares" representing their restaked position.
- EigenPodManager: Manages native ETH restaking via EigenPods — special smart contract wallets that redirect validator withdrawal credentials to EigenLayer.
- DelegationManager: Allows restakers to delegate their restaked stake to Operators who then provide validation services to AVSs.
The Restaking Lifecycle for Agents
- Deposit LSTs (wstETH, rETH, cbETH) into StrategyManager or stake native ETH via EigenPod
- Delegate restaked stake to a chosen Operator via DelegationManager
- Operator registers to validate for one or more AVSs
- AVS pays Operators in its native token; Operators share rewards with restakers
- Earn EigenLayer points on top (eventually converted to EIGEN airdrop/yield)
2. Native vs LST Restaking
EigenLayer supports two fundamentally different restaking approaches, each with distinct requirements, yields, and risk profiles.
LST Restaking
The simpler path. Deposit supported liquid staking tokens directly into EigenLayer's StrategyManager. No validator operation required. The agent simply holds LSTs in an EigenLayer strategy and delegates to an Operator.
Supported tokens and their strategies:
| Token | Protocol | Strategy Address (prefix) | Base APR |
|---|---|---|---|
| stETH | Lido | 0x93c4b9... | 3.8% |
| wstETH | Lido (wrapped) | 0x7ca911... | 3.8% |
| rETH | Rocket Pool | 0x1bea3c... | 3.6% |
| cbETH | Coinbase | 0x54945b... | 3.4% |
| ETHx | Stader | 0x9d7eD... | 4.1% |
| osETH | StakeWise | 0x57ba4... | 3.7% |
| swETH | Swell | 0x0fe4f... | 3.9% |
Native ETH Restaking via EigenPod
Native restaking requires running or controlling Ethereum validators with withdrawal credentials pointed at an EigenPod smart contract. The agent must operate (or delegate operation of) a validator node. The setup is significantly more complex but offers the highest EIGEN points multiplier and no LST wrapper risk.
EIGENPOD_MANAGER = "0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338"
class EigenPodAgent:
"""Manage native ETH restaking via EigenPod."""
def __init__(self, w3, account):
self.w3 = w3
self.account = account
self.pod_manager = w3.eth.contract(
address=EIGENPOD_MANAGER,
abi=EIGENPOD_MANAGER_ABI
)
def create_pod(self) -> str:
"""Deploy a new EigenPod for this agent's address."""
tx = self.pod_manager.functions.createPod().build_transaction({
'from': self.account.address,
'gas': 500000,
'nonce': self.w3.eth.get_transaction_count(self.account.address)
})
signed = self.account.sign_transaction(tx)
tx_hash = self.w3.eth.send_raw_transaction(signed.rawTransaction)
return tx_hash.hex()
def get_pod_address(self) -> str:
"""Get the EigenPod address for this agent."""
return self.pod_manager.functions.ownerToPod(
self.account.address
).call()
def verify_withdrawal_credentials(
self,
oracle_block_number: int,
validator_indices: list,
withdrawal_credential_proofs: list,
validator_fields: list
) -> str:
"""Verify validator withdrawal credentials point to EigenPod."""
pod_address = self.get_pod_address()
pod = self.w3.eth.contract(address=pod_address, abi=EIGENPOD_ABI)
tx = pod.functions.verifyWithdrawalCredentials(
oracle_block_number,
validator_indices,
withdrawal_credential_proofs,
validator_fields
).build_transaction({
'from': self.account.address,
'gas': 800000,
'nonce': self.w3.eth.get_transaction_count(self.account.address)
})
signed = self.account.sign_transaction(tx)
return self.w3.eth.send_raw_transaction(signed.rawTransaction).hex()
Comparison Table
| Factor | LST Restaking | Native ETH Restaking |
|---|---|---|
| Complexity | Low | High |
| Min stake | Any amount | 32 ETH per validator |
| Points multiplier | 1x | 2x (typically) |
| Additional risk | LST smart contract risk | Validator operation risk |
| Liquidity | 7-day withdrawal delay | 7-day + validator exit |
| Gas overhead | Low | High (proof verification) |
| Best for agents | Most agents | Agents with validator infra |
3. AVS Ecosystem
Actively Validated Services are the protocols that rent cryptoeconomic security from EigenLayer. Each AVS has unique reward structures, operational requirements, and slashing conditions. Agent restakers must understand the AVS landscape to make informed delegation decisions.
EigenDA
Ethereum's largest data availability layer. Powers rollups needing cheap, fast DA. Extremely well-funded and low slashing risk.
AltLayer
Restaked rollup infrastructure. Provides decentralized sequencer and fast finality for L2s. Active mainnet with growing fee revenue.
Lagrange
ZK coprocessor network. Enables trustless off-chain computation proofs verified on-chain. High technical requirements for operators.
Hyperlane
Permissionless interoperability protocol. ISM (Interchain Security Module) validation via EigenLayer. Cross-chain message security.
Omni Network
Cross-rollup coordination layer. Restaked ETH secures cross-rollup messaging. Native OMNI token rewards for validators.
Witness Chain
Decentralized oracle for physical world state (watchtowers, location proofs). Novel AVS with higher yield but newer code.
4. Operator Selection Criteria
Restakers don't validate AVSs directly — they delegate their stake to Operators who run the actual infrastructure. Choosing the right operator significantly impacts both yield and slashing risk.
Key Evaluation Metrics
- Total delegated stake: Higher stake = more AVS interest, but also higher slashing exposure per slash event
- Number of AVSs validated: More AVSs = more reward streams, but also more operational complexity and slashing vectors
- Operator commission rate: Operators take 5-20% of rewards before passing to restakers
- Uptime history: Check on-chain evidence of operator reliability via AVS penalty events
- DVT adoption: Operators using Distributed Validator Technology (SSV, Obol) have lower single-point-of-failure risk
import httpx
from dataclasses import dataclass
from typing import List
@dataclass
class OperatorMetrics:
address: str
total_stake: int # in wei
avs_count: int
commission_bps: int # basis points (1000 = 10%)
uptime_score: float # 0-1 scale
dvt_enabled: bool
slashing_events: int
class OperatorSelector:
"""Score and select optimal EigenLayer operators."""
def score_operator(self, op: OperatorMetrics) -> float:
"""Compute composite operator score (higher = better)."""
# Weights: uptime 40%, commission 30%, slashing 20%, DVT 10%
uptime_score = op.uptime_score * 40
commission_score = (1 - op.commission_bps / 10000) * 30
slashing_penalty = min(op.slashing_events * 5, 20)
dvt_bonus = 10 if op.dvt_enabled else 0
return uptime_score + commission_score - slashing_penalty + dvt_bonus
def select_top_operators(
self,
operators: List[OperatorMetrics],
n: int = 3,
max_stake_wei: int = 100_000 * 10**18
) -> List[OperatorMetrics]:
"""Select top N operators by score, excluding over-concentrated ones."""
eligible = [
op for op in operators
if op.total_stake <= max_stake_wei # avoid over-concentrated operators
and op.slashing_events == 0 # zero tolerance for slashing history
]
scored = [(self.score_operator(op), op) for op in eligible]
scored.sort(reverse=True)
return [op for _, op in scored[:n]]
async def fetch_operators(self, eigen_api_url: str) -> List[OperatorMetrics]:
"""Fetch operator data from EigenLayer indexer API."""
async with httpx.AsyncClient() as client:
resp = await client.get(f"{eigen_api_url}/v1/operators")
data = resp.json()
return [
OperatorMetrics(
address=op['address'],
total_stake=int(op['totalStake']),
avs_count=op['avsCount'],
commission_bps=op['commissionBps'],
uptime_score=op['uptimeScore'],
dvt_enabled=op['dvtEnabled'],
slashing_events=op['slashingEvents']
)
for op in data['operators']
]
5. Points Farming Mechanics
EigenLayer distributes "EigenLayer Points" to restakers as a precursor to real yield and governance tokens. Points accrue based on:
- Amount of ETH restaked (1 point per ETH-hour)
- LST multipliers (different LSTs have different point rates)
- AVS-specific points programs (many AVSs run their own parallel points campaigns)
- Referral programs for bringing in new restakers
Multi-Points Strategy
Sophisticated agents stack multiple points programs simultaneously. A wstETH position restaked through EigenLayer and also delegated to an operator validating EigenDA earns:
- Lido staking rewards (3.8% APR)
- EigenLayer points (EIGEN token expectation)
- EigenDA operator rewards (when distributed)
- Liquid restaking token points if using LRT wrappers (ezETH, rsETH, pzETH, etc.)
from dataclasses import dataclass
from datetime import datetime, timedelta
@dataclass
class PointsPosition:
protocol: str
token: str
amount_eth: float
start_time: datetime
point_rate: float # points per ETH per hour
multiplier: float = 1.0
class PointsTracker:
"""Track multi-protocol restaking points accumulation."""
def __init__(self):
self.positions: list[PointsPosition] = []
self.total_points: dict[str, float] = {}
def add_position(self, position: PointsPosition):
self.positions.append(position)
if position.protocol not in self.total_points:
self.total_points[position.protocol] = 0.0
def calculate_points(self, as_of: datetime = None) -> dict[str, float]:
"""Calculate accumulated points across all protocols."""
now = as_of or datetime.utcnow()
result = {}
for pos in self.positions:
hours_elapsed = (now - pos.start_time).total_seconds() / 3600
points = pos.amount_eth * pos.point_rate * pos.multiplier * hours_elapsed
result[pos.protocol] = result.get(pos.protocol, 0) + points
return result
def estimate_token_value(
self,
points: dict[str, float],
price_assumptions: dict[str, float] # $/point for each protocol
) -> float:
"""Estimate USD value of accumulated points."""
return sum(
points.get(protocol, 0) * price_per_point
for protocol, price_per_point in price_assumptions.items()
)
# Example usage
tracker = PointsTracker()
tracker.add_position(PointsPosition(
protocol="eigenlayer",
token="wstETH",
amount_eth=10.0,
start_time=datetime(2026, 1, 1),
point_rate=1.0, # 1 point per ETH per hour
multiplier=1.0
))
6. Slashing Risk Profile
EigenLayer introduces a novel slashing risk: restaked ETH can be slashed by both the Ethereum base layer (for validator misbehavior) AND by AVS-specific conditions. Understanding both layers of slashing is critical for agents sizing their restaking positions.
Ethereum Base Layer Slashing
This is the same slashing risk all ETH stakers face: double-signing, surrounder violations, extended downtime. For LST restaking, this risk is borne by the LST protocol (Lido, Rocket Pool, etc.) and their node operators.
AVS-Specific Slashing
Each AVS defines its own slashing conditions. These can include:
- Signing invalid data batches (EigenDA)
- Providing fraudulent computation proofs (Lagrange, ZK coprocessors)
- Equivocating on finality votes (AltLayer fast finality)
- Failing to deliver cross-chain messages (Hyperlane)
Double-Slashing Risk: A restaker can be slashed by an AVS for AVS-specific misbehavior, reducing their restaked position. This is a new risk vector not present in simple staking. Agents must read each AVS's slashing conditions carefully and model worst-case loss scenarios before committing capital.
Quantifying Slashing Risk
import numpy as np
from scipy import stats
def model_slashing_risk(
avs_list: list[dict],
position_size_eth: float,
time_horizon_years: float = 1.0
) -> dict:
"""Model expected loss from slashing across multiple AVSs."""
expected_losses = []
var_95_losses = []
for avs in avs_list:
# Annual slashing probability and severity estimates
prob_slash = avs['annual_slash_prob'] * time_horizon_years
slash_severity = avs['slash_severity'] # fraction of stake lost
our_exposure = position_size_eth * avs['allocation_pct']
expected_loss = prob_slash * slash_severity * our_exposure
expected_losses.append(expected_loss)
# VaR: 95th percentile loss if slash occurs
var_loss = slash_severity * our_exposure if prob_slash > 0.05 else 0
var_95_losses.append(var_loss)
return {
'expected_loss_eth': sum(expected_losses),
'var_95_eth': max(var_95_losses), # worst-case single AVS slash
'expected_loss_pct': sum(expected_losses) / position_size_eth * 100
}
# Conservative slashing estimates for major AVSs
avs_risk_params = [
{'name': 'EigenDA', 'annual_slash_prob': 0.001, 'slash_severity': 0.1, 'allocation_pct': 1.0},
{'name': 'AltLayer', 'annual_slash_prob': 0.002, 'slash_severity': 0.05, 'allocation_pct': 1.0},
{'name': 'Lagrange', 'annual_slash_prob': 0.003, 'slash_severity': 0.15, 'allocation_pct': 0.5},
]
risk = model_slashing_risk(avs_risk_params, position_size_eth=10.0)
# Expected loss: ~0.0045 ETH/year across all AVSs
7. Combined Yield Calculation
The total yield from a restaking strategy is the sum of multiple streams. Here is a realistic model for a wstETH LST restaking position at $3,200/ETH:
| Yield Source | Type | APR | Notes |
|---|---|---|---|
| Lido staking rewards | Cash | 3.8% | Paid in stETH rebase |
| EigenDA operator rewards | Token | 1.5% | In EigenDA token, market price risk |
| AltLayer rewards | Token | 1.0% | In ALT token |
| EigenLayer EIGEN points | Points | ~1.2% | Estimated token conversion |
| Less: operator commission | Cost | -0.8% | 10% of AVS rewards |
| Less: gas costs | Cost | -0.3% | Annualized on $32K position |
| Less: expected slashing | Risk | -0.05% | Statistical expectation |
| Net APR | 6.35% | vs 3.8% for simple Lido staking |
8. Python EigenAgent with Delegation Management
The following EigenAgent class handles the full restaking lifecycle: deposit, delegation selection, ongoing monitoring, reward harvesting, and rebalancing delegation across operators based on performance.
import asyncio
import logging
from dataclasses import dataclass
from typing import Optional
from web3 import AsyncWeb3
logger = logging.getLogger('EigenAgent')
DELEGATION_MANAGER = "0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37b"
STRATEGY_MANAGER = "0x858646372CC42E1A627fcE94aa7A7033e7CF075A"
@dataclass
class EigenConfig:
target_token: str # wstETH address
target_strategy: str # EigenLayer strategy for wstETH
deposit_amount: int # in wei
rebalance_days: int = 30 # days between operator rebalancing
min_operator_score: float = 70.0
max_slashing_events: int = 0
class EigenAgent:
"""Complete EigenLayer restaking management agent."""
def __init__(self, w3: AsyncWeb3, account, config: EigenConfig):
self.w3 = w3
self.account = account
self.config = config
self.current_operator: Optional[str] = None
self.selector = OperatorSelector()
self.points_tracker = PointsTracker()
self.strategy_mgr = w3.eth.contract(
address=STRATEGY_MANAGER, abi=STRATEGY_MANAGER_ABI
)
self.delegation_mgr = w3.eth.contract(
address=DELEGATION_MANAGER, abi=DELEGATION_MANAGER_ABI
)
async def initialize(self):
"""Deposit into strategy and delegate to best operator."""
# Step 1: Deposit wstETH into EigenLayer strategy
logger.info(f"Depositing {self.config.deposit_amount/1e18:.4f} wstETH into EigenLayer")
await self._approve_and_deposit()
# Step 2: Select best operator
operators = await self.selector.fetch_operators("https://api.eigenlayer.xyz")
top_ops = self.selector.select_top_operators(operators, n=1)
if top_ops:
await self._delegate_to(top_ops[0].address)
self.current_operator = top_ops[0].address
logger.info(f"Delegated to operator {self.current_operator}")
# Step 3: Start points tracking
from datetime import datetime
self.points_tracker.add_position(PointsPosition(
protocol="eigenlayer",
token="wstETH",
amount_eth=self.config.deposit_amount / 1e18,
start_time=datetime.utcnow(),
point_rate=1.0
))
async def run(self, duration_days: int = 365):
"""Main agent loop: monitor health and rebalance operators."""
iterations = (duration_days * 24 * 3600) // (self.config.rebalance_days * 24 * 3600)
for _ in range(int(iterations)):
try:
await self._rebalance_operator_if_needed()
await self._log_position_summary()
except Exception as e:
logger.error(f"Agent error: {e}")
await asyncio.sleep(self.config.rebalance_days * 86400)
async def _rebalance_operator_if_needed(self):
"""Re-evaluate and switch operators if a better one exists."""
operators = await self.selector.fetch_operators("https://api.eigenlayer.xyz")
top_ops = self.selector.select_top_operators(operators, n=1)
if not top_ops:
logger.warning("No eligible operators found. Maintaining current delegation.")
return
best = top_ops[0]
current_score = self.selector.score_operator(
next((o for o in operators if o.address == self.current_operator), best)
)
best_score = self.selector.score_operator(best)
if best.address != self.current_operator and best_score > current_score + 10:
logger.info(f"Switching operator: {self.current_operator} → {best.address} (score {best_score:.1f} vs {current_score:.1f})")
await self._undelegate_and_redelegate(best.address)
self.current_operator = best.address
async def _log_position_summary(self):
points = self.points_tracker.calculate_points()
shares = self.strategy_mgr.functions.stakerStrategyShares(
self.account.address, self.config.target_strategy
).call()
logger.info(
f"Position: {shares/1e18:.4f} wstETH shares | "
f"EigenLayer points: {points.get('eigenlayer', 0):.2f} | "
f"Operator: {self.current_operator}"
)
async def _undelegate_and_redelegate(self, new_operator: str):
"""Undelegate from current operator, wait for completion, redelegate."""
# Queue withdrawal (7-day wait for native ETH, instant for LSTs)
tx = self.delegation_mgr.functions.undelegate(
self.account.address
).build_transaction({
'from': self.account.address,
'gas': 400000,
'nonce': self.w3.eth.get_transaction_count(self.account.address)
})
signed = self.account.sign_transaction(tx)
self.w3.eth.send_raw_transaction(signed.rawTransaction)
# For LSTs, re-delegation can happen immediately after undelegation
await self._delegate_to(new_operator)
9. Liquid Restaking Tokens (LRTs)
Rather than interacting with EigenLayer directly, agents can use Liquid Restaking Token (LRT) protocols that abstract the complexity. LRTs work like Lido does for ETH staking: deposit ETH or LSTs, receive a liquid receipt token that accrues restaking yield.
| Protocol | Token | TVL | Strategy | Extra Points |
|---|---|---|---|---|
| Ether.fi | eETH / weETH | $8.2B | Native ETH restaking | Ether.fi points + EIGEN |
| Renzo | ezETH | $3.1B | Multi-AVS LST | Renzo points + EIGEN |
| Kelp DAO | rsETH | $1.8B | Multi-LST restaking | Kelp miles + EIGEN |
| Puffer Finance | pufETH | $1.4B | Native ETH + DVT | Puffer points + EIGEN |
| Swell | rswETH | $0.9B | swETH restaking | Swell points + EIGEN |
LRT Advantage for Agents: Using LRTs like weETH or ezETH means no direct EigenLayer contract interactions, instant liquidity (trade the LRT token instead of queuing withdrawal), and automatic operator diversification. The trade-off is an additional smart contract layer and LRT governance risk.
10. Risk Framework for EigenLayer Agents
Agents must build a comprehensive risk framework before deploying capital into restaking. The unique risks of EigenLayer compound with existing staking risks to create a more complex risk surface than simple DeFi strategies.
Position Sizing Guidelines
- Max restaking allocation: Never exceed 50% of total ETH holdings in EigenLayer (maintain liquid reserves)
- LRT vs direct restaking: Use LRTs for first 20 ETH of exposure; direct for larger positions wanting full control
- AVS concentration: Ensure no single AVS's slashing condition can destroy more than 5% of total portfolio
- Operator diversification: Spread delegation across 3+ operators for positions above 100 ETH
Monitoring Checklist for Agents
class EigenRiskMonitor:
"""Continuous risk monitoring for EigenLayer positions."""
CHECKS = [
"operator_slashing_events",
"avs_governance_changes",
"lst_depeg_monitoring",
"withdrawal_delay_awareness",
"eigenlayer_contract_upgrades",
"points_program_changes",
]
async def run_all_checks(self) -> dict[str, bool]:
results = {}
for check in self.CHECKS:
check_fn = getattr(self, f"_check_{check}", None)
if check_fn:
results[check] = await check_fn()
return results
async def _check_operator_slashing_events(self) -> bool:
"""Return True if no new slashing events detected."""
# Check on-chain AVSDirectory for SlashingTriggered events
return True # simplified; real impl queries event logs
async def _check_avs_governance_changes(self) -> bool:
"""Check if any AVS has changed slashing conditions."""
# Monitor AVS contract upgrade proxies for impl changes
return True
async def _check_lst_depeg_monitoring(self) -> bool:
"""Verify LST trading at acceptable peg range."""
# Query Curve/Uniswap pools for LST vs ETH price
return True
The Agent Advantage: EigenLayer's complexity, withdrawal delays, and operator monitoring requirements are exactly the kind of tasks AI agents excel at. Human restakers rarely check on-chain slashing events, governance changes, or operator metrics more than once a week. Agents can monitor every block — turning EigenLayer's operational intensity into a competitive advantage.
Build Your Agent's Financial Stack on Purple Flea
Purple Flea provides 6 financial services built for AI agents: casino, perpetuals, wallet, domains, faucet (free trial funds), and escrow (trustless agent-to-agent payments). Start building today.
Explore Purple Flea