Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage Refactor #269

Closed
wants to merge 13 commits into from
Closed
368 changes: 218 additions & 150 deletions src/Morpho.sol

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/interfaces/IIrm.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.5.0;

import {Market} from "./IMorpho.sol";
import {MarketParams} from "./IMorpho.sol";

/// @title IIrm
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Interface that IRMs used by Morpho must implement.
interface IIrm {
/// @notice Returns the borrow rate of a `market`.
function borrowRate(Market memory market) external returns (uint256);
/// @notice Returns the borrow rate of a the market defined by `marketParams`.
function borrowRate(MarketParams memory marketParams) external returns (uint256);
}
100 changes: 60 additions & 40 deletions src/interfaces/IMorpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity >=0.5.0;

import {IFlashLender} from "./IFlashLender.sol";
import {Market, Id} from "../libraries/MarketLib.sol";

type Id is bytes32;

Expand All @@ -11,7 +12,7 @@ type Id is bytes32;
/// @param oracle The address of the oracle.
/// @param irm The address of the interest rate model.
/// @param lltv The Liquidation LTV.
struct Market {
struct MarketParams {
address borrowableToken;
address collateralToken;
address oracle;
Expand Down Expand Up @@ -92,15 +93,15 @@ interface IMorpho is IFlashLender {
/// @notice Enables `lltv` as possible LLTV for market creation.
function enableLltv(uint256 lltv) external;

/// @notice Sets the `newFee` for `market`.
/// @notice Sets the `newFee` for the market defined by `marketParams`.
/// @dev It is the `owner`'s responsibility to ensure `feeRecipient` is set before setting a non-zero fee.
function setFee(Market memory market, uint256 newFee) external;
function setFee(MarketParams memory marketParams, uint256 newFee) external;

/// @notice Sets `recipient` as recipient of the fee.
function setFeeRecipient(address recipient) external;

/// @notice Creates `market`.
function createMarket(Market memory market) external;
/// @notice Creates a market defined by `marketParams`.
function createMarket(MarketParams memory marketParams) external;

/// @notice Supplies the given `assets` or `shares` to the given `market` on behalf of `onBehalf`,
/// optionally calling back the caller's `onMorphoSupply` function with the given `data`.
Expand All @@ -110,96 +111,115 @@ interface IMorpho is IFlashLender {
/// but the possibility to mint a specific assets of shares is given
/// for full compatibility and precision.
/// @dev Supplying a large amount can overflow and revert without any error message.
/// @param market The market to supply assets to.
/// @param marketParams The marketParams defining the market to supply assets to.
/// @param assets The assets of assets to supply.
/// @param shares The assets of shares to mint.
/// @param onBehalf The address that will receive the position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
/// @return assetsSupplied The assets of assets supplied.
/// @return sharesSupplied The assets of shares supplied.
function supply(Market memory market, uint256 assets, uint256 shares, address onBehalf, bytes memory data)
external
returns (uint256 assetsSupplied, uint256 sharesSupplied);

/// @notice Withdraws the given `assets` or `shares` from the given `market` on behalf of `onBehalf`.
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);

/// @notice Withdraws the given `assets` or `shares` from the market defined by `marketParams` on behalf of `onBehalf`.
/// @dev Either `assets` or `shares` should be zero.
/// To withdraw the whole position, pass the `shares`'s balance of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will underflow and revert without any error message.
/// @param market The market to withdraw assets from.
/// @param shares The assets of assets to withdraw.
/// @param marketParams The market parameters defining the market to withdraw assets from.
/// @param assets The assets of assets to withdraw.
/// @param shares The assets of shares to burn.
/// @param onBehalf The address of the owner of the withdrawn assets.
/// @param receiver The address that will receive the withdrawn assets.
/// @return assetsWithdrawn The assets of assets withdrawn.
/// @return sharesWithdrawn The assets of shares withdrawn.
function withdraw(Market memory market, uint256 assets, uint256 shares, address onBehalf, address receiver)
external
returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);

/// @notice Borrows the given `assets` or `shares` from the given `market` on behalf of `onBehalf`.
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);

/// @notice Borrows the given `assets` or `shares` from the market defined by `marketParams` on behalf of `onBehalf`.
/// @dev Either `assets` or `shares` should be zero.
/// Most usecases should rely on `assets` as an input so the caller
/// is guaranteed to borrow `assets` of tokens,
/// but the possibility to burn a specific assets of shares is given
/// for full compatibility and precision.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can underflow and revert without any error message.
/// @param market The market to borrow assets from.
/// @param marketParams The market parameters defining the market to borrow assets from.
/// @param assets The assets of assets to borrow.
/// @param shares The assets of shares to mint.
/// @param onBehalf The address of the owner of the debt.
/// @param receiver The address that will receive the debt.
/// @return assetsBorrowed The assets of assets borrowed.
/// @return sharesBorrowed The assets of shares borrowed.
function borrow(Market memory market, uint256 assets, uint256 shares, address onBehalf, address receiver)
external
returns (uint256 assetsBorrowed, uint256 sharesBorrowed);

/// @notice Repays the given `assets` or `shares` to the given `market` on behalf of `onBehalf`,
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);

/// @notice Repays the given `assets` or `shares` to the market defined by `marketParams` on behalf of `onBehalf`,
/// optionally calling back the caller's `onMorphoReplay` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero.
/// To repay the whole debt, pass the `shares`'s balance of `onBehalf`.
/// @dev Repaying an amount corresponding to more shares than borrowed will underflow and revert without any error message.
/// @param market The market to repay assets to.
/// @param marketParams The market parameters defining the market to repay assets to.
/// @param assets The assets of assets to repay.
/// @param shares The assets of shares to burn.
/// @param onBehalf The address of the owner of the debt.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
/// @return assetsRepaid The assets of assets repaid.
/// @return sharesRepaid The assets of shares repaid.
function repay(Market memory market, uint256 assets, uint256 shares, address onBehalf, bytes memory data)
external
returns (uint256 assetsRepaid, uint256 sharesRepaid);

/// @notice Supplies the given `assets` of collateral to the given `market` on behalf of `onBehalf`,
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);

/// @notice Supplies the given `assets` of collateral to the market defined by `marketParams` on behalf of `onBehalf`,
/// optionally calling back the caller's `onMorphoSupplyCollateral` function with the given `data`.
/// @dev Interests are not accrued since it's not required and it saves gas.
/// @dev Supplying a large amount can overflow and revert without any error message.
/// @param market The market to supply collateral to.
/// @param marketParams The market parameters defining the market to supply collateral to.
/// @param assets The assets of collateral to supply.
/// @param onBehalf The address that will receive the collateral.
/// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
function supplyCollateral(Market memory market, uint256 assets, address onBehalf, bytes memory data) external;
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;

/// @notice Withdraws the given `assets` of collateral from the given `market` on behalf of `onBehalf`.
/// @notice Withdraws the given `assets` of collateral from the market defined by `marketParams` on behalf of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more collateral than supplied will underflow and revert without any error message.
/// @param market The market to withdraw collateral from.
/// @param marketParams The market parameters defining the market to withdraw collateral from.
/// @param assets The assets of collateral to withdraw.
/// @param onBehalf The address of the owner of the collateral.
/// @param receiver The address that will receive the withdrawn collateral.
function withdrawCollateral(Market memory market, uint256 assets, address onBehalf, address receiver) external;
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external;

/// @notice Liquidates the given `seized` assets to the given `market` of the given `borrower`'s position,
/// @notice Liquidates the given `seized` assets to the market defined by `marketParams` of the given `borrower`'s position,
/// optionally calling back the caller's `onMorphoLiquidate` function with the given `data`.
/// @dev Seizing more than the collateral balance will revert without any error message.
/// @dev Repaying more than the borrow balance will overflow and revert without any error message.
/// @param market The market of the position.
/// @param marketParams The market parameters defining the market of the position.
/// @param borrower The owner of the position.
/// @param seized The assets of collateral to seize.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed
function liquidate(Market memory market, address borrower, uint256 seized, bytes memory data) external;
function liquidate(MarketParams memory marketParams, address borrower, uint256 seized, bytes memory data)
external;

/// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
/// @param authorized The authorized address.
Expand All @@ -220,8 +240,8 @@ interface IMorpho is IFlashLender {
Signature calldata signature
) external;

/// @notice Accrues interests for `market`.
function accrueInterests(Market memory market) external;
/// @notice Accrues interests for the market defined by `marketParams`.
function accrueInterests(MarketParams memory market) external;

/// @notice Returns the data stored on the different `slots`.
function extsload(bytes32[] memory slots) external view returns (bytes32[] memory res);
Expand Down
6 changes: 3 additions & 3 deletions src/libraries/EventsLib.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {Id, Market} from "../interfaces/IMorpho.sol";
import {Id, MarketParams} from "../interfaces/IMorpho.sol";

library EventsLib {
/// @notice Emitted when setting a new owner.
Expand All @@ -27,8 +27,8 @@ library EventsLib {

/// @notice Emitted when creating a market.
/// @param id The market id.
/// @param market The market that was created.
event CreateMarket(Id indexed id, Market market);
/// @param marketParams The market parameters that define the market that was created.
event CreateMarket(Id indexed id, MarketParams marketParams);

/// @notice Emitted on supply of assets.
/// @param id The market id.
Expand Down
130 changes: 126 additions & 4 deletions src/libraries/MarketLib.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,137 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {Id, Market} from "../interfaces/IMorpho.sol";
import {MarketParams, Id} from "../interfaces/IMorpho.sol";
import {SafeCastLib} from "solmate/utils/SafeCastLib.sol";

struct Market {
mapping(address => UserBalances) userBalances;
uint128 totalSupply; // Market total supply.
uint128 totalSupplyShares; // Market total supply shares.
uint128 totalBorrow; // Market total borrow.
uint128 totalBorrowShares; // Market total borrow shares.
uint128 lastUpdate; // Interests last update (used to check if a market has been created).
uint128 fee; // Fee.
}

struct UserBalances {
uint128 borrowShares; // User' borrow balances.
uint128 collateral; // User' collateral balance.
uint128 supplyShares; // User' supply balances.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint128 supplyShares; // User' supply balances.
uint256 supplyShares; // User' supply balances.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with this since I find it problematic to use different storage types for the same type of variable. Is it possible that this particular point be isolated to another PR with its own scope of discussion?

Made an issue for it #309

}

/// @title MarketLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library to convert a market to its id.
library MarketLib {
/// @notice Returns the id of a `market`.
function id(Market memory market) internal pure returns (Id) {
return Id.wrap(keccak256(abi.encode(market)));
using SafeCastLib for uint256;

function id(MarketParams memory marketParams) internal pure returns (Id) {
return Id.wrap(keccak256(abi.encode(marketParams)));
}

function supplyShares(Market storage market, address user) internal view returns (uint256) {
return market.userBalances[user].supplyShares;
}

function borrowShares(Market storage market, address user) internal view returns (uint256) {
return market.userBalances[user].borrowShares;
}

function collateral(Market storage market, address user) internal view returns (uint256) {
return market.userBalances[user].collateral;
}

function setSupplyShares(Market storage market, address user, uint256 amount) internal {
market.userBalances[user].supplyShares = amount.safeCastTo128();
}

function increaseSupplyShares(Market storage market, address user, uint256 amount) internal {
setSupplyShares(market, user, supplyShares(market, user) + amount);
}

function decreaseSupplyShares(Market storage market, address user, uint256 amount) internal {
setSupplyShares(market, user, supplyShares(market, user) - amount);
}

function setBorrowShares(Market storage market, address user, uint256 amount) internal {
market.userBalances[user].borrowShares = amount.safeCastTo128();
}

function increaseBorrowShares(Market storage market, address user, uint256 amount) internal {
setBorrowShares(market, user, borrowShares(market, user) + amount);
}

function decreaseBorrowShares(Market storage market, address user, uint256 amount) internal {
setBorrowShares(market, user, borrowShares(market, user) - amount);
}

function setCollateral(Market storage market, address user, uint256 amount) internal {
market.userBalances[user].collateral = amount.safeCastTo128();
}

function increaseCollateral(Market storage market, address user, uint256 amount) internal {
setCollateral(market, user, collateral(market, user) + amount);
}

function decreaseCollateral(Market storage market, address user, uint256 amount) internal {
setCollateral(market, user, collateral(market, user) - amount);
}

function setTotalSupply(Market storage market, uint256 amount) internal {
market.totalSupply = amount.safeCastTo128();
}

function increaseTotalSupply(Market storage market, uint256 amount) internal {
setTotalSupply(market, market.totalSupply + amount);
}

function decreaseTotalSupply(Market storage market, uint256 amount) internal {
setTotalSupply(market, market.totalSupply - amount);
}

function setTotalSupplyShares(Market storage market, uint256 amount) internal {
market.totalSupplyShares = amount.safeCastTo128();
}

function increaseTotalSupplyShares(Market storage market, uint256 amount) internal {
setTotalSupplyShares(market, market.totalSupplyShares + amount);
}

function decreaseTotalSupplyShares(Market storage market, uint256 amount) internal {
setTotalSupplyShares(market, market.totalSupplyShares - amount);
}

function setTotalBorrow(Market storage market, uint256 amount) internal {
market.totalBorrow = amount.safeCastTo128();
}

function increaseTotalBorrow(Market storage market, uint256 amount) internal {
setTotalBorrow(market, market.totalBorrow + amount);
}

function decreaseTotalBorrow(Market storage market, uint256 amount) internal {
setTotalBorrow(market, market.totalBorrow - amount);
}

function setTotalBorrowShares(Market storage market, uint256 amount) internal {
market.totalBorrowShares = amount.safeCastTo128();
}

function increaseTotalBorrowShares(Market storage market, uint256 amount) internal {
setTotalBorrowShares(market, market.totalBorrowShares + amount);
}

function decreaseTotalBorrowShares(Market storage market, uint256 amount) internal {
setTotalBorrowShares(market, market.totalBorrowShares - amount);
}

function setLastUpdate(Market storage market, uint256 amount) internal {
market.lastUpdate = amount.safeCastTo128();
}

function setFee(Market storage market, uint256 amount) internal {
market.fee = amount.safeCastTo128();
}
}
Loading