Skip to content

Commit

Permalink
Resolve audit fix Q-4 w/ _validateMBMarket()
Browse files Browse the repository at this point in the history
  • Loading branch information
0xEinCodes committed Jan 23, 2024
1 parent 51feaae commit 2265d21
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 66 deletions.
Expand Up @@ -29,11 +29,6 @@ contract MorphoBlueCollateralAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
// NA
//====================================================================

/**
* @notice Attempted to interact with an Morpho Blue Lending Market the Cellar is not using.
*/
error MorphoBlueCollateralAdaptor__MarketPositionsMustBeTracked(MarketParams market);

/**
* @notice Removal of collateral causes Cellar Health Factor below what is required
*/
Expand Down Expand Up @@ -76,7 +71,7 @@ contract MorphoBlueCollateralAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
function deposit(uint256 assets, bytes memory adaptorData, bytes memory) public override {
// Deposit assets to Morpho Blue.
MarketParams memory market = abi.decode(adaptorData, (MarketParams));
_validateMBMarket(market);
_validateMBMarket(market, identifier(), false);
ERC20 collateralToken = ERC20(market.collateralToken);
_addCollateral(market, assets, collateralToken);
}
Expand Down Expand Up @@ -136,7 +131,7 @@ contract MorphoBlueCollateralAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* @param _collateralToDeposit The amount of `collateralToken` to add to specified MB market position.
*/
function addCollateral(MarketParams memory _market, uint256 _collateralToDeposit) public {
_validateMBMarket(_market);
_validateMBMarket(_market, identifier(), false);
ERC20 collateralToken = ERC20(_market.collateralToken);
uint256 amountToDeposit = _maxAvailable(collateralToken, _collateralToDeposit);
_addCollateral(_market, amountToDeposit, collateralToken);
Expand All @@ -148,7 +143,7 @@ contract MorphoBlueCollateralAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* @param _collateralAmount The amount of collateral to remove from specified MB market position.
*/
function removeCollateral(MarketParams memory _market, uint256 _collateralAmount) public {
_validateMBMarket(_market);
_validateMBMarket(_market, identifier(), false);
Id id = MarketParamsLib.id(_market);
if (_collateralAmount == type(uint256).max) {
_collateralAmount = _userCollateralBalance(id, address(this));
Expand All @@ -168,24 +163,10 @@ contract MorphoBlueCollateralAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* so a strategist should consider moving some assets into reserves.
*/
function accrueInterest(MarketParams memory market) public {
_validateMBMarket(market);
_validateMBMarket(market, identifier(), false);
_accrueInterest(market);
}

//============================================ Helper Functions ===========================================

/**
* @notice Validates that a given market is set up as a position in the Cellar.
* @dev This function uses `address(this)` as the address of the Cellar.
* @param _market MarketParams struct for a specific Morpho Blue market.
*/
function _validateMBMarket(MarketParams memory _market) internal view {
bytes32 positionHash = keccak256(abi.encode(identifier(), false, abi.encode(_market)));
uint32 positionId = Cellar(address(this)).registry().getPositionHashToPositionId(positionHash);
if (!Cellar(address(this)).isPositionUsed(positionId))
revert MorphoBlueCollateralAdaptor__MarketPositionsMustBeTracked(_market);
}

//============================== Interface Details ==============================
// General message on interface and virtual functions below: The Morpho Blue protocol is meant to be a primitive layer to DeFi, and so other projects may build atop of MB. These possible future projects may implement the same interface to simply interact with MB, and thus this adaptor is implementing a design that allows for future adaptors to simply inherit this "Base Morpho Adaptor" and override what they need appropriately to work with whatever project. Aspects that may be adjusted include using the flexible `bytes` param within `morphoBlue.supplyCollateral()` for example.

Expand Down
25 changes: 3 additions & 22 deletions src/modules/adaptors/Morpho/MorphoBlue/MorphoBlueDebtAdaptor.sol
Expand Up @@ -32,11 +32,6 @@ contract MorphoBlueDebtAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
// NA
//====================================================================

/**
* @notice Attempted to interact with an Morpho Blue Lending Market the Cellar is not using.
*/
error MorphoBlueDebtAdaptor__MarketPositionsMustBeTracked(MarketParams market);

/**
* @notice Attempted tx that results in unhealthy cellar.
*/
Expand Down Expand Up @@ -131,7 +126,7 @@ contract MorphoBlueDebtAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* @param _amountToBorrow the amount of `loanToken` to borrow on the specified MB market.
*/
function borrowFromMorphoBlue(MarketParams memory _market, uint256 _amountToBorrow) public {
_validateMBMarket(_market);
_validateMBMarket(_market, identifier(), true);
Id id = MarketParamsLib.id(_market);
_borrowAsset(_market, _amountToBorrow, address(this));
if (minimumHealthFactor > (_getHealthFactor(id, _market))) {
Expand All @@ -147,7 +142,7 @@ contract MorphoBlueDebtAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* NOTE - MorphoBlue reverts w/ underflow/overflow error if trying to repay with more than what cellar has. That said, we will accomodate for times that strategists tries to pass in type(uint256).max.
*/
function repayMorphoBlueDebt(MarketParams memory _market, uint256 _debtTokenRepayAmount) public {
_validateMBMarket(_market);
_validateMBMarket(_market, identifier(), true);
Id id = MarketParamsLib.id(_market);
_accrueInterest(_market);
ERC20 tokenToRepay = ERC20(_market.loanToken);
Expand Down Expand Up @@ -178,24 +173,10 @@ contract MorphoBlueDebtAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* @param _market identifier of a Morpho Blue market.
*/
function accrueInterest(MarketParams memory _market) public {
_validateMBMarket(_market);
_validateMBMarket(_market, identifier(), true);
_accrueInterest(_market);
}

//============================================ Helper Functions ===========================================

/**
* @notice Validates that a given market is set up as a position in the Cellar.
* @dev This function uses `address(this)` as the address of the Cellar.
* @param _market MarketParams struct for a specific Morpho Blue market.
*/
function _validateMBMarket(MarketParams memory _market) internal view {
bytes32 positionHash = keccak256(abi.encode(identifier(), true, abi.encode(_market)));
uint32 positionId = Cellar(address(this)).registry().getPositionHashToPositionId(positionHash);
if (!Cellar(address(this)).isPositionUsed(positionId))
revert MorphoBlueDebtAdaptor__MarketPositionsMustBeTracked(_market);
}

//============================== Interface Details ==============================
// General message on interface and virtual functions below: The Morpho Blue protocol is meant to be a primitive layer to DeFi, and so other projects may build atop of MB. These possible future projects may implement the same interface to simply interact with MB, and thus this adaptor is implementing a design that allows for future adaptors to simply inherit this "Base Morpho Adaptor" and override what they need appropriately to work with whatever project. Aspects that may be adjusted include using the flexible `bytes` param within `morphoBlue.supplyCollateral()` for example.

Expand Down
20 changes: 20 additions & 0 deletions src/modules/adaptors/Morpho/MorphoBlue/MorphoBlueHelperLogic.sol
Expand Up @@ -7,6 +7,7 @@ import { SharesMathLib } from "src/interfaces/external/Morpho/MorphoBlue/librari
import { IOracle } from "src/interfaces/external/Morpho/MorphoBlue/interfaces/IOracle.sol";
import { UtilsLib } from "src/interfaces/external/Morpho/MorphoBlue/libraries/UtilsLib.sol";
import { MorphoLib } from "src/interfaces/external/Morpho/MorphoBlue/libraries/periphery/MorphoLib.sol";
import { Cellar } from "src/modules/adaptors/BaseAdaptor.sol";

/**
* @title Morpho Blue Helper contract.
Expand All @@ -22,6 +23,11 @@ contract MorphoBlueHelperLogic {
using SharesMathLib for uint256;
using MorphoLib for IMorpho;

/**
* @notice Attempted to interact with an Morpho Blue Lending Market the Cellar is not using.
*/
error MorphoBlueAdaptors__MarketPositionsMustBeTracked(MarketParams market);

/**
* @notice The Morpho Blue contract on current network.
*/
Expand Down Expand Up @@ -98,4 +104,18 @@ contract MorphoBlueHelperLogic {
function _accrueInterest(MarketParams memory _market) internal virtual {
morphoBlue.accrueInterest(_market);
}

/**
* @notice Validates that a given market is set up as a position in the Cellar.
* @dev This function uses `address(this)` as the address of the Cellar.
* @param _market MarketParams struct for a specific Morpho Blue market.
* @param _identifier Identifier unique to an adaptor for a shared registry.
* @param _isDebt Whether or not the respective position is a debt position.
*/
function _validateMBMarket(MarketParams memory _market, bytes32 _identifier, bool _isDebt) internal view {
bytes32 positionHash = keccak256(abi.encode(_identifier, _isDebt, abi.encode(_market)));
uint32 positionId = Cellar(address(this)).registry().getPositionHashToPositionId(positionHash);
if (!Cellar(address(this)).isPositionUsed(positionId))
revert MorphoBlueAdaptors__MarketPositionsMustBeTracked(_market);
}
}
22 changes: 5 additions & 17 deletions src/modules/adaptors/Morpho/MorphoBlue/MorphoBlueSupplyAdaptor.sol
Expand Up @@ -75,7 +75,7 @@ contract MorphoBlueSupplyAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
*/
function deposit(uint256 assets, bytes memory adaptorData, bytes memory) public override {
MarketParams memory market = abi.decode(adaptorData, (MarketParams));
_validateMBMarket(market);
_validateMBMarket(market, identifier(), false);
ERC20 loanToken = ERC20(market.loanToken);
loanToken.safeApprove(address(morphoBlue), assets);
_deposit(market, assets, address(this));
Expand Down Expand Up @@ -105,7 +105,7 @@ contract MorphoBlueSupplyAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
_externalReceiverCheck(receiver);
MarketParams memory market = abi.decode(adaptorData, (MarketParams));
// Withdraw assets from Morpho Blue.
_validateMBMarket(market);
_validateMBMarket(market, identifier(), false);
_withdraw(market, assets, receiver);
}

Expand Down Expand Up @@ -170,7 +170,7 @@ contract MorphoBlueSupplyAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* @param _assets the amount of loanToken to lend on specified MB market.
*/
function lendToMorphoBlue(MarketParams memory _market, uint256 _assets) public {
_validateMBMarket(_market);
_validateMBMarket(_market, identifier(), false);
ERC20 loanToken = ERC20(_market.loanToken);
_assets = _maxAvailable(loanToken, _assets);
loanToken.safeApprove(address(morphoBlue), _assets);
Expand All @@ -185,7 +185,7 @@ contract MorphoBlueSupplyAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* @param _assets the amount of loanToken to withdraw from MB market
*/
function withdrawFromMorphoBlue(MarketParams memory _market, uint256 _assets) public {
_validateMBMarket(_market);
_validateMBMarket(_market, identifier(), false);
Id _id = MarketParamsLib.id(_market);
if (_assets == type(uint256).max) {
uint256 _shares = _userSupplyShareBalance(_id, address(this));
Expand All @@ -206,22 +206,10 @@ contract MorphoBlueSupplyAdaptor is BaseAdaptor, MorphoBlueHelperLogic {
* @param _market identifier of a Morpho Blue market.
*/
function accrueInterest(MarketParams memory _market) public {
_validateMBMarket(_market);
_validateMBMarket(_market, identifier(), false);
_accrueInterest(_market);
}

/**
* @notice Validates that a given market is set up as a position in the Cellar.
* @dev This function uses `address(this)` as the address of the Cellar.
* @param _market MarketParams struct for a specific Morpho Blue market.
*/
function _validateMBMarket(MarketParams memory _market) internal view {
bytes32 positionHash = keccak256(abi.encode(identifier(), false, abi.encode(_market)));
uint32 positionId = Cellar(address(this)).registry().getPositionHashToPositionId(positionHash);
if (!Cellar(address(this)).isPositionUsed(positionId))
revert MorphoBlueSupplyAdaptor__MarketPositionsMustBeTracked(_market);
}

//============================================ Interface Helper Functions ===========================================

//============================== Interface Details ==============================
Expand Down
Expand Up @@ -518,7 +518,7 @@ contract MorphoBlueCollateralAndDebtTest is MainnetStarterTest, AdaptorHelperFun
vm.expectRevert(
bytes(
abi.encodeWithSelector(
MorphoBlueDebtAdaptor.MorphoBlueDebtAdaptor__MarketPositionsMustBeTracked.selector,
MorphoBlueHelperLogic.MorphoBlueAdaptors__MarketPositionsMustBeTracked.selector,
usdcDaiMarket
)
)
Expand Down Expand Up @@ -680,7 +680,7 @@ contract MorphoBlueCollateralAndDebtTest is MainnetStarterTest, AdaptorHelperFun
vm.expectRevert(
bytes(
abi.encodeWithSelector(
MorphoBlueDebtAdaptor.MorphoBlueDebtAdaptor__MarketPositionsMustBeTracked.selector,
MorphoBlueHelperLogic.MorphoBlueAdaptors__MarketPositionsMustBeTracked.selector,
wbtcUsdcMarket
)
)
Expand Down
5 changes: 3 additions & 2 deletions test/testAdaptors/MorphoBlue/MorphoBlueSupplyAdaptor.t.sol
Expand Up @@ -11,6 +11,7 @@ import { MarketParamsLib } from "src/interfaces/external/Morpho/MorphoBlue/libra
import { MorphoLib } from "src/interfaces/external/Morpho/MorphoBlue/libraries/periphery/MorphoLib.sol";
import { IrmMock } from "src/mocks/IrmMock.sol";
import "test/resources/MainnetStarter.t.sol";
import { MorphoBlueHelperLogic } from "src/modules/adaptors/Morpho/MorphoBlue/MorphoBlueHelperLogic.sol";

contract MorphoBlueSupplyAdaptorTest is MainnetStarterTest, AdaptorHelperFunctions {
using SafeTransferLib for ERC20;
Expand Down Expand Up @@ -478,7 +479,7 @@ contract MorphoBlueSupplyAdaptorTest is MainnetStarterTest, AdaptorHelperFunctio
vm.expectRevert(
bytes(
abi.encodeWithSelector(
MorphoBlueSupplyAdaptor.MorphoBlueSupplyAdaptor__MarketPositionsMustBeTracked.selector,
MorphoBlueHelperLogic.MorphoBlueAdaptors__MarketPositionsMustBeTracked.selector,
(UNTRUSTED_mbFakeMarket)
)
)
Expand All @@ -494,7 +495,7 @@ contract MorphoBlueSupplyAdaptorTest is MainnetStarterTest, AdaptorHelperFunctio
vm.expectRevert(
bytes(
abi.encodeWithSelector(
MorphoBlueSupplyAdaptor.MorphoBlueSupplyAdaptor__MarketPositionsMustBeTracked.selector,
MorphoBlueHelperLogic.MorphoBlueAdaptors__MarketPositionsMustBeTracked.selector,
(UNTRUSTED_mbFakeMarket)
)
)
Expand Down

0 comments on commit 2265d21

Please sign in to comment.