Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add functions to handle eigenlayer v0.2 #53

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion scripts/forge/BaseScript.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "../../src/StakingNode.sol";
import "../../src/RewardsReceiver.sol";
import "../../src/ynLSD.sol";
import "../../src/YieldNestOracle.sol";
import "../../src/ynViewer.sol";
import "../../src/LSDStakingNode.sol";
import "../../src/RewardsDistributor.sol";
import "../../src/external/tokens/WETH.sol";
Expand All @@ -27,6 +28,7 @@ abstract contract BaseScript is Script, Utils {
RewardsReceiver consensusLayerReceiver;
RewardsDistributor rewardsDistributor;
StakingNode stakingNodeImplementation;
ynViewer ynViewer;
}

struct ynLSDDeployment {
Expand All @@ -49,6 +51,7 @@ abstract contract BaseScript is Script, Utils {
vm.serializeAddress(json, "consensusLayerReceiver", address(deployment.consensusLayerReceiver));
vm.serializeAddress(json, "rewardsDistributor", address(deployment.rewardsDistributor));
vm.serializeAddress(json, "stakingNodeImplementation", address(deployment.stakingNodeImplementation));
vm.serializeAddress(json, "ynViewer", address(deployment.ynViewer));

string memory finalJson = vm.serializeString(json, "object", "dummy");
vm.writeJson(finalJson, getDeploymentFile());
Expand All @@ -59,6 +62,7 @@ abstract contract BaseScript is Script, Utils {
string memory jsonContent = vm.readFile(deploymentFile);
Deployment memory deployment;
deployment.ynETH = ynETH(payable(jsonContent.readAddress(".ynETH")));
deployment.ynViewer = ynViewer(payable(jsonContent.readAddress(".ynViewer")));
deployment.stakingNodesManager = StakingNodesManager(payable(jsonContent.readAddress(".stakingNodesManager")));
deployment.executionLayerReceiver = RewardsReceiver(payable(jsonContent.readAddress(".executionLayerReceiver")));
deployment.consensusLayerReceiver = RewardsReceiver(payable(jsonContent.readAddress(".consensusLayerReceiver")));
Expand Down Expand Up @@ -103,7 +107,8 @@ abstract contract BaseScript is Script, Utils {
LSD_RESTAKING_MANAGER: vm.envAddress("LSD_RESTAKING_MANAGER_ADDRESS"),
STAKING_NODE_CREATOR: vm.envAddress("LSD_STAKING_NODE_CREATOR_ADDRESS"),
ORACLE_MANAGER: vm.envAddress("YIELDNEST_ORACLE_MANAGER_ADDRESS"),
DEPOSIT_BOOTSTRAPER: vm.envAddress("DEPOSIT_BOOTSTRAPER_ADDRESS")
DEPOSIT_BOOTSTRAPER: vm.envAddress("DEPOSIT_BOOTSTRAPER_ADDRESS"),
VALIDATOR_REMOVER_MANAGER: vm.envAddress("VALIDATOR_REMOVER_MANAGER_ADDRESS")
});
}

Expand Down
27 changes: 23 additions & 4 deletions scripts/forge/DeployYieldNest.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "../../src/StakingNodesManager.sol";
import "../../src/RewardsReceiver.sol";
import "../../src/RewardsDistributor.sol";
import "../../src/ynETH.sol";
import "../../src/StakingNodeV2.sol";
import "../../src/interfaces/IStakingNode.sol";
import "../../src/external/ethereum/IDepositContract.sol";
import "../../src/interfaces/IRewardsDistributor.sol";
Expand Down Expand Up @@ -81,9 +82,22 @@ contract DeployYieldNest is BaseScript {
// Deploy implementations
yneth = new ynETH();
stakingNodesManager = new StakingNodesManager();
executionLayerReceiver = new RewardsReceiver();
consensusLayerReceiver = new RewardsReceiver(); // Instantiating consensusLayerReceiver
stakingNodeImplementation = new StakingNode();

{
RewardsReceiver rewardsReceiverImplementation = new RewardsReceiver();
TransparentUpgradeableProxy executionLayerReceiverProxy = new TransparentUpgradeableProxy(address(rewardsReceiverImplementation), actors.PROXY_ADMIN_OWNER, "");
executionLayerReceiver = RewardsReceiver(payable(executionLayerReceiverProxy));

TransparentUpgradeableProxy consensusLayerReceiverProxy = new TransparentUpgradeableProxy(address(rewardsReceiverImplementation), actors.PROXY_ADMIN_OWNER, "");
consensusLayerReceiver = RewardsReceiver(payable(consensusLayerReceiverProxy));
}

if (block.chainid == 17000) { // holeksy
stakingNodeImplementation = new StakingNode();
} else {
stakingNodeImplementation = new StakingNodeV2();
}

yieldNestOracle = new YieldNestOracle();
ynlsd = new ynLSD();

Expand Down Expand Up @@ -119,13 +133,13 @@ contract DeployYieldNest is BaseScript {
});
yneth.initialize(ynethInit);


// Initialize StakingNodesManager with example parameters
StakingNodesManager.Init memory stakingNodesManagerInit = StakingNodesManager.Init({
admin: actors.ADMIN,
stakingAdmin: actors.STAKING_ADMIN,
stakingNodesAdmin: actors.STAKING_NODES_ADMIN,
validatorManager: actors.VALIDATOR_MANAGER,
validatorRemoverManager: actors.VALIDATOR_REMOVER_MANAGER,
stakingNodeCreatorRole: actors.STAKING_NODE_CREATOR,
maxNodeCount: 10,
depositContract: depositContract,
Expand Down Expand Up @@ -157,6 +171,8 @@ contract DeployYieldNest is BaseScript {
executionLayerReceiver.initialize(rewardsReceiverInit);
consensusLayerReceiver.initialize(rewardsReceiverInit); // Initializing consensusLayerReceiver

ynViewer ynviewer = new ynViewer(IynETH(address(yneth)), IStakingNodesManager(address(stakingNodesManager)));

vm.stopBroadcast();

Deployment memory deployment = Deployment({
Expand All @@ -165,8 +181,11 @@ contract DeployYieldNest is BaseScript {
executionLayerReceiver: executionLayerReceiver,
consensusLayerReceiver: consensusLayerReceiver, // Adding consensusLayerReceiver to the deployment
rewardsDistributor: rewardsDistributor,
ynViewer: ynviewer,
stakingNodeImplementation: stakingNodeImplementation
});



saveDeployment(deployment);
}
Expand Down
76 changes: 45 additions & 31 deletions scripts/forge/DeployYnLSD.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,54 @@ contract DeployYnLSD is BaseScript {
}

IERC20[] memory assets = new IERC20[](2);
assets[0] = IERC20(chainAddresses.lsd.RETH_ADDRESS);
assets[1] = IERC20(chainAddresses.lsd.STETH_ADDRESS);
assets[0] = IERC20(chainAddresses.lsd.STETH_ADDRESS);
assets[1] = IERC20(chainAddresses.lsd.RETH_ADDRESS);


IStrategy[] memory strategies = new IStrategy[](2);
strategies[0] = IStrategy(chainAddresses.lsd.RETH_STRATEGY_ADDRESS);
strategies[1] = IStrategy(chainAddresses.lsd.STETH_STRATEGY_ADDRESS);
strategies[0] = IStrategy(chainAddresses.lsd.STETH_STRATEGY_ADDRESS);
strategies[1] = IStrategy(chainAddresses.lsd.RETH_STRATEGY_ADDRESS);

{
uint256[] memory maxAgesArray = new uint256[](assets.length);
address[] memory priceFeedAddresses = new address[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
maxAgesArray[i] = type(uint256).max;
if (assets[i] == IERC20(chainAddresses.lsd.RETH_ADDRESS)) {
priceFeedAddresses[i] = chainAddresses.lsd.RETH_FEED_ADDRESS;
} else if (assets[i] == IERC20(chainAddresses.lsd.STETH_ADDRESS)) {
priceFeedAddresses[i] = chainAddresses.lsd.STETH_FEED_ADDRESS;
}
}
{
address[] memory assetsAddresses = new address[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
assetsAddresses[i] = address(assets[i]);
}
YieldNestOracle.Init memory yieldNestOracleInit = YieldNestOracle.Init({
assets: assetsAddresses,
priceFeedAddresses: priceFeedAddresses,
maxAges: maxAgesArray,
admin: actors.ORACLE_MANAGER,
oracleManager: actors.ORACLE_MANAGER
});
yieldNestOracle.initialize(yieldNestOracleInit);
}


}

// Initialize ynLSD with example parameters
{
address[] memory lsdPauseWhitelist = new address[](1);
lsdPauseWhitelist[0] = _broadcaster;

IERC20 stETH = IERC20(chainAddresses.lsd.STETH_ADDRESS);
uint256 mintAmount = 1.0001 ether;
(bool success, ) = address(stETH).call{value: mintAmount}("");
require(success, "ETH to stETH mint failed");
stETH.approve(address(ynlsd), mintAmount);

ynLSD.Init memory ynlsdInit = ynLSD.Init({
assets: assets,
strategies: strategies,
Expand All @@ -84,37 +121,12 @@ contract DeployYnLSD is BaseScript {
stakingAdmin: actors.STAKING_ADMIN,
lsdRestakingManager: actors.LSD_RESTAKING_MANAGER, // Assuming no restaking manager is set initially
lsdStakingNodeCreatorRole: actors.STAKING_NODE_CREATOR, // Assuming no staking node creator role is set initially
pauseWhitelist: lsdPauseWhitelist
pauseWhitelist: lsdPauseWhitelist,
depositBootstrapper: actors.DEPOSIT_BOOTSTRAPER
});
ynlsd.initialize(ynlsdInit);
}

uint256[] memory maxAgesArray = new uint256[](assets.length);
address[] memory priceFeedAddresses = new address[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
maxAgesArray[i] = type(uint256).max;
if (assets[i] == IERC20(chainAddresses.lsd.RETH_ADDRESS)) {
priceFeedAddresses[i] = chainAddresses.lsd.RETH_FEED_ADDRESS;
} else if (assets[i] == IERC20(chainAddresses.lsd.STETH_ADDRESS)) {
priceFeedAddresses[i] = chainAddresses.lsd.STETH_FEED_ADDRESS;
}
}

{
address[] memory assetsAddresses = new address[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
assetsAddresses[i] = address(assets[i]);
}
YieldNestOracle.Init memory yieldNestOracleInit = YieldNestOracle.Init({
assets: assetsAddresses,
priceFeedAddresses: priceFeedAddresses,
maxAges: maxAgesArray,
admin: actors.ORACLE_MANAGER,
oracleManager: actors.ORACLE_MANAGER
});
yieldNestOracle.initialize(yieldNestOracleInit);
}

{
LSDStakingNode lsdStakingNodeImplementation = new LSDStakingNode();
ynlsd.registerLSDStakingNodeImplementationContract(address(lsdStakingNodeImplementation));
Expand All @@ -127,5 +139,7 @@ contract DeployYnLSD is BaseScript {

saveynLSDDeployment(deployment);
}

vm.stopBroadcast();
}
}
3 changes: 3 additions & 0 deletions src/StakingNode.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {IDelegationManager} from "./external/eigenlayer/v0.1.0/interfaces/IDeleg
import {IDelayedWithdrawalRouter} from "./external/eigenlayer/v0.1.0/interfaces/IDelayedWithdrawalRouter.sol";
import {IStrategy, IStrategyManager} from "./external/eigenlayer/v0.1.0/interfaces/IStrategyManager.sol";
import {BeaconChainProofs} from "./external/eigenlayer/v0.1.0/BeaconChainProofs.sol";

import {IStakingNodesManager} from "./interfaces/IStakingNodesManager.sol";
import {IStakingNode} from "./interfaces/IStakingNode.sol";

Expand Down Expand Up @@ -180,6 +181,7 @@ contract StakingNode is IStakingNode, StakingNodeEvents, ReentrancyGuardUpgradea

/**
* @notice Delegates the staking operation to a specified operator.
* @dev Calls the function on the version v0.2 of the Eigenlayer interface.
* @param operator The address of the operator to whom the staking operation is being delegated.
*/
function delegate(address operator) public virtual onlyAdmin {
Expand All @@ -193,6 +195,7 @@ contract StakingNode is IStakingNode, StakingNodeEvents, ReentrancyGuardUpgradea
/**
* @notice Undelegates the staking operation from the current operator.
* @dev It retrieves the current operator by calling `delegatedTo` on the DelegationManager for event logging.
* Calls the function on the version v0.2 of the Eigenlayer interface.
*/
function undelegate() public virtual onlyAdmin {

Expand Down
93 changes: 93 additions & 0 deletions src/StakingNodeV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
pragma solidity ^0.8.24;

import {IDelegationManager as IDelegationManagerV02 } from "../../../src/external/eigenlayer/v0.2.1/interfaces/IDelegationManager.sol";
import {IEigenPod as IEigenPodV02 } from "../../../src/external/eigenlayer/v0.2.1/interfaces/IEigenPod.sol";
import {BeaconChainProofs as BeaconChainProofsV02} from "../../../src/external/eigenlayer/v0.2.1/BeaconChainProofs.sol";
import {ISignatureUtils} from "../../../src/external/eigenlayer/v0.2.1/interfaces/ISignatureUtils.sol";
import {BeaconChainProofs as BeaconChainProofsV02} from "../../../src/external/eigenlayer/v0.2.1/BeaconChainProofs.sol";
import {IStrategy as IStrategyV02} from "../../../src/external/eigenlayer/v0.2.1/interfaces/IStrategy.sol";

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {StakingNode} from "../../../src/StakingNode.sol";

/**
The purpose of this file, StakingNodeM2.sol, is to extend the functionality of the StakingNode contract
specifically for the M2 deployment on EigenLayer that is currently operational on the Goerli testnet.
This deployment aims to address and integrate with the unique features and requirements of the EigenLayer M2,
including enhanced delegation management, withdrawal credential verification, and validator management,
tailored to the EigenLayer's specifications and protocols.

Release:

https://github.com/Layr-Labs/eigenlayer-contracts/releases/tag/v0.2.1-goerli-m2

For more detailed information and updates, refer to the GitHub release at:
https://github.com/Layr-Labs/eigenlayer-contracts/releases/

*/
contract StakingNodeV2 is StakingNode {

//--------------------------------------------------------------------------------------
//---------------------------------- VERIFICATION AND DELEGATION --------------------
//--------------------------------------------------------------------------------------

/**
* @notice Delegates the staking operation to a specified operator.
* @param operator The address of the operator to whom the staking operation is being delegated.
*/
function delegate(
address operator,
ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry,
bytes32 approverSalt
) public onlyAdmin {

IDelegationManagerV02 delegationManager = IDelegationManagerV02(address(stakingNodesManager.delegationManager()));
delegationManager.delegateTo(operator, approverSignatureAndExpiry, approverSalt);

emit Delegated(operator, approverSalt);
}


/**
* @notice Undelegates the staking operation from the current operator.
* @dev It retrieves the current operator by calling `delegatedTo` on the DelegationManager for event logging.
* Calls the function on the version v0.2 of the Eigenlayer interface
*/
function undelegate() public override onlyAdmin {

IDelegationManagerV02 delegationManager = IDelegationManagerV02(address(stakingNodesManager.delegationManager()));
address operator = delegationManager.delegatedTo(address(this));
delegationManager.undelegate(address(this));

emit Undelegated(operator);
}

/**
* @notice Validates the withdrawal credentials of validators through the Eigenlayer protocol.
* @dev Upon successful validation, Eigenlayer issues shares to the StakingNode, equivalent to the staked ETH amount.
* @dev Calls the function on the version v0.2 of the Eigenlayer interface.
*/
function verifyWithdrawalCredentials(
uint64 oracleTimestamp,
BeaconChainProofsV02.StateRootProof calldata stateRootProof,
uint40[] calldata validatorIndices,
bytes[] calldata withdrawalCredentialProofs,
bytes32[][] calldata validatorFields
) external onlyAdmin {

if (validatorIndices.length != withdrawalCredentialProofs.length) {
revert MismatchedValidatorIndexAndProofsLengths(validatorIndices.length, withdrawalCredentialProofs.length);
}
if (withdrawalCredentialProofs.length != validatorFields.length) {
revert MismatchedProofsAndValidatorFieldsLengths(withdrawalCredentialProofs.length, validatorFields.length);
}

IEigenPodV02(address(eigenPod)).verifyWithdrawalCredentials(
oracleTimestamp,
stateRootProof,
validatorIndices,
withdrawalCredentialProofs,
validatorFields
);
}
}
15 changes: 15 additions & 0 deletions src/interfaces/IStakingNodeV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import "./IStakingNode.sol";

import {BeaconChainProofs as BeaconChainProofsv021 } from "../external/eigenlayer/v0.2.1/BeaconChainProofs.sol";


interface IStakingNodeV2 is IStakingNode {

function verifyWithdrawalCredentials(
uint256 oracleTimestamp,
BeaconChainProofsv021.StateRootProof memory stateRootProof,
uint40[] memory validatorIndexes,
bytes[] memory validatorFieldsProofs,
bytes32[][] memory validatorFields
) external;
}
2 changes: 1 addition & 1 deletion src/ynLSD.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ contract ynLSD is IynLSD, ynBase, ReentrancyGuardUpgradeable, IynLSDEvents {
bytes32 public constant LSD_RESTAKING_MANAGER_ROLE = keccak256("LSD_RESTAKING_MANAGER_ROLE");
bytes32 public constant LSD_STAKING_NODE_CREATOR_ROLE = keccak256("LSD_STAKING_NODE_CREATOR_ROLE");

uint256 public constant BOOTSTRAP_AMOUNT_UNITS = 10;
uint256 public constant BOOTSTRAP_AMOUNT_UNITS = 1;

//--------------------------------------------------------------------------------------
//---------------------------------- VARIABLES ---------------------------------------
Expand Down
17 changes: 17 additions & 0 deletions test/foundry/ActorAddresses.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ contract ActorAddresses {
DEPOSIT_BOOTSTRAPER: 0xFABB0ac9d68B0B445fB7357272Ff202C5651694a,
VALIDATOR_REMOVER_MANAGER: 0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec
});


actors[17000] = Actors({
PROXY_ADMIN_OWNER: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8,
TRANSFER_ENABLED_EOA: 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC,
ADMIN: 0x90F79bf6EB2c4f870365E785982E1f101E93b906,
STAKING_ADMIN: 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65,
STAKING_NODES_ADMIN: 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc,
VALIDATOR_MANAGER: 0x976EA74026E726554dB657fA54763abd0C3a0aa9,
FEE_RECEIVER: 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955,
PAUSE_ADMIN: 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f,
LSD_RESTAKING_MANAGER: 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720,
STAKING_NODE_CREATOR: 0xBcd4042DE499D14e55001CcbB24a551F3b954096,
ORACLE_MANAGER: 0x71bE63f3384f5fb98995898A86B02Fb2426c5788,
DEPOSIT_BOOTSTRAPER: 0xFABB0ac9d68B0B445fB7357272Ff202C5651694a,
VALIDATOR_REMOVER_MANAGER: 0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec
});
}

function getActors(uint256 chainId) external view returns (Actors memory) {
Expand Down
Loading
Loading