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

Set asset as collateral #569

Merged
merged 45 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fac6976
feat: draft asset as collateral
MerlinEgalite Feb 22, 2023
18656f1
feat: add isCollateral check
MerlinEgalite Feb 22, 2023
b3c60d7
feat: add revert case and mirror behavior
MerlinEgalite Feb 23, 2023
f2c637c
feat: add correct check
MerlinEgalite Feb 23, 2023
4afe5f2
fix: add missing negation
MerlinEgalite Feb 23, 2023
546a14b
test: add first tests
MerlinEgalite Feb 23, 2023
ad47ae3
feat: add functions to interface + small reorder of logic
MerlinEgalite Feb 23, 2023
be28d1d
test: add missing tests
MerlinEgalite Feb 23, 2023
aa89550
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Feb 23, 2023
bf5516d
test: fix test setup
MerlinEgalite Feb 23, 2023
394124a
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Feb 23, 2023
7af52d8
test: fix test after merge
MerlinEgalite Feb 23, 2023
ba87cab
docs: improve comments
MerlinEgalite Feb 24, 2023
5ad3712
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Feb 27, 2023
57b4a3b
refactor: apply error renaming suggestion
MerlinEgalite Feb 27, 2023
073ff49
test: set true for expectEmit
MerlinEgalite Feb 27, 2023
027079d
refactor: remove check collateral
MerlinEgalite Feb 27, 2023
9eb4672
docs: add comment about sending assets with LTV = 0
MerlinEgalite Feb 28, 2023
4ca4957
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Feb 28, 2023
57a57b0
docs: apply doc suggestion
MerlinEgalite Mar 1, 2023
d67a71d
refactor: revert when is collateral on morpho
MerlinEgalite Mar 2, 2023
a1b0590
test: just remove the test
MerlinEgalite Mar 2, 2023
6d68260
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Mar 2, 2023
993b0a5
refactor: revert if asset not collateral on pool
MerlinEgalite Mar 2, 2023
3909682
refactor: remove useless code
MerlinEgalite Mar 2, 2023
6ef27f0
refactor: check first
MerlinEgalite Mar 3, 2023
4166835
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Mar 6, 2023
aa7aaa3
docs: remove outdated comment
MerlinEgalite Mar 6, 2023
0bc1a47
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Mar 7, 2023
f93f8fe
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Mar 10, 2023
bca5964
fix: miss merge conflicts fixes
MerlinEgalite Mar 10, 2023
f35cf44
refactor: correct formatting
MerlinEgalite Mar 13, 2023
482a46f
test: remove useless test
MerlinEgalite Mar 13, 2023
638e2c2
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Mar 13, 2023
a4225cc
Merge branch 'dev' of github.com:morpho-dao/morpho-aave-v3 into feat/…
MerlinEgalite Mar 14, 2023
3df3587
docs: apply comment suggestions
MerlinEgalite Mar 14, 2023
f11b3f2
refactor: revert earlier if isCollateral = false too
MerlinEgalite Mar 14, 2023
a51ce76
refactor: more explicit errors
MerlinEgalite Mar 14, 2023
c65e0f6
refactor: scope to created market for setAssetIsCollateralOnPool
MerlinEgalite Mar 14, 2023
b3de2fb
refactor: remove useless check + add invariant tests
MerlinEgalite Mar 15, 2023
ad29aa5
refactor: remove useless check
MerlinEgalite Mar 15, 2023
0847c12
Merge branch 'feat/asset-as-collateral' of github.com:morpho-dao/morp…
MerlinEgalite Mar 15, 2023
a57a7c0
docs: improve doc
MerlinEgalite Mar 15, 2023
be26bbc
Merge branch 'feat/asset-as-collateral' of github.com:morpho-dao/morp…
MerlinEgalite Mar 15, 2023
84ab598
Merge pull request #680 from morpho-dao/refactor/collateral-setters
MerlinEgalite Mar 16, 2023
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
2 changes: 2 additions & 0 deletions src/MorphoInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ abstract contract MorphoInternal is MorphoStorage {
view
returns (uint256 borrowable, uint256 maxDebt)
{
if (!_market[underlying].isCollateral) return (0, 0);

(uint256 underlyingPrice, uint256 ltv, uint256 liquidationThreshold, uint256 tokenUnit) =
_assetLiquidityData(underlying, vars);

Expand Down
15 changes: 15 additions & 0 deletions src/MorphoSetters.sol
MerlinEgalite marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ abstract contract MorphoSetters is IMorphoSetters, MorphoInternal {
emit Events.TreasuryVaultSet(treasuryVault);
}

/// @notice Sets the `underlying` asset as collateral or not on the pool.
MerlinEgalite marked this conversation as resolved.
Show resolved Hide resolved
/// @dev Note that it is possible to set an asset whose market is not created yet on the protocol.
function setAssetIsCollateralOnPool(address underlying, bool isCollateral) external onlyOwner {
_POOL.setUserUseReserveAsCollateral(underlying, isCollateral);
MerlinEgalite marked this conversation as resolved.
Show resolved Hide resolved
if (!isCollateral && _market[underlying].isCreated()) _market[underlying].setAssetIsCollateral(isCollateral);
}

function setAssetIsCollateral(address underlying, bool isCollateral)
MerlinEgalite marked this conversation as resolved.
Show resolved Hide resolved
external
onlyOwner
isMarketCreated(underlying)
{
_market[underlying].setAssetIsCollateral(isCollateral);
MerlinEgalite marked this conversation as resolved.
Show resolved Hide resolved
}

/// @notice Sets the `underlying`'s reserve factor to `newReserveFactor` (in bps).
function setReserveFactor(address underlying, uint16 newReserveFactor)
external
Expand Down
5 changes: 5 additions & 0 deletions src/PositionsManagerInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {LogarithmicBuckets} from "@morpho-data-structures/LogarithmicBuckets.sol
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

import {DataTypes} from "@aave-v3-core/protocol/libraries/types/DataTypes.sol";
import {UserConfiguration} from "@aave-v3-core/protocol/libraries/configuration/UserConfiguration.sol";
QGarchery marked this conversation as resolved.
Show resolved Hide resolved
import {ReserveConfiguration} from "@aave-v3-core/protocol/libraries/configuration/ReserveConfiguration.sol";

import {ERC20} from "@solmate/tokens/ERC20.sol";
Expand All @@ -43,6 +44,7 @@ abstract contract PositionsManagerInternal is MatchingEngine {
using EnumerableSet for EnumerableSet.AddressSet;
using LogarithmicBuckets for LogarithmicBuckets.Buckets;

using UserConfiguration for DataTypes.UserConfigurationMap;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;

/// @dev Validates the manager's permission.
Expand Down Expand Up @@ -90,6 +92,7 @@ abstract contract PositionsManagerInternal is MatchingEngine {
function _validateSupplyCollateral(address underlying, uint256 amount, address user) internal view {
Types.Market storage market = _validateInput(underlying, amount, user);
if (market.isSupplyCollateralPaused()) revert Errors.SupplyCollateralIsPaused();
if (!market.isCollateral) revert Errors.AssetNotUsedAsCollateral();
}

/// @dev Validates a borrow action.
Expand Down Expand Up @@ -171,6 +174,8 @@ abstract contract PositionsManagerInternal is MatchingEngine {
if (collateralMarket.isLiquidateCollateralPaused()) revert Errors.LiquidateCollateralIsPaused();
if (borrowMarket.isLiquidateBorrowPaused()) revert Errors.LiquidateBorrowIsPaused();

if (!collateralMarket.isCollateral) revert Errors.AssetNotUsedAsCollateral();

if (borrowMarket.isDeprecated()) return Constants.MAX_CLOSE_FACTOR; // Allow liquidation of the whole debt.

uint256 healthFactor = _getUserHealthFactor(borrower);
Expand Down
1 change: 1 addition & 0 deletions src/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ library Errors {

error UnauthorizedWithdraw();
error UnauthorizedLiquidate();
error AssetNotUsedAsCollateral();
MerlinEgalite marked this conversation as resolved.
Show resolved Hide resolved

error ExceedsMaxBasisPoints();

Expand Down
2 changes: 2 additions & 0 deletions src/libraries/Events.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ library Events {
address indexed claimer, address indexed onBehalf, address indexed rewardToken, uint256 amountClaimed
);

event IsCollateralSet(address indexed underlying, bool isCollateral);

event IsSupplyPausedSet(address indexed underlying, bool isPaused);

event IsSupplyCollateralPausedSet(address indexed underlying, bool isPaused);
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/MarketLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ library MarketLib {
return market.pauseStatuses.isP2PDisabled;
}

function setAssetIsCollateral(Types.Market storage market, bool isCollateral) internal {
market.isCollateral = isCollateral;

emit Events.IsCollateralSet(market.underlying, isCollateral);
}

function setIsSupplyPaused(Types.Market storage market, bool isPaused) internal {
market.pauseStatuses.isSupplyPaused = isPaused;

Expand Down
1 change: 1 addition & 0 deletions src/libraries/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ library Types {
// SLOT 6
address underlying; // 160 bits
PauseStatuses pauseStatuses; // 80 bits
bool isCollateral; // 8 bits
Rubilmax marked this conversation as resolved.
Show resolved Hide resolved
MathisGD marked this conversation as resolved.
Show resolved Hide resolved
// SLOT 7
address variableDebtToken; // 160 bits
uint32 lastUpdateTimestamp; // 32 bits
Expand Down
2 changes: 2 additions & 0 deletions test/internal/TestInternalMorphoInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ contract TestInternalMorphoInternal is InternalTest, MorphoInternal {
function testLiquidityDataCollateral(uint256 amount) public {
amount = bound(amount, 0, 1_000_000 ether);

_market[dai].isCollateral = true;

_marketBalances[dai].collateral[address(1)] = amount.rayDivUp(_market[dai].indexes.supply.poolIndex);

DataTypes.EModeCategory memory eModeCategory = _POOL.getEModeCategoryData(0);
Expand Down
12 changes: 11 additions & 1 deletion test/internal/TestInternalPositionsManagerInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ contract TestInternalPositionsManagerInternal is InternalTest, PositionsManagerI
this.validateSupplyCollateral(dai, 1, address(1));
}

function testValidateSupplyCollateral() public view {
function testValidateSupplyCollateral() public {
_market[dai].isCollateral = true;
this.validateSupplyCollateral(dai, 1, address(1));
}

Expand Down Expand Up @@ -195,6 +196,7 @@ contract TestInternalPositionsManagerInternal is InternalTest, PositionsManagerI
}

function testAuthorizeLiquidateShouldReturnMaxCloseFactorIfDeprecatedBorrow() public {
_market[dai].isCollateral = true;
_userCollaterals[address(this)].add(dai);
_userBorrows[address(this)].add(dai);
_market[dai].pauseStatuses.isDeprecated = true;
Expand All @@ -203,6 +205,8 @@ contract TestInternalPositionsManagerInternal is InternalTest, PositionsManagerI
}

function testAuthorizeLiquidateShouldRevertIfSentinelDisallows() public {
_market[dai].isCollateral = true;

uint256 amount = 1e18;
(, uint256 lt,,,,) = _POOL.getConfiguration(dai).getParams();
(, Types.Indexes256 memory indexes) = _computeIndexes(dai);
Expand All @@ -221,6 +225,8 @@ contract TestInternalPositionsManagerInternal is InternalTest, PositionsManagerI
}

function testAuthorizeLiquidateShouldRevertIfBorrowerHealthy() public {
_market[dai].isCollateral = true;

uint256 amount = 1e18;
(, Types.Indexes256 memory indexes) = _computeIndexes(dai);

Expand All @@ -234,6 +240,8 @@ contract TestInternalPositionsManagerInternal is InternalTest, PositionsManagerI
}

function testAuthorizeLiquidateShouldReturnMaxCloseFactorIfBelowMinThreshold(uint256 amount) public {
_market[dai].isCollateral = true;

amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT);
(, uint256 lt,,,,) = _POOL.getConfiguration(dai).getParams();
(, Types.Indexes256 memory indexes) = _computeIndexes(dai);
Expand All @@ -250,6 +258,8 @@ contract TestInternalPositionsManagerInternal is InternalTest, PositionsManagerI
}

function testAuthorizeLiquidateShouldReturnDefaultCloseFactorIfAboveMinThreshold(uint256 amount) public {
_market[dai].isCollateral = true;

// Min amount needs to be high enough to have a precise enough price for this test
amount = bound(amount, 1e12, MAX_AMOUNT);
(, uint256 lt,,,,) = _POOL.getConfiguration(dai).getParams();
Expand Down