Contract Name:
EulerKinkIRMFactory
Contract Source Code:
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {BaseFactory} from "../BaseFactory/BaseFactory.sol";
import {IRMLinearKink} from "evk/InterestRateModels/IRMLinearKink.sol";
/// @title EulerKinkIRMFactory
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice A minimal factory for Kink IRMs.
contract EulerKinkIRMFactory is BaseFactory {
// corresponds to 1000% APY
uint256 internal constant MAX_ALLOWED_INTEREST_RATE = 75986279153383989049;
/// @notice Error thrown when the computed interest rate exceeds the maximum allowed limit.
error IRMFactory_ExcessiveInterestRate();
/// @notice Deploys a new IRMLinearKink.
/// @param baseRate Base interest rate applied when utilization is equal zero
/// @param slope1 Slope of the function before the kink
/// @param slope2 Slope of the function after the kink
/// @param kink Utilization at which the slope of the interest rate function changes. In type(uint32).max scale
/// @return The deployment address.
function deploy(uint256 baseRate, uint256 slope1, uint256 slope2, uint32 kink) external returns (address) {
IRMLinearKink irm = new IRMLinearKink(baseRate, slope1, slope2, kink);
// verify if the IRM is functional
irm.computeInterestRateView(address(0), type(uint32).max, 0);
irm.computeInterestRateView(address(0), type(uint32).max - kink, kink);
uint256 maxInterestRate = irm.computeInterestRateView(address(0), 0, type(uint32).max);
if (maxInterestRate > MAX_ALLOWED_INTEREST_RATE) revert IRMFactory_ExcessiveInterestRate();
deploymentInfo[address(irm)] = DeploymentInfo(msg.sender, uint96(block.timestamp));
deployments.push(address(irm));
emit ContractDeployed(address(irm), msg.sender, block.timestamp);
return address(irm);
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {IFactory} from "./interfaces/IFactory.sol";
/// @title BaseFactory
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice A minimal factory for deploying various contracts.
abstract contract BaseFactory is IFactory {
/// @notice Contracts deployed by the factory.
mapping(address => DeploymentInfo) internal deploymentInfo;
/// @notice An array of addresses of all the contracts deployed by the factory
address[] public deployments;
/// @inheritdoc IFactory
function getDeploymentInfo(address contractAddress) external view returns (address deployer, uint96 deployedAt) {
DeploymentInfo memory info = deploymentInfo[contractAddress];
return (info.deployer, info.deployedAt);
}
/// @inheritdoc IFactory
function isValidDeployment(address contractAddress) external view returns (bool) {
return deploymentInfo[contractAddress].deployedAt != 0;
}
/// @inheritdoc IFactory
function getDeploymentsListLength() external view returns (uint256) {
return deployments.length;
}
/// @inheritdoc IFactory
function getDeploymentsListSlice(uint256 start, uint256 end) external view returns (address[] memory list) {
if (end == type(uint256).max) end = deployments.length;
if (end < start || end > deployments.length) revert Factory_BadQuery();
list = new address[](end - start);
for (uint256 i; i < end - start; ++i) {
list[i] = deployments[start + i];
}
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import "./IIRM.sol";
/// @title IRMLinearKink
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Implementation of an interest rate model, where interest rate grows linearly with utilization, and spikes
/// after reaching kink
contract IRMLinearKink is IIRM {
/// @notice Base interest rate applied when utilization is equal zero
uint256 public immutable baseRate;
/// @notice Slope of the function before the kink
uint256 public immutable slope1;
/// @notice Slope of the function after the kink
uint256 public immutable slope2;
/// @notice Utilization at which the slope of the interest rate function changes. In type(uint32).max scale.
uint256 public immutable kink;
constructor(uint256 baseRate_, uint256 slope1_, uint256 slope2_, uint32 kink_) {
baseRate = baseRate_;
slope1 = slope1_;
slope2 = slope2_;
kink = kink_;
}
/// @inheritdoc IIRM
function computeInterestRate(address vault, uint256 cash, uint256 borrows)
external
view
override
returns (uint256)
{
if (msg.sender != vault) revert E_IRMUpdateUnauthorized();
return computeInterestRateInternal(vault, cash, borrows);
}
/// @inheritdoc IIRM
function computeInterestRateView(address vault, uint256 cash, uint256 borrows)
external
view
override
returns (uint256)
{
return computeInterestRateInternal(vault, cash, borrows);
}
function computeInterestRateInternal(address, uint256 cash, uint256 borrows) internal view returns (uint256) {
uint256 totalAssets = cash + borrows;
uint32 utilization = totalAssets == 0
? 0 // empty pool arbitrarily given utilization of 0
: uint32(borrows * type(uint32).max / totalAssets);
uint256 ir = baseRate;
if (utilization <= kink) {
ir += utilization * slope1;
} else {
ir += kink * slope1;
uint256 utilizationOverKink;
unchecked {
utilizationOverKink = utilization - kink;
}
ir += slope2 * utilizationOverKink;
}
return ir;
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
/// @title IFactory
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice A minimal factory interface for deploying contracts.
interface IFactory {
struct DeploymentInfo {
/// @notice The sender of the deployment call.
address deployer;
/// @notice The timestamp when the contract was deployed.
uint96 deployedAt;
}
/// @notice An instance of a contract was deployed.
/// @param deployedContract The deployment address of the contract.
/// @param deployer The sender of the deployment call.
/// @param deployedAt The deployment timestamp of the contract.
event ContractDeployed(address indexed deployedContract, address indexed deployer, uint256 deployedAt);
/// @notice Error thrown when the query is incorrect.
error Factory_BadQuery();
/// @notice Contracts deployed by the factory.
function getDeploymentInfo(address contractAddress) external view returns (address deployer, uint96 deployedAt);
/// @notice Checks if the deployment at the given address is valid.
/// @param contractAddress The address of the contract to check.
/// @return True if the deployment is valid, false otherwise.
function isValidDeployment(address contractAddress) external view returns (bool);
/// @notice Returns the number of contracts deployed by the factory.
/// @return The number of deployed contracts.
function getDeploymentsListLength() external view returns (uint256);
/// @notice Returns a slice of the list of deployments.
/// @param start The starting index of the slice.
/// @param end The ending index of the slice (exclusive).
/// @return list An array of addresses of the deployed contracts in the specified range.
function getDeploymentsListSlice(uint256 start, uint256 end) external view returns (address[] memory list);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
/// @title IIRM
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Interface of the interest rate model contracts used by EVault
interface IIRM {
error E_IRMUpdateUnauthorized();
/// @notice Perform potentially state mutating computation of the new interest rate
/// @param vault Address of the vault to compute the new interest rate for
/// @param cash Amount of assets held directly by the vault
/// @param borrows Amount of assets lent out to borrowers by the vault
/// @return Then new interest rate in second percent yield (SPY), scaled by 1e27
function computeInterestRate(address vault, uint256 cash, uint256 borrows) external returns (uint256);
/// @notice Perform computation of the new interest rate without mutating state
/// @param vault Address of the vault to compute the new interest rate for
/// @param cash Amount of assets held directly by the vault
/// @param borrows Amount of assets lent out to borrowers by the vault
/// @return Then new interest rate in second percent yield (SPY), scaled by 1e27
function computeInterestRateView(address vault, uint256 cash, uint256 borrows) external view returns (uint256);
}