A sandwich attack on the sweepERC20 function could lead to the theft of a portion of ERC20 tokens accumulated in the DepositQueue contract.
Proof of Concept
Attack Method: By exploiting the sandwich attack, a portion of ERC20 token rewards can be stolen. This is because the accumulated ERC20 tokens in DepositQueue are not considered when calculating TVL (Total Value Locked). However, when sweepERC20 is invoked by the admin, these tokens are transferred to the operator delegator to be deposited into a strategy and affect the TVL calculation.
function sweepERC20(IERC20 token) external onlyERC20RewardsAdmin {
uint256 balance = IERC20(token).balanceOf(address(this));
if (balance > 0) {
uint256 feeAmount = 0;
// Sweep fees if configured
if (feeAddress != address(0x0) && feeBasisPoints > 0) {
feeAmount = (balance * feeBasisPoints) / 10000;
IERC20(token).safeTransfer(feeAddress, feeAmount);
emit ProtocolFeesPaid(token, feeAmount, feeAddress);
}
// Approve and deposit the rewards
token.approve(address(restakeManager), balance - feeAmount);
restakeManager.depositTokenRewardsFromProtocol(token, balance - feeAmount);
// Add to the total earned
totalEarned[address(token)] = totalEarned[address(token)] + balance - feeAmount;
// Emit the rewards event
emit RewardsDeposited(IERC20(address(token)), balance - feeAmount);
}
}
function depositTokenRewardsFromProtocol(
IERC20 _token,
uint256 _amount
) external onlyDepositQueue {
// Get the TVLs for each operator delegator and the total TVL
(, uint256[] memory operatorDelegatorTVLs, uint256 totalTVL) = calculateTVLs();
// Determine which operator delegator to use
IOperatorDelegator operatorDelegator = chooseOperatorDelegatorForDeposit(
operatorDelegatorTVLs,
totalTVL
);
// Transfer the tokens to this address
_token.safeTransferFrom(msg.sender, address(this), _amount);
// Approve the tokens to the operator delegator
_token.safeApprove(address(operatorDelegator), _amount);
// Deposit the tokens into EigenLayer
operatorDelegator.deposit(_token, _amount);
}
TVL Calculation: The TVL calculation in the RestakeManager contract only considers the ETH balance of DepositQueue, not ERC20 tokens. After sweepERC20 is called, the ERC20 tokens are deposited into a strategy, impacting the TVL calculation.
Attacker deposits A value of collateral token into the protocol, and he receives ezETHBalanceOfAttacker = A * totalSupplyOfEzETH / TVL as ezETH.
Admin calls sweepERC20, causing the TVL to increase due to the accumulated ERC20 tokens. Suppose, the added value to TVL is B.
Attacker requests to withdraw by transferring his ezETH balance. The value to be redeemed will be: ezETHBalanceOfAttacker * (TVL + A + B)/(totalSupplyOfEzETH + ezETHBalanceOfAttacker). By replacing ezETHBalanceOfAttacker with A * totalSupplyOfEzETH / TVL as explained in step 1, the value that the attacker will gain will be A * B / (TVL + A). This shows that A / (TVL + A) portion of B (which is accumulated ERC20 value as reward) is stolen by the attacker.
Tools Used
Recommended Mitigation Steps
There are two recomendations:
First: Include the ERC20 balance of DepositQueue into the TVL after deduction of fee amount.
Lines of code
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L274-L349
Vulnerability details
Impact
A sandwich attack on the
sweepERC20
function could lead to the theft of a portion of ERC20 tokens accumulated in theDepositQueue
contract.Proof of Concept
Attack Method: By exploiting the sandwich attack, a portion of ERC20 token rewards can be stolen. This is because the accumulated ERC20 tokens in
DepositQueue
are not considered when calculating TVL (Total Value Locked). However, whensweepERC20
is invoked by the admin, these tokens are transferred to the operator delegator to be deposited into a strategy and affect the TVL calculation.https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Deposits/DepositQueue.sol#L252-L277
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L645-L668
TVL Calculation: The TVL calculation in the
RestakeManager
contract only considers the ETH balance ofDepositQueue
, not ERC20 tokens. AftersweepERC20
is called, the ERC20 tokens are deposited into a strategy, impacting the TVL calculation.https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L274-L349
Attack Scenario
A
value of collateral token into the protocol, and he receivesezETHBalanceOfAttacker = A * totalSupplyOfEzETH / TVL
as ezETH.sweepERC20
, causing the TVL to increase due to the accumulated ERC20 tokens. Suppose, the added value to TVL isB
.ezETHBalanceOfAttacker * (TVL + A + B)/(totalSupplyOfEzETH + ezETHBalanceOfAttacker)
. By replacingezETHBalanceOfAttacker
withA * totalSupplyOfEzETH / TVL
as explained in step 1, the value that the attacker will gain will beA * B / (TVL + A)
. This shows thatA / (TVL + A)
portion ofB
(which is accumulated ERC20 value as reward) is stolen by the attacker.Tools Used
Recommended Mitigation Steps
There are two recomendations:
First: Include the ERC20 balance of
DepositQueue
into the TVL after deduction of fee amount.Second: Whenever TVL is to be calculated, it checks the ERC20 balance of
DepositQueue
. If it is nonzero, then automatically callssweepERC20
.Assessed type
Context