-
Notifications
You must be signed in to change notification settings - Fork 96
[Certora] Liquidate buffer, with executable code #708
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
Merged
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
ba2280f
feat: executable liquidate, attempt prove buffer
QGarchery 712e6a2
fix: repaid shares computation
QGarchery 6b6a8c7
fix: stronger require
QGarchery 914c244
chore: try medium timeout 20
QGarchery 47d7558
chore: one assert
QGarchery 9a6b160
feat: more summarization
QGarchery 2cb3597
Update README.md
Bilogweb3 7df7a63
feat: add flashLoan input validation
QGarchery 1399ed2
docs: improve wording of assumptions for liveness
MathisGD 3fb8394
docs: wording
MathisGD 0efe836
chore: remove bytecode hash from compilation
MathisGD 4f9b5ea
chore: explicitly turn on the optimizer
MathisGD e88a9bf
build: add evm_version
adhusson 02820d4
Update foundry.toml
MathisGD e2e9700
fix : rename harness to helpers
cfb7827
fix: rename harness related paths
c27a99d
chore: rename harness folder to helpers
QGarchery eb75586
Merge branch 'main' into certora/exec-liquidate-buffer
QGarchery 997629b
fix: signature accrueInterest
QGarchery f6148ee
refactor: simplify assumptions and multi-assert
QGarchery b88e4fe
fix: collateralization assumption
QGarchery bb17fe9
fix: totalBorrowAssets declaration
QGarchery 5c9b5fb
refactor: restrict proof
QGarchery 9ee0ccf
chore: add destructive optimizations
QGarchery e47b483
feat: add all verification assumptions
QGarchery db3a34e
docs: comments about require and assert
QGarchery 7655e01
docs: update README
QGarchery 63a90eb
Merge remote-tracking branch 'origin/main' into certora/exec-liquidat…
QGarchery 0202ea3
docs: add comment about the rule
QGarchery 1831743
Update certora/README.md
QGarchery File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ jobs: | |
- ExchangeRate | ||
- Health | ||
- LibSummary | ||
- LiquidateBuffer | ||
- Liveness | ||
- Reentrancy | ||
- Reverts | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"files": [ | ||
"certora/helpers/MorphoHarness.sol", | ||
"certora/helpers/Util.sol" | ||
], | ||
"solc": "solc-0.8.19", | ||
"verify": "MorphoHarness:certora/specs/LiquidateBuffer.spec", | ||
"prover_args": [ | ||
"-depth 5", | ||
"-mediumTimeout 20", | ||
"-timeout 3600", | ||
"-adaptiveSolverConfig false", | ||
"-smt_nonLinearArithmetic true", | ||
"-destructiveOptimizations twostage", | ||
"-solvers [z3:def{randomSeed=1},z3:def{randomSeed=2},z3:def{randomSeed=3},z3:def{randomSeed=4},z3:def{randomSeed=5},z3:def{randomSeed=6},z3:def{randomSeed=7},z3:def{randomSeed=8},z3:def{randomSeed=9},z3:def{randomSeed=10}]" | ||
], | ||
"multi_assert_check": true, | ||
"rule_sanity": "basic", | ||
"server": "production", | ||
"msg": "Morpho Blue Liquidate Buffer" | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
using Util as Util; | ||
|
||
methods { | ||
function extSloads(bytes32[]) external returns (bytes32[]) => NONDET DELETE; | ||
|
||
function lastUpdate(MorphoHarness.Id) external returns (uint256) envfree; | ||
function borrowShares(MorphoHarness.Id, address) external returns (uint256) envfree; | ||
function collateral(MorphoHarness.Id, address) external returns (uint256) envfree; | ||
function totalBorrowShares(MorphoHarness.Id) external returns (uint256) envfree; | ||
function totalBorrowAssets(MorphoHarness.Id) external returns (uint256) envfree; | ||
function virtualTotalBorrowAssets(MorphoHarness.Id) external returns uint256 envfree; | ||
function virtualTotalBorrowShares(MorphoHarness.Id) external returns uint256 envfree; | ||
|
||
function Util.libId(MorphoHarness.MarketParams) external returns (MorphoHarness.Id) envfree; | ||
function Util.lif(uint256) external returns (uint256) envfree; | ||
function Util.oraclePriceScale() external returns (uint256) envfree; | ||
function Util.wad() external returns (uint256) envfree; | ||
|
||
function Morpho._isHealthy(MorphoHarness.MarketParams memory, MorphoHarness.Id,address) internal returns (bool) => NONDET; | ||
function Morpho._accrueInterest(MorphoHarness.MarketParams memory, MorphoHarness.Id) internal => NONDET; | ||
|
||
function _.price() external => constantPrice expect uint256; | ||
} | ||
|
||
persistent ghost uint256 constantPrice; | ||
|
||
// Check that for a position with LTV < 1 / LIF, its health improves after a liquidation. | ||
rule liquidateImprovePosition(env e, MorphoHarness.MarketParams marketParams, address borrower, uint256 seizedAssetsInput, uint256 repaidSharesInput, bytes data) { | ||
// Assume no callback. | ||
require data.length == 0; | ||
|
||
MorphoHarness.Id id = Util.libId(marketParams); | ||
|
||
// We place ourselves at the last block for getting the following variables. | ||
require lastUpdate(id) == e.block.timestamp; | ||
|
||
uint256 borrowerShares = borrowShares(id, borrower); | ||
// Safe require because of the sumBorrowSharesCorrect invariant. | ||
require borrowerShares <= totalBorrowShares(id); | ||
|
||
uint256 borrowerCollateral = collateral(id, borrower); | ||
uint256 lif = Util.lif(marketParams.lltv); | ||
uint256 virtualTotalAssets = virtualTotalBorrowAssets(id); | ||
uint256 virtualTotalShares = virtualTotalBorrowShares(id); | ||
|
||
// Let borrowerAssets = borrowerShares * virtualTotalAssets / virtualTotalShares | ||
// and borrowerCollateralQuoted = borrowerCollateral * constantPrice / Util.oraclePriceScale() | ||
// then the following line is the assumption borrowerAssets / borrowerCollateralQuoted < 1 / LIF. | ||
require borrowerCollateral * constantPrice * virtualTotalShares * Util.wad() > borrowerShares * Util.oraclePriceScale() * virtualTotalAssets * lif; | ||
|
||
uint256 seizedAssets; | ||
(seizedAssets, _) = liquidate(e, marketParams, borrower, seizedAssetsInput, repaidSharesInput, data); | ||
|
||
uint256 newBorrowerShares = borrowShares(id, borrower); | ||
uint256 newBorrowerCollateral = collateral(id, borrower); | ||
uint256 repaidShares = assert_uint256(borrowerShares - newBorrowerShares); | ||
uint256 newVirtualTotalAssets = virtualTotalBorrowAssets(id); | ||
uint256 newVirtualTotalShares = virtualTotalBorrowShares(id); | ||
|
||
// Hint for the prover to show that there is no bad debt realization. | ||
assert newBorrowerCollateral != 0; | ||
// Hint for the prover about the ratio used to close the position. | ||
assert repaidShares * borrowerCollateral >= seizedAssets * borrowerShares; | ||
// Prove that the ratio of shares of debt over collateral is smaller after the liquidation. | ||
assert borrowerShares * newBorrowerCollateral >= newBorrowerShares * borrowerCollateral; | ||
// Prove that the value of borrow shares is smaller after the liquidation. | ||
// Note that this is only shown for the case where there are still borrow positions on the markets. | ||
assert totalBorrowAssets(id) > 0 => newVirtualTotalShares * virtualTotalAssets >= newVirtualTotalAssets * virtualTotalShares; | ||
QGarchery marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.