When _sellStakedUSDe swaps sUSDe into sDAI, the slippage is zero. But it is left 0 intended as the DAI to borrow token swap will check the slippage. But what if borrowToken == address(DAI), then no swap is executed and no slippage check is made in the second leg. Hence the sUSDe -> DAI swap is prone to MEV / slippage issues.
If a private mempool is used, then the volatility and high slippage will impact here. If no private mempool is used, then the MEV attack is easy, frontrun this action by buying the maximum sDAI as possible, and it will increase the sDAI price compared to sUSDe in the curve pool. Then this action will run buying sDAI at a much higher price which will get backrun to sell the sDAI at a higher price than the price bought when frontrunning.
So, overall using 0 slippage when the borrow token is DAI, is prone to slippage. And using using 0 as a limit in the curve swap is an issue.
function _sellStakedUSDe(
uint256 sUSDeAmount,
address borrowToken,
uint256 minPurchaseAmount,
bytes memory exchangeData,
uint16 dexId
) internal returns (uint256 borrowedCurrencyAmount) {
Trade memory sDAITrade = Trade({
tradeType: TradeType.EXACT_IN_SINGLE,
sellToken: address(sUSDe),
buyToken: address(sDAI),
amount: sUSDeAmount,
>>>> limit: 0, // NOTE: no slippage guard is set here, it is enforced in the second leg
// of the trade.
deadline: block.timestamp,
exchangeData: abi.encode(CurveV2Adapter.CurveV2SingleData({
pool: 0x167478921b907422F8E88B43C4Af2B8BEa278d3A,
fromIndex: 1, // sUSDe
toIndex: 0 // sDAI
}))
});
(/* */, uint256 sDAIAmount) = sDAITrade._executeTrade(uint16(DexId.CURVE_V2));
// Unwraps the sDAI to DAI
uint256 daiAmount = sDAI.redeem(sDAIAmount, address(this), address(this));
>>>> if (borrowToken != address(DAI)) {
Trade memory trade = Trade({
tradeType: TradeType.EXACT_IN_SINGLE,
sellToken: address(DAI),
buyToken: borrowToken,
amount: daiAmount,
limit: minPurchaseAmount,
deadline: block.timestamp,
exchangeData: exchangeData
});
// Trades the unwrapped DAI back to the given token.
(/* */, borrowedCurrencyAmount) = trade._executeTrade(dexId);
} else {
borrowedCurrencyAmount = daiAmount;
}
}
Impact
If a private mempool is used, then the volatility and high slippage will impact here. If no private mempool is used, then the MEV attack is easy. Executing the curve swap with 0 slippage when borrowToken == address(DAI) is a loss of funds to protocol. So high impact with medium likelihood, due to borrowToken == address(DAI) condition.
Ironsidesec
Medium
_sellStakedUSDe
is prone to slippage and MEVSummary
issue & likelihood: Executing the curve swap with 0 slippage when
borrowToken == address(DAI)
root cause : 0 slippage limit in curvesUSDe -> sDAI
swapVulnerability Detail
Call flow : BaseStrategyVault.redeemFromNotional() -> BaseStakingVault._redeemFromNotional() -> EthenaVault._executeInstantRedemption() -> Ethena._sellStakedUSDe()
When
_sellStakedUSDe
swaps sUSDe into sDAI, the slippage is zero. But it is left 0 intended as the DAI to borrow token swap will check the slippage. But what ifborrowToken == address(DAI)
, then no swap is executed and no slippage check is made in the second leg. Hence the sUSDe -> DAI swap is prone to MEV / slippage issues.If a private mempool is used, then the volatility and high slippage will impact here. If no private mempool is used, then the MEV attack is easy, frontrun this action by buying the maximum sDAI as possible, and it will increase the sDAI price compared to sUSDe in the curve pool. Then this action will run buying sDAI at a much higher price which will get backrun to sell the sDAI at a higher price than the price bought when frontrunning.
So, overall using 0 slippage when the borrow token is DAI, is prone to slippage. And using using 0 as a limit in the curve swap is an issue.
https://github.com/sherlock-audit/2024-06-leveraged-vaults/blob/14d3eaf0445c251c52c86ce88a84a3f5b9dfad94/leveraged-vaults-private/contracts/vaults/staking/protocols/Ethena.sol#L124-L167
Impact
If a private mempool is used, then the volatility and high slippage will impact here. If no private mempool is used, then the MEV attack is easy. Executing the curve swap with 0 slippage when
borrowToken == address(DAI)
is a loss of funds to protocol. So high impact with medium likelihood, due toborrowToken == address(DAI)
condition.Code Snippet
https://github.com/sherlock-audit/2024-06-leveraged-vaults/blob/14d3eaf0445c251c52c86ce88a84a3f5b9dfad94/leveraged-vaults-private/contracts/vaults/staking/protocols/Ethena.sol#L124-L167
Tool used
Manual Review
Recommendation
https://github.com/sherlock-audit/2024-06-leveraged-vaults/blob/14d3eaf0445c251c52c86ce88a84a3f5b9dfad94/leveraged-vaults-private/contracts/vaults/staking/protocols/Ethena.sol#L124-L167
Duplicate of #18