Skip to content

Commit

Permalink
Merge pull request #241 from morpho-labs/refactor/libraries
Browse files Browse the repository at this point in the history
Various changes in libs
  • Loading branch information
MathisGD authored Aug 10, 2023
2 parents 553c16a + 38eadc2 commit 8d31147
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 207 deletions.
109 changes: 51 additions & 58 deletions src/Blue.sol
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

import {
IBlueLiquidateCallback,
IBlueRepayCallback,
IBlueSupplyCallback,
IBlueSupplyCollateralCallback,
IBlueFlashLoanCallback
} from "./interfaces/IBlueCallbacks.sol";
import "./interfaces/IBlue.sol";
import "./interfaces/IBlueCallbacks.sol";
import {IIrm} from "./interfaces/IIrm.sol";
import {IERC20} from "./interfaces/IERC20.sol";
import {IOracle} from "./interfaces/IOracle.sol";
import {Id, Market, Signature, IBlue} from "./interfaces/IBlue.sol";

import {Errors} from "./libraries/Errors.sol";
import {EventsLib} from "./libraries/EventsLib.sol";
import {UtilsLib} from "./libraries/UtilsLib.sol";
import {SharesMath} from "./libraries/SharesMath.sol";
import {FixedPointMathLib} from "./libraries/FixedPointMathLib.sol";
import {EventsLib} from "./libraries/EventsLib.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {MarketLib} from "./libraries/MarketLib.sol";
import {SharesMathLib} from "./libraries/SharesMathLib.sol";
import {SafeTransferLib} from "./libraries/SafeTransferLib.sol";
import {FixedPointMathLib, WAD} from "./libraries/FixedPointMathLib.sol";

uint256 constant MAX_FEE = 0.25e18;
uint256 constant ALPHA = 0.5e18;
Expand All @@ -32,10 +26,10 @@ bytes32 constant AUTHORIZATION_TYPEHASH =
keccak256("Authorization(address authorizer,address authorized,bool isAuthorized,uint256 nonce,uint256 deadline)");

contract Blue is IBlue {
using SharesMath for uint256;
using FixedPointMathLib for uint256;
using SafeTransferLib for IERC20;
using MarketLib for Market;
using SharesMathLib for uint256;
using SafeTransferLib for IERC20;
using FixedPointMathLib for uint256;

// Immutables.

Expand Down Expand Up @@ -85,7 +79,7 @@ contract Blue is IBlue {
// Modifiers.

modifier onlyOwner() {
require(msg.sender == owner, Errors.NOT_OWNER);
require(msg.sender == owner, ErrorsLib.NOT_OWNER);
_;
}

Expand All @@ -104,7 +98,7 @@ contract Blue is IBlue {
}

function enableLltv(uint256 lltv) external onlyOwner {
require(lltv < FixedPointMathLib.WAD, Errors.LLTV_TOO_HIGH);
require(lltv < WAD, ErrorsLib.LLTV_TOO_HIGH);
isLltvEnabled[lltv] = true;

emit EventsLib.EnableLltv(lltv);
Expand All @@ -113,8 +107,8 @@ contract Blue is IBlue {
/// @notice It is the owner's responsibility to ensure a fee recipient is set before setting a non-zero fee.
function setFee(Market memory market, uint256 newFee) external onlyOwner {
Id id = market.id();
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(newFee <= MAX_FEE, Errors.MAX_FEE_EXCEEDED);
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(newFee <= MAX_FEE, ErrorsLib.MAX_FEE_EXCEEDED);

// Accrue interests using the previous fee set before changing it.
_accrueInterests(market, id);
Expand All @@ -134,9 +128,9 @@ contract Blue is IBlue {

function createMarket(Market memory market) external {
Id id = market.id();
require(isIrmEnabled[market.irm], Errors.IRM_NOT_ENABLED);
require(isLltvEnabled[market.lltv], Errors.LLTV_NOT_ENABLED);
require(lastUpdate[id] == 0, Errors.MARKET_CREATED);
require(isIrmEnabled[market.irm], ErrorsLib.IRM_NOT_ENABLED);
require(isLltvEnabled[market.lltv], ErrorsLib.LLTV_NOT_ENABLED);
require(lastUpdate[id] == 0, ErrorsLib.MARKET_CREATED);

lastUpdate[id] = block.timestamp;

Expand All @@ -149,9 +143,9 @@ contract Blue is IBlue {
external
{
Id id = market.id();
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(amount, shares), Errors.INCONSISTENT_INPUT);
require(onBehalf != address(0), Errors.ZERO_ADDRESS);
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(amount, shares), ErrorsLib.INCONSISTENT_INPUT);
require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);

_accrueInterests(market, id);

Expand All @@ -173,11 +167,11 @@ contract Blue is IBlue {
external
{
Id id = market.id();
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(amount, shares), Errors.INCONSISTENT_INPUT);
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(amount, shares), ErrorsLib.INCONSISTENT_INPUT);
// No need to verify that onBehalf != address(0) thanks to the authorization check.
require(receiver != address(0), Errors.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), Errors.UNAUTHORIZED);
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), ErrorsLib.UNAUTHORIZED);

_accrueInterests(market, id);

Expand All @@ -190,7 +184,7 @@ contract Blue is IBlue {

emit EventsLib.Withdraw(id, msg.sender, onBehalf, receiver, amount, shares);

require(totalBorrow[id] <= totalSupply[id], Errors.INSUFFICIENT_LIQUIDITY);
require(totalBorrow[id] <= totalSupply[id], ErrorsLib.INSUFFICIENT_LIQUIDITY);

IERC20(market.borrowableAsset).safeTransfer(receiver, amount);
}
Expand All @@ -201,11 +195,11 @@ contract Blue is IBlue {
external
{
Id id = market.id();
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(amount, shares), Errors.INCONSISTENT_INPUT);
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(amount, shares), ErrorsLib.INCONSISTENT_INPUT);
// No need to verify that onBehalf != address(0) thanks to the authorization check.
require(receiver != address(0), Errors.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), Errors.UNAUTHORIZED);
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), ErrorsLib.UNAUTHORIZED);

_accrueInterests(market, id);

Expand All @@ -218,8 +212,8 @@ contract Blue is IBlue {

emit EventsLib.Borrow(id, msg.sender, onBehalf, receiver, amount, shares);

require(_isHealthy(market, id, onBehalf), Errors.INSUFFICIENT_COLLATERAL);
require(totalBorrow[id] <= totalSupply[id], Errors.INSUFFICIENT_LIQUIDITY);
require(_isHealthy(market, id, onBehalf), ErrorsLib.INSUFFICIENT_COLLATERAL);
require(totalBorrow[id] <= totalSupply[id], ErrorsLib.INSUFFICIENT_LIQUIDITY);

IERC20(market.borrowableAsset).safeTransfer(receiver, amount);
}
Expand All @@ -228,9 +222,9 @@ contract Blue is IBlue {
external
{
Id id = market.id();
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(amount, shares), Errors.INCONSISTENT_INPUT);
require(onBehalf != address(0), Errors.ZERO_ADDRESS);
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(amount, shares), ErrorsLib.INCONSISTENT_INPUT);
require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);

_accrueInterests(market, id);

Expand All @@ -253,9 +247,9 @@ contract Blue is IBlue {
/// @dev Don't accrue interests because it's not required and it saves gas.
function supplyCollateral(Market memory market, uint256 amount, address onBehalf, bytes calldata data) external {
Id id = market.id();
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(amount != 0, Errors.ZERO_AMOUNT);
require(onBehalf != address(0), Errors.ZERO_ADDRESS);
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(amount != 0, ErrorsLib.ZERO_AMOUNT);
require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);

// Don't accrue interests because it's not required and it saves gas.

Expand All @@ -270,19 +264,19 @@ contract Blue is IBlue {

function withdrawCollateral(Market memory market, uint256 amount, address onBehalf, address receiver) external {
Id id = market.id();
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(amount != 0, Errors.ZERO_AMOUNT);
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(amount != 0, ErrorsLib.ZERO_AMOUNT);
// No need to verify that onBehalf != address(0) thanks to the authorization check.
require(receiver != address(0), Errors.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), Errors.UNAUTHORIZED);
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), ErrorsLib.UNAUTHORIZED);

_accrueInterests(market, id);

collateral[id][onBehalf] -= amount;

emit EventsLib.WithdrawCollateral(id, msg.sender, onBehalf, receiver, amount);

require(_isHealthy(market, id, onBehalf), Errors.INSUFFICIENT_COLLATERAL);
require(_isHealthy(market, id, onBehalf), ErrorsLib.INSUFFICIENT_COLLATERAL);

IERC20(market.collateralAsset).safeTransfer(receiver, amount);
}
Expand All @@ -291,19 +285,18 @@ contract Blue is IBlue {

function liquidate(Market memory market, address borrower, uint256 seized, bytes calldata data) external {
Id id = market.id();
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(seized != 0, Errors.ZERO_AMOUNT);
require(lastUpdate[id] != 0, ErrorsLib.MARKET_NOT_CREATED);
require(seized != 0, ErrorsLib.ZERO_AMOUNT);

_accrueInterests(market, id);

(uint256 collateralPrice, uint256 priceScale) = IOracle(market.oracle).price();

require(!_isHealthy(market, id, borrower, collateralPrice, priceScale), Errors.HEALTHY_POSITION);
require(!_isHealthy(market, id, borrower, collateralPrice, priceScale), ErrorsLib.HEALTHY_POSITION);

// The liquidation incentive is 1 + ALPHA * (1 / LLTV - 1).
uint256 incentive = FixedPointMathLib.WAD
+ ALPHA.mulWadDown(FixedPointMathLib.WAD.divWadDown(market.lltv) - FixedPointMathLib.WAD);
uint256 repaid = seized.mulDivUp(collateralPrice, priceScale).divWadUp(incentive);
uint256 incentive = WAD + ALPHA.wMulDown(WAD.wDivDown(market.lltv) - WAD);
uint256 repaid = seized.mulDivUp(collateralPrice, priceScale).wDivUp(incentive);
uint256 repaidShares = repaid.toSharesDown(totalBorrow[id], totalBorrowShares[id]);

borrowShares[id][borrower] -= repaidShares;
Expand Down Expand Up @@ -360,15 +353,15 @@ contract Blue is IBlue {
uint256 deadline,
Signature calldata signature
) external {
require(block.timestamp < deadline, Errors.SIGNATURE_EXPIRED);
require(block.timestamp < deadline, ErrorsLib.SIGNATURE_EXPIRED);

uint256 usedNonce = nonce[authorizer]++;
bytes32 hashStruct =
keccak256(abi.encode(AUTHORIZATION_TYPEHASH, authorizer, authorized, newIsAuthorized, usedNonce, deadline));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hashStruct));
address signatory = ecrecover(digest, signature.v, signature.r, signature.s);

require(signatory != address(0) && authorizer == signatory, Errors.INVALID_SIGNATURE);
require(signatory != address(0) && authorizer == signatory, ErrorsLib.INVALID_SIGNATURE);

emit EventsLib.IncrementNonce(msg.sender, authorizer, usedNonce);

Expand All @@ -392,13 +385,13 @@ contract Blue is IBlue {

if (marketTotalBorrow != 0) {
uint256 borrowRate = IIrm(market.irm).borrowRate(market);
uint256 accruedInterests = marketTotalBorrow.mulWadDown(borrowRate.wTaylorCompounded(elapsed));
uint256 accruedInterests = marketTotalBorrow.wMulDown(borrowRate.wTaylorCompounded(elapsed));
totalBorrow[id] = marketTotalBorrow + accruedInterests;
totalSupply[id] += accruedInterests;

uint256 feeShares;
if (fee[id] != 0) {
uint256 feeAmount = accruedInterests.mulWadDown(fee[id]);
uint256 feeAmount = accruedInterests.wMulDown(fee[id]);
// The fee amount is subtracted from the total supply in this calculation to compensate for the fact that total supply is already updated.
feeShares = feeAmount.mulDivDown(totalSupplyShares[id], totalSupply[id] - feeAmount);
supplyShares[id][feeRecipient] += feeShares;
Expand Down Expand Up @@ -427,7 +420,7 @@ contract Blue is IBlue {
returns (bool)
{
uint256 borrowed = borrowShares[id][user].toAssetsUp(totalBorrow[id], totalBorrowShares[id]);
uint256 maxBorrow = collateral[id][user].mulDivDown(collateralPrice, priceScale).mulWadDown(market.lltv);
uint256 maxBorrow = collateral[id][user].mulDivDown(collateralPrice, priceScale).wMulDown(market.lltv);

return maxBorrow >= borrowed;
}
Expand Down
36 changes: 0 additions & 36 deletions src/libraries/Errors.sol

This file was deleted.

21 changes: 21 additions & 0 deletions src/libraries/ErrorsLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

library ErrorsLib {
string constant NOT_OWNER = "not owner";
string constant LLTV_TOO_HIGH = "LLTV too high";
string constant MAX_FEE_EXCEEDED = "MAX_FEE exceeded";
string constant IRM_NOT_ENABLED = "IRM not enabled";
string constant LLTV_NOT_ENABLED = "LLTV not enabled";
string constant MARKET_CREATED = "market created";
string constant MARKET_NOT_CREATED = "market not created";
string constant INCONSISTENT_INPUT = "inconsistent input";
string constant ZERO_AMOUNT = "zero amount";
string constant ZERO_ADDRESS = "zero address";
string constant UNAUTHORIZED = "unauthorized";
string constant INSUFFICIENT_COLLATERAL = "insufficient collateral";
string constant INSUFFICIENT_LIQUIDITY = "insufficient liquidity";
string constant HEALTHY_POSITION = "position is healthy";
string constant INVALID_SIGNATURE = "invalid signature";
string constant SIGNATURE_EXPIRED = "signature expired";
}
Loading

0 comments on commit 8d31147

Please sign in to comment.