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

Make pool & addresses provider immutable #81

Merged
merged 4 commits into from
Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
17 changes: 12 additions & 5 deletions src/EntryPositionsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,20 @@ import {WadRayMath} from "@morpho-utils/math/WadRayMath.sol";

import {ERC20, SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";

import {MorphoStorage} from "./MorphoStorage.sol";
import {PositionsManagerInternal} from "./PositionsManagerInternal.sol";

contract EntryPositionsManager is IEntryPositionsManager, PositionsManagerInternal {
using WadRayMath for uint256;
using SafeTransferLib for ERC20;
using PoolLib for IPool;

/// CONSTRUCTOR ///

constructor(address addressesProvider) MorphoStorage(addressesProvider) {}

/// EXTERNAL ///

function supplyLogic(address underlying, uint256 amount, address from, address onBehalf, uint256 maxLoops)
external
returns (uint256 supplied)
Expand All @@ -31,8 +38,8 @@ contract EntryPositionsManager is IEntryPositionsManager, PositionsManagerIntern
(uint256 onPool, uint256 inP2P, uint256 toRepay, uint256 toSupply) =
_executeSupply(underlying, amount, onBehalf, maxLoops, indexes);

if (toRepay > 0) _pool.repayToPool(underlying, _market[underlying].variableDebtToken, toRepay);
if (toSupply > 0) _pool.supplyToPool(underlying, toSupply);
if (toRepay > 0) _POOL.repayToPool(underlying, _market[underlying].variableDebtToken, toRepay);
if (toSupply > 0) _POOL.supplyToPool(underlying, toSupply);

emit Events.Supplied(from, onBehalf, underlying, amount, onPool, inP2P);
return amount;
Expand All @@ -49,7 +56,7 @@ contract EntryPositionsManager is IEntryPositionsManager, PositionsManagerIntern

_marketBalances[underlying].collateral[onBehalf] += amount.rayDiv(indexes.supply.poolIndex);

_pool.supplyToPool(underlying, amount);
_POOL.supplyToPool(underlying, amount);

emit Events.CollateralSupplied(
from, onBehalf, underlying, amount, _marketBalances[underlying].collateral[onBehalf]
Expand All @@ -67,8 +74,8 @@ contract EntryPositionsManager is IEntryPositionsManager, PositionsManagerIntern
(uint256 onPool, uint256 inP2P, uint256 toWithdraw, uint256 toBorrow) =
_executeBorrow(underlying, amount, borrower, maxLoops, indexes);

if (toWithdraw > 0) _pool.withdrawFromPool(underlying, _market[underlying].aToken, toWithdraw);
if (toBorrow > 0) _pool.borrowFromPool(underlying, toBorrow);
if (toWithdraw > 0) _POOL.withdrawFromPool(underlying, _market[underlying].aToken, toWithdraw);
if (toBorrow > 0) _POOL.borrowFromPool(underlying, toBorrow);
ERC20(underlying).safeTransfer(receiver, amount);

emit Events.Borrowed(borrower, underlying, amount, onPool, inP2P);
Expand Down
25 changes: 16 additions & 9 deletions src/ExitPositionsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {PercentageMath} from "@morpho-utils/math/PercentageMath.sol";

import {ERC20, SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";

import {MorphoStorage} from "./MorphoStorage.sol";
import {PositionsManagerInternal} from "./PositionsManagerInternal.sol";

contract ExitPositionsManager is IExitPositionsManager, PositionsManagerInternal {
Expand All @@ -24,6 +25,12 @@ contract ExitPositionsManager is IExitPositionsManager, PositionsManagerInternal
using PercentageMath for uint256;
using MarketBalanceLib for Types.MarketBalances;

/// CONSTRUCTOR ///

constructor(address addressesProvider) MorphoStorage(addressesProvider) {}

/// EXTERNAL ///

function withdrawLogic(address underlying, uint256 amount, address supplier, address receiver)
external
returns (uint256 withdrawn)
Expand All @@ -35,8 +42,8 @@ contract ExitPositionsManager is IExitPositionsManager, PositionsManagerInternal
(uint256 onPool, uint256 inP2P, uint256 toWithdraw, uint256 toBorrow) =
_executeWithdraw(underlying, amount, supplier, _defaultMaxLoops.withdraw, indexes);

if (toWithdraw > 0) _pool.withdrawFromPool(underlying, _market[underlying].aToken, toWithdraw);
if (toBorrow > 0) _pool.borrowFromPool(underlying, toBorrow);
if (toWithdraw > 0) _POOL.withdrawFromPool(underlying, _market[underlying].aToken, toWithdraw);
if (toBorrow > 0) _POOL.borrowFromPool(underlying, toBorrow);
ERC20(underlying).safeTransfer(receiver, amount);

emit Events.Withdrawn(supplier, receiver, underlying, amount, onPool, inP2P);
Expand All @@ -55,7 +62,7 @@ contract ExitPositionsManager is IExitPositionsManager, PositionsManagerInternal

_marketBalances[underlying].collateral[supplier] -= amount.rayDiv(indexes.supply.poolIndex);

_pool.withdrawFromPool(underlying, _market[underlying].aToken, amount);
_POOL.withdrawFromPool(underlying, _market[underlying].aToken, amount);
ERC20(underlying).safeTransfer(receiver, amount);

emit Events.CollateralWithdrawn(
Expand All @@ -77,8 +84,8 @@ contract ExitPositionsManager is IExitPositionsManager, PositionsManagerInternal
(uint256 onPool, uint256 inP2P, uint256 toRepay, uint256 toSupply) =
_executeRepay(underlying, amount, onBehalf, _defaultMaxLoops.repay, indexes);

if (toRepay > 0) _pool.repayToPool(underlying, _market[underlying].variableDebtToken, toRepay);
if (toSupply > 0) _pool.supplyToPool(underlying, toSupply);
if (toRepay > 0) _POOL.repayToPool(underlying, _market[underlying].variableDebtToken, toRepay);
if (toSupply > 0) _POOL.supplyToPool(underlying, toSupply);

emit Events.Repaid(repayer, onBehalf, underlying, amount, onPool, inP2P);
return amount;
Expand Down Expand Up @@ -126,10 +133,10 @@ contract ExitPositionsManager is IExitPositionsManager, PositionsManagerInternal
(,, vars.toWithdraw, vars.toBorrow) =
_executeWithdraw(underlyingCollateral, vars.amountToSeize, borrower, 0, collateralIndexes);

_pool.repayToPool(underlyingBorrowed, _market[underlyingBorrowed].variableDebtToken, vars.toRepay);
_pool.supplyToPool(underlyingBorrowed, vars.toSupply);
_pool.withdrawFromPool(underlyingCollateral, _market[underlyingCollateral].aToken, vars.toWithdraw);
_pool.borrowFromPool(underlyingCollateral, vars.toBorrow);
_POOL.repayToPool(underlyingBorrowed, _market[underlyingBorrowed].variableDebtToken, vars.toRepay);
_POOL.supplyToPool(underlyingBorrowed, vars.toSupply);
_POOL.withdrawFromPool(underlyingCollateral, _market[underlyingCollateral].aToken, vars.toWithdraw);
_POOL.borrowFromPool(underlyingCollateral, vars.toBorrow);

ERC20(underlyingCollateral).safeTransfer(liquidator, vars.amountToSeize);

Expand Down
5 changes: 5 additions & 0 deletions src/Morpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {IERC1155} from "./interfaces/IERC1155.sol";

import {DelegateCall} from "@morpho-utils/DelegateCall.sol";

import {MorphoStorage} from "./MorphoStorage.sol";
import {MorphoGetters} from "./MorphoGetters.sol";
import {MorphoSetters} from "./MorphoSetters.sol";
import {EntryPositionsManager} from "./EntryPositionsManager.sol";
Expand All @@ -15,6 +16,10 @@ import {ExitPositionsManager} from "./ExitPositionsManager.sol";
contract Morpho is IMorpho, MorphoGetters, MorphoSetters {
using DelegateCall for address;

/// CONSTRUCTOR ///

constructor(address addressesProvider) MorphoStorage(addressesProvider) {}

/// EXTERNAL ///

function supply(address underlying, uint256 amount, address onBehalf, uint256 maxLoops)
Expand Down
8 changes: 8 additions & 0 deletions src/MorphoGetters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ abstract contract MorphoGetters is IMorphoGetters, MorphoInternal {

/// STORAGE ///

function POOL() external view returns (address) {
return address(_POOL);
}

function ADDRESSES_PROVIDER() external view returns (address) {
return address(_ADDRESSES_PROVIDER);
}
Rubilmax marked this conversation as resolved.
Show resolved Hide resolved

function market(address underlying) external view returns (Types.Market memory) {
return _market[underlying];
}
Expand Down
12 changes: 6 additions & 6 deletions src/MorphoInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {IPriceOracleGetter} from "@aave/core-v3/contracts/interfaces/IPriceOracl
import {Types} from "./libraries/Types.sol";
import {Events} from "./libraries/Events.sol";
import {Errors} from "./libraries/Errors.sol";
import {PoolLib} from "./libraries/PoolLib.sol";
import {MarketLib} from "./libraries/MarketLib.sol";
import {MarketBalanceLib} from "./libraries/MarketBalanceLib.sol";
import {PoolLib} from "./libraries/PoolLib.sol";
import {InterestRatesLib} from "./libraries/InterestRatesLib.sol";

import {Math} from "@morpho-utils/math/Math.sol";
Expand Down Expand Up @@ -96,10 +96,10 @@ abstract contract MorphoInternal is MorphoStorage {
view
returns (Types.LiquidityData memory liquidityData)
{
IPriceOracleGetter oracle = IPriceOracleGetter(_addressesProvider.getPriceOracle());
IPriceOracleGetter oracle = IPriceOracleGetter(_ADDRESSES_PROVIDER.getPriceOracle());
address[] memory userCollaterals = _userCollaterals[user].values();
address[] memory userBorrows = _userBorrows[user].values();
DataTypes.UserConfigurationMap memory morphoPoolConfig = _pool.getUserConfiguration(address(this));
DataTypes.UserConfigurationMap memory morphoPoolConfig = _POOL.getUserConfiguration(address(this));

for (uint256 i; i < userCollaterals.length; ++i) {
address collateral = userCollaterals[i];
Expand Down Expand Up @@ -175,10 +175,10 @@ abstract contract MorphoInternal is MorphoStorage {
underlyingPrice = oracle.getAssetPrice(underlying);

uint256 decimals;
(ltv, liquidationThreshold,, decimals,,) = _pool.getConfiguration(underlying).getParams();
(ltv, liquidationThreshold,, decimals,,) = _POOL.getConfiguration(underlying).getParams();

// LTV should be zero if Morpho has not enabled this asset as collateral
if (!morphoPoolConfig.isUsingAsCollateral(_pool.getReserveData(underlying).id)) {
if (!morphoPoolConfig.isUsingAsCollateral(_POOL.getReserveData(underlying).id)) {
ltv = 0;
}

Expand Down Expand Up @@ -271,7 +271,7 @@ abstract contract MorphoInternal is MorphoStorage {
return lastIndexes;
}

(indexes.supply.poolIndex, indexes.borrow.poolIndex) = _pool.getCurrentPoolIndexes(market.underlying);
(indexes.supply.poolIndex, indexes.borrow.poolIndex) = _POOL.getCurrentPoolIndexes(underlying);

(indexes.supply.p2pIndex, indexes.borrow.p2pIndex) = InterestRatesLib.computeP2PIndexes(
Types.RatesParams({
Expand Down
13 changes: 5 additions & 8 deletions src/MorphoSetters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,16 @@ import {ERC20, SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {MorphoInternal} from "./MorphoInternal.sol";

abstract contract MorphoSetters is IMorphoSetters, MorphoInternal {
using PoolLib for IPool;
using MarketLib for Types.Market;
using SafeTransferLib for ERC20;
using PoolLib for IPool;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;

/// SETTERS ///

function initialize(
address newEntryPositionsManager,
address newExitPositionsManager,
address newAddressesProvider,
Types.MaxLoops memory newDefaultMaxLoops,
uint256 newMaxSortedUsers
) external initializer {
Expand All @@ -41,8 +40,6 @@ abstract contract MorphoSetters is IMorphoSetters, MorphoInternal {

_entryPositionsManager = newEntryPositionsManager;
_exitPositionsManager = newExitPositionsManager;
_addressesProvider = IPoolAddressesProvider(newAddressesProvider);
_pool = IPool(_addressesProvider.getPool());

_defaultMaxLoops = newDefaultMaxLoops;
_maxSortedUsers = newMaxSortedUsers;
Expand All @@ -54,9 +51,9 @@ abstract contract MorphoSetters is IMorphoSetters, MorphoInternal {
revert Errors.ExceedsMaxBasisPoints();
}

if (!_pool.getConfiguration(underlying).getActive()) revert Errors.MarketIsNotListedOnAave();
if (!_POOL.getConfiguration(underlying).getActive()) revert Errors.MarketIsNotListedOnAave();

DataTypes.ReserveData memory reserveData = _pool.getReserveData(underlying);
DataTypes.ReserveData memory reserveData = _POOL.getReserveData(underlying);

Types.Market storage market = _market[underlying];

Expand All @@ -65,7 +62,7 @@ abstract contract MorphoSetters is IMorphoSetters, MorphoInternal {
Types.Indexes256 memory indexes;
indexes.supply.p2pIndex = WadRayMath.RAY;
indexes.borrow.p2pIndex = WadRayMath.RAY;
(indexes.supply.poolIndex, indexes.borrow.poolIndex) = _pool.getCurrentPoolIndexes(underlying);
(indexes.supply.poolIndex, indexes.borrow.poolIndex) = _POOL.getCurrentPoolIndexes(underlying);

market.setIndexes(indexes);
market.lastUpdateTimestamp = uint32(block.timestamp);
Expand All @@ -78,7 +75,7 @@ abstract contract MorphoSetters is IMorphoSetters, MorphoInternal {

_marketsCreated.push(underlying);

ERC20(underlying).safeApprove(address(_pool), type(uint256).max);
ERC20(underlying).safeApprove(address(_POOL), type(uint256).max);

emit Events.MarketCreated(underlying, reserveFactor, p2pIndexCursor);
}
Expand Down
20 changes: 14 additions & 6 deletions src/MorphoStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ import {Initializable} from "@openzeppelin-upgradeable/proxy/utils/Initializable
import {OwnableUpgradeable} from "@openzeppelin-upgradeable/access/OwnableUpgradeable.sol";

import {Types} from "./libraries/Types.sol";
import {Errors} from "./libraries/Errors.sol";
import {Constants} from "./libraries/Constants.sol";
import {WadRayMath} from "@morpho-utils/math/WadRayMath.sol";

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

contract MorphoStorage is Initializable, OwnableUpgradeable {
abstract contract MorphoStorage is Initializable, OwnableUpgradeable {
/// IMMUTABLES ///

IPool internal immutable _POOL;
IPoolAddressesProvider internal immutable _ADDRESSES_PROVIDER;
Rubilmax marked this conversation as resolved.
Show resolved Hide resolved

/// STORAGE ///

address[] internal _marketsCreated; // Keeps track of the created markets.
Expand All @@ -22,19 +29,20 @@ contract MorphoStorage is Initializable, OwnableUpgradeable {
uint256 internal _maxSortedUsers; // The max number of users to sort in the data structure.
Types.MaxLoops internal _defaultMaxLoops;

IPoolAddressesProvider internal _addressesProvider;
IPool internal _pool;
address internal _entryPositionsManager;
address internal _exitPositionsManager;
// IInterestRatesManager internal _interestRatesManager;
// IRewardsController internal _rewardsController;
// IRewardsManager internal _rewardsManager;

address internal _treasuryVault;
bool internal _isClaimRewardsPaused; // Whether claiming rewards is paused or not.

/// @dev The contract is automatically marked as initialized when deployed to prevent highjacking the implementation contract.
constructor() {
constructor(address addressesProvider) {
if (addressesProvider == address(0)) revert Errors.AddressIsZero();

_disableInitializers();

_ADDRESSES_PROVIDER = IPoolAddressesProvider(addressesProvider);
_POOL = IPool(_ADDRESSES_PROVIDER.getPool());
}
}
14 changes: 7 additions & 7 deletions src/PositionsManagerInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ abstract contract PositionsManagerInternal is MatchingEngine {
Types.Market storage market = _market[underlying];
if (!market.isCreated()) revert Errors.MarketNotCreated();
if (market.pauseStatuses.isBorrowPaused) revert Errors.BorrowIsPaused();
if (!_pool.getConfiguration(underlying).getBorrowingEnabled()) revert Errors.BorrowingNotEnabled();
if (!_POOL.getConfiguration(underlying).getBorrowingEnabled()) revert Errors.BorrowingNotEnabled();

// Aave can enable an oracle sentinel in specific circumstances which can prevent users to borrow.
// In response, Morpho mirrors this behavior.
address priceOracleSentinel = _addressesProvider.getPriceOracleSentinel();
address priceOracleSentinel = _ADDRESSES_PROVIDER.getPriceOracleSentinel();
if (priceOracleSentinel != address(0) && !IPriceOracleSentinel(priceOracleSentinel).isBorrowAllowed()) {
revert Errors.PriceOracleSentinelBorrowDisabled();
}
Expand Down Expand Up @@ -304,7 +304,7 @@ abstract contract PositionsManagerInternal is MatchingEngine {

// Aave can enable an oracle sentinel in specific circumstances which can prevent users to borrow.
// For safety concerns and as a withdraw on Morpho can trigger a borrow on pool, Morpho prevents withdrawals in such circumstances.
address priceOracleSentinel = _addressesProvider.getPriceOracleSentinel();
address priceOracleSentinel = _ADDRESSES_PROVIDER.getPriceOracleSentinel();
if (priceOracleSentinel != address(0) && !IPriceOracleSentinel(priceOracleSentinel).isBorrowAllowed()) {
revert Errors.PriceOracleSentinelBorrowPaused();
}
Expand Down Expand Up @@ -428,7 +428,7 @@ abstract contract PositionsManagerInternal is MatchingEngine {
return Constants.MAX_CLOSE_FACTOR; // Allow liquidation of the whole debt.
} else {
uint256 healthFactor = _getUserHealthFactor(address(0), borrower, 0);
address priceOracleSentinel = _addressesProvider.getPriceOracleSentinel();
address priceOracleSentinel = _ADDRESSES_PROVIDER.getPriceOracleSentinel();

if (
priceOracleSentinel != address(0) && !IPriceOracleSentinel(priceOracleSentinel).isLiquidationAllowed()
Expand All @@ -454,15 +454,15 @@ abstract contract PositionsManagerInternal is MatchingEngine {
) internal view returns (uint256 amountToLiquidate, uint256 amountToSeize) {
amountToLiquidate = maxToLiquidate;
(,, uint256 liquidationBonus, uint256 collateralTokenUnit,,) =
_pool.getConfiguration(underlyingCollateral).getParams();
(,,, uint256 borrowTokenUnit,,) = _pool.getConfiguration(underlyingBorrowed).getParams();
_POOL.getConfiguration(underlyingCollateral).getParams();
(,,, uint256 borrowTokenUnit,,) = _POOL.getConfiguration(underlyingBorrowed).getParams();

unchecked {
collateralTokenUnit = 10 ** collateralTokenUnit;
borrowTokenUnit = 10 ** borrowTokenUnit;
}

IPriceOracleGetter oracle = IPriceOracleGetter(_addressesProvider.getPriceOracle());
IPriceOracleGetter oracle = IPriceOracleGetter(_ADDRESSES_PROVIDER.getPriceOracle());
uint256 borrowPrice = oracle.getAssetPrice(underlyingBorrowed);
uint256 collateralPrice = oracle.getAssetPrice(underlyingCollateral);

Expand Down
3 changes: 2 additions & 1 deletion src/interfaces/IMorpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ interface IMorphoGetters {
function maxSortedUsers() external view returns (uint256);
function isClaimRewardsPaused() external view returns (bool);

function POOL() external view returns (address);
function ADDRESSES_PROVIDER() external view returns (address);
function market(address underlying) external view returns (Types.Market memory);

function scaledCollateralBalance(address underlying, address user) external view returns (uint256);
Expand All @@ -23,7 +25,6 @@ interface IMorphoSetters {
function initialize(
address newEntryPositionsManager,
address newExitPositionsManager,
address newAddressesProvider,
Types.MaxLoops memory newDefaultMaxLoops,
uint256 newMaxSortedUsers
) external;
Expand Down
7 changes: 3 additions & 4 deletions test/TestSetup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ contract TestSetup is Test {
}

function deployAndSet() public {
entryPositionsManager = new EntryPositionsManager();
exitPositionsManager = new ExitPositionsManager();
morphoImplementation = new Morpho();
entryPositionsManager = new EntryPositionsManager(address(addressesProvider));
exitPositionsManager = new ExitPositionsManager(address(addressesProvider));
morphoImplementation = new Morpho(address(addressesProvider));

proxyAdmin = new ProxyAdmin();
morphoProxy = new TransparentUpgradeableProxy(payable(address(morphoImplementation)), address(proxyAdmin), "");
Expand All @@ -73,7 +73,6 @@ contract TestSetup is Test {
morpho.initialize(
address(entryPositionsManager),
address(exitPositionsManager),
address(addressesProvider),
Types.MaxLoops({supply: 10, borrow: 10, repay: 10, withdraw: 10}),
20
);
Expand Down