Skip to content

Commit

Permalink
fix: use bps instead of ray
Browse files Browse the repository at this point in the history
  • Loading branch information
CheyenneAtapour committed Aug 6, 2024
1 parent 1762d1f commit 2015f8c
Show file tree
Hide file tree
Showing 8 changed files with 860 additions and 10 deletions.
10 changes: 8 additions & 2 deletions src/contracts/misc/GhoAaveSteward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ contract GhoAaveSteward is RiskCouncilControlled, IGhoAaveSteward {
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using Address for address;

/// @inheritdoc IGhoAaveSteward
uint256 public constant GHO_BORROW_RATE_CHANGE_MAX = 0.0500e27; // 5.00%

/// @inheritdoc IGhoAaveSteward
uint256 public constant GHO_BORROW_RATE_MAX = 0.2500e27; // 25.00%

/// @inheritdoc IGhoAaveSteward
address public immutable CONFIG_ENGINE;

Expand Down Expand Up @@ -88,6 +94,7 @@ contract GhoAaveSteward is RiskCouncilControlled, IGhoAaveSteward {

/// @inheritdoc IGhoAaveSteward
function updateGhoBorrowRate(
/* TODO: Add all 4 parameters back */
uint256 baseVariableBorrowRate
) external onlyRiskCouncil notTimelocked(_ghoTimelocks.ghoBorrowCapLastUpdate) {
_validateRatesUpdate(baseVariableBorrowRate);
Expand Down Expand Up @@ -185,15 +192,14 @@ contract GhoAaveSteward is RiskCouncilControlled, IGhoAaveSteward {

function _validateRatesUpdate(uint256 baseVariableBorrowRate) internal view {
(, uint256 currentBaseVariableBorrowRate, , ) = _getInterestRatesForAsset(GHO_TOKEN);

require(
_updateWithinAllowedRange(
currentBaseVariableBorrowRate,
baseVariableBorrowRate,
0.05e4,
false
),
'INVALID_BASE_VARIABLE_BORROW_RATE_UPDATE'
'INVALID_BORROW_RATE_UPDATE'
);
}

Expand Down
544 changes: 544 additions & 0 deletions src/contracts/misc/deps/Dependencies.sol

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/contracts/misc/interfaces/IGhoAaveSteward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ interface IGhoAaveSteward {
*/
function updateGhoSupplyCap(uint256 newSupplyCap) external;

/**
* @notice Returns the maximum increase/decrease for GHO borrow rate updates.
* @return The maximum increase change for borrow rate updates in ray (e.g. 0.010e27 results in 1.00%)
*/
function GHO_BORROW_RATE_CHANGE_MAX() external view returns (uint256);

/**
* @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 (uint256);

/**
* @notice The address of the config engine used to perform the borrow rate update via delegatecall
*/
Expand Down
88 changes: 82 additions & 6 deletions src/test/TestGhoAaveSteward.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,35 @@ pragma solidity ^0.8.0;

import './TestGhoBase.t.sol';
import {IGhoAaveSteward} from '../contracts/misc/interfaces/IGhoAaveSteward.sol';
import {IDefaultInterestRateStrategyV2} from '../contracts/misc/deps/Dependencies.sol';

contract TestGhoAaveSteward is TestGhoBase {
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;

function setUp() public {
// Deploy Gho Aave Steward
MockConfigEngine engine = new MockConfigEngine();
MockConfigEngine engine = new MockConfigEngine(address(CONFIGURATOR), address(PROVIDER));
GHO_AAVE_STEWARD = new GhoAaveSteward(
address(PROVIDER),
address(AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER),
address(MOCK_POOL_DATA_PROVIDER),
address(engine),
address(GHO_TOKEN),
address(FIXED_RATE_STRATEGY_FACTORY),
RISK_COUNCIL
);

MockConfigEngine.RateStrategyUpdate[] memory update = new MockConfigEngine.RateStrategyUpdate[](
1
);
update[0].asset = address(GHO_TOKEN);
update[0].params = MockConfigEngine.InterestRateInputData({
optimalUsageRatio: 1_00,
baseVariableBorrowRate: 0.25e4,
variableRateSlope1: 0,
variableRateSlope2: 0
});
engine.updateRateStrategies(update);

/// @dev Since block.timestamp starts at 0 this is a necessary condition (block.timestamp > `MINIMUM_DELAY`) for the timelocked contract methods to work.
vm.warp(GHO_AAVE_STEWARD.MINIMUM_DELAY() + 1);
}
Expand All @@ -27,10 +40,7 @@ contract TestGhoAaveSteward is TestGhoBase {
assertEq(GHO_AAVE_STEWARD.MINIMUM_DELAY(), MINIMUM_DELAY_V2);

assertEq(GHO_AAVE_STEWARD.POOL_ADDRESSES_PROVIDER(), address(PROVIDER));
assertEq(
GHO_AAVE_STEWARD.POOL_DATA_PROVIDER(),
address(AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER)
);
assertEq(GHO_AAVE_STEWARD.POOL_DATA_PROVIDER(), address(MOCK_POOL_DATA_PROVIDER));
assertEq(GHO_AAVE_STEWARD.GHO_TOKEN(), address(GHO_TOKEN));
assertEq(GHO_AAVE_STEWARD.FIXED_RATE_STRATEGY_FACTORY(), address(FIXED_RATE_STRATEGY_FACTORY));
assertEq(GHO_AAVE_STEWARD.RISK_COUNCIL(), RISK_COUNCIL);
Expand Down Expand Up @@ -257,6 +267,41 @@ contract TestGhoAaveSteward is TestGhoBase {
GHO_AAVE_STEWARD.updateGhoSupplyCap(oldSupplyCap * 2 + 1);
}

function testUpdateGhoBorrowRate() public {
vm.prank(RISK_COUNCIL);
GHO_AAVE_STEWARD.updateGhoBorrowRate(0.26e4);
assertEq(_getGhoBorrowRate(), 0.26e4);
}

function testUpdateGhoBorrowRateUpwards() public {
uint256 oldBorrowRate = _getGhoBorrowRate();
uint256 newBorrowRate = oldBorrowRate + 1;
vm.prank(RISK_COUNCIL);
GHO_AAVE_STEWARD.updateGhoBorrowRate(newBorrowRate);
uint256 currentBorrowRate = _getGhoBorrowRate();
assertEq(currentBorrowRate, newBorrowRate);
}

function testRevertUpdateGhoBorrowRateIfMaxExceededDownwards() public {
vm.startPrank(RISK_COUNCIL);

// set a high borrow rate
GHO_AAVE_STEWARD.updateGhoBorrowRate(
_getGhoBorrowRate() + GHO_AAVE_STEWARD.GHO_BORROW_RATE_CHANGE_MAX() / 1e23
);
vm.warp(block.timestamp + GHO_AAVE_STEWARD.MINIMUM_DELAY() + 1);

uint256 oldBorrowRate = _getGhoBorrowRate();
uint256 newBorrowRate = oldBorrowRate -
GHO_AAVE_STEWARD.GHO_BORROW_RATE_CHANGE_MAX() /
1e23 -
1;
vm.expectRevert('INVALID_BORROW_RATE_UPDATE');
GHO_AAVE_STEWARD.updateGhoBorrowRate(newBorrowRate);

vm.stopPrank();
}

function _setGhoBorrowCapViaConfigurator(uint256 newBorrowCap) internal {
CONFIGURATOR.setBorrowCap(address(GHO_TOKEN), newBorrowCap);
}
Expand All @@ -278,4 +323,35 @@ contract TestGhoAaveSteward is TestGhoBase {
);
return configuration.getSupplyCap();
}

function _setGhoBorrowRateViaConfigurator(
uint256 newBorrowRate
) internal returns (GhoInterestRateStrategy, uint256) {
GhoInterestRateStrategy newRateStrategy = new GhoInterestRateStrategy(
address(PROVIDER),
newBorrowRate
);
CONFIGURATOR.setReserveInterestRateStrategyAddress(
address(GHO_TOKEN),
address(newRateStrategy)
);
address currentInterestRateStrategy = POOL.getReserveInterestRateStrategyAddress(
address(GHO_TOKEN)
);
uint256 currentBorrowRate = GhoInterestRateStrategy(currentInterestRateStrategy)
.getBaseVariableBorrowRate();
assertEq(currentInterestRateStrategy, address(newRateStrategy));
assertEq(currentBorrowRate, newBorrowRate);
return (newRateStrategy, newBorrowRate);
}

function _getGhoBorrowRate() internal view returns (uint256) {
address currentInterestRateStrategy = POOL.getReserveInterestRateStrategyAddress(
address(GHO_TOKEN)
);
return
IDefaultInterestRateStrategyV2(currentInterestRateStrategy).getBaseVariableBorrowRate(
address(GHO_TOKEN)
) / 1e23; // Convert to bps
}
}
3 changes: 3 additions & 0 deletions src/test/TestGhoBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {PriceOracle} from '@aave/core-v3/contracts/mocks/oracle/PriceOracle.sol'
import {TestnetERC20} from '@aave/periphery-v3/contracts/mocks/testnet-helpers/TestnetERC20.sol';
import {WETH9Mock} from '@aave/periphery-v3/contracts/mocks/WETH9Mock.sol';
import {MockConfigEngine} from './mocks/MockConfigEngine.sol';
import {MockPoolDataProvider} from './mocks/MockPoolDataProvider.sol';

// interfaces
import {IAaveIncentivesController} from '@aave/core-v3/contracts/interfaces/IAaveIncentivesController.sol';
Expand Down Expand Up @@ -143,6 +144,7 @@ contract TestGhoBase is Test, Constants, Events {
GhoCcipSteward GHO_CCIP_STEWARD;
GhoGsmSteward GHO_GSM_STEWARD;
GhoBucketCapacitySteward GHO_BUCKET_CAPACITY_STEWARD;
MockPoolDataProvider MOCK_POOL_DATA_PROVIDER;

FixedRateStrategyFactory FIXED_RATE_STRATEGY_FACTORY;
GsmFeeStrategyFactory GSM_FEE_STRATEGY_FACTORY;
Expand All @@ -161,6 +163,7 @@ contract TestGhoBase is Test, Constants, Events {
bytes memory empty;
ACL_MANAGER = new MockAclManager();
PROVIDER = new MockAddressesProvider(address(ACL_MANAGER));
MOCK_POOL_DATA_PROVIDER = new MockPoolDataProvider(address(PROVIDER));
POOL = new MockPool(IPoolAddressesProvider(address(PROVIDER)));
CONFIGURATOR = new MockConfigurator(IPool(POOL));
PRICE_ORACLE = new PriceOracle();
Expand Down
39 changes: 37 additions & 2 deletions src/test/mocks/MockConfigEngine.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {MockConfigurator} from './MockConfigurator.sol';
import {GhoInterestRateStrategy} from 'src/contracts/facilitators/aave/interestStrategy/GhoInterestRateStrategy.sol';
import {DefaultReserveInterestRateStrategyV2} from '../../contracts/misc/deps/Dependencies.sol';
import {IDefaultInterestRateStrategyV2} from '../../contracts/misc/deps/Dependencies.sol';

contract MockConfigEngine {
constructor() {}
address public immutable CONFIGURATOR;
address public immutable PROVIDER;

constructor(address configurator, address provider) {
CONFIGURATOR = configurator;
PROVIDER = provider;
}

struct InterestRateInputData {
uint256 optimalUsageRatio;
Expand All @@ -16,5 +27,29 @@ contract MockConfigEngine {
InterestRateInputData params;
}

function updateRateStrategies(RateStrategyUpdate[] calldata updates) external {}
function updateRateStrategies(RateStrategyUpdate[] calldata updates) external {
/*
GhoInterestRateStrategy newRateStrategy = new GhoInterestRateStrategy(
address(PROVIDER),
updates[0].params.baseVariableBorrowRate
);*/
DefaultReserveInterestRateStrategyV2 newRateStrategy = new DefaultReserveInterestRateStrategyV2(
address(PROVIDER)
);

MockConfigurator(CONFIGURATOR).setReserveInterestRateStrategyAddress(
address(updates[0].asset),
address(newRateStrategy)
);

MockConfigurator(CONFIGURATOR).setReserveInterestRateParams(
address(updates[0].asset),
IDefaultInterestRateStrategyV2.InterestRateData({
optimalUsageRatio: uint16(updates[0].params.optimalUsageRatio),
baseVariableBorrowRate: uint32(updates[0].params.baseVariableBorrowRate),
variableRateSlope1: uint32(updates[0].params.variableRateSlope1),
variableRateSlope2: uint32(updates[0].params.variableRateSlope2)
})
);
}
}
14 changes: 14 additions & 0 deletions src/test/mocks/MockConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pragma solidity ^0.8.0;
import {IPool} from '@aave/core-v3/contracts/interfaces/IPool.sol';
import {DataTypes} from '@aave/core-v3/contracts/protocol/libraries/types/DataTypes.sol';
import {ReserveConfiguration} from '@aave/core-v3/contracts/protocol/libraries/configuration/ReserveConfiguration.sol';
import {DefaultReserveInterestRateStrategyV2} from '../../contracts/misc/deps/Dependencies.sol';
import {IDefaultInterestRateStrategyV2} from '../../contracts/misc/deps/Dependencies.sol';

contract MockConfigurator {
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
Expand Down Expand Up @@ -39,6 +41,18 @@ contract MockConfigurator {
emit ReserveInterestRateStrategyChanged(asset, oldRateStrategyAddress, newRateStrategyAddress);
}

function setReserveInterestRateParams(
address asset,
IDefaultInterestRateStrategyV2.InterestRateData calldata rateParams
) external {
DataTypes.ReserveData memory reserve = _pool.getReserveData(asset);
address rateStrategyAddress = reserve.interestRateStrategyAddress;
DefaultReserveInterestRateStrategyV2(rateStrategyAddress).setInterestRateParams(
asset,
rateParams
);
}

function setBorrowCap(address asset, uint256 newBorrowCap) external {
DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
uint256 oldBorrowCap = currentConfig.getBorrowCap();
Expand Down
Loading

0 comments on commit 2015f8c

Please sign in to comment.