During open, the protocol borrows borrowToken from Aave and immediately swaps it to the collateral/flash‑loan token (_asset) to repay the flash loan. The helper _call1InchSwap should therefore be told the destination token (the token expected to be received from 1inch), so that if the router returns no data, the fallback balance check inspects the correct token.
In _executeOpenOperation, the code passes flashParams.borrowToken (the input of the swap) as the _asset argument to _call1InchSwap. The swap path is borrowToken → collateralToken (_asset), so the destination is the collateral token. If 1inch returns no return data, _call1InchSwap falls back to IERC20(_asset).balanceOf(address(this))—but _asset is incorrectly set to the borrow token, so the balance check reads the wrong token, and may revert even when the router returned the correct output.
Likelihood: Medium
1inch (or any router) may legitimately return no data for certain paths/encodings, or a non‑conforming integration may produce empty return bytes. In such cases, this bug will trigger the fallback branch.
Multi‑chain differences and router upgrades make “empty return” behavior plausible during normal operations.
Impact: Medium
False negative on repayment: Even when the swap correctly returns collateral tokens (_asset), the code inspects the borrow token balance and can report returnAmount = 0, causing a revert at require(returnAmount >= totalDebt, ...).
Operational DoS: Valid position opens can fail unpredictably depending on router behavior or calldata shape.
In a drop‑in test, deploy a MockOneInchRouter whose fallback:
Transfers USDC (the collateral/flash‑loan token) to msg.sender (Stratax) in an amount ≥ flash‑loan + premium, and
Returns empty bytes (no return data).
Then call createLeveragedPosition (USDC as _flashLoanToken, WETH as _borrowToken).
Inside _executeOpenOperation, _call1InchSwap receives flashParams.borrowToken (WETH) as _asset, so the fallback reads balanceOf(WETH) which is 0, setting returnAmount = 0.
The subsequent check require(returnAmount >= totalDebt, "Insufficient funds to repay flash loan"); reverts despite the contract holding enough USDC to repay - because the balance check looked at the wrong token.
Pass the destination token to _call1InchSwap in the open path—i.e., the collateral/flash‑loan token (_asset), not borrowToken. Optionally add an assertion that the open path’s destination equals the flash‑loan asset.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.