Contract Name:
JumpRateModelV2
Contract Source Code:
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.22;
import "./BaseJumpRateModelV2.sol";
import "./InterestRateModel.sol";
/**
* @title Mach's JumpRateModel Contract V2 for V2 cTokens
* @author Arr00
* @notice Supports only for V2 cTokens
*/
contract JumpRateModelV2 is InterestRateModel, BaseJumpRateModelV2 {
/**
* @notice Calculates the current borrow rate per timestamp
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market
* @return The borrow rate percentage per timestamp as a mantissa (scaled by 1e18)
*/
function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) external view override returns (uint256) {
return getBorrowRateInternal(cash, borrows, reserves);
}
constructor(
uint256 baseRatePerYear,
uint256 multiplierPerYear,
uint256 jumpMultiplierPerYear,
uint256 kink_,
address owner_
) public BaseJumpRateModelV2(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_, owner_) {}
}
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.22;
import "./InterestRateModel.sol";
/**
* @title Logic for Mach's JumpRateModel Contract V2.
* @author Compound (modified by Dharma Labs, refactored by Arr00)
* @notice Version 2 modifies Version 1 by enabling updateable parameters.
*/
abstract contract BaseJumpRateModelV2 is InterestRateModel {
event NewInterestParams(
uint256 baseRatePerTimestamp, uint256 multiplierPerTimestamp, uint256 jumpMultiplierPerTimestamp, uint256 kink
);
uint256 private constant BASE = 1e18;
/**
* @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly
*/
address public owner;
/**
* @notice The approximate number of timestamps per year that is assumed by the interest rate model
*/
uint256 public constant timestampsPerYear = 60 * 60 * 24 * 365;
/**
* @notice The multiplier of utilization rate that gives the slope of the interest rate
*/
uint256 public multiplierPerTimestamp;
/**
* @notice The base interest rate which is the y-intercept when utilization rate is 0
*/
uint256 public baseRatePerTimestamp;
/**
* @notice The multiplierPerTimestamp after hitting a specified utilization point
*/
uint256 public jumpMultiplierPerTimestamp;
/**
* @notice The utilization point at which the jump multiplier is applied
*/
uint256 public kink;
/**
* @notice Construct an interest rate model
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerTimestamp after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
* @param owner_ The address of the owner, i.e. the Timelock contract (which has the ability to update parameters directly)
*/
constructor(
uint256 baseRatePerYear,
uint256 multiplierPerYear,
uint256 jumpMultiplierPerYear,
uint256 kink_,
address owner_
) internal {
owner = owner_;
updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);
}
/**
* @notice Update the parameters of the interest rate model (only callable by owner, i.e. Timelock)
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerTimestamp after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
*/
function updateJumpRateModel(
uint256 baseRatePerYear,
uint256 multiplierPerYear,
uint256 jumpMultiplierPerYear,
uint256 kink_
) external virtual {
require(msg.sender == owner, "only the owner may call this function.");
updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);
}
/**
* @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)`
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market (currently unused)
* @return The utilization rate as a mantissa between [0, BASE]
*/
function utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) public pure returns (uint256) {
// Utilization rate is 0 when there are no borrows
if (borrows == 0) {
return 0;
}
return (borrows * BASE) / (cash + borrows - reserves);
}
/**
* @notice Calculates the current borrow rate per timestamp, with the error code expected by the market
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market
* @return The borrow rate percentage per timestamp as a mantissa (scaled by BASE)
*/
function getBorrowRateInternal(uint256 cash, uint256 borrows, uint256 reserves) internal view returns (uint256) {
uint256 util = utilizationRate(cash, borrows, reserves);
if (util <= kink) {
return ((util * multiplierPerTimestamp) / BASE) + baseRatePerTimestamp;
} else {
uint256 normalRate = ((kink * multiplierPerTimestamp) / BASE) + baseRatePerTimestamp;
uint256 excessUtil = util - kink;
return ((excessUtil * jumpMultiplierPerTimestamp) / BASE) + normalRate;
}
}
/**
* @notice Calculates the current supply rate per timestamp
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market
* @param reserveFactorMantissa The current reserve factor for the market
* @return The supply rate percentage per timestamp as a mantissa (scaled by BASE)
*/
function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa)
public
view
virtual
override
returns (uint256)
{
uint256 oneMinusReserveFactor = BASE - reserveFactorMantissa;
uint256 borrowRate = getBorrowRateInternal(cash, borrows, reserves);
uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / BASE;
return (utilizationRate(cash, borrows, reserves) * rateToPool) / BASE;
}
/**
* @notice Internal function to update the parameters of the interest rate model
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerTimestamp after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
*/
function updateJumpRateModelInternal(
uint256 baseRatePerYear,
uint256 multiplierPerYear,
uint256 jumpMultiplierPerYear,
uint256 kink_
) internal {
baseRatePerTimestamp = ((baseRatePerYear * BASE) / timestampsPerYear) / BASE;
multiplierPerTimestamp = (multiplierPerYear * BASE) / (timestampsPerYear * kink_);
jumpMultiplierPerTimestamp = ((jumpMultiplierPerYear * BASE) / timestampsPerYear) / BASE;
kink = kink_;
emit NewInterestParams(baseRatePerTimestamp, multiplierPerTimestamp, jumpMultiplierPerTimestamp, kink);
}
}
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.22;
/**
* @title Mach's InterestRateModel Interface
* @author Mach Finance
*/
abstract contract InterestRateModel {
/// @notice Indicator that this is an InterestRateModel contract (for inspection)
bool public constant isInterestRateModel = true;
/**
* @notice Calculates the current borrow interest rate per timestamp
* @param cash The total amount of cash the market has
* @param borrows The total amount of borrows the market has outstanding
* @param reserves The total amount of reserves the market has
* @return The borrow rate per timestamp (as a percentage, and scaled by 1e18)
*/
function getBorrowRate(uint256 cash, uint256 borrows, uint256 reserves) external view virtual returns (uint256);
/**
* @notice Calculates the current supply interest rate per timestamp
* @param cash The total amount of cash the market has
* @param borrows The total amount of borrows the market has outstanding
* @param reserves The total amount of reserves the market has
* @param reserveFactorMantissa The current reserve factor the market has
* @return The supply rate per timestamp (as a percentage, and scaled by 1e18)
*/
function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa)
external
view
virtual
returns (uint256);
}