Skip to content

Commit

Permalink
Merge branch 'main' into certora
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelMorami committed Jan 9, 2025
2 parents c24441d + cf6ee42 commit bd4fab0
Show file tree
Hide file tree
Showing 19 changed files with 324 additions and 93 deletions.
1 change: 0 additions & 1 deletion .github/workflows/certora-steward.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,3 @@ jobs:
- GhoBucketSteward.conf
- GhoCcipSteward.conf
- GhoGsmSteward.conf

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ You can find all audit reports under the [audits](./audits/) folder
- [2023-12-07 - Certora Formal Verification (GHO Stability Module)](./certora/reports/Formal_Verification_Report_of_GHO_Stability_Module.pdf)
- [2024-03-14 - Certora Formal Verification (GhoStewardV2)](./audits/2024-03-14_GhoStewardV2_Certora.pdf)
- [2024-06-11 - Certora Formal Verification (UpgradeableGHO)](./audits/2024-06-11_UpgradeableGHO_Certora.pdf)
- [2024-06-11 - Certora Formal Verification (Modular Gho Stewards)](./audits/2024-09-15_ModularGhoStewards_Certora.pdf)

## Getting Started

Expand Down
Binary file added audits/2024-09-15_ModularGhoStewards_Certora.pdf
Binary file not shown.
6 changes: 0 additions & 6 deletions certora/steward/harness/GhoCcipSteward_Harness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,4 @@ contract GhoCcipSteward_Harness is GhoCcipSteward {
address riskCouncil,
bool bridgeLimitEnabled
) GhoCcipSteward(ghoToken, ghoTokenPool, riskCouncil, bridgeLimitEnabled) {}

function getCcipTimelocks() external view returns (CcipDebounce memory) {
return _ccipTimelocks;
}


}
18 changes: 0 additions & 18 deletions certora/steward/specs/GhoAaveSteward.spec
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ methods {


function getGhoTimelocks() external returns (IGhoAaveSteward.GhoDebounce) envfree;
function GHO_BORROW_RATE_MAX() external returns uint32 envfree;
function MINIMUM_DELAY() external returns uint256 envfree;
function RISK_COUNCIL() external returns address envfree;

Expand Down Expand Up @@ -225,23 +224,6 @@ rule updateGhoSupplyCap__correctness() {
}


rule updateGhoBorrowRate__correctness() {
env e; uint16 optimalUsageRatio; uint32 baseVariableBorrowRate;
uint32 variableRateSlope1; uint32 variableRateSlope2;

uint16 optimalUsageRatio_before = OPTIMAL_USAGE_RATIO;
uint32 baseVariableBorrowRate_before = BASE_VARIABLE_BORROW_RATE;
uint32 variableRateSlope1_before = VARIABLE_RATE_SLOPE1;
uint32 variableRateSlope2_before = VARIABLE_RATE_SLOPE2;

updateGhoBorrowRate(e,optimalUsageRatio, baseVariableBorrowRate, variableRateSlope1, variableRateSlope2);


assert baseVariableBorrowRate + variableRateSlope1 + variableRateSlope2 <= to_mathint(GHO_BORROW_RATE_MAX());
}






Expand Down
38 changes: 38 additions & 0 deletions docs/gho-stewards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Overview

These contracts each control different parameters related to GHO and its facilitators. They allow the Aave DAO and an approved Risk Council to change these parameters, according to set rules and configurations.

Each Steward is designed to have a specific set of segregated responsibilities in an effort to avoid having to redeploy the entire original Steward. Instead, only the specific steward whose responsibilities are affected will have to be redeployed.

### [GhoAaveSteward](/src/contracts/misc/GhoAaveSteward.sol)

This Steward manages parameters related to the GHO token. Specifically, it allows the Risk Council to change the following parameters:

- Borrow Rate
- Borrow Cap
- Supply Cap

In addition, the Aave DAO is allowed to change the configuration for the GHO Borrow Rate. This puts restrictions on how much the Risk Council is allowed to change parameters related to the borrow rate. There are 4 parameters that comprise the borrow rate:

- `optimalUsageRatio`
- `baseVariableBorrowRate`
- `variableRateSlope1`
- `variableRateSlope2`

For example, the Aave DAO can specify that the optimalUsageRatio variable may only be changed by 3% at a time.

### [GhoBucketSteward](/src/contracts/misc/GhoBucketSteward.sol)

This Steward allows the Risk Council to set the bucket capacities of controlled facilitators. Additionally, it allows the Aave DAO to add or remove controlled facilitators.

### [GhoCcipSteward](/src/contracts/misc/GhoCcipSteward.sol)

This Steward allows the management of parameters related to CCIP token pools. It allows the Risk Council to update the CCIP bridge limit, and to update the CCIP rate limit configuration.

### [GhoGsmSteward](/src/contracts/misc/GhoGsmSteward.sol)

This Steward allows the Risk Council to update the exposure cap of the GSM, and to update the buy and sell fees of the GSM.

### [RiskCouncilControlled](/src/contracts/misc/RiskCouncilControlled.sol)

This is a helper contract to define the approved Risk Council and enforce its authority to call permissioned functions.
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ contract GhoVariableDebtToken is DebtTokenBase, ScaledBalanceTokenBase, IGhoVari
}

/// @inheritdoc IGhoVariableDebtToken
function getBalanceFromInterest(address user) external view override returns (uint256) {
{function getBalanceFromInterest(address user) external view override returns (uint256) {
return _ghoUserState[user].accumulatedDebtInterest;
}

Expand Down
11 changes: 0 additions & 11 deletions src/contracts/misc/GhoAaveSteward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ import {RiskCouncilControlled} from './RiskCouncilControlled.sol';
contract GhoAaveSteward is Ownable, RiskCouncilControlled, IGhoAaveSteward {
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;

/// @inheritdoc IGhoAaveSteward
uint32 public constant GHO_BORROW_RATE_MAX = 0.25e4; // 25.00%

uint256 internal constant BPS_MAX = 100_00;

/// @inheritdoc IGhoAaveSteward
Expand Down Expand Up @@ -227,14 +224,6 @@ contract GhoAaveSteward is Ownable, RiskCouncilControlled, IGhoAaveSteward {
),
'INVALID_VARIABLE_RATE_SLOPE2'
);

require(
uint256(newRates.baseVariableBorrowRate) +
uint256(newRates.variableRateSlope1) +
uint256(newRates.variableRateSlope2) <=
GHO_BORROW_RATE_MAX,
'BORROW_RATE_HIGHER_THAN_MAX'
);
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/contracts/misc/GhoBucketSteward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ contract GhoBucketSteward is Ownable, RiskCouncilControlled, IGhoBucketSteward {
return _controlledFacilitators.values();
}

/// @inheritdoc IGhoBucketSteward
function isControlledFacilitator(address facilitator) external view returns (bool) {
return _controlledFacilitatorsByAddress[facilitator];
}

/// @inheritdoc IGhoBucketSteward
function getFacilitatorBucketCapacityTimelock(
address facilitator
Expand Down
7 changes: 6 additions & 1 deletion src/contracts/misc/GhoCcipSteward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@ contract GhoCcipSteward is RiskCouncilControlled, IGhoCcipSteward {
}

/// @inheritdoc IGhoCcipSteward
function RISK_COUNCIL() public view override returns (address) {
function getCcipTimelocks() external view override returns (CcipDebounce memory) {
return _ccipTimelocks;
}

/// @inheritdoc IGhoCcipSteward
function RISK_COUNCIL() external view override returns (address) {
return _riskCouncil;
}

Expand Down
7 changes: 0 additions & 7 deletions src/contracts/misc/interfaces/IGhoAaveSteward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ interface IGhoAaveSteward {
* @notice Updates the borrow rate of GHO, only if:
* - respects `MINIMUM_DELAY`, the minimum time delay between updates
* - the update changes parameters up to the maximum allowed change according to risk config
* - the update is lower than `GHO_BORROW_RATE_MAX`
* @dev Only callable by Risk Council
* @dev Values are all expressed in BPS
* @param optimalUsageRatio The new optimal usage ratio
Expand Down Expand Up @@ -90,12 +89,6 @@ interface IGhoAaveSteward {
*/
function getGhoTimelocks() external view returns (GhoDebounce memory);

/**
* @notice Returns maximum value that can be assigned to GHO borrow rate.
* @return The maximum value that can be assigned to GHO borrow rate in ray (e.g. 0.01e27 results in 1.0%)
*/
function GHO_BORROW_RATE_MAX() external view returns (uint32);

/**
* @notice The address of pool data provider of the POOL the steward controls
*/
Expand Down
7 changes: 7 additions & 0 deletions src/contracts/misc/interfaces/IGhoBucketSteward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ interface IGhoBucketSteward {
*/
function getControlledFacilitators() external view returns (address[] memory);

/**
* @notice Checks if a facilitator is controlled by this steward
* @param facilitator The facilitator address to check
* @return True if the facilitator is controlled by this steward
*/
function isControlledFacilitator(address facilitator) external view returns (bool);

/**
* @notice Returns timestamp of the facilitators last bucket capacity update
* @param facilitator The facilitator address
Expand Down
9 changes: 9 additions & 0 deletions src/contracts/misc/interfaces/IGhoCcipSteward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ pragma solidity ^0.8.10;
* @notice Defines the basic interface of the GhoCcipSteward
*/
interface IGhoCcipSteward {
/**
* @notice Struct storing the last update by the steward of the bridge and rate limit param.
*/
struct CcipDebounce {
uint40 bridgeLimitLastUpdate;
uint40 rateLimitLastUpdate;
Expand Down Expand Up @@ -41,6 +44,12 @@ interface IGhoCcipSteward {
uint128 inboundRate
) external;

/**
* @notice Returns timestamp of the last update of Ccip parameters.
* @return The CcipDebounce struct describing the last update of Ccip parameters.
*/
function getCcipTimelocks() external view returns (CcipDebounce memory);

/**
* @notice Returns the minimum delay that must be respected between parameters update.
* @return The minimum delay between parameter updates (in seconds)
Expand Down
41 changes: 22 additions & 19 deletions src/test/TestGhoAaveSteward.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,21 @@ contract TestGhoAaveSteward is TestGhoBase {
assertEq(currentBorrowRate, newBorrowRate);
}

function testUpdateGhoBorrowRateUpwardsFromHigh() public {
// set a very high borrow rate of 80%
uint32 highBaseBorrowRate = 0.80e4;
_setGhoBorrowRateViaConfigurator(highBaseBorrowRate);
highBaseBorrowRate += 0.04e4;
vm.prank(RISK_COUNCIL);
GHO_AAVE_STEWARD.updateGhoBorrowRate(
defaultRateParams.optimalUsageRatio,
highBaseBorrowRate,
defaultRateParams.variableRateSlope1,
defaultRateParams.variableRateSlope2
);
assertEq(highBaseBorrowRate, _getGhoBorrowRate());
}

function testUpdateGhoBorrowRateDownwards() public {
uint32 oldBorrowRate = _getGhoBorrowRate();
uint32 newBorrowRate = oldBorrowRate - 1;
Expand All @@ -341,18 +356,19 @@ contract TestGhoAaveSteward is TestGhoBase {
assertEq(currentBorrowRate, newBorrowRate);
}

function testUpdateGhoBorrowRateMaxValue() public {
uint32 ghoBorrowRateMax = GHO_AAVE_STEWARD.GHO_BORROW_RATE_MAX();
_setGhoBorrowRateViaConfigurator(ghoBorrowRateMax - 1);
function testUpdateGhoBorrowRateDownwardsFromHigh() public {
// set a very high borrow rate of 80%
uint32 highBaseBorrowRate = 0.80e4;
_setGhoBorrowRateViaConfigurator(highBaseBorrowRate);
highBaseBorrowRate -= 0.04e4;
vm.prank(RISK_COUNCIL);
GHO_AAVE_STEWARD.updateGhoBorrowRate(
defaultRateParams.optimalUsageRatio,
ghoBorrowRateMax,
highBaseBorrowRate,
defaultRateParams.variableRateSlope1,
defaultRateParams.variableRateSlope2
);
uint32 currentBorrowRate = _getGhoBorrowRate();
assertEq(currentBorrowRate, ghoBorrowRateMax);
assertEq(highBaseBorrowRate, _getGhoBorrowRate());
}

function testUpdateGhoBorrowRateMaxIncrement() public {
Expand Down Expand Up @@ -660,19 +676,6 @@ contract TestGhoAaveSteward is TestGhoBase {
);
}

function testRevertUpdateGhoBorrowRateIfValueMoreThanMax() public {
uint32 maxGhoBorrowRate = GHO_BORROW_RATE_MAX;
_setGhoBorrowRateViaConfigurator(maxGhoBorrowRate);
vm.prank(RISK_COUNCIL);
vm.expectRevert('BORROW_RATE_HIGHER_THAN_MAX');
GHO_AAVE_STEWARD.updateGhoBorrowRate(
defaultRateParams.optimalUsageRatio,
maxGhoBorrowRate + 1,
defaultRateParams.variableRateSlope1,
defaultRateParams.variableRateSlope2
);
}

function testRevertUpdateGhoBorrowRateIfMaxExceededUpwards() public {
uint32 oldBorrowRate = _getGhoBorrowRate();
uint32 newBorrowRate = oldBorrowRate + GHO_BORROW_RATE_CHANGE_MAX + 1;
Expand Down
11 changes: 11 additions & 0 deletions src/test/TestGhoBucketSteward.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,15 @@ contract TestGhoBucketSteward is TestGhoBase {
newGsmList[0] = address(GHO_GSM_4626);
GHO_BUCKET_STEWARD.setControlledFacilitator(newGsmList, true);
}

function testIsControlledFacilitator() public {
address facilitator = makeAddr('FACILITATOR');
address[] memory controlledFacilitators = new address[](1);
controlledFacilitators[0] = facilitator;
vm.prank(SHORT_EXECUTOR);
GHO_BUCKET_STEWARD.setControlledFacilitator(controlledFacilitators, true);
assertTrue(GHO_BUCKET_STEWARD.isControlledFacilitator(facilitator));
address nonFacilitator = makeAddr('NON_FACILITATOR');
assertFalse(GHO_BUCKET_STEWARD.isControlledFacilitator(nonFacilitator));
}
}
Loading

0 comments on commit bd4fab0

Please sign in to comment.