Stratax.unwindPosition() accepts _collateralToWithdraw, but the flash-loan callback ignores it and recomputes withdrawal amount with liquidationThreshold instead of LTV. This creates deterministic under-withdrawal during unwind and breaks caller intent.
src/Stratax.sol:236 (unwindPosition input includes _collateralToWithdraw)
src/Stratax.sol:244 (UnwindParams.collateralToWithdraw encoded)
src/Stratax.sol:552 (_executeUnwindOperation)
src/Stratax.sol:566 (reads liqThreshold)
src/Stratax.sol:575 (withdraw formula uses liqThreshold)
src/Stratax.sol:579 (withdraw executes with recomputed value, not user value)
Two logic issues combine:
User input is ignored:
_collateralToWithdraw is provided by caller and encoded into UnwindParams, but never used in callback execution.
Wrong risk variable used:
callback uses liquidationThreshold in denominator for unwind sizing, not LTV-based sizing/user-provided sizing.
As a result, unwind behavior diverges from caller intent and from expected debt-to-collateral conversion semantics.
Forced partial unwind behavior even when caller requests specific collateral withdrawal.
Deterministic withdrawal shortfall relative to LTV-based sizing.
Residual collateral remains in Aave position after debt is fully repaid, requiring extra non-obvious manual recovery flow.
This is a protocol logic failure in core position management and can cause significant user-facing loss of expected unwind proceeds.
Validated in real Codespace environment:
Codespace: strix-ssh-20260216-134645-5g67qw6p66v43r5j
Repo path: /workspaces/strix/2026-02-stratax-contracts
Branch/commit: main / f6525334ddeb7910733432a992daecb0a8041430
Forge: 1.5.1-stable
Fork block: 24329390
test/PoC_UnwindWrongRisk_E2E.t.sol
LTV: 7500
Liq threshold: 7800
Debt before unwind: 711165158412156265
User supplied _collateralToWithdraw: 1
Actual USDC withdrawn from Aave: 2740384615
Expected (liqThreshold formula): 2740384615
Expected (LTV formula): 2849999999
Remaining aUSDC after unwind: 397537642
Remaining variable debt after unwind: 0
Caller passed _collateralToWithdraw = 1, but actual withdrawal was 2,740,384,615.
Confirms caller-provided value is ignored.
Actual withdrawal exactly matches liqThreshold formula and is lower than LTV-based sizing.
Confirms wrong risk parameter is used.
Use caller-provided unwind amount (or a consistently validated computed amount) and remove liqThreshold-based recomputation in callback.
In _executeUnwindOperation(...):
Replace recomputation block with usage of unwindParams.collateralToWithdraw.
Validate non-zero and bounded amount.
Example:
Also add invariant tests:
callback withdrawal must equal user-provided amount (modulo pool rounding), not recomputed from unrelated risk parameters.
unwind math path must be internally consistent between calculateUnwindParams and execution.
function logic ignores user input
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.