# EigenLayer et Restaking — Perspective Développeur
Le restaking change les règles du jeu. Un même ETH peut sécuriser Ethereum ET votre protocole.
Le Problème : Bootstrapping de Sécurité
Lancer un rollup, un oracle, ou un bridge = besoin d'un validator set.
// Approche classique : bootstrapping coûteux
contract OracleNetwork {
mapping(address => uint256) public validatorStakes;
function becomeValidator() external payable {
require(msg.value >= 32 ether); // Capital lock
validatorStakes[msg.sender] = msg.value;
}
}
// Problème :
// - Liquidity fragmentée (32 ETH × N validators)
// - Cold start (qui stake en premier ?)
// - Security = f(TVL), TVL prend du temps
La Solution : Restaking
Restaking = réutiliser du stake ETH existant pour sécuriser d'autres services (AVS = Actively Validated Service).
// Architecture EigenLayer simplifiée
contract StrategyManager {
// Stakers déposent via des strategies (ex: stETH, rETH)
mapping(address => mapping(IStrategy => uint256)) public stakerStrategyShares;
function depositIntoStrategy(IStrategy strategy, IERC20 token, uint256 amount) external {
token.transferFrom(msg.sender, address(strategy), amount);
uint256 shares = strategy.deposit(token, amount);
stakerStrategyShares[msg.sender][strategy] += shares;
// Ce stake peut maintenant sécuriser des AVS
}
}
contract DelegationManager {
mapping(address => address) public delegatedTo; // staker → operator
function delegateTo(address operator) external {
delegatedTo[msg.sender] = operator;
// L'operator peut maintenant valider pour des AVS
}
}
Construire un AVS Simple
Votre AVS = 3 contrats principaux.
1. ServiceManager
import {ServiceManagerBase} from "eigenlayer-middleware/ServiceManagerBase.sol";
contract OracleAVS is ServiceManagerBase {
struct Task {
uint256 blockNumber;
bytes32 dataHash;
uint256 respondByBlock;
}
mapping(uint256 => Task) public tasks;
uint256 public nextTaskId;
function createTask(bytes32 dataHash) external onlyTaskGenerator {
tasks[nextTaskId] = Task({
blockNumber: block.number,
dataHash: dataHash,
respondByBlock: block.number + 100
});
emit TaskCreated(nextTaskId, dataHash);
nextTaskId++;
}
function respondToTask(uint256 taskId, bytes calldata data, bytes calldata signature) external {
Task storage task = tasks[taskId];
require(block.number <= task.respondByBlock, "Too late");
require(keccak256(data) == task.dataHash, "Wrong data");
// Verify signature from registered operator
address operator = recoverSigner(taskId, data, signature);
require(stakeRegistry.isOperatorRegistered(operator), "Not registered");
// Process response...
}
}
2. StakeRegistry
contract OracleStakeRegistry {
IStrategyManager public strategyManager;
IStrategy[] public strategies; // Quorum strategies (ex: stETH)
mapping(address => bool) public isOperatorRegistered;
function registerOperator() external {
address operator = msg.sender;
// Check minimum stake across strategies
uint256 totalStake = 0;
for (uint256 i = 0; i < strategies.length; i++) {
totalStake += strategyManager.stakerStrategyShares(operator, strategies[i]);
}
require(totalStake >= MIN_STAKE, "Insufficient stake");
isOperatorRegistered[operator] = true;
emit OperatorRegistered(operator, totalStake);
}
function getOperatorStake(address operator) public view returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < strategies.length; i++) {
total += strategyManager.stakerStrategyShares(operator, strategies[i]);
}
return total;
}
}
3. Slashing Logic
contract OracleSlasher {
ISlasher public eigenSlasher;
struct SlashingParams {
uint256 slashAmount; // En basis points (10000 = 100%)
uint256 challengePeriod;
}
function proveOperatorMisbehavior(
address operator,
uint256 taskId,
bytes calldata wrongData,
bytes calldata signature
) external {
// 1. Verify signature
require(recoverSigner(taskId, wrongData, signature) == operator, "Wrong sig");
// 2. Verify data is actually wrong
require(keccak256(wrongData) != getCorrectDataHash(taskId), "Data correct");
// 3. Slash via EigenLayer
eigenSlasher.freezeOperator(operator);
eigenSlasher.slashShares(
operator,
strategies,
slashingParams.slashAmount
);
emit OperatorSlashed(operator, taskId, slashingParams.slashAmount);
}
}
Risques du Restaking
1. Slashing Corrélé
// Un operator peut être slashé par PLUSIEURS AVS
contract Operator {
// Stake dans EigenLayer : 32 ETH
// AVS enregistrés : OracleAVS, BridgeAVS, RollupAVS
// Si faute simultanée :
// - OracleAVS slash 10% → -3.2 ETH
// - BridgeAVS slash 15% → -4.8 ETH (sur les 28.8 restants)
// - Total slashed > stake initial possible !
}
Mitigation : caps de slashing par période, pools de collateral séparés.
2. Depeg de LRT
Les Liquid Restaking Tokens (ex: eETH, rsETH) wrappent votre stake EigenLayer.
// Si un AVS slash massivement :
// 1. Les LRT holders perdent leur backing
// 2. Depeg : 1 eETH != 1 ETH
// 3. Cascading liquidations dans DeFi
// Exemple : eETH utilisé comme collateral dans Aave
// eETH depeg → liquidations → pression vente → spiral
Exemples Réels
EigenDA
Data availability layer sécurisé par restaking.
// Operators stockent des blobs, prouvent la disponibilité
contract EigenDAServiceManager {
function confirmBatch(
BatchHeader calldata batchHeader,
NonSignerStakesAndSignature calldata nonSignerStakesAndSignature
) external {
// Verify quorum de signatures d'operators
// Si <2/3 quorum → revert
// Si OK → batch confirmé on-chain
}
}
AltLayer
Rollup-as-a-Service avec restaked rollups (RaaS).
// Chaque rollup = son propre AVS
// Operators validés par restaking
// Slashing si fraud proof non challengé
contract AltLayerAVS {
function submitStateRoot(bytes32 stateRoot, bytes calldata proof) external onlyOperator {
// Operator soumet state root
// Challenge period
// Si pas de challenge → finalized
}
}
Timeline
Verdict
Le restaking = superpuissance pour bootstrapping. Mais avec le pouvoir vient la responsabilité : un bug de slashing peut vaporiser des millions.
Testez, auditez, puis lancez.