DeFiFoundrySolidity
16,653 OP
View results
Submission Details
Severity: low
Invalid

Lack of Slippage and Price Protection in _swapUnderlyingToAsset Function

Summary

In StrategyOp.sol and StrategyArb.sol, the claimAndSwap function has a price check that requires minOut > _amount, but this is insufficient as a slippage protection mechanism since it only ensures receiving more than 1:1, not accounting for actual market price and maximum acceptable slippage.

Vulnerability Details

Found in:

  1. StrategyOp.sol [Lines 92-105]:

function claimAndSwap(uint256 _amountClaim, uint256 _minOut, IVeloRouter.route[] calldata _path ) external onlyKeepers {
transmuter.claim(_amountClaim, address(this));
uint256 balBefore = asset.balanceOf(address(this));
_swapUnderlyingToAsset(_amountClaim, _minOut, _path);
uint256 balAfter = asset.balanceOf(address(this));
require((balAfter - balBefore) >= _minOut, "Slippage too high");
transmuter.deposit(asset.balanceOf(address(this)), address(this));
}
function _swapUnderlyingToAsset(uint256 _amount, uint256 minOut, IVeloRouter.route[] calldata _path) internal {
// TODO : we swap WETH to ALETH -> need to check that price is better than 1:1
// uint256 oraclePrice = 1e18 * 101 / 100;
require(minOut > _amount, "minOut too low"); // @audit - insufficient slippage protection
//...
}
  1. StrategyArb.sol has the same issue with identical code structure.

Impact

  • MEV bots can sandwich the swaps

  • No protection against price manipulation in the path

  • Keepers could potentially frontrun with unfavorable prices as long as it's slightly above 1:1

  • Loss of value through excessive slippage

Proof of Code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "forge-std/Test.sol";
contract SlippageExploitTest is Test {
address keeper = address(0x1);
address strategy = address(0x2);
function testSlippageExploit() public {
// Setup: WETH/alETH price is 1:1.5
uint256 marketPrice = 1.5 ether;
// Keeper calls with minimum output just above 1:1
uint256 keeperMinOut = 1.01 ether;
// This would pass the check
assertTrue(keeperMinOut > 1 ether, "Passes minOut check");
// But results in significant loss vs market price
uint256 loss = marketPrice - keeperMinOut;
assertGt(loss, 0.4 ether, "Significant loss occurred");
// In reality, this could be exploited via:
// 1. Keeper frontruns with unfavorable price
// 2. MEV sandwich attack
// 3. Path manipulation through specified route
}
}

Recommendations

  1. Implement proper slippage protection using an oracle or TWAP:

function _swapUnderlyingToAsset(uint256 _amount, uint256 minOut, IVeloRouter.route[] calldata _path) internal {
// Get oracle price
uint256 oraclePrice = getOraclePrice(); // Implement oracle price fetch
// Calculate minimum acceptable output with slippage
uint256 expectedOutput = (_amount * oraclePrice) / 1e18;
uint256 minAcceptableOutput = (expectedOutput * (10000 - MAX_SLIPPAGE)) / 10000;
// Enforce minimum output
require(minOut >= minAcceptableOutput, "Excessive slippage");
// Perform swap
require(underlying.balanceOf(address(this)) >= _amount, "not enough underlying balance");
IVeloRouter(router).swapExactTokensForTokens(_amount, minOut, _path, address(this), block.timestamp);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
6 months ago

Appeal created

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.