Skip to content

Commit

Permalink
Merge pull request #109 from morpho-dao/feat/supply-cap
Browse files Browse the repository at this point in the history
Feat/supply cap
  • Loading branch information
pakim249CAL authored Jan 13, 2023
2 parents 5d9b8de + df46046 commit 21bb683
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 10 deletions.
16 changes: 15 additions & 1 deletion src/MorphoInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {ReserveConfiguration} from "./libraries/aave/ReserveConfiguration.sol";

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

import {ERC20} from "@solmate/tokens/ERC20.sol";

abstract contract MorphoInternal is MorphoStorage {
using PoolLib for IPool;
using MarketLib for Types.Market;
Expand Down Expand Up @@ -375,7 +377,8 @@ abstract contract MorphoInternal is MorphoStorage {
poolBorrowIndex: indexes.borrow.poolIndex,
reserveFactor: market.reserveFactor,
p2pIndexCursor: market.p2pIndexCursor,
deltas: market.deltas
deltas: market.deltas,
proportionIdle: _proportionIdle(underlying)
})
);
}
Expand All @@ -392,4 +395,15 @@ abstract contract MorphoInternal is MorphoStorage {

return liquidityData.debt > 0 ? liquidityData.maxDebt.wadDiv(liquidityData.debt) : type(uint256).max;
}

/// @dev Returns a ray.
function _proportionIdle(address underlying) internal view returns (uint256) {
Types.Market storage market = _market[underlying];
uint256 idleSupply = market.idleSupply;
if (idleSupply == 0) {
return 0;
}
uint256 totalP2PSupplied = market.deltas.p2pSupplyAmount.rayMul(market.indexes.supply.p2pIndex);
return idleSupply.rayDivUp(totalP2PSupplied);
}
}
42 changes: 40 additions & 2 deletions src/PositionsManagerInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet

import {MatchingEngine} from "./MatchingEngine.sol";

import {ERC20} from "@solmate/tokens/ERC20.sol";

abstract contract PositionsManagerInternal is MatchingEngine {
using Math for uint256;
using WadRayMath for uint256;
Expand Down Expand Up @@ -231,6 +233,18 @@ abstract contract PositionsManagerInternal is MatchingEngine {
vars.onPool = marketBalances.scaledPoolBorrowBalance(user);
vars.inP2P = marketBalances.scaledP2PBorrowBalance(user);

/// Idle borrow ///

{
uint256 idleSupply = market.idleSupply;
if (idleSupply > 0) {
uint256 matchedIdle = Math.min(idleSupply, amount); // In underlying.
market.idleSupply -= matchedIdle;
amount -= matchedIdle;
vars.inP2P += matchedIdle.rayDiv(indexes.borrow.p2pIndex);
}
}

/// Peer-to-peer borrow ///

// Match the peer-to-peer supply delta.
Expand Down Expand Up @@ -303,7 +317,7 @@ abstract contract PositionsManagerInternal is MatchingEngine {
_userBorrows[user].remove(underlying);
}

return (onPool, inP2P, toSupply, toRepay);
return (onPool, inP2P, 0, toRepay);
}
}

Expand Down Expand Up @@ -368,7 +382,8 @@ abstract contract PositionsManagerInternal is MatchingEngine {
deltas.p2pBorrowAmount -= Math.min(amount.rayDiv(indexes.borrow.p2pIndex), deltas.p2pBorrowAmount);
emit Events.P2PAmountsUpdated(underlying, deltas.p2pSupplyAmount, deltas.p2pBorrowAmount);

toSupply = amount;
/// Note: Only used in breaking repay. Suppliers should not be able to supply if the pool is supply capped.
toSupply = _handleSupplyCap(underlying, amount);
}

if (inP2P == 0 && onPool == 0) _userBorrows[user].remove(underlying);
Expand Down Expand Up @@ -408,6 +423,15 @@ abstract contract PositionsManagerInternal is MatchingEngine {
}

vars.inP2P -= Math.min(vars.inP2P, amount.rayDiv(indexes.supply.p2pIndex)); // In peer-to-peer supply unit.

/// Idle Withdraw ///

if (amount > 0 && market.idleSupply > 0 && vars.inP2P > 0) {
uint256 matchedIdle =
Math.min(Math.min(market.idleSupply, amount), vars.inP2P.rayMul(indexes.supply.p2pIndex));
market.idleSupply -= matchedIdle;
}

_updateSupplierInDS(underlying, user, vars.onPool, vars.inP2P);

// Reduce the peer-to-peer supply delta.
Expand Down Expand Up @@ -486,4 +510,18 @@ abstract contract PositionsManagerInternal is MatchingEngine {
).percentDiv(liquidationBonus);
}
}

function _handleSupplyCap(address underlying, uint256 amount) internal returns (uint256 toSupply) {
DataTypes.ReserveConfigurationMap memory config = _POOL.getConfiguration(underlying);
uint256 supplyCap = config.getSupplyCap() * (10 ** config.getDecimals());
if (supplyCap == 0) return amount;

uint256 totalSupply = ERC20(_market[underlying].aToken).totalSupply();
if (totalSupply + amount > supplyCap) {
toSupply = supplyCap - totalSupply;
_market[underlying].idleSupply += amount - toSupply;
} else {
toSupply = amount;
}
}
}
24 changes: 17 additions & 7 deletions src/libraries/InterestRatesLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ library InterestRatesLib {
growthFactors.p2pSupplyGrowthFactor,
params.lastSupplyIndexes,
params.deltas.p2pSupplyDelta,
params.deltas.p2pSupplyAmount
params.deltas.p2pSupplyAmount,
params.proportionIdle
);
newP2PBorrowIndex = computeP2PIndex(
growthFactors.poolBorrowGrowthFactor,
growthFactors.p2pBorrowGrowthFactor,
params.lastBorrowIndexes,
params.deltas.p2pBorrowDelta,
params.deltas.p2pBorrowAmount
params.deltas.p2pBorrowAmount,
0
);
}

Expand Down Expand Up @@ -88,18 +90,26 @@ library InterestRatesLib {
uint256 p2pGrowthFactor,
Types.MarketSideIndexes256 memory lastIndexes,
uint256 p2pDelta,
uint256 p2pAmount
uint256 p2pAmount,
uint256 proportionIdle
) internal pure returns (uint256) {
if (p2pAmount == 0 || p2pDelta == 0) {
return lastIndexes.p2pIndex.rayMul(p2pGrowthFactor);
}

uint256 shareOfTheDelta = Math.min(
uint256 proportionDelta = Math.min(
p2pDelta.rayMul(lastIndexes.poolIndex).rayDivUp(p2pAmount.rayMul(lastIndexes.p2pIndex)),
WadRayMath.RAY // To avoid shareOfTheDelta > 1 with rounding errors.
WadRayMath.RAY - proportionIdle // To avoid proportionDelta + proportionIdle > 1 with rounding errors.
); // In ray.

return
lastIndexes.p2pIndex.rayMul(WadRayMath.rayWeightedAvg(p2pGrowthFactor, poolGrowthFactor, shareOfTheDelta));
// Equivalent to:
// lastP2PIndex * (
// p2pGrowthFactor * (1 - proportionDelta - proportionIdle) +
// poolGrowthFactor * proportionDelta +
// idleGrowthFactor * proportionIdle)
return lastIndexes.p2pIndex.rayMul(
p2pGrowthFactor.rayMul(WadRayMath.RAY - proportionDelta - proportionIdle)
+ poolGrowthFactor.rayMul(proportionDelta) + proportionIdle
);
}
}
3 changes: 3 additions & 0 deletions src/libraries/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ library Types {
uint16 p2pIndexCursor; // 16 bits
// SLOT 8
address aToken; // 160 bits
// SLOT 9
uint256 idleSupply; // 256 bits
}

// Contains storage-only dynamic arrays and mappings.
Expand Down Expand Up @@ -91,6 +93,7 @@ library Types {
uint256 reserveFactor; // The reserve factor percentage (10 000 = 100%).
uint256 p2pIndexCursor; // The peer-to-peer index cursor (10 000 = 100%).
Deltas deltas; // The deltas and peer-to-peer amounts.
uint256 proportionIdle; // In ray.
}

struct GrowthFactors {
Expand Down
5 changes: 5 additions & 0 deletions src/libraries/aave/ReserveConfiguration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ library ReserveConfiguration {
uint256 internal constant RESERVE_DECIMALS_START_BIT_POSITION = 48;
uint256 internal constant RESERVE_FACTOR_START_BIT_POSITION = 64;
uint256 internal constant EMODE_CATEGORY_START_BIT_POSITION = 168;
uint256 internal constant SUPPLY_CAP_START_BIT_POSITION = 116;

function getActive(DataTypes.ReserveConfigurationMap memory self) internal pure returns (bool) {
return (self.data & ~ACTIVE_MASK) != 0;
Expand Down Expand Up @@ -75,6 +76,10 @@ library ReserveConfiguration {
);
}

function getSupplyCap(DataTypes.ReserveConfigurationMap memory self) internal pure returns (uint256) {
return (self.data & ~SUPPLY_CAP_MASK) >> SUPPLY_CAP_START_BIT_POSITION;
}

function getDecimals(DataTypes.ReserveConfigurationMap memory self) internal pure returns (uint256) {
return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;
}
Expand Down

0 comments on commit 21bb683

Please sign in to comment.