Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: medium
Likelihood: low

Wrong Token Address In `_call1InchSwap` Fallback Balance Check During `_executeOpenOperation`

Author Revealed upon completion

The _call1InchSwap() helper function accepts an _asset parameter documented in its NatSpec as the "Address of the asset being swapped to." It has two paths for determining the return amount: a primary path that decodes the router's return data, and a fallback path that reads IERC20(_asset).balanceOf(address(this)) when no return data is available.

In _executeOpenOperation(), the swap direction is borrow token to collateral token (the flash-loaned asset _asset). However, on Stratax.sol on line 514, the function passes flashParams.borrowToken (the source token) instead of _asset (the destination token):

// Step 3: Swap borrowed tokens via 1inch to get back the collateral token
IERC20(flashParams.borrowToken).approve(address(oneInchRouter), flashParams.borrowAmount);
// Execute swap via 1inch
uint256 returnAmount =
_call1InchSwap(flashParams.oneInchSwapData, flashParams.borrowToken, flashParams.minReturnAmount);
// @audit flashParams.borrowToken is the SOURCE token of the swap, not the DESTINATION

When the 1inch router returns no data, the fallback path in _call1InchSwap() reads the wrong token balance:

function _call1InchSwap(bytes memory _swapParams, address _asset, uint256 _minReturnAmount)
internal
returns (uint256 returnAmount)
{
(bool success, bytes memory result) = address(oneInchRouter).call(_swapParams);
require(success, "1inch swap failed");
if (result.length > 0) {
(returnAmount,) = abi.decode(result, (uint256, uint256));
} else {
// @audit In _executeOpenOperation, _asset is flashParams.borrowToken (wrong token)
returnAmount = IERC20(_asset).balanceOf(address(this));
}
require(returnAmount >= _minReturnAmount, "Insufficient return amount from swap");
return returnAmount;
}

After the swap consumes the borrowed tokens, the borrow token balance returns to prevBorrowTokenBalance, which is typically zero. This causes returnAmount to be set to zero (or to a residual borrow token balance from prior operations), rather than the actual collateral tokens received from the swap. The subsequent check on Stratax.sol on line 522 (require(returnAmount >= totalDebt)) then compares this borrow-token-denominated value against a collateral-token-denominated flash loan debt, a cross-denomination comparison that produces meaningless results.

By contrast, _executeUnwindOperation() correctly passes _asset (the flash-loaned debt token, which is the destination of the collateral-to-debt swap) on Stratax.sol on line 584:

uint256 returnAmount = _call1InchSwap(unwindParams.oneInchSwapData, _asset, unwindParams.minReturnAmount);

This inconsistency between the two call sites confirms the bug in _executeOpenOperation().

This issue has a medium impact as incorrect accounting in the fallback path leads to cross-denomination comparisons in slippage protection and flash loan repayment checks. In the most common fallback scenario (no pre-existing borrow tokens), the operation reverts with a misleading error message. In the less common scenario where the contract holds residual borrow tokens, the checks could pass with meaningless values before failing at a later step. Aave's flash loan enforcement mechanism prevents direct fund loss, as the transaction would ultimately revert if insufficient collateral tokens are available for repayment.

This issue has a low likelihood as the fallback path is only triggered when the 1inch router returns no data, which is uncommon with the standard 1inch aggregation router's swap() function. However, since the code uses a raw .call() with arbitrary calldata on Stratax.sol on line 617, non-standard router functions or proxy configurations could trigger this path.

recommendation

Pass the correct destination token address (_asset, the flash loan collateral token) to _call1InchSwap() in _executeOpenOperation() by changing flashParams.borrowToken to _asset on Stratax.sol on line 514. This ensures the fallback balance check reads the collateral token balance, maintaining correct denomination throughout all downstream accounting checks.

Support

FAQs

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

Give us feedback!