Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion script/deploy_fixedRateIrm_impl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import { FixedRateIrm } from "interest-rate-model/FixedRateIrm.sol";
import { Moolah } from "moolah/Moolah.sol";

contract FixedRateIrmDeploy is DeployBase {
address moolah = 0x8F73b65B4caAf64FBA2aF91cC5D4a2A1318E5D8C;

function run() public {
uint256 deployerPrivateKey = _deployerKey();
address deployer = vm.addr(deployerPrivateKey);
console.log("Deployer: ", deployer);
vm.startBroadcast(deployerPrivateKey);

// Deploy InterestRateModel implementation
FixedRateIrm impl = new FixedRateIrm();
FixedRateIrm impl = new FixedRateIrm(moolah);
console.log("FixedRateIrm implementation: ", address(impl));

vm.stopBroadcast();
Expand Down
4 changes: 3 additions & 1 deletion script/eth/deploy_fixedRateIrm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import { FixedRateIrm } from "interest-rate-model/FixedRateIrm.sol";
import { Moolah } from "moolah/Moolah.sol";

contract FixedRateIrmDeploy is DeployBase {
address moolah = 0xf820fB4680712CD7263a0D3D024D5b5aEA82Fd70;

function run() public {
uint256 deployerPrivateKey = _deployerKey();
address deployer = vm.addr(deployerPrivateKey);
console.log("Deployer: ", deployer);
vm.startBroadcast(deployerPrivateKey);

// Deploy InterestRateModel implementation
FixedRateIrm impl = new FixedRateIrm();
FixedRateIrm impl = new FixedRateIrm(moolah);
console.log("FixedRateIrm implementation: ", address(impl));
// Deploy InterestRateModel proxy
ERC1967Proxy proxy = new ERC1967Proxy(
Expand Down
29 changes: 27 additions & 2 deletions src/interest-rate-model/FixedRateIrm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IIrm } from "moolah/interfaces/IIrm.sol";
import { IFixedRateIrm } from "./interfaces/IFixedRateIrm.sol";

import { MarketParamsLib } from "../moolah/libraries/MarketParamsLib.sol";
import { Id, MarketParams, Market } from "moolah/interfaces/IMoolah.sol";
import { IMoolah, Id, MarketParams, Market } from "moolah/interfaces/IMoolah.sol";
import { ErrorsLib } from "./libraries/ErrorsLib.sol";

/* ERRORS */
Expand Down Expand Up @@ -44,6 +44,11 @@ contract FixedRateIrm is UUPSUpgradeable, AccessControlEnumerableUpgradeable, IF
/// @inheritdoc IFixedRateIrm
int256 public constant MAX_BORROW_RATE = 8.0 ether / int256(365 days);

/* IMMUTABLES */

/// @inheritdoc IFixedRateIrm
address public immutable MOOLAH;

/* STORAGE */

/// @inheritdoc IFixedRateIrm
Expand All @@ -64,8 +69,11 @@ contract FixedRateIrm is UUPSUpgradeable, AccessControlEnumerableUpgradeable, IF
/* CONSTRUCTOR */

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
/// @param moolah The address of the Moolah contract.
constructor(address moolah) {
require(moolah != address(0), ErrorsLib.ZERO_ADDRESS);
_disableInitializers();
MOOLAH = moolah;
}

/// @notice Constructor.
Expand Down Expand Up @@ -96,6 +104,9 @@ contract FixedRateIrm is UUPSUpgradeable, AccessControlEnumerableUpgradeable, IF
require(newBorrowRate >= int256(rateFloor[id]), "rate below floor");
}

// settle interest accrued at the old rate before it changes
_accrueInterest(id);

borrowRateStored[id] = newBorrowRate;

emit SetBorrowRate(id, newBorrowRate);
Expand All @@ -107,6 +118,9 @@ contract FixedRateIrm is UUPSUpgradeable, AccessControlEnumerableUpgradeable, IF
require(newRateCap >= minCap && newRateCap != oldCap && newRateCap <= uint256(MAX_BORROW_RATE), "invalid rate cap");
require(rateFloor[id] <= newRateCap, "invalid new cap vs floor");

// settle interest accrued under the old cap before it changes
_accrueInterest(id);

rateCap[id] = newRateCap;

emit BorrowRateCapUpdate(id, oldCap, newRateCap);
Expand All @@ -122,11 +136,22 @@ contract FixedRateIrm is UUPSUpgradeable, AccessControlEnumerableUpgradeable, IF
if (_cap < minCap) _cap = minCap;
require(newRateFloor <= _cap, "invalid rate floor vs cap");

// settle interest accrued under the old floor before it changes
_accrueInterest(id);

rateFloor[id] = newRateFloor;

emit BorrowRateFloorUpdate(id, oldFloor, newRateFloor);
}

/// @dev Accrues interest on Moolah for `id` so pending interest is settled at the current rate bounds.
/// @dev No-op when the market does not exist yet, so bounds can still be pre-set before market creation.
function _accrueInterest(Id id) private {
if (IMoolah(MOOLAH).market(id).lastUpdate == 0) return;

IMoolah(MOOLAH).accrueInterest(IMoolah(MOOLAH).idToMarketParams(id));
}

/// @dev Updates the minimum borrow rate cap for all markets.
function updateMinCap(uint256 newMinCap) external onlyRole(MANAGER) {
uint256 oldMinCap = minCap;
Expand Down
16 changes: 15 additions & 1 deletion src/interest-rate-model/InterestRateModel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ExpLib } from "./libraries/ExpLib.sol";
import { MathLib, WAD_INT as WAD } from "./libraries/MathLib.sol";
import { ConstantsLib } from "./libraries/ConstantsLib.sol";
import { MarketParamsLib } from "../moolah/libraries/MarketParamsLib.sol";
import { Id, MarketParams, Market } from "moolah/interfaces/IMoolah.sol";
import { IMoolah, Id, MarketParams, Market } from "moolah/interfaces/IMoolah.sol";
import { MathLib as MoolahMathLib } from "moolah/libraries/MathLib.sol";

/// @title InterestRateModel
Expand Down Expand Up @@ -204,6 +204,9 @@ contract InterestRateModel is UUPSUpgradeable, AccessControlEnumerableUpgradeabl
require(newRateCap >= minCap && newRateCap != oldCap, "invalid rate cap");
require(rateFloor[id] <= newRateCap, "invalid new cap vs floor");

// settle interest accrued under the old cap before it changes
_accrueInterest(id);

rateCap[id] = newRateCap;

emit BorrowRateCapUpdate(id, oldCap, newRateCap);
Expand All @@ -219,11 +222,22 @@ contract InterestRateModel is UUPSUpgradeable, AccessControlEnumerableUpgradeabl
if (_cap < minCap) _cap = minCap;
require(newRateFloor <= _cap, "invalid rate floor vs cap");

// settle interest accrued under the old floor before it changes
_accrueInterest(id);

rateFloor[id] = newRateFloor;

emit BorrowRateFloorUpdate(id, oldFloor, newRateFloor);
}

/// @dev Accrues interest on Moolah for `id` so pending interest is settled at the current rate bounds.
/// @dev No-op when the market does not exist yet, so bounds can still be pre-set before market creation.
function _accrueInterest(Id id) private {
if (IMoolah(MOOLAH).market(id).lastUpdate == 0) return;

IMoolah(MOOLAH).accrueInterest(IMoolah(MOOLAH).idToMarketParams(id));
}

/// @dev Updates the minimum borrow rate cap for all markets.
function updateMinCap(uint256 newMinCap) external onlyRole(MANAGER) {
uint256 oldMinCap = minCap;
Expand Down
3 changes: 3 additions & 0 deletions src/interest-rate-model/interfaces/IFixedRateIrm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ interface IFixedRateIrm is IIrm {

/* EXTERNAL */

/// @notice The address of the Moolah contract.
function MOOLAH() external view returns (address);

/// @notice Max settable borrow rate (800%).
function MAX_BORROW_RATE() external returns (int256);

Expand Down
3 changes: 2 additions & 1 deletion test/interest-rate-model/AlphaIrmTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ contract AlpahIrmMainnetTest is Test {
address admin = 0x07D274a68393E8b8a2CCf19A2ce4Ba3518735253; // timelock
address manager = 0x8d388136d578dCD791D081c6042284CED6d9B0c6;
address alphaIrm = 0x5F9f9173B405C6CEAfa7f98d09e4B8447e9797E6;
address moolah = 0x8F73b65B4caAf64FBA2aF91cC5D4a2A1318E5D8C;

FixedRateIrm fixedRateIrm = FixedRateIrm(alphaIrm);

Expand All @@ -21,7 +22,7 @@ contract AlpahIrmMainnetTest is Test {
function setUp() external {
vm.createSelectFork("https://bsc-dataseed.bnbchain.org");

address impl = address(new FixedRateIrm());
address impl = address(new FixedRateIrm(moolah));

vm.startPrank(admin);
UUPSUpgradeable proxy = UUPSUpgradeable(alphaIrm);
Expand Down
9 changes: 8 additions & 1 deletion test/interest-rate-model/FixedRateIrmTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ contract FixedRateIrmTest is Test {
address bot = makeAddr("bot");

function setUp() external {
FixedRateIrm impl = new FixedRateIrm();
// this contract stands in as MOOLAH; see the `market` stub below
FixedRateIrm impl = new FixedRateIrm(address(this));
ERC1967Proxy proxy = new ERC1967Proxy(
address(impl),
abi.encodeWithSelector(impl.initialize.selector, admin, manager)
Expand Down Expand Up @@ -144,4 +145,10 @@ contract FixedRateIrmTest is Test {

assertEq(fixedRateIrm.borrowRateView(marketPrams, market), uint256(newBorrowRate));
}

/* MOOLAH STUB */

/// @dev This contract is deployed as the IRM's MOOLAH. `updateRateCap`/`updateRateFloor` probe the market
/// before accruing interest; returning an empty market (lastUpdate == 0) makes the accrual a no-op.
function market(Id) external pure returns (Market memory m) {}
}
6 changes: 6 additions & 0 deletions test/interest-rate-model/InterestRateModelTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,12 @@ contract InterestRateModelTest is Test {
assertEq(irm.rateFloor(id), newFloor);
}

/* MOOLAH STUB */

/// @dev This contract is deployed as the IRM's MOOLAH. `updateRateCap`/`updateRateFloor` probe the market
/// before accruing interest; returning an empty market (lastUpdate == 0) makes the accrual a no-op.
function market(Id) external pure returns (Market memory m) {}

/* HANDLERS */

function handleBorrowRate(uint256 totalSupplyAssets, uint256 totalBorrowAssets, uint256 elapsed) external {
Expand Down
Loading
Loading