Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT
2 : : pragma solidity ^0.8.0;
3 : :
4 : : import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
5 : : import {WadRayMath} from '../protocol/libraries/math/WadRayMath.sol';
6 : : import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol';
7 : : import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
8 : : import {Errors} from '../protocol/libraries/helpers/Errors.sol';
9 : : import {IDefaultInterestRateStrategyV2} from '../interfaces/IDefaultInterestRateStrategyV2.sol';
10 : : import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol';
11 : : import {IPoolAddressesProvider} from '../interfaces/IPoolAddressesProvider.sol';
12 : :
13 : : /**
14 : : * @title DefaultReserveInterestRateStrategyV2 contract
15 : : * @author BGD Labs
16 : : * @notice Default interest rate strategy used by the Aave protocol
17 : : * @dev Strategies are pool-specific: each contract CAN'T be used across different Aave pools
18 : : * due to the caching of the PoolAddressesProvider and the usage of underlying addresses as
19 : : * index of the _interestRateData
20 : : */
21 : : contract DefaultReserveInterestRateStrategyV2 is IDefaultInterestRateStrategyV2 {
22 : : using WadRayMath for uint256;
23 : : using PercentageMath for uint256;
24 : :
25 : : struct CalcInterestRatesLocalVars {
26 : : uint256 availableLiquidity;
27 : : uint256 currentVariableBorrowRate;
28 : : uint256 currentLiquidityRate;
29 : : uint256 borrowUsageRatio;
30 : : uint256 supplyUsageRatio;
31 : : uint256 availableLiquidityPlusDebt;
32 : : }
33 : :
34 : : /// @inheritdoc IDefaultInterestRateStrategyV2
35 : : IPoolAddressesProvider public immutable ADDRESSES_PROVIDER;
36 : :
37 : : /// @inheritdoc IDefaultInterestRateStrategyV2
38 : : uint256 public constant MAX_BORROW_RATE = 1000_00;
39 : :
40 : : /// @inheritdoc IDefaultInterestRateStrategyV2
41 : : uint256 public constant MIN_OPTIMAL_POINT = 1_00;
42 : :
43 : : /// @inheritdoc IDefaultInterestRateStrategyV2
44 : : uint256 public constant MAX_OPTIMAL_POINT = 99_00;
45 : :
46 : : /// @dev Map of reserves address and their interest rate data (reserveAddress => interestRateData)
47 : : mapping(address => InterestRateData) internal _interestRateData;
48 : :
49 : : modifier onlyPoolConfigurator() {
50 : 190067 : require(
51 : : msg.sender == ADDRESSES_PROVIDER.getPoolConfigurator(),
52 : : Errors.CALLER_NOT_POOL_CONFIGURATOR
53 : : );
54 : : _;
55 : : }
56 : :
57 : : /**
58 : : * @dev Constructor.
59 : : * @param provider The address of the PoolAddressesProvider of the associated Aave pool
60 : : */
61 : : constructor(address provider) {
62 : 147 : require(provider != address(0), Errors.INVALID_ADDRESSES_PROVIDER);
63 : 165 : ADDRESSES_PROVIDER = IPoolAddressesProvider(provider);
64 : : }
65 : :
66 : : /// @inheritdoc IReserveInterestRateStrategy
67 : : function setInterestRateParams(
68 : : address reserve,
69 : : bytes calldata rateData
70 : : ) external onlyPoolConfigurator {
71 : 188067 : _setInterestRateParams(reserve, abi.decode(rateData, (InterestRateData)));
72 : : }
73 : :
74 : : /// @inheritdoc IDefaultInterestRateStrategyV2
75 : : function setInterestRateParams(
76 : : address reserve,
77 : : InterestRateData calldata rateData
78 : : ) external onlyPoolConfigurator {
79 : 10000 : _setInterestRateParams(reserve, rateData);
80 : : }
81 : :
82 : : /// @inheritdoc IDefaultInterestRateStrategyV2
83 : : function getInterestRateData(address reserve) external view returns (InterestRateDataRay memory) {
84 : 1000 : return _rayifyRateData(_interestRateData[reserve]);
85 : : }
86 : :
87 : : /// @inheritdoc IDefaultInterestRateStrategyV2
88 : : function getInterestRateDataBps(address reserve) external view returns (InterestRateData memory) {
89 : 1000 : return _interestRateData[reserve];
90 : : }
91 : :
92 : : /// @inheritdoc IDefaultInterestRateStrategyV2
93 : : function getOptimalUsageRatio(address reserve) external view returns (uint256) {
94 : 8088 : return _bpsToRay(uint256(_interestRateData[reserve].optimalUsageRatio));
95 : : }
96 : :
97 : : /// @inheritdoc IDefaultInterestRateStrategyV2
98 : : function getVariableRateSlope1(address reserve) external view returns (uint256) {
99 : 8092 : return _bpsToRay(uint256(_interestRateData[reserve].variableRateSlope1));
100 : : }
101 : :
102 : : /// @inheritdoc IDefaultInterestRateStrategyV2
103 : : function getVariableRateSlope2(address reserve) external view returns (uint256) {
104 : 5088 : return _bpsToRay(uint256(_interestRateData[reserve].variableRateSlope2));
105 : : }
106 : :
107 : : /// @inheritdoc IDefaultInterestRateStrategyV2
108 : : function getBaseVariableBorrowRate(address reserve) external view override returns (uint256) {
109 : 11092 : return _bpsToRay(uint256(_interestRateData[reserve].baseVariableBorrowRate));
110 : : }
111 : :
112 : : /// @inheritdoc IDefaultInterestRateStrategyV2
113 : : function getMaxVariableBorrowRate(address reserve) external view override returns (uint256) {
114 : 5084 : return
115 : 5084 : _bpsToRay(
116 : : uint256(
117 : : _interestRateData[reserve].baseVariableBorrowRate +
118 : : _interestRateData[reserve].variableRateSlope1 +
119 : : _interestRateData[reserve].variableRateSlope2
120 : : )
121 : : );
122 : : }
123 : :
124 : : /// @inheritdoc IReserveInterestRateStrategy
125 : : function calculateInterestRates(
126 : : DataTypes.CalculateInterestRatesParams memory params
127 : : ) external view virtual override returns (uint256, uint256) {
128 : 92717 : InterestRateDataRay memory rateData = _rayifyRateData(_interestRateData[params.reserve]);
129 : :
130 : : // @note This is a short circuit to allow mintable assets (ex. GHO), which by definition cannot be supplied
131 : : // and thus do not use virtual underlying balances.
132 : 92717 : if (!params.usingVirtualBalance) {
133 : 1000 : return (0, rateData.baseVariableBorrowRate);
134 : : }
135 : :
136 : 91717 : CalcInterestRatesLocalVars memory vars;
137 : :
138 : 91717 : vars.currentLiquidityRate = 0;
139 : 91717 : vars.currentVariableBorrowRate = rateData.baseVariableBorrowRate;
140 : :
141 : 91717 : if (params.totalDebt != 0) {
142 : 32099 : vars.availableLiquidity =
143 : : params.virtualUnderlyingBalance +
144 : : params.liquidityAdded -
145 : : params.liquidityTaken;
146 : :
147 : 32098 : vars.availableLiquidityPlusDebt = vars.availableLiquidity + params.totalDebt;
148 : 32098 : vars.borrowUsageRatio = params.totalDebt.rayDiv(vars.availableLiquidityPlusDebt);
149 : 32098 : vars.supplyUsageRatio = params.totalDebt.rayDiv(
150 : : vars.availableLiquidityPlusDebt + params.unbacked
151 : : );
152 : : } else {
153 : 59618 : return (0, vars.currentVariableBorrowRate);
154 : : }
155 : :
156 : 32098 : if (vars.borrowUsageRatio > rateData.optimalUsageRatio) {
157 : 6390 : uint256 excessBorrowUsageRatio = (vars.borrowUsageRatio - rateData.optimalUsageRatio).rayDiv(
158 : : WadRayMath.RAY - rateData.optimalUsageRatio
159 : : );
160 : :
161 : 6390 : vars.currentVariableBorrowRate +=
162 : : rateData.variableRateSlope1 +
163 : : rateData.variableRateSlope2.rayMul(excessBorrowUsageRatio);
164 : : } else {
165 : 25708 : vars.currentVariableBorrowRate += rateData
166 : : .variableRateSlope1
167 : : .rayMul(vars.borrowUsageRatio)
168 : : .rayDiv(rateData.optimalUsageRatio);
169 : : }
170 : :
171 : 32098 : vars.currentLiquidityRate = vars
172 : : .currentVariableBorrowRate
173 : : .rayMul(vars.supplyUsageRatio)
174 : : .percentMul(PercentageMath.PERCENTAGE_FACTOR - params.reserveFactor);
175 : :
176 : 32098 : return (vars.currentLiquidityRate, vars.currentVariableBorrowRate);
177 : : }
178 : :
179 : : /**
180 : : * @dev Doing validations and data update for an asset
181 : : * @param reserve address of the underlying asset of the reserve
182 : : * @param rateData Encoded reserve interest rate data to apply
183 : : */
184 : : function _setInterestRateParams(address reserve, InterestRateData memory rateData) internal {
185 : 198067 : require(reserve != address(0), Errors.ZERO_ADDRESS_NOT_VALID);
186 : :
187 : 194067 : require(
188 : : rateData.optimalUsageRatio <= MAX_OPTIMAL_POINT &&
189 : : rateData.optimalUsageRatio >= MIN_OPTIMAL_POINT,
190 : : Errors.INVALID_OPTIMAL_USAGE_RATIO
191 : : );
192 : :
193 : 186067 : require(
194 : : rateData.variableRateSlope1 <= rateData.variableRateSlope2,
195 : : Errors.SLOPE_2_MUST_BE_GTE_SLOPE_1
196 : : );
197 : :
198 : : // The maximum rate should not be above certain threshold
199 : 182067 : require(
200 : : uint256(rateData.baseVariableBorrowRate) +
201 : : uint256(rateData.variableRateSlope1) +
202 : : uint256(rateData.variableRateSlope2) <=
203 : : MAX_BORROW_RATE,
204 : : Errors.INVALID_MAX_RATE
205 : : );
206 : :
207 : 178067 : _interestRateData[reserve] = rateData;
208 : 178067 : emit RateDataUpdate(
209 : : reserve,
210 : : rateData.optimalUsageRatio,
211 : : rateData.baseVariableBorrowRate,
212 : : rateData.variableRateSlope1,
213 : : rateData.variableRateSlope2
214 : : );
215 : : }
216 : :
217 : : /**
218 : : * @dev Transforms an InterestRateData struct to an InterestRateDataRay struct by multiplying all values
219 : : * by 1e23, turning them into ray values
220 : : *
221 : : * @param data The InterestRateData struct to transform
222 : : *
223 : : * @return The resulting InterestRateDataRay struct
224 : : */
225 : : function _rayifyRateData(
226 : : InterestRateData memory data
227 : : ) internal pure returns (InterestRateDataRay memory) {
228 : 93717 : return
229 : : InterestRateDataRay({
230 : : optimalUsageRatio: _bpsToRay(uint256(data.optimalUsageRatio)),
231 : : baseVariableBorrowRate: _bpsToRay(uint256(data.baseVariableBorrowRate)),
232 : : variableRateSlope1: _bpsToRay(uint256(data.variableRateSlope1)),
233 : : variableRateSlope2: _bpsToRay(uint256(data.variableRateSlope2))
234 : : });
235 : : }
236 : :
237 : : // @dev helper function added here, as generally the protocol doesn't use bps
238 : : function _bpsToRay(uint256 n) internal pure returns (uint256) {
239 : 412312 : return n * 1e23;
240 : : }
241 : : }
|