编译器
0.8.19+commit.7dd6d404
文件 1 的 14:ConstantsLib.sol
pragma solidity ^0.8.0;
uint256 constant MAX_FEE = 0.25e18;
uint256 constant ORACLE_PRICE_SCALE = 1e36;
uint256 constant LIQUIDATION_CURSOR = 0.3e18;
uint256 constant MAX_LIQUIDATION_INCENTIVE_FACTOR = 1.15e18;
bytes32 constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
bytes32 constant AUTHORIZATION_TYPEHASH =
keccak256("Authorization(address authorizer,address authorized,bool isAuthorized,uint256 nonce,uint256 deadline)");
文件 2 的 14:ErrorsLib.sol
pragma solidity ^0.8.0;
library ErrorsLib {
string internal constant NOT_OWNER = "not owner";
string internal constant MAX_LLTV_EXCEEDED = "max LLTV exceeded";
string internal constant MAX_FEE_EXCEEDED = "max fee exceeded";
string internal constant ALREADY_SET = "already set";
string internal constant IRM_NOT_ENABLED = "IRM not enabled";
string internal constant LLTV_NOT_ENABLED = "LLTV not enabled";
string internal constant MARKET_ALREADY_CREATED = "market already created";
string internal constant NO_CODE = "no code";
string internal constant MARKET_NOT_CREATED = "market not created";
string internal constant INCONSISTENT_INPUT = "inconsistent input";
string internal constant ZERO_ASSETS = "zero assets";
string internal constant ZERO_ADDRESS = "zero address";
string internal constant UNAUTHORIZED = "unauthorized";
string internal constant INSUFFICIENT_COLLATERAL = "insufficient collateral";
string internal constant INSUFFICIENT_LIQUIDITY = "insufficient liquidity";
string internal constant HEALTHY_POSITION = "position is healthy";
string internal constant INVALID_SIGNATURE = "invalid signature";
string internal constant SIGNATURE_EXPIRED = "signature expired";
string internal constant INVALID_NONCE = "invalid nonce";
string internal constant TRANSFER_REVERTED = "transfer reverted";
string internal constant TRANSFER_RETURNED_FALSE = "transfer returned false";
string internal constant TRANSFER_FROM_REVERTED = "transferFrom reverted";
string internal constant TRANSFER_FROM_RETURNED_FALSE = "transferFrom returned false";
string internal constant MAX_UINT128_EXCEEDED = "max uint128 exceeded";
}
文件 3 的 14:EventsLib.sol
pragma solidity ^0.8.0;
import {Id, MarketParams} from "../interfaces/IMorpho.sol";
library EventsLib {
event SetOwner(address indexed newOwner);
event SetFee(Id indexed id, uint256 newFee);
event SetFeeRecipient(address indexed newFeeRecipient);
event EnableIrm(address indexed irm);
event EnableLltv(uint256 lltv);
event CreateMarket(Id indexed id, MarketParams marketParams);
event Supply(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets, uint256 shares);
event Withdraw(
Id indexed id,
address caller,
address indexed onBehalf,
address indexed receiver,
uint256 assets,
uint256 shares
);
event Borrow(
Id indexed id,
address caller,
address indexed onBehalf,
address indexed receiver,
uint256 assets,
uint256 shares
);
event Repay(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets, uint256 shares);
event SupplyCollateral(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets);
event WithdrawCollateral(
Id indexed id, address caller, address indexed onBehalf, address indexed receiver, uint256 assets
);
event Liquidate(
Id indexed id,
address indexed caller,
address indexed borrower,
uint256 repaidAssets,
uint256 repaidShares,
uint256 seizedAssets,
uint256 badDebtAssets,
uint256 badDebtShares
);
event FlashLoan(address indexed caller, address indexed token, uint256 assets);
event SetAuthorization(
address indexed caller, address indexed authorizer, address indexed authorized, bool newIsAuthorized
);
event IncrementNonce(address indexed caller, address indexed authorizer, uint256 usedNonce);
event AccrueInterest(Id indexed id, uint256 prevBorrowRate, uint256 interest, uint256 feeShares);
}
文件 4 的 14:IERC20.sol
pragma solidity >=0.5.0;
interface IERC20 {}
文件 5 的 14:IIrm.sol
pragma solidity >=0.5.0;
import {MarketParams, Market} from "./IMorpho.sol";
interface IIrm {
function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256);
function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256);
}
文件 6 的 14:IMorpho.sol
pragma solidity >=0.5.0;
type Id is bytes32;
struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}
struct Position {
uint256 supplyShares;
uint128 borrowShares;
uint128 collateral;
}
struct Market {
uint128 totalSupplyAssets;
uint128 totalSupplyShares;
uint128 totalBorrowAssets;
uint128 totalBorrowShares;
uint128 lastUpdate;
uint128 fee;
}
struct Authorization {
address authorizer;
address authorized;
bool isAuthorized;
uint256 nonce;
uint256 deadline;
}
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
interface IMorphoBase {
function DOMAIN_SEPARATOR() external view returns (bytes32);
function owner() external view returns (address);
function feeRecipient() external view returns (address);
function isIrmEnabled(address irm) external view returns (bool);
function isLltvEnabled(uint256 lltv) external view returns (bool);
function isAuthorized(address authorizer, address authorized) external view returns (bool);
function nonce(address authorizer) external view returns (uint256);
function setOwner(address newOwner) external;
function enableIrm(address irm) external;
function enableLltv(uint256 lltv) external;
function setFee(MarketParams memory marketParams, uint256 newFee) external;
function setFeeRecipient(address newFeeRecipient) external;
function createMarket(MarketParams memory marketParams) external;
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external;
function liquidate(
MarketParams memory marketParams,
address borrower,
uint256 seizedAssets,
uint256 repaidShares,
bytes memory data
) external returns (uint256, uint256);
function flashLoan(address token, uint256 assets, bytes calldata data) external;
function setAuthorization(address authorized, bool newIsAuthorized) external;
function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;
function accrueInterest(MarketParams memory marketParams) external;
function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}
interface IMorphoStaticTyping is IMorphoBase {
function position(Id id, address user)
external
view
returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);
function market(Id id)
external
view
returns (
uint128 totalSupplyAssets,
uint128 totalSupplyShares,
uint128 totalBorrowAssets,
uint128 totalBorrowShares,
uint128 lastUpdate,
uint128 fee
);
function idToMarketParams(Id id)
external
view
returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}
interface IMorpho is IMorphoBase {
function position(Id id, address user) external view returns (Position memory p);
function market(Id id) external view returns (Market memory m);
function idToMarketParams(Id id) external view returns (MarketParams memory);
}
文件 7 的 14:IMorphoCallbacks.sol
pragma solidity >=0.5.0;
interface IMorphoLiquidateCallback {
function onMorphoLiquidate(uint256 repaidAssets, bytes calldata data) external;
}
interface IMorphoRepayCallback {
function onMorphoRepay(uint256 assets, bytes calldata data) external;
}
interface IMorphoSupplyCallback {
function onMorphoSupply(uint256 assets, bytes calldata data) external;
}
interface IMorphoSupplyCollateralCallback {
function onMorphoSupplyCollateral(uint256 assets, bytes calldata data) external;
}
interface IMorphoFlashLoanCallback {
function onMorphoFlashLoan(uint256 assets, bytes calldata data) external;
}
文件 8 的 14:IOracle.sol
pragma solidity >=0.5.0;
interface IOracle {
function price() external view returns (uint256);
}
文件 9 的 14:MarketParamsLib.sol
pragma solidity ^0.8.0;
import {Id, MarketParams} from "../interfaces/IMorpho.sol";
library MarketParamsLib {
uint256 internal constant MARKET_PARAMS_BYTES_LENGTH = 5 * 32;
function id(MarketParams memory marketParams) internal pure returns (Id marketParamsId) {
assembly ("memory-safe") {
marketParamsId := keccak256(marketParams, MARKET_PARAMS_BYTES_LENGTH)
}
}
}
文件 10 的 14:MathLib.sol
pragma solidity ^0.8.0;
uint256 constant WAD = 1e18;
library MathLib {
function wMulDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD);
}
function wDivDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y);
}
function wDivUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y);
}
function mulDivDown(uint256 x, uint256 y, uint256 d) internal pure returns (uint256) {
return (x * y) / d;
}
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256) {
return (x * y + (d - 1)) / d;
}
function wTaylorCompounded(uint256 x, uint256 n) internal pure returns (uint256) {
uint256 firstTerm = x * n;
uint256 secondTerm = mulDivDown(firstTerm, firstTerm, 2 * WAD);
uint256 thirdTerm = mulDivDown(secondTerm, firstTerm, 3 * WAD);
return firstTerm + secondTerm + thirdTerm;
}
}
文件 11 的 14:Morpho.sol
pragma solidity 0.8.19;
import {
Id,
IMorphoStaticTyping,
IMorphoBase,
MarketParams,
Position,
Market,
Authorization,
Signature
} from "./interfaces/IMorpho.sol";
import {
IMorphoLiquidateCallback,
IMorphoRepayCallback,
IMorphoSupplyCallback,
IMorphoSupplyCollateralCallback,
IMorphoFlashLoanCallback
} from "./interfaces/IMorphoCallbacks.sol";
import {IIrm} from "./interfaces/IIrm.sol";
import {IERC20} from "./interfaces/IERC20.sol";
import {IOracle} from "./interfaces/IOracle.sol";
import "./libraries/ConstantsLib.sol";
import {UtilsLib} from "./libraries/UtilsLib.sol";
import {EventsLib} from "./libraries/EventsLib.sol";
import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {MathLib, WAD} from "./libraries/MathLib.sol";
import {SharesMathLib} from "./libraries/SharesMathLib.sol";
import {MarketParamsLib} from "./libraries/MarketParamsLib.sol";
import {SafeTransferLib} from "./libraries/SafeTransferLib.sol";
contract Morpho is IMorphoStaticTyping {
using MathLib for uint128;
using MathLib for uint256;
using UtilsLib for uint256;
using SharesMathLib for uint256;
using SafeTransferLib for IERC20;
using MarketParamsLib for MarketParams;
bytes32 public immutable DOMAIN_SEPARATOR;
address public owner;
address public feeRecipient;
mapping(Id => mapping(address => Position)) public position;
mapping(Id => Market) public market;
mapping(address => bool) public isIrmEnabled;
mapping(uint256 => bool) public isLltvEnabled;
mapping(address => mapping(address => bool)) public isAuthorized;
mapping(address => uint256) public nonce;
mapping(Id => MarketParams) public idToMarketParams;
constructor(address newOwner) {
require(newOwner != address(0), ErrorsLib.ZERO_ADDRESS);
DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, block.chainid, address(this)));
owner = newOwner;
emit EventsLib.SetOwner(newOwner);
}
modifier onlyOwner() {
require(msg.sender == owner, ErrorsLib.NOT_OWNER);
_;
}
function setOwner(address newOwner) external onlyOwner {
require(newOwner != owner, ErrorsLib.ALREADY_SET);
owner = newOwner;
emit EventsLib.SetOwner(newOwner);
}
function enableIrm(address irm) external onlyOwner {
require(!isIrmEnabled[irm], ErrorsLib.ALREADY_SET);
isIrmEnabled[irm] = true;
emit EventsLib.EnableIrm(irm);
}
function enableLltv(uint256 lltv) external onlyOwner {
require(!isLltvEnabled[lltv], ErrorsLib.ALREADY_SET);
require(lltv < WAD, ErrorsLib.MAX_LLTV_EXCEEDED);
isLltvEnabled[lltv] = true;
emit EventsLib.EnableLltv(lltv);
}
function setFee(MarketParams memory marketParams, uint256 newFee) external onlyOwner {
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(newFee != market[id].fee, ErrorsLib.ALREADY_SET);
require(newFee <= MAX_FEE, ErrorsLib.MAX_FEE_EXCEEDED);
_accrueInterest(marketParams, id);
market[id].fee = uint128(newFee);
emit EventsLib.SetFee(id, newFee);
}
function setFeeRecipient(address newFeeRecipient) external onlyOwner {
require(newFeeRecipient != feeRecipient, ErrorsLib.ALREADY_SET);
feeRecipient = newFeeRecipient;
emit EventsLib.SetFeeRecipient(newFeeRecipient);
}
function createMarket(MarketParams memory marketParams) external {
Id id = marketParams.id();
require(isIrmEnabled[marketParams.irm], ErrorsLib.IRM_NOT_ENABLED);
require(isLltvEnabled[marketParams.lltv], ErrorsLib.LLTV_NOT_ENABLED);
require(market[id].lastUpdate == 0, ErrorsLib.MARKET_ALREADY_CREATED);
market[id].lastUpdate = uint128(block.timestamp);
idToMarketParams[id] = marketParams;
emit EventsLib.CreateMarket(id, marketParams);
if (marketParams.irm != address(0)) IIrm(marketParams.irm).borrowRate(marketParams, market[id]);
}
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes calldata data
) external returns (uint256, uint256) {
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(assets, shares), ErrorsLib.INCONSISTENT_INPUT);
require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);
_accrueInterest(marketParams, id);
if (assets > 0) shares = assets.toSharesDown(market[id].totalSupplyAssets, market[id].totalSupplyShares);
else assets = shares.toAssetsUp(market[id].totalSupplyAssets, market[id].totalSupplyShares);
position[id][onBehalf].supplyShares += shares;
market[id].totalSupplyShares += shares.toUint128();
market[id].totalSupplyAssets += assets.toUint128();
emit EventsLib.Supply(id, msg.sender, onBehalf, assets, shares);
if (data.length > 0) IMorphoSupplyCallback(msg.sender).onMorphoSupply(assets, data);
IERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), assets);
return (assets, shares);
}
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256, uint256) {
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(assets, shares), ErrorsLib.INCONSISTENT_INPUT);
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), ErrorsLib.UNAUTHORIZED);
_accrueInterest(marketParams, id);
if (assets > 0) shares = assets.toSharesUp(market[id].totalSupplyAssets, market[id].totalSupplyShares);
else assets = shares.toAssetsDown(market[id].totalSupplyAssets, market[id].totalSupplyShares);
position[id][onBehalf].supplyShares -= shares;
market[id].totalSupplyShares -= shares.toUint128();
market[id].totalSupplyAssets -= assets.toUint128();
require(market[id].totalBorrowAssets <= market[id].totalSupplyAssets, ErrorsLib.INSUFFICIENT_LIQUIDITY);
emit EventsLib.Withdraw(id, msg.sender, onBehalf, receiver, assets, shares);
IERC20(marketParams.loanToken).safeTransfer(receiver, assets);
return (assets, shares);
}
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256, uint256) {
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(assets, shares), ErrorsLib.INCONSISTENT_INPUT);
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), ErrorsLib.UNAUTHORIZED);
_accrueInterest(marketParams, id);
if (assets > 0) shares = assets.toSharesUp(market[id].totalBorrowAssets, market[id].totalBorrowShares);
else assets = shares.toAssetsDown(market[id].totalBorrowAssets, market[id].totalBorrowShares);
position[id][onBehalf].borrowShares += shares.toUint128();
market[id].totalBorrowShares += shares.toUint128();
market[id].totalBorrowAssets += assets.toUint128();
require(_isHealthy(marketParams, id, onBehalf), ErrorsLib.INSUFFICIENT_COLLATERAL);
require(market[id].totalBorrowAssets <= market[id].totalSupplyAssets, ErrorsLib.INSUFFICIENT_LIQUIDITY);
emit EventsLib.Borrow(id, msg.sender, onBehalf, receiver, assets, shares);
IERC20(marketParams.loanToken).safeTransfer(receiver, assets);
return (assets, shares);
}
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes calldata data
) external returns (uint256, uint256) {
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(assets, shares), ErrorsLib.INCONSISTENT_INPUT);
require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);
_accrueInterest(marketParams, id);
if (assets > 0) shares = assets.toSharesDown(market[id].totalBorrowAssets, market[id].totalBorrowShares);
else assets = shares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares);
position[id][onBehalf].borrowShares -= shares.toUint128();
market[id].totalBorrowShares -= shares.toUint128();
market[id].totalBorrowAssets = UtilsLib.zeroFloorSub(market[id].totalBorrowAssets, assets).toUint128();
emit EventsLib.Repay(id, msg.sender, onBehalf, assets, shares);
if (data.length > 0) IMorphoRepayCallback(msg.sender).onMorphoRepay(assets, data);
IERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), assets);
return (assets, shares);
}
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes calldata data)
external
{
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(assets != 0, ErrorsLib.ZERO_ASSETS);
require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);
position[id][onBehalf].collateral += assets.toUint128();
emit EventsLib.SupplyCollateral(id, msg.sender, onBehalf, assets);
if (data.length > 0) IMorphoSupplyCollateralCallback(msg.sender).onMorphoSupplyCollateral(assets, data);
IERC20(marketParams.collateralToken).safeTransferFrom(msg.sender, address(this), assets);
}
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external
{
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(assets != 0, ErrorsLib.ZERO_ASSETS);
require(receiver != address(0), ErrorsLib.ZERO_ADDRESS);
require(_isSenderAuthorized(onBehalf), ErrorsLib.UNAUTHORIZED);
_accrueInterest(marketParams, id);
position[id][onBehalf].collateral -= assets.toUint128();
require(_isHealthy(marketParams, id, onBehalf), ErrorsLib.INSUFFICIENT_COLLATERAL);
emit EventsLib.WithdrawCollateral(id, msg.sender, onBehalf, receiver, assets);
IERC20(marketParams.collateralToken).safeTransfer(receiver, assets);
}
function liquidate(
MarketParams memory marketParams,
address borrower,
uint256 seizedAssets,
uint256 repaidShares,
bytes calldata data
) external returns (uint256, uint256) {
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(seizedAssets, repaidShares), ErrorsLib.INCONSISTENT_INPUT);
_accrueInterest(marketParams, id);
{
uint256 collateralPrice = IOracle(marketParams.oracle).price();
require(!_isHealthy(marketParams, id, borrower, collateralPrice), ErrorsLib.HEALTHY_POSITION);
uint256 liquidationIncentiveFactor = UtilsLib.min(
MAX_LIQUIDATION_INCENTIVE_FACTOR,
WAD.wDivDown(WAD - LIQUIDATION_CURSOR.wMulDown(WAD - marketParams.lltv))
);
if (seizedAssets > 0) {
uint256 seizedAssetsQuoted = seizedAssets.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE);
repaidShares = seizedAssetsQuoted.wDivUp(liquidationIncentiveFactor).toSharesUp(
market[id].totalBorrowAssets, market[id].totalBorrowShares
);
} else {
seizedAssets = repaidShares.toAssetsDown(market[id].totalBorrowAssets, market[id].totalBorrowShares)
.wMulDown(liquidationIncentiveFactor).mulDivDown(ORACLE_PRICE_SCALE, collateralPrice);
}
}
uint256 repaidAssets = repaidShares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares);
position[id][borrower].borrowShares -= repaidShares.toUint128();
market[id].totalBorrowShares -= repaidShares.toUint128();
market[id].totalBorrowAssets = UtilsLib.zeroFloorSub(market[id].totalBorrowAssets, repaidAssets).toUint128();
position[id][borrower].collateral -= seizedAssets.toUint128();
uint256 badDebtShares;
uint256 badDebtAssets;
if (position[id][borrower].collateral == 0) {
badDebtShares = position[id][borrower].borrowShares;
badDebtAssets = UtilsLib.min(
market[id].totalBorrowAssets,
badDebtShares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares)
);
market[id].totalBorrowAssets -= badDebtAssets.toUint128();
market[id].totalSupplyAssets -= badDebtAssets.toUint128();
market[id].totalBorrowShares -= badDebtShares.toUint128();
position[id][borrower].borrowShares = 0;
}
emit EventsLib.Liquidate(
id, msg.sender, borrower, repaidAssets, repaidShares, seizedAssets, badDebtAssets, badDebtShares
);
IERC20(marketParams.collateralToken).safeTransfer(msg.sender, seizedAssets);
if (data.length > 0) IMorphoLiquidateCallback(msg.sender).onMorphoLiquidate(repaidAssets, data);
IERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), repaidAssets);
return (seizedAssets, repaidAssets);
}
function flashLoan(address token, uint256 assets, bytes calldata data) external {
require(assets != 0, ErrorsLib.ZERO_ASSETS);
emit EventsLib.FlashLoan(msg.sender, token, assets);
IERC20(token).safeTransfer(msg.sender, assets);
IMorphoFlashLoanCallback(msg.sender).onMorphoFlashLoan(assets, data);
IERC20(token).safeTransferFrom(msg.sender, address(this), assets);
}
function setAuthorization(address authorized, bool newIsAuthorized) external {
require(newIsAuthorized != isAuthorized[msg.sender][authorized], ErrorsLib.ALREADY_SET);
isAuthorized[msg.sender][authorized] = newIsAuthorized;
emit EventsLib.SetAuthorization(msg.sender, msg.sender, authorized, newIsAuthorized);
}
function setAuthorizationWithSig(Authorization memory authorization, Signature calldata signature) external {
require(block.timestamp <= authorization.deadline, ErrorsLib.SIGNATURE_EXPIRED);
require(authorization.nonce == nonce[authorization.authorizer]++, ErrorsLib.INVALID_NONCE);
bytes32 hashStruct = keccak256(abi.encode(AUTHORIZATION_TYPEHASH, authorization));
bytes32 digest = keccak256(bytes.concat("\x19\x01", DOMAIN_SEPARATOR, hashStruct));
address signatory = ecrecover(digest, signature.v, signature.r, signature.s);
require(signatory != address(0) && authorization.authorizer == signatory, ErrorsLib.INVALID_SIGNATURE);
emit EventsLib.IncrementNonce(msg.sender, authorization.authorizer, authorization.nonce);
isAuthorized[authorization.authorizer][authorization.authorized] = authorization.isAuthorized;
emit EventsLib.SetAuthorization(
msg.sender, authorization.authorizer, authorization.authorized, authorization.isAuthorized
);
}
function _isSenderAuthorized(address onBehalf) internal view returns (bool) {
return msg.sender == onBehalf || isAuthorized[onBehalf][msg.sender];
}
function accrueInterest(MarketParams memory marketParams) external {
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
_accrueInterest(marketParams, id);
}
function _accrueInterest(MarketParams memory marketParams, Id id) internal {
uint256 elapsed = block.timestamp - market[id].lastUpdate;
if (elapsed == 0) return;
if (marketParams.irm != address(0)) {
uint256 borrowRate = IIrm(marketParams.irm).borrowRate(marketParams, market[id]);
uint256 interest = market[id].totalBorrowAssets.wMulDown(borrowRate.wTaylorCompounded(elapsed));
market[id].totalBorrowAssets += interest.toUint128();
market[id].totalSupplyAssets += interest.toUint128();
uint256 feeShares;
if (market[id].fee != 0) {
uint256 feeAmount = interest.wMulDown(market[id].fee);
feeShares =
feeAmount.toSharesDown(market[id].totalSupplyAssets - feeAmount, market[id].totalSupplyShares);
position[id][feeRecipient].supplyShares += feeShares;
market[id].totalSupplyShares += feeShares.toUint128();
}
emit EventsLib.AccrueInterest(id, borrowRate, interest, feeShares);
}
market[id].lastUpdate = uint128(block.timestamp);
}
function _isHealthy(MarketParams memory marketParams, Id id, address borrower) internal view returns (bool) {
if (position[id][borrower].borrowShares == 0) return true;
uint256 collateralPrice = IOracle(marketParams.oracle).price();
return _isHealthy(marketParams, id, borrower, collateralPrice);
}
function _isHealthy(MarketParams memory marketParams, Id id, address borrower, uint256 collateralPrice)
internal
view
returns (bool)
{
uint256 borrowed = uint256(position[id][borrower].borrowShares).toAssetsUp(
market[id].totalBorrowAssets, market[id].totalBorrowShares
);
uint256 maxBorrow = uint256(position[id][borrower].collateral).mulDivDown(collateralPrice, ORACLE_PRICE_SCALE)
.wMulDown(marketParams.lltv);
return maxBorrow >= borrowed;
}
function extSloads(bytes32[] calldata slots) external view returns (bytes32[] memory res) {
uint256 nSlots = slots.length;
res = new bytes32[](nSlots);
for (uint256 i; i < nSlots;) {
bytes32 slot = slots[i++];
assembly ("memory-safe") {
mstore(add(res, mul(i, 32)), sload(slot))
}
}
}
}
文件 12 的 14:SafeTransferLib.sol
pragma solidity ^0.8.0;
import {IERC20} from "../interfaces/IERC20.sol";
import {ErrorsLib} from "../libraries/ErrorsLib.sol";
interface IERC20Internal {
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
library SafeTransferLib {
function safeTransfer(IERC20 token, address to, uint256 value) internal {
require(address(token).code.length > 0, ErrorsLib.NO_CODE);
(bool success, bytes memory returndata) =
address(token).call(abi.encodeCall(IERC20Internal.transfer, (to, value)));
require(success, ErrorsLib.TRANSFER_REVERTED);
require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TRANSFER_RETURNED_FALSE);
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
require(address(token).code.length > 0, ErrorsLib.NO_CODE);
(bool success, bytes memory returndata) =
address(token).call(abi.encodeCall(IERC20Internal.transferFrom, (from, to, value)));
require(success, ErrorsLib.TRANSFER_FROM_REVERTED);
require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TRANSFER_FROM_RETURNED_FALSE);
}
}
文件 13 的 14:SharesMathLib.sol
pragma solidity ^0.8.0;
import {MathLib} from "./MathLib.sol";
library SharesMathLib {
using MathLib for uint256;
uint256 internal constant VIRTUAL_SHARES = 1e6;
uint256 internal constant VIRTUAL_ASSETS = 1;
function toSharesDown(uint256 assets, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return assets.mulDivDown(totalShares + VIRTUAL_SHARES, totalAssets + VIRTUAL_ASSETS);
}
function toAssetsDown(uint256 shares, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return shares.mulDivDown(totalAssets + VIRTUAL_ASSETS, totalShares + VIRTUAL_SHARES);
}
function toSharesUp(uint256 assets, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return assets.mulDivUp(totalShares + VIRTUAL_SHARES, totalAssets + VIRTUAL_ASSETS);
}
function toAssetsUp(uint256 shares, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return shares.mulDivUp(totalAssets + VIRTUAL_ASSETS, totalShares + VIRTUAL_SHARES);
}
}
文件 14 的 14:UtilsLib.sol
pragma solidity ^0.8.0;
import {ErrorsLib} from "../libraries/ErrorsLib.sol";
library UtilsLib {
function exactlyOneZero(uint256 x, uint256 y) internal pure returns (bool z) {
assembly {
z := xor(iszero(x), iszero(y))
}
}
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
function toUint128(uint256 x) internal pure returns (uint128) {
require(x <= type(uint128).max, ErrorsLib.MAX_UINT128_EXCEEDED);
return uint128(x);
}
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
}
{
"compilationTarget": {
"src/Morpho.sol": "Morpho"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 999999
},
"remappings": [
":ds-test/=lib/forge-std/lib/ds-test/src/",
":eth-gas-reporter/=node_modules/eth-gas-reporter/",
":forge-std/=lib/forge-std/src/",
":hardhat/=node_modules/hardhat/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"}],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"}],"name":"createMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"irm","type":"address"}],"name":"enableIrm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lltv","type":"uint256"}],"name":"enableLltv","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"slots","type":"bytes32[]"}],"name":"extSloads","outputs":[{"internalType":"bytes32[]","name":"res","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"Id","name":"","type":"bytes32"}],"name":"idToMarketParams","outputs":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isAuthorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isIrmEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isLltvEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizedAssets","type":"uint256"},{"internalType":"uint256","name":"repaidShares","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"Id","name":"","type":"bytes32"}],"name":"market","outputs":[{"internalType":"uint128","name":"totalSupplyAssets","type":"uint128"},{"internalType":"uint128","name":"totalSupplyShares","type":"uint128"},{"internalType":"uint128","name":"totalBorrowAssets","type":"uint128"},{"internalType":"uint128","name":"totalBorrowShares","type":"uint128"},{"internalType":"uint128","name":"lastUpdate","type":"uint128"},{"internalType":"uint128","name":"fee","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Id","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"position","outputs":[{"internalType":"uint256","name":"supplyShares","type":"uint256"},{"internalType":"uint128","name":"borrowShares","type":"uint128"},{"internalType":"uint128","name":"collateral","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"repay","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorized","type":"address"},{"internalType":"bool","name":"newIsAuthorized","type":"bool"}],"name":"setAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"address","name":"authorized","type":"address"},{"internalType":"bool","name":"isAuthorized","type":"bool"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct Authorization","name":"authorization","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Signature","name":"signature","type":"tuple"}],"name":"setAuthorizationWithSig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"supplyCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"withdrawCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"}]