-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathStayHealthy.spec
118 lines (94 loc) · 4.96 KB
/
StayHealthy.spec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// SPDX-License-Identifier: GPL-2.0-or-later
import "Health.spec";
// Check that without accruing interest, no interaction can put an healthy account into an unhealthy one.
// The liquidate function times out in this rule, but has been checked separately.
rule stayHealthy(env e, method f, calldataarg data)
filtered {
f -> !f.isView &&
f.selector != sig:liquidate(MorphoHarness.MarketParams, address, uint256, uint256, bytes).selector
}
{
MorphoHarness.MarketParams marketParams;
MorphoHarness.Id id = Util.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;
f(e, data);
// Safe require because of the invariant sumBorrowSharesCorrect.
require borrowShares(id, user) <= totalBorrowShares(id);
bool stillHealthy = isHealthy(marketParams, user);
assert !priceChanged => stillHealthy;
}
// The liquidate case for the stayHealthy rule, assuming no bad debt realization, otherwise it times out.
// This particular rule makes the following assumptions:
// - the market of the liquidation is the market of the user, see the *DifferentMarkets rule,
// - there is still some borrow on the market after liquidation, see the *LastBorrow rule.
rule stayHealthyLiquidate(env e, MorphoHarness.MarketParams marketParams, address borrower, uint256 seizedAssets, bytes data) {
MorphoHarness.Id id = Util.libId(marketParams);
address user;
// Assume the invariant initially.
require isHealthy(marketParams, user);
uint256 debtSharesBefore = borrowShares(id, user);
uint256 debtAssetsBefore = summaryMulDivUp(debtSharesBefore, virtualTotalBorrowAssets(id), virtualTotalBorrowShares(id));
// 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;
liquidate(e, marketParams, borrower, seizedAssets, 0, data);
require !priceChanged;
// Safe require because of the invariant sumBorrowSharesCorrect.
require borrowShares(id, user) <= totalBorrowShares(id);
// Assume that there is still some borrow on the market after liquidation.
require totalBorrowAssets(id) > 0;
// Assume no bad debt realization.
require collateral(id, borrower) > 0;
assert user != borrower;
assert debtSharesBefore == borrowShares(id, user);
assert debtAssetsBefore >= summaryMulDivUp(debtSharesBefore, virtualTotalBorrowAssets(id), virtualTotalBorrowShares(id));
bool stillHealthy = isHealthy(marketParams, user);
require !priceChanged;
assert stillHealthy;
}
rule stayHealthyLiquidateDifferentMarkets(env e, MorphoHarness.MarketParams marketParams, address borrower, uint256 seizedAssets, bytes data) {
MorphoHarness.Id id = Util.libId(marketParams);
address user;
MorphoHarness.MarketParams liquidationMarketParams;
// Assume the invariant initially.
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;
// Assume that the liquidation is on a different market.
require liquidationMarketParams != marketParams;
liquidate(e, liquidationMarketParams, borrower, seizedAssets, 0, data);
require !priceChanged;
// Safe require because of the invariant sumBorrowSharesCorrect.
require borrowShares(id, user) <= totalBorrowShares(id);
bool stillHealthy = isHealthy(marketParams, user);
require !priceChanged;
assert stillHealthy;
}
rule stayHealthyLiquidateLastBorrow(env e, MorphoHarness.MarketParams marketParams, address borrower, uint256 seizedAssets, bytes data) {
MorphoHarness.Id id = Util.libId(marketParams);
address user;
// Assume the invariant initially.
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;
liquidate(e, marketParams, borrower, seizedAssets, 0, data);
require !priceChanged;
// Safe require because of the invariant sumBorrowSharesCorrect.
require borrowShares(id, user) <= totalBorrowShares(id);
// Assume that there is no remaining borrow on the market after liquidation.
require totalBorrowAssets(id) == 0;
bool stillHealthy = isHealthy(marketParams, user);
require !priceChanged;
assert stillHealthy;
}