Skip to content

[Certora] post-price-drop realizable bad debt cannot increase (liquidate) - #1084

Merged
MathisGD merged 14 commits into
mainfrom
claude/certora-post-drop-rbd-liquidate
Sep 1, 2026
Merged

[Certora] post-price-drop realizable bad debt cannot increase (liquidate)#1084
MathisGD merged 14 commits into
mainfrom
claude/certora-post-drop-rbd-liquidate

Conversation

@claude

@claude claude Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Requested by Mathis GD · Slack thread

Before / After

Before: there is no Certora statement that liquidating a position ahead of an oracle price drop cannot make the post-drop bad debt worse. The existing liquidate leg only reasons at a single, static price.

After: a rule proving R' <= R for liquidate, where the realizable bad debt is measured at a dropped measurement price p' <= p while liquidate itself executes at the pre-drop call-time price p. R is the do-nothing post-drop rbd (measured before liquidating) and R' is the post-liquidate post-drop rbd. In words: having liquidated first never leaves more realizable bad debt at the dropped price than doing nothing.

How

  • Explicit-price getter (realizableBadDebtAtPrice in certora/helpers/MidnightWrapper.sol): a verbatim structural copy of the realizableBadDebt getter that values each active collateral at an explicitly passed price instead of reading IOracle(...).price(). This decouples the measurement price p' from the price liquidate reads.
  • _.price() pinned to p: the per-callee constant price summary is the call-time price p liquidate reads; the measurement price p' is a separate rule variable, constrained p' <= p on the liquidated collateral's oracle.
  • Shortcuts (matching the isolated liquidate leg): single seized collateral, !postMaturityMode (so lif == maxLif), and a split along liquidate's exclusive-input branch (repaidUnits == 0 || seizedAssets == 0), one CI leg rule per branch.
  • Proof: the p'-measured coverage drop is bounded by g_{p'}(seized) (reuses [Certora] realizable bad debt cannot increase without price update #1079's getter-form double sub-additivity), then price-monotonicity of the getter term gives g_{p'}(seized) <= g_p(seized), and [Certora] realizable bad debt cannot increase without price update #1079's seize-value bound closes g_p(seized) <= repaidUnits. So coverage removed at p' is at most the debt removed, and zeroFloorSub monotonicity yields R' <= R. The one new ingredient over [Certora] realizable bad debt cannot increase without price update #1079 is getter-form price-monotonicity (composed from the already-proven mulDivMonotoneA / mulDivMonotoneB in MulDiv.spec).

Builds on #1079 (base branch claude/certora-realizable-bad-debt), inheriting its rbd getter and MulDiv lemmas.

corresponding thread

claude added 2 commits July 26, 2026 19:49
…ate)

Add a rule proving that liquidating ahead of an oracle price drop cannot
worsen the post-drop realizable bad debt: with liquidate executed at the
call-time price p and realizable bad debt measured at a dropped price
p' <= p, the post-liquidate p'-rbd R' is at most the do-nothing p'-rbd R.

- Add realizableBadDebtAtPrice getter in MidnightWrapper.sol: a verbatim
  structural copy of realizableBadDebt that values each active collateral
  at an explicitly passed price instead of reading IOracle(...).price(),
  decoupling the measurement price from the price liquidate reads.
- Add PostDropRealizableBadDebt.spec + conf: two rules (split along
  liquidate's exclusive-input branch), reusing the seize-value bound and
  double sub-additivity lemmas and adding getter-form price monotonicity
  (g is non-decreasing in the price argument) to bridge the p'-measured
  coverage drop to the p-priced seize/repay logic. Restricted to
  !postMaturityMode and a single seized collateral, matching the isolated
  liquidate leg it builds on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GL2969EWAXpsqmnFCNFxHR
…ound

Split the post-drop realizable-bad-debt liquidate leg so the verified
seize-input rule (postDropRbdLiquidateNonIncreaseSeizeInput) runs green
in its own conf, and isolate the heavy repaid-input rule in a new
PostDropRealizableBadDebtRepaid.conf for iteration.

Add mulDivSeizeValueAtDroppedPriceBounded to MulDiv.spec: the up-up value
at a dropped price pDrop <= price of the down-down seized collateral is
still <= the repaid units r (mulDivSeizeValueBounded composed with price
monotonicity). Mirror it as the ghost-form axiomSeizeValueAtDroppedPrice
and use a single ground instance in the repaid-input rule to collapse the
former call-time-bound + price-bridge chain into one step, leaving fewer
unification steps for the solver. Seize-input rule left untouched.
Comment thread certora/helpers/MidnightWrapper.sol Outdated
Comment thread certora/specs/MulDiv.spec Outdated
@jhoenicke jhoenicke self-assigned this Jul 30, 2026
@jhoenicke
jhoenicke marked this pull request as ready for review July 31, 2026 13:07

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

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

Copy link
Copy Markdown

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: eab9d09d7e

ℹ️ 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/PostDropRealizableBadDebt.conf
Comment thread certora/specs/PostDropRealizableBadDebt.spec
Comment thread certora/specs/PostDropRealizableBadDebt.spec
Base automatically changed from claude/certora-realizable-bad-debt to main August 17, 2026 11:55
Comment thread certora/specs/PostDropRealizableBadDebt.spec Outdated
Comment thread certora/confs/PostDropRealizableBadDebt.conf Outdated
Comment thread certora/specs/PostDropRealizableBadDebt.spec Outdated
Comment thread certora/specs/PostDropRealizableBadDebt.spec Outdated
Comment thread certora/specs/PostDropRealizableBadDebt.spec
Comment thread certora/specs/PostDropRealizableBadDebt.spec
Comment thread certora/specs/PostDropRealizableBadDebt.spec Outdated
Comment thread certora/specs/PostDropRealizableBadDebt.spec Outdated
Comment thread certora/specs/PostDropRealizableBadDebt.spec Outdated
Comment thread certora/specs/PostDropRealizableBadDebt.spec
claude and others added 2 commits September 1, 2026 09:34
Signed-off-by: MathisGD <74971347+MathisGD@users.noreply.github.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T09:46:20.574611Z e37b053 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@MathisGD
MathisGD merged commit 1e1b086 into main Sep 1, 2026
58 of 59 checks passed
@MathisGD
MathisGD deleted the claude/certora-post-drop-rbd-liquidate branch September 1, 2026 09:42
@MathisGD MathisGD mentioned this pull request Sep 1, 2026
77 tasks

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

Copy link
Copy Markdown

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: e37b053f8c

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +45 to +47
function _.transfer(address, uint256) external => HAVOC_ECF;
function _.transferFrom(address, address, uint256) external => HAVOC_ECF;
function _.onLiquidate(address, bytes32, Midnight.Market, uint256, uint256, uint256, address, address, bytes, uint256) external => HAVOC_ECF;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Cover reentrant liquidation callbacks

When callback is nonzero and authorized to act for the borrower, Midnight.liquidate invokes it after changing the position (src/Midnight.sol:737-754), so it can reenter and alter collateral or debt before this rule measures badDebt2b; these HAVOC_ECF summaries model only a non-reentrant callee footprint and therefore omit such legal executions while the README states the property without that qualification. Either scope and document the rule with callback == 0 or use a summary that accounts for reentrant Midnight state changes.

AGENTS.md reference: AGENTS.md:L45-L50

Useful? React with 👍 / 👎.

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.

5 participants