Skip to content

Commit

Permalink
feat: refactor to updateFacilitator instead of GHO and GSM by separate
Browse files Browse the repository at this point in the history
  • Loading branch information
JoaquinBattilana committed Feb 16, 2024
1 parent 1373dae commit 7000996
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 167 deletions.
118 changes: 40 additions & 78 deletions src/contracts/misc/GhoStewardV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet

/**
* @title GhoStewardV2
* @author Aave
* @author Aave Labs
* @notice Helper contract for managing parameters of the GHO reserve and GSM
* @dev This contract must be granted `PoolAdmin` in the Aave V3 Ethereum Pool, `BucketManager` in GHO Token and `Configurator` in every GSM asset that will be managed by the risk council.
* @dev Only the Risk Council is able to action contract's functions.
Expand Down Expand Up @@ -53,10 +53,13 @@ contract GhoStewardV2 is Ownable, IGhoStewardV2 {
/// @inheritdoc IGhoStewardV2
address public immutable RISK_COUNCIL;

GhoDebounce internal _ghoTimelocks;
mapping(address => bool) internal _approvedGsmsByAddress;
EnumerableSet.AddressSet internal _approvedGsms;
uint40 internal _ghoBorrowRateLastUpdated;
mapping(address => uint40) _facilitatorsBucketCapacityTimelocks;
mapping(address => GsmDebounce) internal _gsmTimelocksByAddress;

mapping(address => bool) internal _controlledFacilitatorsByAddress;
EnumerableSet.AddressSet internal _controlledFacilitators;

mapping(uint256 => address) internal _ghoBorrowRateStrategiesByRate;
EnumerableSet.AddressSet internal _ghoBorrowRateStrategies;
mapping(uint256 => mapping(uint256 => address)) internal _gsmFeeStrategiesByRates;
Expand All @@ -77,13 +80,6 @@ contract GhoStewardV2 is Ownable, IGhoStewardV2 {
require(block.timestamp - timelock > MINIMUM_DELAY, 'DEBOUNCE_NOT_RESPECTED');
_;
}
/**
* @dev Only approved GSM can be used in methods marked by this modifier.
*/
modifier onlyApprovedGsm(address gsm) {
require(_approvedGsmsByAddress[gsm], 'GSM_NOT_APPROVED');
_;
}

/**
* @dev Constructor
Expand All @@ -103,17 +99,12 @@ contract GhoStewardV2 is Ownable, IGhoStewardV2 {
}

/// @inheritdoc IGhoStewardV2
function updateGhoBucketCapacity(
function updateFacilitatorBucketCapacity(
address facilitator,
uint128 newBucketCapacity
) external onlyRiskCouncil notLocked(_ghoTimelocks.ghoBucketCapacityLastUpdated) {
DataTypes.ReserveData memory ghoReserveData = IPool(
IPoolAddressesProvider(POOL_ADDRESSES_PROVIDER).getPool()
).getReserveData(GHO_TOKEN);
require(ghoReserveData.aTokenAddress != address(0), 'GHO_ATOKEN_NOT_FOUND');

(uint256 currentBucketCapacity, ) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(
ghoReserveData.aTokenAddress
);
) external onlyRiskCouncil notLocked(_facilitatorsBucketCapacityTimelocks[facilitator]) {
require(_controlledFacilitatorsByAddress[facilitator], 'FACILITATOR_NOT_APPROVED');
(uint256 currentBucketCapacity, ) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(facilitator);
require(
_isChangePositiveAndIncreaseLowerThanMax(
currentBucketCapacity,
Expand All @@ -123,18 +114,15 @@ contract GhoStewardV2 is Ownable, IGhoStewardV2 {
'INVALID_BUCKET_CAPACITY_UPDATE'
);

_ghoTimelocks.ghoBucketCapacityLastUpdated = uint40(block.timestamp);
_facilitatorsBucketCapacityTimelocks[facilitator] = uint40(block.timestamp);

IGhoToken(GHO_TOKEN).setFacilitatorBucketCapacity(
ghoReserveData.aTokenAddress,
newBucketCapacity
);
IGhoToken(GHO_TOKEN).setFacilitatorBucketCapacity(facilitator, newBucketCapacity);
}

/// @inheritdoc IGhoStewardV2
function updateGhoBorrowRate(
uint256 newBorrowRate
) external onlyRiskCouncil notLocked(_ghoTimelocks.ghoBorrowRateLastUpdated) {
) external onlyRiskCouncil notLocked(_ghoBorrowRateLastUpdated) {
DataTypes.ReserveData memory ghoReserveData = IPool(
IPoolAddressesProvider(POOL_ADDRESSES_PROVIDER).getPool()
).getReserveData(GHO_TOKEN);
Expand Down Expand Up @@ -166,7 +154,7 @@ contract GhoStewardV2 is Ownable, IGhoStewardV2 {
_ghoBorrowRateStrategies.add(cachedStrategyAddress);
}

_ghoTimelocks.ghoBorrowRateLastUpdated = uint40(block.timestamp);
_ghoBorrowRateLastUpdated = uint40(block.timestamp);

IPoolConfigurator(IPoolAddressesProvider(POOL_ADDRESSES_PROVIDER).getPoolConfigurator())
.setReserveInterestRateStrategyAddress(GHO_TOKEN, cachedStrategyAddress);
Expand All @@ -176,12 +164,7 @@ contract GhoStewardV2 is Ownable, IGhoStewardV2 {
function updateGsmExposureCap(
address gsm,
uint128 newExposureCap
)
external
onlyRiskCouncil
notLocked(_gsmTimelocksByAddress[gsm].gsmExposureCapLastUpdated)
onlyApprovedGsm(gsm)
{
) external onlyRiskCouncil notLocked(_gsmTimelocksByAddress[gsm].gsmExposureCapLastUpdated) {
uint128 currentExposureCap = IGsm(gsm).getExposureCap();
require(
_isChangePositiveAndIncreaseLowerThanMax(
Expand All @@ -195,40 +178,12 @@ contract GhoStewardV2 is Ownable, IGhoStewardV2 {
IGsm(gsm).updateExposureCap(newExposureCap);
}

/// @inheritdoc IGhoStewardV2
function updateGsmBucketCapacity(
address gsm,
uint128 newBucketCapacity
)
external
onlyRiskCouncil
notLocked(_gsmTimelocksByAddress[gsm].gsmBucketCapacityLastUpdated)
onlyApprovedGsm(gsm)
{
(uint256 currentBucketCapacity, ) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(gsm);
require(
_isChangePositiveAndIncreaseLowerThanMax(
currentBucketCapacity,
newBucketCapacity,
currentBucketCapacity
),
'INVALID_BUCKET_CAPACITY_UPDATE'
);
_gsmTimelocksByAddress[gsm].gsmBucketCapacityLastUpdated = uint40(block.timestamp);
IGhoToken(GHO_TOKEN).setFacilitatorBucketCapacity(gsm, newBucketCapacity);
}

/// @inheritdoc IGhoStewardV2
function updateGsmFeeStrategy(
address gsm,
uint256 buyFee,
uint256 sellFee
)
external
onlyRiskCouncil
notLocked(_gsmTimelocksByAddress[gsm].gsmFeeStrategyLastUpdated)
onlyApprovedGsm(gsm)
{
) external onlyRiskCouncil notLocked(_gsmTimelocksByAddress[gsm].gsmFeeStrategyLastUpdated) {
address currentFeeStrategy = IGsm(gsm).getFeeStrategy();
require(currentFeeStrategy != address(0), 'GSM_FEE_STRATEGY_NOT_FOUND');
uint256 currentBuyFee = IGsmFeeStrategy(gsm).getBuyFee(10e5);
Expand All @@ -250,34 +205,41 @@ contract GhoStewardV2 is Ownable, IGhoStewardV2 {
}

/// @inheritdoc IGhoStewardV2
function addApprovedGsms(address[] memory gsms) external onlyOwner {
for (uint256 i = 0; i < gsms.length; i++) {
_approvedGsmsByAddress[gsms[i]] = true;
_approvedGsms.add(gsms[i]);
function controlFacilitators(address[] memory facilitatorList, bool approve) external onlyOwner {
for (uint256 i = 0; i < facilitatorList.length; i++) {
_controlledFacilitatorsByAddress[facilitatorList[i]] = approve;
if (approve) {
IGhoToken.Facilitator memory facilitator = IGhoToken(GHO_TOKEN).getFacilitator(
facilitatorList[i]
);
require(bytes(facilitator.label).length > 0, 'FACILITATOR_DOES_NOT_EXIST');
_controlledFacilitators.add(facilitatorList[i]);
} else {
_controlledFacilitators.remove(facilitatorList[i]);
}
}
}

/// @inheritdoc IGhoStewardV2
function removeApprovedGsms(address[] memory gsms) external onlyOwner {
for (uint256 i = 0; i < gsms.length; i++) {
_approvedGsmsByAddress[gsms[i]] = false;
_approvedGsms.remove(gsms[i]);
}
function getControlledFacilitators() external view returns (address[] memory) {
return _controlledFacilitators.values();
}

/// @inheritdoc IGhoStewardV2
function getApprovedGsms() external view returns (address[] memory) {
return _approvedGsms.values();
function getGhoBorrowRateTimelock() external view returns (uint40) {
return _ghoBorrowRateLastUpdated;
}

/// @inheritdoc IGhoStewardV2
function getGhoTimelocks() external view returns (GhoDebounce memory) {
return _ghoTimelocks;
function getGsmTimelocks(address gsm) external view returns (GsmDebounce memory) {
return _gsmTimelocksByAddress[gsm];
}

/// @inheritdoc IGhoStewardV2
function getGsmTimelocks(address gsm) external view returns (GsmDebounce memory) {
return _gsmTimelocksByAddress[gsm];
function getFacilitatorBucketCapacityTimelock(
address facilitator
) external view returns (uint40) {
return _facilitatorsBucketCapacityTimelocks[facilitator];
}

/// @inheritdoc IGhoStewardV2
Expand Down
43 changes: 11 additions & 32 deletions src/contracts/misc/interfaces/IGhoStewardV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@ pragma solidity ^0.8.10;
* @notice Defines the basic interface of the GhoStewardV2
*/
interface IGhoStewardV2 {
struct GhoDebounce {
uint40 ghoBorrowCapLastUpdated;
uint40 ghoBucketCapacityLastUpdated;
uint40 ghoBorrowRateLastUpdated;
}
struct GsmDebounce {
uint40 gsmExposureCapLastUpdated;
uint40 gsmBucketCapacityLastUpdated;
uint40 gsmFeeStrategyLastUpdated;
}

Expand Down Expand Up @@ -61,13 +55,14 @@ interface IGhoStewardV2 {
function RISK_COUNCIL() external view returns (address);

/**
* @notice Updates the bucket capacity of GHO, only if:
* @notice Updates the bucket capacity of facilitator, only if:
* - respects the debounce duration (7 day pause between updates must be respected)
* - the update changes up to 100% upwards
* - the facilitator is controlled
* @dev Only callable by Risk Council
* @param newBucketCapacity The new GHO bucket capacity of the facilitator (AAVE)
*/
function updateGhoBucketCapacity(uint128 newBucketCapacity) external;
function updateFacilitatorBucketCapacity(address facilitator, uint128 newBucketCapacity) external;

/**
* @notice Updates the borrow rate of GHO, only if:
Expand All @@ -90,17 +85,6 @@ interface IGhoStewardV2 {
*/
function updateGsmExposureCap(address gsm, uint128 newExposureCap) external;

/**
* @notice Updates the borrow rate of GHO, only if:
* - respects the debounce duration (7 day pause between updates must be respected)
* - the GSM address is approved
* - the update changes up to 100% upwards
* @dev Only callable by Risk Council
* @param gsm The gsm address to update
* @param newBucketCapacity The new bucket capacity of the GSM facilitator
*/
function updateGsmBucketCapacity(address gsm, uint128 newBucketCapacity) external;

/**
* @notice Updates the borrow rate of GHO, only if:
* - respects the debounce duration (7 day pause between updates must be respected)
Expand All @@ -116,35 +100,30 @@ interface IGhoStewardV2 {
/**
* @notice Adds approved GSMs
* @dev Only callable by owner
* @param gsms A list of GSMs addresses to add to the approved list
*/
function addApprovedGsms(address[] memory gsms) external;

/**
* @notice Removes approved GSMs
* @dev Only callable by owner
* @param gsms A list of GSMs addresses to remove from the approved list
* @param facilitatorList A list of facilitators addresses to add to control
*/
function removeApprovedGsms(address[] memory gsms) external;
function controlFacilitators(address[] memory facilitatorList, bool approve) external;

/**
* @notice Returns the list of approved GSMs
* @return An array of GSM addresses
*/
function getApprovedGsms() external view returns (address[] memory);
function getControlledFacilitators() external view returns (address[] memory);

/**
* @notice Returns the GHO timelock values for all parameters updates
* @return The GhoDebounce struct with parameters' timelock
*/
function getGhoTimelocks() external view returns (GhoDebounce memory);
function getGhoBorrowRateTimelock() external view returns (uint40);

function getGsmTimelocks(address gsm) external view returns (GsmDebounce memory);

/**
* @notice Returns the Gsm timelocks values for all parameters updates
* @param gsm The gsm address
* @param facilitator The facilitator address
* @return The GsmDebounce struct with parameters' timelock
*/
function getGsmTimelocks(address gsm) external view returns (GsmDebounce memory);
function getFacilitatorBucketCapacityTimelock(address facilitator) external view returns (uint40);

/**
* @notice Returns the list of Fixed Fee Strategies for GSM
Expand Down
7 changes: 4 additions & 3 deletions src/test/TestGhoBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,11 @@ contract TestGhoBase is Test, Constants, Events {
);
GHO_TOKEN.grantRole(GHO_TOKEN_BUCKET_MANAGER_ROLE, address(GHO_STEWARD_V2));
GHO_GSM.grantRole(GSM_CONFIGURATOR_ROLE, address(GHO_STEWARD_V2));
address[] memory gsmsToApprove = new address[](1);
gsmsToApprove[0] = address(GHO_GSM);
address[] memory controlledFacilitators = new address[](2);
controlledFacilitators[0] = address(GHO_ATOKEN);
controlledFacilitators[1] = address(GHO_GSM);
vm.prank(SHORT_EXECUTOR);
GHO_STEWARD_V2.addApprovedGsms(gsmsToApprove);
GHO_STEWARD_V2.controlFacilitators(controlledFacilitators);
}

function ghoFaucet(address to, uint256 amount) public {
Expand Down
Loading

0 comments on commit 7000996

Please sign in to comment.