Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .github/workflows/bls-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ on:
- "contracts/src/eigenlayer/ecdsa/**"
- "contracts/script/eigenlayer/ecdsa/**"
- "contracts/test/**"
- ".github/workflows/ecdsa-e2e.yml"
- "scripts/ecdsa/**"
- "docker/ECDSA_CLI.md"
- "README.md"
workflow_dispatch:

# Ensures that only a single workflow per PR will run at a time. Cancels in-progress jobs if new commit is pushed.
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/ecdsa-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ on:
- "contracts/src/eigenlayer/bls/**"
- "contracts/script/eigenlayer/bls/**"
- "contracts/test/**"
- ".github/workflows/bls-e2e.yml"
- "scripts/bls/**"
- "docker/BLS_CLI.md"
- "README.md"
workflow_dispatch:

# Ensures that only a single workflow per PR will run at a time. Cancels in-progress jobs if new commit is pushed.
Expand Down
60 changes: 60 additions & 0 deletions contracts/script/eigenlayer/bls/WavsDepositIntoStrategy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";

import {ReadCoreLib} from "./utils/ReadCoreLib.sol";
import {WavsDepositIntoStrategyLib} from "./utils/WavsDepositIntoStrategyLib.sol";

/**
* @title WavsDepositIntoStrategy
* @author Lay3rLabs
* @notice This script deposits into a WAVS strategy.
* @dev This script is used to deposit into a WAVS strategy.
*/
contract WavsDepositIntoStrategy is Script {
/// @notice The environment variable for the LST contract address.
string public constant ENV_LST_CONTRACT = "LST_CONTRACT_ADDRESS";
/// @notice The environment variable for the LST strategy address.
string public constant ENV_LST_STRATEGY = "LST_STRATEGY_ADDRESS";
/// @notice The environment variable for the amount to delegate.
string public constant ENV_AMOUNT = "WAVS_DELEGATE_AMOUNT";

address private _strategyManager;
address private _delegationManager;
address private _lstContractAddress;
address private _lstStrategyAddress;
uint256 private _stakeAmount;

/// @notice The setup function for the script.
function setUp() public virtual {
ReadCoreLib.DeploymentData memory coreDeployment =
ReadCoreLib.readDeploymentJson("deployments/eigenlayer-core/", block.chainid);

_strategyManager = coreDeployment.strategyManager;
_delegationManager = coreDeployment.delegationManager;

// Get the configuration from environment
_lstContractAddress = vm.envAddress(ENV_LST_CONTRACT);
_lstStrategyAddress = vm.envAddress(ENV_LST_STRATEGY);
_stakeAmount = vm.envUint(ENV_AMOUNT);
}

/// @notice The run function for the script.
function run() external {
vm.startBroadcast();

(, address operatorAddr,) = vm.readCallers();

WavsDepositIntoStrategyLib.depositIntoStrategy(
_strategyManager,
_delegationManager,
_lstContractAddress,
_lstStrategyAddress,
operatorAddr,
_stakeAmount
);

vm.stopBroadcast();
}
}
11 changes: 0 additions & 11 deletions contracts/script/eigenlayer/bls/WavsRegisterOperator.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,15 @@ import {ReadCoreLib} from "./utils/ReadCoreLib.sol";
* @dev This script is used to register an operator to the WAVS service manager.
*/
contract WavsRegisterOperator is Script {
/// @notice The environment variable for the LST contract address.
string public constant ENV_LST_CONTRACT = "LST_CONTRACT_ADDRESS";
/// @notice The environment variable for the LST strategy address.
string public constant ENV_LST_STRATEGY = "LST_STRATEGY_ADDRESS";
/// @notice The environment variable for the WAVS service manager address.
string public constant ENV_SERVICE_MANAGER = "WAVS_SERVICE_MANAGER_ADDRESS";
/// @notice The environment variable for the amount to delegate.
string public constant ENV_AMOUNT = "WAVS_DELEGATE_AMOUNT";
/// @notice The environment variable for the operator key.
string public constant ENV_OPERATOR_KEY = "OPERATOR_KEY";

address private _lstContractAddress;
address private _lstStrategyAddress;
address private _serviceManagerAddress;
uint256 private _stakeAmount;
uint256 private _operatorKey;

/// @notice The core deployment data.
Expand All @@ -39,20 +33,15 @@ contract WavsRegisterOperator is Script {
ReadCoreLib.readDeploymentJson("deployments/eigenlayer-core/", block.chainid);

// Get the configuration from environment
_lstContractAddress = vm.envAddress(ENV_LST_CONTRACT);
_lstStrategyAddress = vm.envAddress(ENV_LST_STRATEGY);
_serviceManagerAddress = vm.envAddress(ENV_SERVICE_MANAGER);
_stakeAmount = vm.envUint(ENV_AMOUNT);
_operatorKey = vm.envUint(ENV_OPERATOR_KEY);
}

/// @notice The run function for the script.
function run() external {
vm.startBroadcast();

WavsRegisterOperatorLib.setupOperator(
coreDeployment, _lstContractAddress, _lstStrategyAddress, _stakeAmount
);
WavsRegisterOperatorLib.registerToAvs(
_operatorKey,
_serviceManagerAddress,
Expand Down
119 changes: 119 additions & 0 deletions contracts/script/eigenlayer/bls/utils/WavsDepositIntoStrategyLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {console2} from "forge-std/console2.sol";
import {IStrategyManager} from "@eigenlayer/contracts/interfaces/IStrategyManager.sol";
import {IDelegationManager} from "@eigenlayer/contracts/interfaces/IDelegationManager.sol";
import {IStrategy} from "@eigenlayer/contracts/interfaces/IStrategy.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";

/**
* @title WavsDepositIntoStrategyLib
* @author Lay3rLabs
* @notice This library is used to deposit into a WAVS strategy.
* @dev This library is used to deposit into a WAVS strategy.
*/
library WavsDepositIntoStrategyLib {
using Strings for *;

/// @notice The error for the failed to approve LST tokens.
error WavsDepositIntoStrategy__FailedToApproveLSTTokens();
/// @notice The error for the failed to mint LST tokens.
error WavsDepositIntoStrategy__FailedToMintLSTTokens();

/**
* @notice The function to deposit into a strategy.
* @param _strategyManagerAddress The address of the strategy manager.
* @param _delegationManagerAddress The address of the delegation manager.
* @param _lstContractAddress The address of the LST contract.
* @param _lstStrategyAddress The address of the LST strategy.
* @param _operatorAddr The address of the operator.
* @param _stakeAmount The amount of LST to stake.
*/
function depositIntoStrategy(
address _strategyManagerAddress,
address _delegationManagerAddress,
address _lstContractAddress,
address _lstStrategyAddress,
address _operatorAddr,
uint256 _stakeAmount
) internal {
IStrategyManager strategyManager = IStrategyManager(_strategyManagerAddress);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay this is the code that was pulled out from the register lib, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

uint256 numDeposit = strategyManager.stakerStrategyListLength(_operatorAddr);
if (numDeposit == 0) {
// Check if operator already has LST balance
IERC20 lstToken = IERC20(_lstContractAddress);
uint256 lstBalance = lstToken.balanceOf(_operatorAddr);

// Only mint LSTs if operator has no balance
if (lstBalance < _stakeAmount) {
console2.log("Operator has insufficient LST balance, minting new tokens");

uint256 amountToMint = _stakeAmount - lstBalance;

// Call the submit function on the LST contract with the operator as the referral
(bool success,) = _lstContractAddress.call{value: amountToMint}(
abi.encodeWithSignature("submit(address)", _operatorAddr)
);
if (!success) {
revert WavsDepositIntoStrategy__FailedToMintLSTTokens();
}

// Update the LST balance after minting
lstBalance = lstToken.balanceOf(_operatorAddr);
console2.log(
string.concat(
"Minted ", Strings.toString(lstBalance), " LST tokens for operator"
)
);
} else {
console2.log(
string.concat(
"Operator already has LST balance of ", Strings.toString(lstBalance)
)
);
}

// Approve the strategy manager to spend the LST tokens
bool approved = lstToken.approve(_strategyManagerAddress, _stakeAmount);
if (!approved) {
revert WavsDepositIntoStrategy__FailedToApproveLSTTokens();
}
console2.log(
string.concat(
"Approved ", Strings.toString(_stakeAmount), " LST tokens for StrategyManager"
)
);

// Create a new deposit with the LSTs
console2.log(
string.concat(
"Creating new deposit for operator ",
Strings.toHexString(uint160(_operatorAddr), 20)
)
);
uint256 shares = strategyManager.depositIntoStrategy(
IStrategy(_lstStrategyAddress), lstToken, _stakeAmount
);
console2.log(
string.concat("Created deposit with ", Strings.toString(shares), " shares")
);
} else {
console2.log(
string.concat(
"Operator ",
Strings.toHexString(uint160(_operatorAddr), 20),
" already has deposits, skipping LST operations"
)
);
}

IDelegationManager delegationManager = IDelegationManager(_delegationManagerAddress);
if (!delegationManager.isDelegated(_operatorAddr)) {
// TODO: allow to override foo.bar with env variable?
delegationManager.registerAsOperator(address(0), 0, "foo.bar");
console2.log("Registered operator as operator");
}
}
}
108 changes: 0 additions & 108 deletions contracts/script/eigenlayer/bls/utils/WavsRegisterOperatorLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@ pragma solidity ^0.8.27;
import {console2} from "forge-std/Test.sol";
import {Vm} from "forge-std/Vm.sol";
import {stdJson} from "forge-std/StdJson.sol";
import {IStrategyManager} from "@eigenlayer/contracts/interfaces/IStrategyManager.sol";
import {IDelegationManager} from "@eigenlayer/contracts/interfaces/IDelegationManager.sol";
import {IStrategy} from "@eigenlayer-middleware/src/interfaces/IECDSAStakeRegistry.sol";
import {
IAllocationManagerTypes,
IAllocationManager
} from "@eigenlayer/contracts/interfaces/IAllocationManager.sol";
import {OperatorSet} from "@eigenlayer/contracts/libraries/OperatorSetLib.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import {UpgradeableProxyLib} from "./UpgradeableProxyLib.sol";
import {ReadCoreLib} from "./ReadCoreLib.sol";
import {BLSKeyGenerator} from "./BLSKeyGenerator.sol";

import {
Expand All @@ -40,105 +36,9 @@ library WavsRegisterOperatorLib {

Vm internal constant VM = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));

/// @notice The error for the failed to mint LST tokens.
error WavsRegisterOperatorLib__FailedToMintLSTTokens();
/// @notice The error for the failed to approve LST tokens.
error WavsRegisterOperatorLib__FailedToApproveLSTTokens();
/// @notice The error for the failed to get allocation configuration delay.
error WavsRegisterOperatorLib__FailedToGetAllocationConfigurationDelay();

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taken from here?

* @notice The setup operator function.
* @param coreDeployment The core deployment data.
* @param lstContractAddress The LST contract address.
* @param lstStrategyAddress The LST strategy address.
* @param stakeAmount The stake amount.
*/
function setupOperator(
ReadCoreLib.DeploymentData memory coreDeployment,
address lstContractAddress,
address lstStrategyAddress,
uint256 stakeAmount
) internal {
// This is the address for private key forge is running the script as.
// Calculated from the --private-key argument
(, address operatorAddr,) = VM.readCallers();

IStrategyManager strategyManager = IStrategyManager(coreDeployment.strategyManager);
uint256 numDeposit = strategyManager.stakerStrategyListLength(operatorAddr);
if (numDeposit == 0) {
// Check if operator already has LST balance
IERC20 lstToken = IERC20(lstContractAddress);
uint256 lstBalance = lstToken.balanceOf(operatorAddr);

// Only mint LSTs if operator has no balance
if (lstBalance == 0) {
console2.log("Operator has no LST balance, minting new tokens");

// Call the submit function on the LST contract with the operator as the referral
(bool success,) = lstContractAddress.call{value: stakeAmount}(
abi.encodeWithSignature("submit(address)", operatorAddr)
);
if (!success) {
revert WavsRegisterOperatorLib__FailedToMintLSTTokens();
}

// Update the LST balance after minting
lstBalance = lstToken.balanceOf(operatorAddr);
console2.log(
string.concat(
"Minted ", Strings.toString(lstBalance), " LST tokens for operator"
)
);
} else {
console2.log(
string.concat(
"Operator already has LST balance of ", Strings.toString(lstBalance)
)
);
}

// Approve the strategy manager to spend the LST tokens
bool approved = lstToken.approve(coreDeployment.strategyManager, stakeAmount);
if (!approved) {
revert WavsRegisterOperatorLib__FailedToApproveLSTTokens();
}
console2.log(
string.concat(
"Approved ", Strings.toString(stakeAmount), " LST tokens for StrategyManager"
)
);

// Create a new deposit with the LSTs
console2.log(
string.concat(
"Creating new deposit for operator ",
Strings.toHexString(uint160(operatorAddr), 20)
)
);
uint256 shares = strategyManager.depositIntoStrategy(
IStrategy(lstStrategyAddress), lstToken, stakeAmount
);
console2.log(
string.concat("Created deposit with ", Strings.toString(shares), " shares")
);
} else {
console2.log(
string.concat(
"Operator ",
Strings.toHexString(uint160(operatorAddr), 20),
" already has deposits, skipping LST operations"
)
);
}

IDelegationManager delegationManager = IDelegationManager(coreDeployment.delegationManager);
if (!delegationManager.isDelegated(operatorAddr)) {
// TODO: allow to override foo.bar with env variable?
delegationManager.registerAsOperator(address(0), 0, "foo.bar");
}
}

/**
* @notice The register to AVS function.
* @param operatorKey The operator key.
Expand All @@ -160,14 +60,6 @@ library WavsRegisterOperatorLib {
IAllocationManager allocationManager = IAllocationManager(allocationManagerAddress);
OperatorSet memory opSetQuery = OperatorSet({avs: serviceManagerAddress, id: 0});
if (!allocationManager.isMemberOfOperatorSet(operatorAddr, opSetQuery)) {
(bool success, bytes memory result) = address(allocationManager).staticcall(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the ugly workaround gone 😄

abi.encodeWithSignature("ALLOCATION_CONFIGURATION_DELAY()")
);
if (!success) {
revert WavsRegisterOperatorLib__FailedToGetAllocationConfigurationDelay();
}
uint32 allocationConfigurationDelay = abi.decode(result, (uint32));
VM.roll(block.number + allocationConfigurationDelay + 1); // Workaround for testnet, txs can't be in the same block
IStrategy[] memory strategies = new IStrategy[](1);
strategies[0] = IStrategy(lstStrategyAddress);
uint64[] memory newMagnitudes = new uint64[](1);
Expand Down
Loading
Loading