Stratax::calculateUnwindParams returns aggregate debt across all positions sharing the same borrow token, causing cross-position interference or DOS on unwindStratax::calculateUnwindParams reads the outstanding debt via balanceOf on Aave's variable debt token:
Since all positions created through a single Stratax contract share the same Aave account, balanceOf on the variable debt token returns the aggregate debt across every open position that borrows the same token — not the debt for any individual position. There are no guards on Stratax:createLeveragedPosition preventing multiple positions with the same borrow token.
For example, a user could have:
Position 1: USDC collateral / WETH debt
Position 2: LINK collateral / WETH debt
Both positions contribute to the same WETH variable debt balance. When the user calls calculateUnwindParams(USDC, WETH) intending to unwind only Position 1, the returned debtAmount includes Position 2's WETH debt as well.
This inflated debtAmount then:
Becomes the flash loan amount in Stratax::unwindPosition, flash loaning far more WETH than needed
aavePool.repay in Stratax:"_executeUnwindOperation repays all WETH debt, unwinding Position 2 as collateral damage
collateralToWithdraw is calculated based on the total debt, attempting to withdraw more USDC collateral than Position 1 warrants
The third point is where the critical failure occurs. Since Position 1's USDC collateral only backs Position 1's share of the debt, the aavePool.withdraw call attempts to burn more aUSDC than the contract holds — causing the entire unwind transaction to revert. This effectively makes it impossible to unwind any individual position via the normal flow once multiple positions share a borrow token.
Likelihood:
The contract is designed for users to hold multiple leveraged positions simultaneously — the createLeveragedPosition function has no guard preventing a second position that borrows the same token as an existing one. Since each Stratax proxy holds all positions under a single Aave account, any two positions sharing a borrow token (e.g., USDC/WETH and LINK/WETH) will pool their variable debt balances.
This is not an edge case it is very common for users to borrow the same asset across multiple positions on Aave
Impact:
The collateralToWithdraw value returned by Stratax::calculateUnwindParams is derived from the aggregate debt, so it will exceed the aToken collateral actually deposited for the target position. When Stratax::unwindPosition passes this inflated value to aavePool.withdraw, Aave reverts because the contract attempts to burn more aTokens than it holds for that collateral type. The user's position is stuck — they cannot unwind through the protocol's intended flow.
If the target position's collateral happens to be large enough to cover the inflated withdrawal (an unlikely but possible scenario), the unwind succeeds but repays the total WETH debt across all positions in a single flash loan. This wipes out the debt backing the other position, leaving its collateral stranded in Aave with no corresponding debt, and the user absorbs unnecessary flash loan fees on the excess amount.
A user opens a position using USDC as collateral borrowing WETH
The user opens a second posititon uisng LINK as collateral borrowing WETH
The user then tries to unwind the USDC/WETH position, but it reverts as the calcualted debt accounts for the WETH across both positions
Add the following test to /test/fork/Stratax.t.sol
Track per-position debt internally rather than relying on the aggregate Aave debt token balance:
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.