Skip to content

Commit

Permalink
fix(contracts): test + eigenlayer logic
Browse files Browse the repository at this point in the history
  • Loading branch information
thedevbirb committed Sep 11, 2024
1 parent 2a82620 commit 64654b1
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 41 deletions.
91 changes: 63 additions & 28 deletions bolt-contracts/src/contracts/BoltManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,17 @@ contract BoltManager is IBoltManager, Ownable {
eigenLayerStrategies.enable(msg.sender);
}

/// @notice Check if a strategy is currently enabled to work in Bolt Protocol.
/// @param strategy The strategy address to check the enabled status for.
/// @return True if the strategy is enabled, false otherwise.
function isEigenLayerStrategyEnabled(
address strategy
) public view returns (bool) {
(uint48 enabledTime, uint48 disabledTime) = eigenLayerStrategies
.getTimes(strategy);
return enabledTime != 0 && disabledTime == 0;
}

/// @notice Check if an operator is currently enabled to work in Bolt Protocol.
/// @param operator The operator address to check the enabled status for.
/// @return True if the operator is enabled, false otherwise.
Expand Down Expand Up @@ -728,7 +739,7 @@ contract BoltManager is IBoltManager, Ownable {

status.amounts[i] = getEigenLayerOperatorStake(
operator,
IERC20(collateral)
collateral
);
}
}
Expand All @@ -739,28 +750,54 @@ contract BoltManager is IBoltManager, Ownable {
// @return tokenAmounts The amount of tokens delegated to the operator for each strategy.
function getEigenLayerOperatorStake(
address operator,
IERC20 collateral
address collateral
) public view returns (uint256 amount) {
// NOTE: Can this be done more gas-efficiently?
address[] memory strategiesRaw = whitelistedEigenLayerCollaterals
.values();
IStrategy[] memory strategies = new IStrategy[](strategiesRaw.length);
for (uint256 i = 0; i < strategiesRaw.length; i++) {
strategies[i] = IStrategy(strategiesRaw[i]);
uint48 timestamp = Time.timestamp();
return getEigenLayerOperatorStakeAt(operator, collateral, timestamp);
}

/// @notice Get the stake of an operator in EigenLayer protocol at a given timestamp.
/// @param operator The operator address to check the stake for.
/// @param collateral The collateral address to check the stake for.
/// @param timestamp The timestamp to check the stake at.
/// @return amount The stake of the operator at the given timestamp, in collateral token.
function getEigenLayerOperatorStakeAt(
address operator,
address collateral,
uint48 timestamp
) public view returns (uint256 amount) {
if (timestamp > Time.timestamp() || timestamp < START_TIMESTAMP) {
revert InvalidQuery();
}

// NOTE: order is preserved i.e., shares[i] corresponds to strategies[i]
uint256[] memory shares = EIGENLAYER_DELEGATION_MANAGER
.getOperatorShares(operator, strategies);
uint48 epochStartTs = getEpochStartTs(getEpochAtTs(timestamp));

for (uint256 i = 0; i < strategies.length; i++) {
if (
isEigenLayerCollateralWhitelisted(address(strategies[i])) &&
address(strategies[i].underlyingToken()) == address(collateral)
) {
amount += strategies[i].sharesToUnderlyingView(shares[i]);
// NOTE: Can this be done more gas-efficiently?
IStrategy[] memory strategyMem = new IStrategy[](1);

for (uint256 i = 0; i < eigenLayerStrategies.length(); i++) {
(
address strategy,
uint48 enabledTime,
uint48 disabledTime
) = eigenLayerStrategies.atWithTimes(i);

if (collateral != address(IStrategy(strategy).underlyingToken())) {
continue;
}

if (!_wasEnabledAt(enabledTime, disabledTime, epochStartTs)) {
continue;
}

strategyMem[0] = IStrategy(strategy);
// NOTE: order is preserved i.e., shares[i] corresponds to strategies[i]
uint256[] memory shares = EIGENLAYER_DELEGATION_MANAGER
.getOperatorShares(operator, strategyMem);
amount += IStrategy(strategy).sharesToUnderlyingView(shares[0]);
}

return amount;
}

/// @notice Get the total stake of all EigenLayer operators at a given epoch for a collateral asset.
Expand All @@ -774,13 +811,14 @@ contract BoltManager is IBoltManager, Ownable {
uint48 epochStartTs = getEpochStartTs(epoch);

// for epoch older than SLASHING_WINDOW total stake can be invalidated
if (
epochStartTs < SLASHING_WINDOW ||
epochStartTs < Time.timestamp() - SLASHING_WINDOW ||
epochStartTs > Time.timestamp()
) {
revert InvalidQuery();
}
// NOTE: not available in EigenLayer yet since slashing is not live
// if (
// epochStartTs < SLASHING_WINDOW ||
// epochStartTs < Time.timestamp() - SLASHING_WINDOW ||
// epochStartTs > Time.timestamp()
// ) {
// revert InvalidQuery();
// }

for (uint256 i; i < eigenLayerOperators.length(); ++i) {
(
Expand All @@ -794,10 +832,7 @@ contract BoltManager is IBoltManager, Ownable {
continue;
}

totalStake += getEigenLayerOperatorStake(
operator,
IERC20(collateral)
);
totalStake += getEigenLayerOperatorStake(operator, collateral);
}
}

Expand Down
75 changes: 62 additions & 13 deletions bolt-contracts/test/BoltManager.EigenLayer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ import {IAVSDirectory} from "@eigenlayer/src/contracts/interfaces/IAVSDirectory.
import {IStrategy} from "@eigenlayer/src/contracts/interfaces/IStrategy.sol";
import {EigenLayerDeployer} from "../test/fixtures/EigenLayerDeployer.f.sol";

import {BLS12381} from "../src/lib/bls/BLS12381.sol";

contract BoltManagerEigenLayerTest is Test {
BoltValidators public validators;
BoltManager public manager;
EigenLayerDeployer public eigenLayerDeployer;

address staker = makeAddr("staker");
address validator = makeAddr("validator");
address operator;
uint256 operatorSk;

Expand Down Expand Up @@ -50,6 +53,15 @@ contract BoltManagerEigenLayerTest is Test {
}

function _eigenLayerOptInRoutine() internal {
// PART 0: Admin setup -- Collateral whitelist
vm.startPrank(admin);
manager.addWhitelistedEigenLayerCollateral(
address(eigenLayerDeployer.weth())
);
vm.stopPrank();

// PART 1: External EigenLayer opt-in to BOLT AVS

// 1. As a staker, I deposit some LSTs into a Stategy via the StrategyManager.depositIntoStrategy function.
// After this, I get back some shares that I can use at a later time for withdrawal

Expand Down Expand Up @@ -162,6 +174,42 @@ contract BoltManagerEigenLayerTest is Test {
manager.checkIfEigenLayerOperatorRegisteredToAVS(operator),
true
);

// PART 2: Validator and proposer opt into BOLT manager
//
// 1. --- Register Validator in BoltValidators ---

// pubkeys aren't checked, any point will be fine
BLS12381.G1Point memory pubkey = BLS12381.generatorG1();

vm.prank(validator);
validators.registerValidatorUnsafe(pubkey, staker, operator);
assertEq(validators.getValidatorByPubkey(pubkey).exists, true);
assertEq(
validators.getValidatorByPubkey(pubkey).authorizedOperator,
operator
);
assertEq(
validators
.getValidatorByPubkey(pubkey)
.authorizedCollateralProvider,
staker
);

// 2. --- Operator and strategy registration into BoltManager (middleware) ---

manager.registerEigenLayerOperator(operator);
assertEq(manager.isEigenLayerOperatorEnabled(operator), true);

manager.registerEigenLayerStrategy(
address(eigenLayerDeployer.wethStrat())
);
assertEq(
manager.isEigenLayerStrategyEnabled(
address(eigenLayerDeployer.wethStrat())
),
true
);
}

function test_deregisterEigenLayerOperatorFromAVS() public {
Expand All @@ -174,17 +222,18 @@ contract BoltManagerEigenLayerTest is Test {
);
}

// function test_getEigenLayerOperatorStake() public {
// _eigenLayerOptInRoutine();
//
// IStrategy[] memory strategies = new IStrategy[](1);
// strategies[0] = eigenLayerDeployer.wethStrat();
//
// uint256[] memory tokensAmounts = manager.getEigenLayerOperatorStake(
// operator,
// strategies
// );
// assertEq(tokensAmounts.length, 1);
// assertEq(tokensAmounts[0], 1 ether);
// }
function test_getEigenLayerOperatorStake() public {
_eigenLayerOptInRoutine();

uint256 amount = manager.getEigenLayerOperatorStake(
operator,
address(eigenLayerDeployer.weth())
);
uint256 totalStake = manager.getEigenLayerTotalStake(
2,
address(eigenLayerDeployer.weth())
);
assertEq(amount, 1 ether);
assertEq(totalStake, 1 ether);
}
}

0 comments on commit 64654b1

Please sign in to comment.