Skip to content

Conversation

@jordanschalm
Copy link
Member

@jordanschalm jordanschalm commented Dec 17, 2025

Closes: #???

Description

Implements a manual liquidation path. Anyone is allowed to perform a liquidation under the following circumstances:

  • The position is unhealthy (H<1)
  • The liquidation offer provides a better implied price for the seized collateral than the protocol could get from a DEX
  • The liquidation offer does not cause the health to exceed target (1.05)
  • The price provided by the DEX does not diverge too far from the price provided by the oracle

Notes for reviewers while in draft state

The skeleton of the implementation is largely complete, but this lacks tests, and proper documentation in some places.

  • This PR introduces SwapperProvider to represent a DEX. We need to add an implementation of SwapperProvider that can be used.
  • There are lots of TODO comments I left as I read through the code, of varying relevance to liquidation. I suggest focussing review on the new liquidation logic in manualLiquidation and _doLiquidation

For contributor use:

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the standards mentioned here.
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

@jordanschalm jordanschalm changed the title [DRAFT] Improve Liquidation [DRAFT] Implement manual liquidation path Dec 20, 2025
@jordanschalm jordanschalm requested a review from dete December 20, 2025 00:45

// Ensure liquidation amounts don't exceed position amounts
let Nc = positionView.trueBalance(ofToken: seizeType) // number of collateral tokens (true balance)
let Nd = positionView.trueBalance(ofToken: debtType) // number of debt tokens (true balance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trueBalance always uses the snapshot's creditIndex. Should this use the debitIndex here?

Comment on lines +382 to +383
self.creditInterestIndex = FlowCreditMarketMath.one // TODO: hard-coded to 1?
self.debitInterestIndex = FlowCreditMarketMath.one // TODO: hard-coded to 1?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below: FlowCreditMarketMath.one is deprecated, just use the literal:

Suggested change
self.creditInterestIndex = FlowCreditMarketMath.one // TODO: hard-coded to 1?
self.debitInterestIndex = FlowCreditMarketMath.one // TODO: hard-coded to 1?
self.creditInterestIndex = 1.0
self.debitInterestIndex = 1.0

Comment on lines +580 to +584
let trueBalance = FlowCreditMarket.scaledBalanceToTrueBalance(
balance.scaledBalance,
interestIndex: tokenSnapshot.creditIndex
)
return trueBalance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let trueBalance = FlowCreditMarket.scaledBalanceToTrueBalance(
balance.scaledBalance,
interestIndex: tokenSnapshot.creditIndex
)
return trueBalance
return FlowCreditMarket.scaledBalanceToTrueBalance(
balance.scaledBalance,
interestIndex: tokenSnapshot.creditIndex
)

Also see below: Maybe there should be two functions, or make it more obvious in the function name that the creditIndex is used and not debitIndex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants