When unwinding, the contract should repay the entire variable debt so the position can be fully closed in a single transaction.
calculateUnwindParams determines debtAmount using the current variable debt token balance. However, Aave variable debt accrues interest continuously. Between (a) computing debtAmount off‑chain or via the view helper and (b) the actual unwindPosition execution mined on‑chain, a small interest delta accrues. Since unwindPosition flash‑loans exactly _debtAmount and immediately calls repay(_asset, _amount, 2, address(this)), this leaves a tiny residual (“dust”) debt un‑repaid. The unwind then proceeds to withdraw collateral proportional to the repaid amount, but the leftover dust prevents a full exit—the position remains open with a minimal debt balance.
Likelihood: Medium
Variable debt increases every second; even a one‑block delay between quoting and inclusion causes non‑zero delta.
Busy networks, mempool delays, or multi‑step flows make such delays routine - so dust debt will occur.
Impact: Medium
Incomplete unwind / stuck residuals: Users expecting to exit fully end up with a tiny remaining debt and residual collateral still locked.
Operational friction: Requires a second unwind or manual repay to clear the dust, increasing gas and UX complexity.
Conceptual pseudocode:
Add a small repay buffer to the debt you flash‑loan so you always have enough to cover accrual between quote and execution. Any leftover debt token simply reduces the amount you need to receive from the collateral → debt swap (and if still leftover at the end, you can return/supply it).
Introduce a parameter/constant, e.g. DEBT_REPAY_BUFFER_BPS (1–5 bps), or an absolute floor of +1 wei.
In the view helper and/or in unwindPosition, bump the amount you flash‑loan:
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.