Skip to content

Commit 6056adf

Browse files
committed
rules for steward
1 parent 9b4e8cb commit 6056adf

File tree

4 files changed

+324
-0
lines changed

4 files changed

+324
-0
lines changed

certora/steward/conf/sanity.conf

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"files": [
3+
"src/contracts/misc/GhoStewardV2.sol",
4+
],
5+
// "link": [
6+
// "AToken:POOL=SymbolicLendingPoolL1",
7+
// "AToken:_underlyingAsset=DummyERC20_aTokenUnderlying",
8+
// "ATokenVaultHarness:AAVE_POOL=SymbolicLendingPoolL1",
9+
//"ATokenVaultHarness:ATOKEN=AToken",
10+
// "ATokenVaultHarness:DUMMY=DummyContract",
11+
// "ATokenVaultHarness:UNDERLYING=DummyERC20_aTokenUnderlying",
12+
// "SymbolicLendingPoolL1:aToken=AToken",
13+
// "SymbolicLendingPoolL1:underlyingToken=DummyERC20_aTokenUnderlying"
14+
// ],
15+
"packages": [
16+
"@aave/core-v3/=lib/aave-v3-core",
17+
"@aave/periphery-v3/=lib/aave-v3-periphery",
18+
"@aave/=lib/aave-token",
19+
"@openzeppelin/=lib/openzeppelin-contracts",
20+
"aave-stk-v1-5/=lib/aave-stk-v1-5",
21+
"ds-test/=lib/forge-std/lib/ds-test/src",
22+
// "eth-gas-reporter/=node_modules/eth-gas-reporter",
23+
"forge-std/=lib/forge-std/src",
24+
// "hardhat-deploy/=node_modules/hardhat-deploy",
25+
// "hardhat/=node_modules/hardhat",
26+
"aave-address-book/=lib/aave-address-book/src",
27+
"aave-helpers/=lib/aave-stk-v1-5/lib/aave-helpers",
28+
"aave-v3-core/=lib/aave-address-book/lib/aave-v3-core",
29+
// "aave-v3-periphery/=lib/aave-address-book/lib/aave-v3-periphery",
30+
"erc4626-tests/=lib/aave-stk-v1-5/lib/openzeppelin-contracts/lib/erc4626-tests",
31+
"openzeppelin-contracts/=lib/aave-stk-v1-5/lib/openzeppelin-contracts",
32+
"solidity-utils/=lib/solidity-utils/src"
33+
],
34+
"optimistic_loop": true,
35+
"process": "emv",
36+
"prover_args": ["-depth 15","-mediumTimeout 1000"],
37+
"smt_timeout": "2000",
38+
"solc": "solc8.10",
39+
"verify": "GhoStewardV2:certora/steward/specs/sanity.spec",
40+
// "rule": ["positiveSupply_imply_positiveAssets_all_mint"],
41+
"msg": "positiveSupply_imply_positiveAssets_all_mintSteward::sanity"
42+
}

certora/steward/conf/timelock.conf

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"files": [
3+
"src/contracts/misc/GhoStewardV2.sol",
4+
],
5+
"packages": [
6+
"@aave/core-v3/=lib/aave-v3-core",
7+
"@aave/periphery-v3/=lib/aave-v3-periphery",
8+
"@aave/=lib/aave-token",
9+
"@openzeppelin/=lib/openzeppelin-contracts",
10+
"aave-stk-v1-5/=lib/aave-stk-v1-5",
11+
"ds-test/=lib/forge-std/lib/ds-test/src",
12+
"forge-std/=lib/forge-std/src",
13+
"aave-address-book/=lib/aave-address-book/src",
14+
"aave-helpers/=lib/aave-stk-v1-5/lib/aave-helpers",
15+
"aave-v3-core/=lib/aave-address-book/lib/aave-v3-core",
16+
"erc4626-tests/=lib/aave-stk-v1-5/lib/openzeppelin-contracts/lib/erc4626-tests",
17+
"openzeppelin-contracts/=lib/aave-stk-v1-5/lib/openzeppelin-contracts",
18+
"solidity-utils/=lib/solidity-utils/src"
19+
],
20+
"optimistic_loop": true,
21+
"process": "emv",
22+
"prover_args": ["-depth 15","-mediumTimeout 1000"],
23+
"smt_timeout": "2000",
24+
"solc": "solc8.10",
25+
"verify": "GhoStewardV2:certora/steward/specs/timelock.spec",
26+
"msg": "STEWARD:timelock"
27+
}

certora/steward/specs/sanity.spec

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
3+
/* =================================================================================
4+
Rule: sanity / sanity_false.
5+
Status: all fail as expected. For that we use:
6+
- hashing_length_bound: 384. This is the minimal (in 32 jumps) that works.
7+
- copyLoopUnroll: 10 (this parameter may not be the minimal).
8+
================================================================================*/
9+
rule sanity(method f) {
10+
env e;
11+
calldataarg args;
12+
f(e,args);
13+
satisfy true;
14+
}
15+
16+

certora/steward/specs/timelock.spec

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
2+
3+
methods {
4+
/*
5+
function _.updateGsmExposureCap(uint128) external => NONDET;
6+
function _.getExposureCap() external => NONDET;
7+
8+
function _.updateExposureCap(uint128) external => NONDET;
9+
function _.getFacilitatorBucket(address) external => NONDET;
10+
function _.setFacilitatorBucketCapacity(address,uint128) external => NONDET;
11+
function _.getReserveData(address) external => NONDET;
12+
*/
13+
14+
15+
function _.getPool() external => NONDET;
16+
function _.getConfiguration(address) external => NONDET;
17+
function _.getPoolConfigurator() external => NONDET;
18+
19+
20+
function _.getBorrowCap(DataTypes.ReserveConfigurationMap memory) internal =>
21+
getBorrowCap_func() expect uint256 ;
22+
function _.setBorrowCap(address token, uint256 newCap) external =>
23+
setBorrowCap_func(token,newCap) expect void ALL;
24+
25+
26+
function _.getBaseVariableBorrowRate() external =>
27+
;
28+
function _.setReserveInterestRateStrategyAddress(address,address) external =>;
29+
30+
function owner() external returns (address) envfree;
31+
function getGhoTimelocks() external returns (IGhoStewardV2.GhoDebounce) envfree;
32+
function getGsmTimelocks(address) external returns (IGhoStewardV2.GsmDebounce) envfree;
33+
function MINIMUM_DELAY() external returns uint256 envfree;
34+
function RISK_COUNCIL() external returns address envfree;
35+
}
36+
37+
38+
ghost uint256 BorrowRate_gst {
39+
axiom BorrowRate_gst <= 10^27;
40+
}
41+
42+
function getBorrowRate_func() returns uint256 {
43+
return BorrowRate_gst;
44+
}
45+
46+
function setBorrowRate_func(address token, uint256 newCap) {
47+
BorrowRate_gst = newCap;
48+
}
49+
50+
51+
52+
ghost uint256 getBorrowCap_gst {
53+
axiom 1==1;
54+
}
55+
56+
function getBorrowCap_func() returns uint256 {
57+
return getBorrowCap_gst;
58+
}
59+
60+
function setBorrowCap_func(address token, uint256 newCap) {
61+
getBorrowCap_gst = newCap;
62+
}
63+
64+
65+
66+
67+
/* =================================================================================
68+
updateGhoBorrowCap
69+
================================================================================*/
70+
rule ghoBorrowCapLastUpdate__updated_only_by_updateGhoBorrowCap(method f) {
71+
env e; calldataarg args;
72+
73+
uint40 ghoBorrowCapLastUpdate_before = getGhoTimelocks().ghoBorrowCapLastUpdate;
74+
f(e,args);
75+
uint40 ghoBorrowCapLastUpdate_after = getGhoTimelocks().ghoBorrowCapLastUpdate;
76+
77+
assert (ghoBorrowCapLastUpdate_after != ghoBorrowCapLastUpdate_before) =>
78+
f.selector == sig:updateGhoBorrowCap(uint256).selector;
79+
}
80+
81+
rule updateGhoBorrowCap_update_correctly__ghoBorrowCapLastUpdate() {
82+
env e; uint256 newBorrowCap;
83+
updateGhoBorrowCap(e,newBorrowCap);
84+
assert getGhoTimelocks().ghoBorrowCapLastUpdate == require_uint40(e.block.timestamp);
85+
}
86+
87+
rule updateGhoBorrowCap_timelock() {
88+
uint40 ghoBorrowCapLastUpdate_before = getGhoTimelocks().ghoBorrowCapLastUpdate;
89+
env e; uint256 newBorrowCap;
90+
updateGhoBorrowCap(e,newBorrowCap);
91+
92+
assert to_mathint(e.block.timestamp) > ghoBorrowCapLastUpdate_before + MINIMUM_DELAY();
93+
}
94+
95+
96+
/* =================================================================================
97+
updateGhoBorrowRate
98+
================================================================================*/
99+
rule ghoBorrowRateLastUpdate__updated_only_by_updateGhoBorrowRate(method f) {
100+
env e; calldataarg args;
101+
102+
uint40 ghoBorrowRateLastUpdate_before = getGhoTimelocks().ghoBorrowRateLastUpdate;
103+
f(e,args);
104+
uint40 ghoBorrowRateLastUpdate_after = getGhoTimelocks().ghoBorrowRateLastUpdate;
105+
106+
assert (ghoBorrowRateLastUpdate_after != ghoBorrowRateLastUpdate_before) =>
107+
f.selector == sig:updateGhoBorrowRate(uint256).selector;
108+
}
109+
110+
rule updateGhoBorrowRate_update_correctly__ghoBorrowRateLastUpdate() {
111+
env e; uint256 newBorrowRate;
112+
updateGhoBorrowRate(e,newBorrowRate);
113+
assert getGhoTimelocks().ghoBorrowRateLastUpdate == require_uint40(e.block.timestamp);
114+
}
115+
116+
rule updateGhoBorrowRate_timelock() {
117+
uint40 ghoBorrowRateLastUpdate_before = getGhoTimelocks().ghoBorrowRateLastUpdate;
118+
env e; uint256 newBorrowRate;
119+
updateGhoBorrowRate(e,newBorrowRate);
120+
121+
assert to_mathint(e.block.timestamp) > ghoBorrowRateLastUpdate_before + MINIMUM_DELAY();
122+
}
123+
124+
125+
126+
/* =================================================================================
127+
updateGsmExposureCap
128+
================================================================================*/
129+
rule gsmExposureCapLastUpdated__updated_only_by_updateGsmExposureCap(method f) {
130+
env e; calldataarg args;
131+
address gsm;
132+
133+
uint40 gsmExposureCapLastUpdated_before = getGsmTimelocks(gsm).gsmExposureCapLastUpdated;
134+
f(e,args);
135+
uint40 gsmExposureCapLastUpdated_after = getGsmTimelocks(gsm).gsmExposureCapLastUpdated;
136+
137+
assert (gsmExposureCapLastUpdated_after != gsmExposureCapLastUpdated_before) =>
138+
f.selector == sig:updateGsmExposureCap(address,uint128).selector;
139+
}
140+
141+
rule updateGsmExposureCap_update_correctly__gsmExposureCapLastUpdated() {
142+
env e; address gsm; uint128 newExposureCap;
143+
updateGsmExposureCap(e,gsm, newExposureCap);
144+
assert getGsmTimelocks(gsm).gsmExposureCapLastUpdated == require_uint40(e.block.timestamp);
145+
}
146+
147+
rule updateGsmExposureCap_timelock() {
148+
env e; address gsm; uint128 newExposureCap;
149+
uint40 gsmExposureCapLastUpdated_before = getGsmTimelocks(gsm).gsmExposureCapLastUpdated;
150+
updateGsmExposureCap(e,gsm, newExposureCap);
151+
152+
assert to_mathint(e.block.timestamp) > gsmExposureCapLastUpdated_before + MINIMUM_DELAY();
153+
}
154+
155+
156+
157+
/* =================================================================================
158+
updateGsmBuySellFees
159+
================================================================================*/
160+
rule gsmFeeStrategyLastUpdated__updated_only_by_updateGsmBuySellFees(method f) {
161+
env e; calldataarg args;
162+
address gsm;
163+
164+
uint40 gsmFeeStrategyLastUpdated_before = getGsmTimelocks(gsm).gsmFeeStrategyLastUpdated;
165+
f(e,args);
166+
uint40 gsmFeeStrategyLastUpdated_after = getGsmTimelocks(gsm).gsmFeeStrategyLastUpdated;
167+
168+
assert (gsmFeeStrategyLastUpdated_after != gsmFeeStrategyLastUpdated_before) =>
169+
f.selector == sig:updateGsmBuySellFees(address,uint256,uint256).selector;
170+
}
171+
172+
rule updateGsmBuySellFees_update_correctly__gsmFeeStrategyLastUpdated() {
173+
env e; address gsm; uint256 buyFee; uint256 sellFee;
174+
updateGsmBuySellFees(e,gsm, buyFee, sellFee);
175+
assert getGsmTimelocks(gsm).gsmFeeStrategyLastUpdated == require_uint40(e.block.timestamp);
176+
}
177+
178+
rule updateGsmBuySellFees_timelock() {
179+
env e; address gsm; uint256 buyFee; uint256 sellFee;
180+
uint40 gsmFeeStrategyLastUpdated_before = getGsmTimelocks(gsm).gsmFeeStrategyLastUpdated;
181+
updateGsmBuySellFees(e,gsm, buyFee, sellFee);
182+
183+
assert to_mathint(e.block.timestamp) > gsmFeeStrategyLastUpdated_before + MINIMUM_DELAY();
184+
}
185+
186+
187+
188+
189+
rule only_RISK_COUNCIL_can_call__updateFacilitatorBucketCapacity() {
190+
env e; address facilitator; uint128 newBucketCapacity;
191+
192+
updateFacilitatorBucketCapacity(e,facilitator,newBucketCapacity);
193+
assert (e.msg.sender==RISK_COUNCIL());
194+
}
195+
rule only_RISK_COUNCIL_can_call__updateGhoBorrowCap() {
196+
env e; uint256 newBorrowCap;
197+
198+
updateGhoBorrowCap(e,newBorrowCap);
199+
assert (e.msg.sender==RISK_COUNCIL());
200+
}
201+
rule only_RISK_COUNCIL_can_call__updateGhoBorrowRate() {
202+
env e; uint256 newBorrowRate;
203+
204+
updateGhoBorrowRate(e,newBorrowRate);
205+
assert (e.msg.sender==RISK_COUNCIL());
206+
}
207+
rule only_RISK_COUNCIL_can_call__updateGsmExposureCap() {
208+
env e; address gsm; uint128 newExposureCap;
209+
210+
updateGsmExposureCap(e,gsm,newExposureCap);
211+
assert (e.msg.sender==RISK_COUNCIL());
212+
}
213+
rule only_RISK_COUNCIL_can_call__updateGsmBuySellFees() {
214+
env e; address gsm; uint256 buyFee; uint256 sellFee;
215+
216+
217+
updateGsmBuySellFees(e,gsm,buyFee,sellFee);
218+
assert (e.msg.sender==RISK_COUNCIL());
219+
}
220+
221+
rule only_RISK_COUNCIL_can_call__setControlledFacilitator() {
222+
env e;
223+
address[] facilitatorList;
224+
bool approve;
225+
226+
setControlledFacilitator(e,facilitatorList,approve);
227+
assert (e.msg.sender==owner());
228+
}
229+
230+
231+
232+
rule updateGhoBorrowCap__correctness() {
233+
env e; uint256 newBorrowCap;
234+
uint256 borrow_cap_before = getBorrowCap_gst;
235+
updateGhoBorrowCap(e,newBorrowCap);
236+
uint256 borrow_cap_after = getBorrowCap_gst;
237+
238+
assert borrow_cap_before <= borrow_cap_after && to_mathint(borrow_cap_after) <= 2*borrow_cap_before;
239+
}

0 commit comments

Comments
 (0)