2023-12-16 12:33:50 +00:00
|
|
|
//SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity ^0.8.2;
|
|
|
|
|
2023-12-16 12:38:07 +00:00
|
|
|
import {Id, IMorpho, MarketParams, Position, Market} from "./interfaces/IMorpho.sol";
|
2023-12-16 12:33:50 +00:00
|
|
|
import "../../common/stores.sol";
|
|
|
|
import "../../common/basic.sol";
|
|
|
|
import "../../common/interfaces.sol";
|
2023-12-16 12:38:07 +00:00
|
|
|
import {MorphoBalancesLib} from "./libraries/periphery/MorphoBalancesLib.sol";
|
2024-01-10 18:04:11 +00:00
|
|
|
import {MorphoLib} from "./libraries/periphery/MorphoLib.sol";
|
2023-12-16 12:38:07 +00:00
|
|
|
import {UtilsLib} from "./libraries/UtilsLib.sol";
|
|
|
|
import {MarketParamsLib} from "./libraries/MarketParamsLib.sol";
|
2023-12-16 13:30:43 +00:00
|
|
|
import {SharesMathLib} from "./libraries/SharesMathLib.sol";
|
2023-12-16 12:33:50 +00:00
|
|
|
|
|
|
|
abstract contract Helpers is Stores, Basic {
|
2023-12-16 12:38:07 +00:00
|
|
|
using MorphoBalancesLib for IMorpho;
|
2024-01-10 18:04:11 +00:00
|
|
|
using MorphoLib for IMorpho;
|
2023-12-16 12:38:07 +00:00
|
|
|
using MarketParamsLib for MarketParams;
|
|
|
|
using UtilsLib for uint256;
|
2023-12-16 13:30:43 +00:00
|
|
|
using SharesMathLib for uint256;
|
2023-12-16 12:38:07 +00:00
|
|
|
|
|
|
|
IMorpho public constant MORPHO_BLUE =
|
|
|
|
IMorpho(0x777777c9898D384F785Ee44Acfe945efDFf5f3E0); // TODO: Update
|
|
|
|
|
|
|
|
uint256 internal constant MARKET_PARAMS_BYTES_LENGTH = 5 * 32;
|
|
|
|
|
|
|
|
/// @dev The number of virtual assets of 1 enforces a conversion rate between shares and assets when a market is
|
|
|
|
/// empty.
|
|
|
|
uint256 internal constant VIRTUAL_ASSETS = 1;
|
|
|
|
|
|
|
|
/// @dev The number of virtual shares has been chosen low enough to prevent overflows, and high enough to ensure
|
|
|
|
/// high precision computations.
|
|
|
|
uint256 internal constant VIRTUAL_SHARES = 1e6;
|
|
|
|
|
|
|
|
enum Mode {
|
|
|
|
Collateral,
|
|
|
|
Repay,
|
|
|
|
Supply
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @notice Handles Eth to Weth conversion if assets are provided.
|
|
|
|
function _performEthToWethConversion(
|
|
|
|
MarketParams memory _marketParams,
|
|
|
|
uint256 _assets,
|
|
|
|
address _onBehalf,
|
|
|
|
uint256 _getId,
|
|
|
|
Mode _mode
|
2023-12-16 13:30:43 +00:00
|
|
|
) internal returns (Id _id, MarketParams memory, uint256 _amt) {
|
2023-12-16 12:38:07 +00:00
|
|
|
_amt = getUint(_getId, _assets);
|
|
|
|
|
2023-12-16 15:52:19 +00:00
|
|
|
bool _isModeCollateral = _mode == Mode.Collateral;
|
|
|
|
|
|
|
|
bool _isEth = _isModeCollateral
|
2023-12-16 12:38:07 +00:00
|
|
|
? _marketParams.collateralToken == ethAddr
|
|
|
|
: _marketParams.loanToken == ethAddr;
|
|
|
|
|
|
|
|
_marketParams = updateTokenAddresses(_marketParams);
|
|
|
|
|
2023-12-16 13:30:43 +00:00
|
|
|
_id = _marketParams.id();
|
|
|
|
|
2023-12-16 12:38:07 +00:00
|
|
|
// Check for max value
|
|
|
|
if (_assets == type(uint256).max) {
|
2023-12-16 15:52:19 +00:00
|
|
|
uint256 _maxBalance = _isEth
|
2023-12-16 12:38:07 +00:00
|
|
|
? address(this).balance
|
2023-12-16 15:52:19 +00:00
|
|
|
: _isModeCollateral
|
|
|
|
? TokenInterface(_marketParams.collateralToken).balanceOf(
|
|
|
|
address(this)
|
|
|
|
)
|
2023-12-16 12:38:07 +00:00
|
|
|
: TokenInterface(_marketParams.loanToken).balanceOf(
|
|
|
|
address(this)
|
|
|
|
);
|
2023-12-16 15:52:19 +00:00
|
|
|
|
2023-12-16 12:38:07 +00:00
|
|
|
if (_mode == Mode.Repay) {
|
2023-12-16 15:52:19 +00:00
|
|
|
uint256 _amtDebt = getPaybackBalance(
|
|
|
|
_id,
|
|
|
|
_marketParams,
|
|
|
|
_onBehalf
|
|
|
|
);
|
|
|
|
|
|
|
|
_amt = UtilsLib.min(_maxBalance, _amtDebt);
|
2023-12-16 12:38:07 +00:00
|
|
|
} else {
|
2023-12-16 15:52:19 +00:00
|
|
|
_amt = _maxBalance;
|
2023-12-16 12:38:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-16 15:52:19 +00:00
|
|
|
// Perform eth to weth conversion if necessary
|
|
|
|
convertEthToWeth(
|
2024-01-10 18:04:11 +00:00
|
|
|
_isEth,
|
2023-12-16 15:52:19 +00:00
|
|
|
_isModeCollateral
|
|
|
|
? TokenInterface(_marketParams.collateralToken)
|
|
|
|
: TokenInterface(_marketParams.loanToken),
|
|
|
|
_amt
|
|
|
|
);
|
2023-12-16 12:38:07 +00:00
|
|
|
|
2023-12-16 13:30:43 +00:00
|
|
|
return (_id, _marketParams, _amt);
|
2023-12-16 12:38:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @notice Handles Eth to Weth conversion if shares are provided.
|
|
|
|
function _performEthToWethSharesConversion(
|
|
|
|
MarketParams memory _marketParams,
|
|
|
|
uint256 _shares,
|
|
|
|
address _onBehalf,
|
|
|
|
uint256 _getId,
|
|
|
|
bool _isRepay
|
2023-12-16 13:30:43 +00:00
|
|
|
) internal returns (Id _id, MarketParams memory, uint256 _assets) {
|
2023-12-16 12:38:07 +00:00
|
|
|
uint256 _shareAmt = getUint(_getId, _shares);
|
|
|
|
bool _isEth = _marketParams.loanToken == ethAddr;
|
|
|
|
|
|
|
|
_marketParams = updateTokenAddresses(_marketParams);
|
|
|
|
|
2023-12-16 13:30:43 +00:00
|
|
|
_id = _marketParams.id();
|
|
|
|
|
2023-12-16 12:38:07 +00:00
|
|
|
// Handle the max share case
|
|
|
|
if (_shares == type(uint256).max) {
|
2023-12-16 15:52:19 +00:00
|
|
|
uint256 _maxBalance = _isEth
|
2023-12-16 12:38:07 +00:00
|
|
|
? address(this).balance
|
|
|
|
: TokenInterface(_marketParams.loanToken).balanceOf(
|
|
|
|
address(this)
|
|
|
|
);
|
|
|
|
|
|
|
|
// If it's repay calculate the min of balance available and debt to repay
|
|
|
|
if (_isRepay) {
|
2023-12-16 15:52:19 +00:00
|
|
|
_assets = UtilsLib.min(
|
|
|
|
_maxBalance,
|
|
|
|
getPaybackBalance(_id, _marketParams, _onBehalf)
|
|
|
|
);
|
2023-12-16 12:38:07 +00:00
|
|
|
} else {
|
2023-12-16 15:52:19 +00:00
|
|
|
_assets = _maxBalance;
|
2023-12-16 12:38:07 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
(
|
|
|
|
uint256 totalSupplyAssets,
|
|
|
|
uint256 totalSupplyShares,
|
2023-12-16 15:52:19 +00:00
|
|
|
uint256 totalBorrowAssets,
|
|
|
|
uint256 totalBorrowShares
|
2023-12-16 12:38:07 +00:00
|
|
|
) = MORPHO_BLUE.expectedMarketBalances(_marketParams);
|
|
|
|
|
2023-12-16 15:52:19 +00:00
|
|
|
if (_isRepay) {
|
|
|
|
_assets = _shareAmt.toAssetsUp(
|
|
|
|
totalBorrowAssets,
|
|
|
|
totalBorrowShares
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
_assets = _shareAmt.toAssetsUp(
|
|
|
|
totalSupplyAssets,
|
|
|
|
totalSupplyShares
|
|
|
|
);
|
|
|
|
}
|
2023-12-16 12:38:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Perform ETH to WETH conversion if necessary
|
|
|
|
convertEthToWeth(
|
2024-01-10 18:04:11 +00:00
|
|
|
_isEth,
|
2023-12-16 12:38:07 +00:00
|
|
|
TokenInterface(_marketParams.loanToken),
|
|
|
|
_assets
|
|
|
|
);
|
|
|
|
|
2023-12-16 13:30:43 +00:00
|
|
|
return (_id, _marketParams, _assets);
|
2023-12-16 12:38:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @notice Returns the payback balance in assets.
|
|
|
|
function getPaybackBalance(
|
2023-12-16 13:30:43 +00:00
|
|
|
Id _id,
|
2023-12-16 12:38:07 +00:00
|
|
|
MarketParams memory _marketParams,
|
|
|
|
address _onBehalf
|
|
|
|
) internal view returns (uint256 _assets) {
|
2024-01-10 18:04:11 +00:00
|
|
|
uint256 _borrowedShareAmt = MORPHO_BLUE.borrowShares(_id, _onBehalf);
|
2023-12-16 12:38:07 +00:00
|
|
|
|
2023-12-16 15:52:19 +00:00
|
|
|
(, , uint256 totalBorrowAssets, uint256 totalBorrowShares) = MORPHO_BLUE
|
2023-12-16 12:38:07 +00:00
|
|
|
.expectedMarketBalances(_marketParams);
|
|
|
|
|
2023-12-16 15:52:19 +00:00
|
|
|
_assets = _borrowedShareAmt.toAssetsUp(
|
|
|
|
totalBorrowAssets,
|
|
|
|
totalBorrowShares
|
|
|
|
);
|
2023-12-16 12:38:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function updateTokenAddresses(
|
|
|
|
MarketParams memory _marketParams
|
|
|
|
) internal pure returns (MarketParams memory) {
|
|
|
|
_marketParams.loanToken = _marketParams.loanToken == ethAddr
|
|
|
|
? wethAddr
|
|
|
|
: _marketParams.loanToken;
|
|
|
|
|
|
|
|
_marketParams.collateralToken = _marketParams.collateralToken == ethAddr
|
|
|
|
? wethAddr
|
|
|
|
: _marketParams.collateralToken;
|
|
|
|
|
|
|
|
return _marketParams;
|
|
|
|
}
|
2023-12-16 12:33:50 +00:00
|
|
|
}
|