Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix bug in _calculateSurplusAndCap() for debt redistribution case #674

Merged
merged 4 commits into from
Oct 11, 2023

Conversation

rayeaster
Copy link
Contributor

@rayeaster rayeaster commented Oct 5, 2023

The issue is found during Medusa invariant run and failure-analysis https://gist.github.com/GalloDaSballo/68046d8b089c4d29af40f31d197cc53a?permalink_comment_id=4714393#gistcomment-4714393

When a CDP is fully liquidated with some bad debt distributed (in recovery mode), there should be zero collateral as surplus for CDP owner to claim.

In previous implementation depending on Solidity multiplication and division, it might end with some rounding error that CDP ower got 1 wei collateral as surplus.

Now the issue is fixed by this PR

Comment on lines +549 to +559
// now CDP owner should have zero surplus to claim
cappedColPortion = _totalColToSend;
} else {
// for partial liquidation, new ICR would deteriorate
// since we give more incentive (103%) than current _ICR allowed
_incentiveColl = (_totalDebtToBurn * LICR) / _price;
}
}
cappedColPortion = collateral.getSharesByPooledEth(_incentiveColl);
if (cappedColPortion == 0) {
cappedColPortion = collateral.getSharesByPooledEth(_incentiveColl);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you ELI5 why this works in this way?

I don't understand why cap would be 0 and if it's 0 then we use the index for it

Copy link
Contributor

@dapp-whisperer dapp-whisperer Oct 6, 2023

Choose a reason for hiding this comment

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

@rayeaster I'd second the request here, could use more context

Can you describe how the error is fixed in this case when it previously wasnt in an example?

Copy link
Contributor Author

@rayeaster rayeaster Oct 6, 2023

Choose a reason for hiding this comment

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

@GalloDaSballo @dapp-whisperer When ICR is less than LICR and it is a full liquidation, the _incentiveColl is calculated by getPooledEthByShares(_totalColToSend).

In previous impl, the cappedColPortion is always calculated as getSharesByPooledEth(_incentiveColl), so it essentially equivalent to getSharesByPooledEth(getPooledEthByShares(_totalColToSend)) which might differ some wei from the expected result of _totalColToSend due to rounding error. In Alex's Medusa run, the CDP owner got 1 wei surplus (which shouldn't in theory) to claim

Now with this fix, we just explicitly set cappedColPortion=_totalColToSend for the scenario (full liquidation with ICR < LICR)

@GalloDaSballo
Copy link
Collaborator

Mostly trying to understand if:

  • Do we need to constantly ping back and forth between shares and coll?
  • Can we proof there's no reentrancy, hence we can just cache the math for stETH to avoid the 400+ gas per conversion back and forth (and is it worth it)

It may be worth getting more eyes on this specific change and this flow

@GalloDaSballo
Copy link
Collaborator

This merge will prob have conflicts since this doesn't use shares everywhere

Copy link
Collaborator

@GalloDaSballo GalloDaSballo left a comment

Choose a reason for hiding this comment

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

The code for surplus will benefit by a refactoring which I can apply after we merge down the rest of the code

The logic is basically a 4x4
-> Underwater or Not
-> Full or Partial Liq

If not underwater then math is straightforward

If underwater:

  • Assumption 1 Partial doesn't create Bad debt since it leaves some CDP left -> Need to think about this one further
  • Assumption 2 Full Liquidation is capped (less coll than debt), so we basically sell discounted coll per debt, which is why we do the extra math back from shares to Value

This causes some of the additional checks to be skippable in different scenarios (gas savings)

The logic is sound, imo can be clarified, and I have a draft refactoring I can send once we merge down this + any conflict

Lastly @dapp-whisperer the naming here doesn't have shares not even in the new PR, worth figuring this one out before doing any code changes

@dapp-whisperer
Copy link
Contributor

great, will merge it down and track this as an issue

@dapp-whisperer dapp-whisperer merged commit 769553b into feat/release-0.5 Oct 11, 2023
3 checks passed
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