Platform: Code4rena
Start Date: 27/04/2023
Pot Size: $90,500 USDC
Total HM: 4
Participants: 43
Period: 7 days
Judge: GalloDaSballo
Id: 233
League: ETH
Rank: 40/43
Findings: 1
Award: $71.60
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: volodya
Also found by: 0xWaitress, 0xnev, ABA, Aymen0909, Cyfrin, QiuhaoLi, RaymondFam, btk, bughunter007, ihtishamsudo, juancito, libratus, niser93, sashik_eth
71.6048 USDC - $71.60
Total Low issues |
---|
Risk | Issues Details | Number |
---|---|---|
[L-01] | MAX_STAKER_STRATEGY_LIST_LENGTH is not implemented correctltly | 1 |
[L-02] | _setWithdrawalDelayBlocks() lacks sanity checks | 1 |
MAX_STAKER_STRATEGY_LIST_LENGTH
is not implemented correctltlyThe _addShares()
function in the StrategyManager.sol
contract is currently implemented in a way that causes it to revert when the depositor's strategy list is equal to MAX_STAKER_STRATEGY_LIST_LENGTH
. This is not correct, as it should only revert when the list is greater than max length.
The stakerStrategyList
mapping has a maximum length of MAX_STAKER_STRATEGY_LIST_LENGTH
. Therefore, the _addShares()
function should only revert when stakerStrategyList[depositor].length > MAX_STAKER_STRATEGY_LIST_LENGTH
:
function _addShares(address depositor, IStrategy strategy, uint256 shares) internal { // sanity checks on inputs require(depositor != address(0), "StrategyManager._addShares: depositor cannot be zero address"); require(shares != 0, "StrategyManager._addShares: shares should not be zero!"); // if they dont have existing shares of this strategy, add it to their strats if (stakerStrategyShares[depositor][strategy] == 0) { require( stakerStrategyList[depositor].length < MAX_STAKER_STRATEGY_LIST_LENGTH, "StrategyManager._addShares: deposit would exceed MAX_STAKER_STRATEGY_LIST_LENGTH" ); stakerStrategyList[depositor].push(strategy); } // add the returned shares to their existing shares for this strategy stakerStrategyShares[depositor][strategy] += shares; // if applicable, increase delegated shares accordingly delegation.increaseDelegatedShares(depositor, strategy, shares); }
As you can see in the code, the function currently throws when the depositor tries to add the 32nd strategy to their list, which is not consistent with the maximum length of the list.
Note that while this issue may not directly impact users of EigenLayer, it could have an impact on protocols built on top of EigenLayer.
Manual Review
We recommend to update the _addShares() function as follows:
function _addShares(address depositor, IStrategy strategy, uint256 shares) internal { // sanity checks on inputs require(depositor != address(0), "StrategyManager._addShares: depositor cannot be zero address"); require(shares != 0, "StrategyManager._addShares: shares should not be zero!"); // if they dont have existing shares of this strategy, add it to their strats if (stakerStrategyShares[depositor][strategy] == 0) { require( stakerStrategyList[depositor].length <= MAX_STAKER_STRATEGY_LIST_LENGTH, "StrategyManager._addShares: deposit would exceed MAX_STAKER_STRATEGY_LIST_LENGTH" ); stakerStrategyList[depositor].push(strategy); } // add the returned shares to their existing shares for this strategy stakerStrategyShares[depositor][strategy] += shares; // if applicable, increase delegated shares accordingly delegation.increaseDelegatedShares(depositor, strategy, shares); }
This updated function will only revert when the depositor's strategy list exceeds MAX_STAKER_STRATEGY_LIST_LENGTH
.
_setWithdrawalDelayBlocks()
lacks sanity checksThe _setWithdrawalDelayBlocks()
function lacks sanity checks to prevent the withdrawalDelayBlocks
variable from being set to 0, which could allow for malicious withdrawals to be executed instantly.
The withdrawalDelayBlocks
variable is used to enforce a 7-day delay window for completing queued withdrawals in the StrategyManager.sol
contract. This delay is measured in blocks and can be adjusted by the contract owner, but is subject to a maximum value of MAX_WITHDRAWAL_DELAY_BLOCKS
. However, the function is missing a MIN_WITHDRAWAL_DELAY_BLOCKS
check, which means that the delay could be set to 0.
function _setWithdrawalDelayBlocks(uint256 _withdrawalDelayBlocks) internal { require(_withdrawalDelayBlocks <= MAX_WITHDRAWAL_DELAY_BLOCKS, "StrategyManager.setWithdrawalDelay: _withdrawalDelayBlocks too high"); emit WithdrawalDelayBlocksSet(withdrawalDelayBlocks, _withdrawalDelayBlocks); withdrawalDelayBlocks = _withdrawalDelayBlocks; }
Manual Review
To make the contract more robust, a MIN_WITHDRAWAL_DELAY_BLOCKS
check should be added to the _setWithdrawalDelayBlocks()
function to ensure that the withdrawalDelayBlocks variable is not set to 0. This will provide an additional layer of protection against malicious withdrawals.
#0 - GalloDaSballo
2023-06-01T17:59:49Z
[L-01] MAX_STAKER_STRATEGY_LIST_LENGTH is not implemented correctltly R
_setWithdrawalDelayBlocks L
#1 - c4-judge
2023-06-02T09:38:49Z
GalloDaSballo marked the issue as grade-b