From 57ed340c1b112e26e62a8414144714750f85f083 Mon Sep 17 00:00:00 2001 From: Rooh Afza <96720500+r0ohafza@users.noreply.github.com> Date: Tue, 1 Nov 2022 08:30:41 -0700 Subject: [PATCH] feat: add new rate model (#239) * feat: add new rate model * chore: update docs --- src/core/LinearRateModel.sol | 107 +++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 src/core/LinearRateModel.sol diff --git a/src/core/LinearRateModel.sol b/src/core/LinearRateModel.sol new file mode 100644 index 0000000..82cf94a --- /dev/null +++ b/src/core/LinearRateModel.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol"; +import {IRateModel} from "../interface/core/IRateModel.sol"; + +/** + @title Linear Rate Model + @notice Rate model contract used by Lending pools to calculate borrow rate + per sec + Forked from aave https://github.com/aave/aave-v3-core/blob/master/contracts/protocol/pool/DefaultReserveInterestRateStrategy.sol +*/ +contract LinearRateModel is IRateModel { + using FixedPointMathLib for uint; + + /// @notice Base rate + uint public immutable baseRate; + + /// @notice Slope of the variable interest curve when usage ratio > 0 and <= OPTIMAL_USAGE_RATIO + uint public immutable slope1; + + /// @notice Slope of the variable interest curve when usage ratio > OPTIMAL_USAGE_RATIO + uint public immutable slope2; + + /// @notice This constant represents the usage ratio at which the pool aims to obtain most competitive borrow rates + uint public immutable OPTIMAL_USAGE_RATIO; + + /// @notice This constant represents the excess usage ratio above the optimal. It's always equal to 1-optimal usage ratio. + uint public immutable MAX_EXCESS_USAGE_RATIO; + + /// @notice Number of seconds per year + uint immutable secsPerYear; + + /** + @notice Contract constructor + @param _baseRate default value = 0 + @param _slope1 default value = 40000000000000000 + @param _slope2 default value = 750000000000000000 + @param _optimalUsageRatio default value = 850000000000000000 + @param _maxExcessUsageRatio default value = 150000000000000000 + @param _secsPerYear secs in a year, default value = 31556952 * 1e18 + */ + constructor( + uint _baseRate, + uint _slope1, + uint _slope2, + uint _optimalUsageRatio, + uint _maxExcessUsageRatio, + uint _secsPerYear + ) + { + baseRate = _baseRate; + slope1 = _slope1; + slope2 = _slope2; + OPTIMAL_USAGE_RATIO = _optimalUsageRatio; + MAX_EXCESS_USAGE_RATIO = _maxExcessUsageRatio; + secsPerYear = _secsPerYear; + } + + /** + @notice Calculates Borrow rate per second + @param liquidity total balance of the underlying asset in the pool + @param totalDebt balance of underlying assets borrowed from the pool + @return uint borrow rate per sec + */ + function getBorrowRatePerSecond( + uint liquidity, + uint totalDebt + ) + external + view + returns (uint) + { + uint utilization = _utilization(liquidity, totalDebt); + + if (utilization > OPTIMAL_USAGE_RATIO) { + return ( + baseRate + slope1 + slope2.mulWadDown( + getExcessBorrowUsage(utilization) + ) + ).divWadDown(secsPerYear); + } else { + return ( + baseRate + slope1.mulDivDown(utilization, OPTIMAL_USAGE_RATIO) + ).divWadDown(secsPerYear); + } + } + + function getExcessBorrowUsage(uint utilization) + internal + view + returns (uint) + { + return (utilization - OPTIMAL_USAGE_RATIO).divWadDown( + MAX_EXCESS_USAGE_RATIO + ); + } + + function _utilization(uint liquidity, uint borrows) + internal + pure + returns (uint) + { + uint totalAssets = liquidity + borrows; + return (totalAssets == 0) ? 0 : borrows.divWadDown(totalAssets); + } +} \ No newline at end of file