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.
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.