Skip to content

[Certora] no debt without collateral improvement#891

Open
lilCertora wants to merge 31 commits into
mainfrom
certora/noDebtWithoutCollateral
Open

[Certora] no debt without collateral improvement#891
lilCertora wants to merge 31 commits into
mainfrom
certora/noDebtWithoutCollateral

Conversation

@lilCertora
Copy link
Copy Markdown
Collaborator

@lilCertora lilCertora commented May 19, 2026

wishlist item : "no position can have collateral = 0 everywhere and some debt, see #764 (comment)"

Comes in complementary if the invariant in collateralBitmap

corresponding thread

@lilCertora lilCertora marked this pull request as ready for review May 25, 2026 12:05
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea35e44ad0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/confs/NoDebtWithoutCollateral.conf Outdated
Comment thread certora/confs/NoDebtWithoutCollateral.conf Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47aa6e1ac8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d00e5b30f5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread certora/confs/NoDebtWithoutCollateral.conf
Signed-off-by: lilCertora <lilian@certora.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f716dc6ad7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread certora/helpers/Utils.sol Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment on lines +24 to +26
// Mirror the transient liquidation-lock slot into `ghostLocked`.
// This makes the persistent ghost the source of truth and sidesteps CVL's caveat that transient storage
// is only nullified in the base step of invariants (see https://docs.certora.com/en/latest/docs/cvl/transient.html).
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't understand this, why is this modeling an issue ?
The problem with those summaries is that they use a persistent ghost, so that HAVOC_ALL does not impact the lock (as it should)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Wording was a bit off that's right, there are 2 reasons for the ghosts being persistent , 1st is that the strong invariant's "Reset transient storage" check (transaction boundary) clears a real transient lock while the persistent debt/bitmap state persists which leads to a counter example on lockedOrNoDebtWithoutCollateral (lock=true, debt=1, bitmap=0, then reset → false). and the second is that -havocAllByDefault would havoc the non persistent ghost and during take the bitmap==0 => debt==0 can't hold at the callback boundary , the seller's debt is bumped at L414, before the callbacks, and solvency is only enforced at L476 so this would create a counter example, maybe that's not what you meant ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I meant why can't we use the native transient storage value (no ghost at all):

  • first reason is weak invariant that should hold (there is a weak invariant about every transient variable, that this variable is 0). Maybe it's not possible to do in CVL but we could just document that it holds, instead of an actual weak invariant
  • For the second reason, you would still need to state the strong invariant as !liquidationLocked || (bitmap == 0 => debt == 0), but using the getter for the transient value liquidationLocked

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

but the strong invariant liquidationLocked || (bitmap == 0 => debt == 0) doesn't hold if HAVOC_ALL impact the lock and reset it to false while the debt has increased before the callback , and in reality the callback can't write the transient lock so we would over assume and get a spurious CEX here

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

but the strong invariant liquidationLocked || (bitmap == 0 => debt == 0) doesn't hold if HAVOC_ALL impact the lock and reset it to false

why not ? Isn't it the same thing as HAVOC_ALL changing the bitmap or the debt variables ?

and in reality the callback can't write the transient lock so we would over assume and get a spurious CEX here

curious to see the CEX

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

why not ? Isn't it the same thing as HAVOC_ALL changing the bitmap or the debt variables ?

I mean debt/bitmap are regular storage and a reentrant call into Midnight (take, liquidate, …) really can change them via the public entrypoints, so HAVOC_ALL havocing them is faithful and pinning them would be unsound but the lock is transient storage so not modifiable via reentrancy.

Here is the CEX without the ghost :

  • weak invariant liquidationLocked == false fails after every method with an external call because -havocAllByDefault havocs the transient slot at the unresolved call, so the lock is nonzero when the method returns
  • the strong invariant liquidationLocked || (bitmap==0 ⇒ debt==0) fails at the "Reset transient storage" step: the prover nullifies the lock at the tx boundary → liquidationLocked becomes false while the persistent debt/bitmap still hold a mid-take state (debt>0, bitmap=0) → violation.

Copy link
Copy Markdown
Collaborator

@QGarchery QGarchery Jun 4, 2026

Choose a reason for hiding this comment

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

the lock is transient storage so not modifiable via reentrancy.

I don't think this holds: I can create a function that changes the transient storage (take does it) and that function could change it in arbitrary ways. This means that a reentrancy could change the transient storage in arbitrary ways. So, without further analysis, the safe modeling is that external calls havoc the transient storage.

weak invariant liquidationLocked == false fails after every method with an external call because -havocAllByDefault havocs the transient slot at the unresolved call, so the lock is nonzero when the method returns

For this counter-example, it's showing that we are missing a lemma to make the proof go through, not that we need to constrain the behavior of the transient storage.
here we are missing the property that each external call leaves the lock unchanged. This property can first be proven by assuming that external calls leave the lock unchanged as well, and by induction it would hold in the general case

the strong invariant liquidationLocked || (bitmap==0 ⇒ debt==0) fails at the "Reset transient storage" step: the prover nullifies the lock at the tx boundary → liquidationLocked becomes false while the persistent debt/bitmap still hold a mid-take state (debt>0, bitmap=0) → violation.

this explains the ghost, if there is no way to explain to the prover that weak invariant liquidationLocked == false is enough to rule out this counter-example. But we could still use a non-persistent ghost I think

Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
review changes

Co-authored-by: Quentin Garchery <garchery.quentin@gmail.com>
Signed-off-by: lilCertora <lilian@certora.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 874caefd02

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread certora/confs/NoDebtWithoutCollateral.conf
Comment thread certora/specs/NoDebtWithoutCollateral.spec Outdated
lilCertora and others added 2 commits June 2, 2026 20:18
Co-authored-by: Quentin Garchery <garchery.quentin@gmail.com>
Signed-off-by: lilCertora <lilian@certora.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants