Skip to content

Commit

Permalink
feat: add back Health verification
Browse files Browse the repository at this point in the history
  • Loading branch information
QGarchery committed Feb 20, 2024
1 parent 20d6f9c commit a52b262
Showing 1 changed file with 62 additions and 0 deletions.
62 changes: 62 additions & 0 deletions certora/specs/Health.spec
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,68 @@ function summaryMin(uint256 a, uint256 b) returns uint256 {
return a < b ? a : b;
}

// Check that without accruing interest, no interaction can put an healthy account into an unhealthy one.
// This rule times out for liquidate, repay and borrow.
rule stayHealthy(env e, method f, calldataarg data)
filtered {
f -> !f.isView &&
f.selector != sig:liquidate(MorphoHarness.MarketParams, address, uint256, uint256, bytes).selector &&
f.selector != sig:repay(MorphoHarness.MarketParams, uint256, uint256, address, bytes).selector &&
f.selector != sig:borrow(MorphoHarness.MarketParams, uint256, uint256, address, address).selector
}
{
MorphoHarness.MarketParams marketParams;
MorphoHarness.Id id = libId(marketParams);
address user;

// Assume that the position is healthy before the interaction.
require isHealthy(marketParams, user);
// Safe require because of the invariants onlyEnabledLltv and lltvSmallerThanWad in ConsistentState.spec.
require marketParams.lltv < 10^18;
// Assumption to ensure that no interest is accumulated.
require lastUpdate(id) == e.block.timestamp;

priceChanged = false;
f(e, data);

// Safe require because of the invariant sumBorrowSharesCorrect.
require borrowShares(id, user) <= totalBorrowShares(id);

bool stillHealthy = isHealthy(marketParams, user);
assert !priceChanged => stillHealthy;
}

// Check that users cannot lose collateral by unauthorized parties except in case of an unhealthy position.
rule healthyUserCannotLoseCollateral(env e, method f, calldataarg data)
filtered { f -> !f.isView }
{
MorphoHarness.MarketParams marketParams;
MorphoHarness.Id id = libId(marketParams);
address user;

// Assume that the e.msg.sender is not authorized.
require !isAuthorized(user, e.msg.sender);
require user != e.msg.sender;
// Assumption to ensure that no interest is accumulated.
require lastUpdate(id) == e.block.timestamp;
// Assume that the user is healthy.
require isHealthy(marketParams, user);

mathint collateralBefore = collateral(id, user);

priceChanged = false;
f(e, data);

mathint collateralAfter = collateral(id, user);

assert !priceChanged => collateralAfter >= collateralBefore;
}

// Check that users without collateral also have no debt.
// This invariant ensures that bad debt realization cannot be bypassed.
invariant alwaysCollateralized(MorphoHarness.Id id, address borrower)
borrowShares(id, borrower) != 0 => collateral(id, borrower) != 0;

// Checks that passing a seized amount input to liquidate leads to repaid shares S and repaid amount A such that liquidating instead with shares S also repays the amount A.
rule liquidateEquivalentInputDebtAndInputCollateral(env e, MorphoHarness.MarketParams marketParams, address borrower, uint256 seizedAssets, bytes data) {
MorphoHarness.Id id = libId(marketParams);
Expand Down

0 comments on commit a52b262

Please sign in to comment.