EigenLayer Contest - ABA's results

Enabling restaking of staked Ether, to be used as cryptoeconomic security for decentralized protocols and applications.

General Information

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

EigenLayer

Findings Distribution

Researcher Performance

Rank: 18/43

Findings: 2

Award: $1,223.48

QA:
grade-a

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: ABA

Also found by: 0xWaitress, 8olidity, ABA, MiloTruck, ToonVH, bughunter007, bytes032, juancito, rvierdiiev

Labels

bug
2 (Med Risk)
disagree with severity
downgraded by judge
primary issue
satisfactory
selected for report
M-02

Awards

695.2259 USDC - $695.23

External Links

Lines of code

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L786-L789

Vulnerability details

Impact

A malicious strategy can permanently DoS all currently pending withdrawals that contain it.

Vulnerability details

In order to withdrawal funds from the project a user has to:

  1. queue a withdrawal (via queueWithdrawal)
  2. complete a withdrawal (via completeQueuedWithdrawal(s))

Queuing a withdrawal, via queueWithdrawal modifies all internal accounting to reflect this:

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L345-L346

        // modify delegated shares accordingly, if applicable
        delegation.decreaseDelegatedShares(msg.sender, strategies, shares);

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L370

    if (_removeShares(msg.sender, strategyIndexes[strategyIndexIndex], strategies[i], shares[i])) {

and saves the withdrawl hash in order to be used in completeQueuedWithdrawal(s)

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L400-L415

            queuedWithdrawal = QueuedWithdrawal({
                strategies: strategies,
                shares: shares,
                depositor: msg.sender,
                withdrawerAndNonce: withdrawerAndNonce,
                withdrawalStartBlock: uint32(block.number),
                delegatedAddress: delegatedAddress
            });


        }


        // calculate the withdrawal root
        bytes32 withdrawalRoot = calculateWithdrawalRoot(queuedWithdrawal);


        // mark withdrawal as pending
        withdrawalRootPending[withdrawalRoot] = true;

In other words, it is final (as there is no cancelWithdrawl mechanism implemented).

When executingcompleteQueuedWithdrawal(s), the withdraw function of the strategy is called (if receiveAsTokens is set to true).

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L786-L789

    // tell the strategy to send the appropriate amount of funds to the depositor
    queuedWithdrawal.strategies[i].withdraw(
        msg.sender, tokens[i], queuedWithdrawal.shares[i]
    );

In this case, a malicious strategy can always revert, blocking the user from retrieving his tokens.

If a user sets receiveAsTokens to false, the other case, then the tokens will be added as shares to the delegation contract

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L797-L800

    for (uint256 i = 0; i < strategiesLength;) {
        _addShares(msg.sender, queuedWithdrawal.strategies[i], queuedWithdrawal.shares[i]);
        unchecked {
            ++i;

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L646-L647

        // if applicable, increase delegated shares accordingly
        delegation.increaseDelegatedShares(depositor, strategy, shares);

This still poses a problem because the increaseDelegatedShares function's counterpart, decreaseDelegatedShares is only callable by the strategy manager (so as for users to indirectly get theier rewards worth back via this workaround)

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/DelegationManager.sol#L168-L179

    /**
     * @notice Decreases the `staker`'s delegated shares in each entry of `strategies` by its respective `shares[i]`, typically called when the staker withdraws from EigenLayer
     * @dev Callable only by the StrategyManager
     */
    function decreaseDelegatedShares(
        address staker,
        IStrategy[] calldata strategies,
        uint256[] calldata shares
    )
        external
        onlyStrategyManager
    {

but in StrategyManager there are only 3 cases where this is called, none of which is beneficial for the user:

In other words, the workaround (of setting receiveAsTokens to false in completeQueuedWithdrawal(s)) just leaves the funds accounted and stuck in DelegationManager.

In both cases all shares/tokens associated with other strategies in the pending withdrawal are permanently blocked.

Proof of Concept

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L786-L789

Tools Used

Manual analysis

Add a cancelQueuedWithdrawl function that will undo the accounting and cancel out any dependency on the malicious strategy. Although this solution may create a front-running opportunity for when their withdrawal will be slashed via slashQueuedWithdrawal, there may exist workarounds to this.

Another possibility is to implement a similar mechanism to how slashQueuedWithdrawal treats malicious strategies: adding a list of strategy indices to skip

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L532-L535 https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L560-L566

     * @param indicesToSkip Optional input parameter -- indices in the `strategies` array to skip (i.e. not call the 'withdraw' function on). This input exists
     * so that, e.g., if the slashed QueuedWithdrawal contains a malicious strategy in the `strategies` array which always reverts on calls to its 'withdraw' function,
     * then the malicious strategy can be skipped (with the shares in effect "burned"), while the non-malicious strategies are still called as normal.
     */
     
     ...

        for (uint256 i = 0; i < strategiesLength;) {
            // check if the index i matches one of the indices specified in the `indicesToSkip` array
            if (indicesToSkipIndex < indicesToSkip.length && indicesToSkip[indicesToSkipIndex] == i) {
                unchecked {
                    ++indicesToSkipIndex;
                }
            } else {     

Assessed type

DoS

#0 - c4-pre-sort

2023-05-09T13:37:22Z

0xSorryNotSorry marked the issue as primary issue

#1 - c4-sponsor

2023-05-12T00:39:38Z

Sidu28 marked the issue as disagree with severity

#2 - Sidu28

2023-05-12T00:39:42Z

The description of lack of check here is accurate. There is zero actual impact; we think this is informational severity.

#3 - GalloDaSballo

2023-05-28T19:32:01Z

@Sidu28 if we assumed the Strategy not to be malicious, but to revert for some reason (e.g. lack of liquidity, smart contract bug, etc...)

Would you consider the finding as valid since the user cannot withdraw from all others due to having one withdraw, or is there some other reason why you believe the finding to be Informational?

#4 - c4-judge

2023-05-31T18:13:59Z

GalloDaSballo changed the severity to 2 (Med Risk)

#5 - GalloDaSballo

2023-05-31T18:16:19Z

The Warden has shown how, any revert in a strategy (for example it being paused), will make queued withdrawals revert, even if the withdrawal should work for other strategies

This falls into the category of DOS and I believe is more appropriately judged as Medium

#6 - ChaoticWalrus

2023-06-04T14:54:58Z

The Warden has shown how, any revert in a strategy (for example it being paused), will make queued withdrawals revert, even if the withdrawal should work for other strategies

This falls into the category of DOS and I believe is more appropriately judged as Medium

Even if a malicious strategy exists, there is no permanent delay here.

Users can mark the receiveAsTokens input to completeQueuedWithdrawal as false here https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L437-L442 and then the shares will be transferred to the 'withrdrawing' user here https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L795-L803 who can then queue a new withdrawal not containing the malicious strategy.

The description provided by the warden of the DelegationManager's behavior is inaccurate -- the funds do not end up 'stuck in the DelegationManager' -- they will be withdrawable as part of a new queued withdrawal which excludes the malicious strategy.

#7 - abarbatei

2023-06-05T09:14:16Z

The Warden has shown how, any revert in a strategy (for example it being paused), will make queued withdrawals revert, even if the withdrawal should work for other strategies This falls into the category of DOS and I believe is more appropriately judged as Medium

Even if a malicious strategy exists, there is no permanent delay here.

Users can mark the receiveAsTokens input to completeQueuedWithdrawal as false here https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L437-L442 and then the shares will be transferred to the 'withrdrawing' user here https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L795-L803 who can then queue a new withdrawal not containing the malicious strategy.

The description provided by the warden of the DelegationManager's behavior is inaccurate -- the funds do not end up 'stuck in the DelegationManager' -- they will be withdrawable as part of a new queued withdrawal which excludes the malicious strategy.

Hey, https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L795-L803 does not do:

shares will be transferred to the 'withrdrawing' user

it simply increments internal accounting and delegated shares associated to user in the delegation contract. But these are not withdrawn without a queueWithdrawal call

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L647

queue a new withdrawal not containing the malicious strategy.

a new queue can not reuse the already used balance as it was already accounted for in https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L345-L346

Maybe I am missing something of course. Regardless, awaiting judge feedback.

#8 - ChaoticWalrus

2023-06-05T14:55:35Z

it simply increments internal accounting and delegated shares associated to user in the delegation contract. But these are not withdrawn without a queueWithdrawal call

Yes, this is what I would describe as transferring the shares, similar to how the 'transfer in' portion of an ERC20 transfer works. But this is a semantic argument; I agree with the substance of your description.

a new queue can not reuse the already used balance as it was already accounted for in https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L345-L346

Maybe I am missing something of course. Regardless, awaiting judge feedback.

I think perhaps you are missing that the internal _addShares function calls the Delegation Manager as well? See here https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L646-L647

If the user marks receiveAsTokens as false, then this line will be triggered https://github.com/code-423n4/2023-04-eigenlayer/blob/5e4872358cd2bda1936c29f460ece2308af4def6/src/contracts/core/StrategyManager.sol#L798 which calls into the internal _addShares function and 're-adds' these delegated shares, so they can indeed be queued in a new withdrawal.

I can provide an example if it will help?

#9 - ChaoticWalrus

2023-06-05T14:57:30Z

Basically, the 're-adding' reverses the accounting taken in the initial queueWithdrawal action, to clarify. This then allows the accounting done in the queueWithdrawal action to be performed once again, when a new withdrawal is queued.

#10 - ChaoticWalrus

2023-06-05T14:59:52Z

@GalloDaSballo would appreciate you taking another look at this -- I am happy to provide additional context and/or an example, if desired.

#11 - GalloDaSballo

2023-06-05T15:09:50Z

Thank you @ChaoticWalrus for the tag, will check today

#12 - GalloDaSballo

2023-06-06T14:57:08Z

@ChaoticWalrus

It seems like the worst case scenario would be having to re-queue without the missing strategy which would require waiting for the withdrawal to unlock

So the question left to answer is whether an additional wait period is acceptable

NOTE: I edited this comment because as you pointed out the shares accounting is internal and doesn't trigger an interaction with the strategy

#13 - ChaoticWalrus

2023-06-06T17:36:15Z

It seems like the worst case scenario would be having to re-queue without the missing strategy which would require waiting for the withdrawal to unlock

Yes, agreed this is the impact + worst-case scenario. The existing functionality was designed -- in part at least -- to address concerns around malicious Strategies.

So the question left to answer is whether an additional wait period is acceptable

I suppose so, yes. We have deemed this acceptable ourselves but I could see it being viewed differently. Regardless, the impact here is orders of magnitude less than the original claimed impact.

#14 - GalloDaSballo

2023-06-08T10:10:05Z

The Warden has shown how, due to the possibility of queueing of a withdrawal with multiple strategies, in the case in which one of the strategies stops working (reverts, paused, malicious), the withdrawal would be denied

As the sponsor said, in those scenarios, the withdrawer would have to perform a second withdrawal, which would have to be re-queued

Intuitively, a withdrawer that always withdraws a separate strategy would also never see their withdrawal denied (except for the malicious strategy)

As we can see there are plenty of side steps to the risk shown, however, the functionality of the function is denied, even if temporarily, leading to it not working as intended, and for this reason I believe Medium Severity to be the most appropriate

As shown above, the finding could be nofixed, however it seems to me like most users would want to plan around the scenarios described in this finding and its duplicates

#15 - c4-judge

2023-06-08T12:26:57Z

GalloDaSballo marked the issue as satisfactory

#16 - c4-judge

2023-06-08T12:28:11Z

GalloDaSballo marked the issue as selected for report

Findings Information

🌟 Selected for report: ABA

Also found by: 0xWaitress, 8olidity, ABA, MiloTruck, ToonVH, bughunter007, bytes032, juancito, rvierdiiev

Labels

bug
2 (Med Risk)
satisfactory
duplicate-132

Awards

695.2259 USDC - $695.23

External Links

Lines of code

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L329-L340 https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L442-L446 https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L456-L464

Vulnerability details

Impact

A pod malfunction or a malicious actor exploiting it pauses all strategies withdrawals with the current existing pauses mechanism. Depending on the issue, user funds may remain blocked for a undetermined period of time.

Vulnerability details

In StrategyManager the function that calls the beacon chain ETH withdraw is _withdrawBeaconChainETH

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L834-L835

        // withdraw the beaconChainETH to the recipient
        eigenPodManager.withdrawRestakedBeaconChainETH(staker, recipient, amount);

StrategyManager uses a pause mechanism that has onlyWhenNotPaused(PAUSED_WITHDRAWALS): it pauses all withdraws, for both pods and normal tokens.

If there is an issue only with withdrawing from the beacon chain, other strategies will also result in being paused. This in turn leads to user funds being blocked, either temporary or permanently.

Proof of Concept

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L329-L340 https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L442-L446 https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L456-L464

Tools Used

Manual analysis.

Add a PAUSED_WITHDRAW_RESTAKED_ETH pause state, similar to how it is done in EigenPodManager and guard StrategyManager._withdrawBeaconChainETH with it.

Assessed type

DoS

#0 - c4-pre-sort

2023-05-09T13:39:18Z

0xSorryNotSorry marked the issue as duplicate of #132

#1 - c4-judge

2023-06-08T12:26:46Z

GalloDaSballo marked the issue as satisfactory

Findings Information

Labels

bug
grade-a
high quality report
QA (Quality Assurance)
Q-16

Awards

528.2547 USDC - $528.25

External Links

QA Report for contest

Overview

During the audit, 1 low, 4 non-critical and 3 refactoring issues were found.

Low Risk Issues

Total: 1 instances over 1 issues

#IssueInstances
[L-01]StrategyManager._removeShares does not check for 0 address; reverts with misleading message1

Refactoring Issues

Total: 5 instances over 3 issues

#IssueInstances
[R-01]Reuse userShares in StrategyManager.recordOvercommittedBeaconChainETH calculation1
[R-02]Use already defined PAUSE_ALL instead of type(uint256).max3
[R-03]Add createIfNotExisting flag on EigenPodManager.stake1

Non-critical Issues

Total: 8 instances over 4 issues

#IssueInstances
[NC-01]If amount is 0 the executions passes through in StrateguManager.recordOvercommittedBeaconChainETH1
[NC-02]Check that argument _pauserRegistry from Pausable._initializePauser is a contract1
[NC-03]Remove redundant functions that wrap over other functions from StrategyBase3
[NC-04]Misleading or incorrect documentation3

Low Risk Issues (1)

[L-01] StrategyManager._removeShares does not check for 0 address; reverts with misleading message

Description

Wehn withdrawing from the project, execution flow reaches StrategyManager._removeShares. This function takes an strategy object (address) as one of its parameter but it does not check if it is 0.

        // sanity checks on inputs
        require(depositor != address(0), "StrategyManager._removeShares: depositor cannot be zero address");
        require(shareAmount != 0, "StrategyManager._removeShares: shareAmount should not be zero!");

Execution will revert but only because of the 0 address strategy not being found in _removeStrategyFromStakerStrategyList

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L736

            require(j != stratsLength, "StrategyManager._removeStrategyFromStakerStrategyList: strategy not found");

_removeShares expects callers to check the address but not all flows do check this. Examples - queueWithdrawal -> _removeShares - slashShares -> _removeShares

As such, if a user mistakenly adds the 0 address in the list of strategies to withdraw from, when calling queueWithdrawal, or the admin when calling slashShares, then the misleading strategy not found revert message will be seen.

Instances (1)

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L683-L685

Recommendation

Add 0 address check in _removeShares.

Refactoring Issues (3)

[R-01] Reuse userShares in StrategyManager.recordOvercommittedBeaconChainETH calculation

Description

In StrategyManager at line 191 debt is calculate as so:

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L191

    uint256 debt = amount - userShares;

and at line 193 amount is then set to its new value:

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L193

    amount -= debt;

There is a redundant subtraction here that can be changed to

    amount = userShares;
Instances (1)

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L191-L193

Recommendation

Change line 193 to:

    amount = userShares;

[R-02] Use already defined PAUSE_ALL instead of type(uint256).max

Description

The Pausable contract declares a PAUSE_ALL constant with the value type(uint256).max

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/permissions/Pausable.sol#L23

    uint256 constant internal PAUSE_ALL = type(uint256).max;

But further down in the contract, in the function Pausable.pauseAll that is used to pause all functionalities of a contract, it is not used.

    /**
     * @notice Alias for `pause(type(uint256).max)`.
     */
    function pauseAll() external onlyPauser {
        _paused = type(uint256).max;
        emit Paused(msg.sender, type(uint256).max);
    }
Instances (3)

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/permissions/Pausable.sol#L78-L84

Recommendation

Change type(uint256).max) to PAUSE_ALL in the contest of Pausable.pauseAll.

[R-03] Add "createIfNotExisting" flag on EigenPodManager.stake

Description

In EigenPodManager, the function stake creates a pod if the one you want to stake in does not exists (as it's documented to do). Although this is to be a QoL feature, when staking one does not consider naturally to also create the staking environment.

Consider adding a flag that if true will create the pod if not existing.

Instances

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/pods/EigenPodManager.sol#L112

Recommendation

Add a flag that if true will create the pod if not existing, do not have this behavior as default.

Non-critical Issues (4)

[NC-01] If amount is 0 the executions passes through in StrateguManager.recordOvercommittedBeaconChainETH

Description

In StrateguManager.recordOvercommittedBeaconChainETH there is a check that if amount is not 0 then _removeShares should not be called.

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L196-L198

if (amount != 0) { _removeShares(overcommittedPodOwner, beaconChainETHStrategyIndex, beaconChainETHStrategy, amount); }

This check should include all the leftover code as it would call a decreaseDelegatedShares with an empty amount to withdrawal.

Instances (1)

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/core/StrategyManager.sol#L196-L198

Recommendation

Add all the code after the check in the if block.

[NC-02] Check that argument _pauserRegistry from Pausable._initializePauser is a contract

Description

The currently done checks in the function Pausable._initializePauser for the _pauserRegistry do not include a contract check. As such, an EOA can be set.

    function _initializePauser(IPauserRegistry _pauserRegistry, uint256 initPausedStatus) internal {
        require(
            address(pauserRegistry) == address(0) && address(_pauserRegistry) != address(0),
            "Pausable._initializePauser: _initializePauser() can only be called once"
        );
Instances (1)

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/permissions/Pausable.sol#L55-L59

Recommendation

Add a check that _pauserRegistry should be a contract.

[NC-03] Remove redundant functions that wrap over other functions from StrategyBase

Description

In StrategyBase there are several functions where the documentation indicates

* @notice In contrast to <next_function>, this function **may** make state modifications

while simply they simply call the function that, in its turn indicatesthat it does not modify state changes.

    /**
     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
     * @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
     * @param amountShares is the amount of shares to calculate its conversion into the underlying token
     * @dev Implementation for these functions in particular may vary signifcantly for different strategies
     */
    function sharesToUnderlyingView(uint256 amountShares) public view virtual override returns (uint256) {
        if (totalShares == 0) {
            return amountShares;
        } else {
            return (_tokenBalance() * amountShares) / totalShares;
        }
    }


    /**
     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
     * @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
     * @param amountShares is the amount of shares to calculate its conversion into the underlying token
     * @dev Implementation for these functions in particular may vary signifcantly for different strategies
     */
    function sharesToUnderlying(uint256 amountShares) public view virtual override returns (uint256) {
        return sharesToUnderlyingView(amountShares);
    }

All these functions are view so they cannot change state.

Instances (3)

https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/strategies/StrategyBase.sol#L166-L188 https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/strategies/StrategyBase.sol#L190-L213 https://github.com/code-423n4/2023-04-eigenlayer/blob/main/src/contracts/strategies/StrategyBase.sol#L215-L229

Recommendation

Leave only one example of each (the one without the View in the name, as this is not standard).

[NC-04] Misleading or incorrect documentation

Description

There are places in the project where there is either incorrect or misleading code documentation (either via NatSpec or inline). These need to be corrected

Instances (3)
  • StrategyManager.depositBeaconChainETH declares the amount param 2 times, the second time being a leftover from a copy-paste (code)

  • in StrategyManager functions addStrategiesToDepositWhitelist and removeStrategiesFromDepositWhitelist document that they are Owner-only function when in fact they are executable only by the strategy whitelister (onlyStrategyWhitelister) (code)

  • in BeaconChainProofs.getBalanceFromBalanceRoot remove incorrect "is" from documentation (code)

Recommendation

Resolve the mentioned issues

#0 - c4-pre-sort

2023-05-09T14:34:29Z

0xSorryNotSorry marked the issue as high quality report

#1 - GalloDaSballo

2023-06-02T09:17:00Z

| [L-01] | StrategyManager._removeShares does not check for 0 address; reverts with misleading message | 1 | R | [R-01]| Reuse userShares in StrategyManager.recordOvercommittedBeaconChainETH calculation | 1 | R | [R-02]| Use already defined PAUSE_ALL instead of type(uint256).max | 3 | R | [R-03]| Add createIfNotExisting flag on EigenPodManager.stake | 1 | Disagree, I think their solution is comfier | [NC-01]| If amount is 0 the executions passes through in StrateguManager.recordOvercommittedBeaconChainETH | 1 | NC | [NC-02]| Check that argument _pauserRegistry from Pausable._initializePauser is a contract | 1 | R | [NC-03]| Remove redundant functions that wrap over other functions from StrategyBase | 3 | Disagree, the base inherits from interface and changes to view, but the function is non-view so it can be overriden as such | [NC-04]| Misleading or incorrect documentation | 3 | L because docs

1L 4R 1NC

#2 - c4-judge

2023-06-02T09:38:31Z

GalloDaSballo marked the issue as grade-a

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter