Normal behavior:
When unwinding a leveraged position, the contract should withdraw sufficient collateral from Aave to cover the flash loan repayment after swapping. The withdrawal amount must be calculated using the asset's loan-to-value (LTV) ratio, which determines how much debt can be backed by a given collateral amount.
Problem:
The _executeUnwindOperation() function incorrectly uses the liquidation threshold (index 2) instead of the LTV ratio (index 1) from Aave's reserve configuration data when calculating collateral to withdraw. Since liquidation thresholds are typically higher than LTV ratios (e.g., 82.5% vs 80%), this causes the contract to withdraw less collateral than required, potentially failing to generate enough proceeds to repay the flash loan.
https://github.com/CodeHawks-Contests/2026-02-stratax-contracts/blob/f6525334ddeb7910733432a992daecb0a8041430/src/Stratax.sol#L380-420
function _executeUnwindOperation(address _asset, uint256 _amount, uint256 _premium, bytes calldata _params)
internal
returns (bool)
{
uint256 withdrawnAmount;
{
@> (,, uint256 liqThreshold,,,,,,,) =
aaveDataProvider.getReserveConfigurationData(unwindParams.collateralToken);
uint256 debtTokenPrice = IStrataxOracle(strataxOracle).getPrice(_asset);
uint256 collateralTokenPrice = IStrataxOracle(strataxOracle).getPrice(unwindParams.collateralToken);
require(debtTokenPrice > 0 && collateralTokenPrice > 0, "Invalid prices");
uint256 collateralToWithdraw = (
_amount * debtTokenPrice * (10 ** IERC20(unwindParams.collateralToken).decimals()) * LTV_PRECISION
) / (collateralTokenPrice * (10 ** IERC20(_asset).decimals()) * liqThreshold);
Risk
Proof of Concept
Recommended Mitigation
- function _executeUnwindOperation(address _asset, uint256 _amount, uint256 _premium, bytes calldata _params)
internal
returns (bool)
{
// ...
uint256 withdrawnAmount;
{
- // Get LTV from Aave for the collateral token
- (,, uint256 liqThreshold,,,,,,,) =
+ // Get LTV (index 1) not liquidation threshold (index 2) for debt-backed collateral calculation
+ (, uint256 ltv,,,,,,,,) =
aaveDataProvider.getReserveConfigurationData(unwindParams.collateralToken);
uint256 debtTokenPrice = IStrataxOracle(strataxOracle).getPrice(_asset);
uint256 collateralTokenPrice = IStrataxOracle(strataxOracle).getPrice(unwindParams.collateralToken);
require(debtTokenPrice > 0 && collateralTokenPrice > 0, "Invalid prices");
uint256 collateralToWithdraw = (
_amount * debtTokenPrice * (10 ** IERC20(unwindParams.collateralToken).decimals()) * LTV_PRECISION
- ) / (collateralTokenPrice * (10 ** IERC20(_asset).decimals()) * liqThreshold);
+ ) / (collateralTokenPrice * (10 ** IERC20(_asset).decimals()) * ltv);
withdrawnAmount = aavePool.withdraw(unwindParams.collateralToken, collateralToWithdraw, address(this));
}
// ...
}
+