diff --git a/contracts/mainnet/connectors/morpho-compound/events.sol b/contracts/mainnet/connectors/morpho-compound/events.sol new file mode 100644 index 00000000..47779061 --- /dev/null +++ b/contracts/mainnet/connectors/morpho-compound/events.sol @@ -0,0 +1,39 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +contract Events { + event LogDeposit( + address tokenAddress, + address poolTokenAddress, + uint256 amount, + uint256 getId, + uint256 setId + ); + + event LogBorrow( + bool isETH, + address poolTokenAddress, + uint256 amount, + uint256 getId, + uint256 setId + ); + + event LogWithdraw( + bool isETH, + address poolTokenAddress, + uint256 amt, + uint256 getId, + uint256 setId + ); + + event LogPayback( + bool isETH, + address poolTokenAddress, + uint256 amt, + uint256 getId, + uint256 setId + ); + + event LogClaimed(address[] tokenAddresses, bool tradeForMorphoToken); +} diff --git a/contracts/mainnet/connectors/morpho-compound/helpers.sol b/contracts/mainnet/connectors/morpho-compound/helpers.sol new file mode 100644 index 00000000..0ba31604 --- /dev/null +++ b/contracts/mainnet/connectors/morpho-compound/helpers.sol @@ -0,0 +1,15 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; +import "./interface.sol"; +import "../../common/stores.sol"; +import "../../common/basic.sol"; +import "../../common/interfaces.sol"; + +abstract contract Helpers is Stores, Basic { + IMorphoCore public constant morphoCompound = + IMorphoCore(0x8888882f8f843896699869179fB6E4f7e3B58888); + + IMorphoCompoundLens public constant morphoCompoundLens = + IMorphoCompoundLens(0x930f1b46e1D081Ec1524efD95752bE3eCe51EF67); +} diff --git a/contracts/mainnet/connectors/morpho-compound/interface.sol b/contracts/mainnet/connectors/morpho-compound/interface.sol new file mode 100644 index 00000000..acb46a7d --- /dev/null +++ b/contracts/mainnet/connectors/morpho-compound/interface.sol @@ -0,0 +1,60 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +interface IMorphoCore { + function supply( + address _poolTokenAddress, + address _onBehalf, + uint256 _amount + ) external; + + function borrow(address _poolTokenAddress, uint256 _amount) external; + + function withdraw(address _poolTokenAddress, uint256 _amount) external; + + function repay( + address _poolTokenAddress, + address _onBehalf, + uint256 _amount + ) external; + + function liquidate( + address _poolTokenBorrowedAddress, + address _poolTokenCollateralAddress, + address _borrower, + uint256 _amount + ) external; + + // (For AAVEV2: (aToken or variable debt token), COMPOUNDV2: cToken addresses) + function claimRewards( + address[] calldata _tokenAddresses, + bool _tradeForMorphoToken + ) external; +} + +interface IMorphoCompoundLens { + function getCurrentBorrowBalanceInOf( + address _poolTokenAddress, + address _user + ) + external + view + returns ( + uint256 balanceOnPool, + uint256 balanceInP2P, + uint256 totalBalance + ); + + function getCurrentSupplyBalanceInOf( + address _poolTokenAddress, + address _user + ) + external + view + returns ( + uint256 balanceOnPool, + uint256 balanceInP2P, + uint256 totalBalance + ); +} diff --git a/contracts/mainnet/connectors/morpho-compound/main.sol b/contracts/mainnet/connectors/morpho-compound/main.sol new file mode 100644 index 00000000..1bc3b903 --- /dev/null +++ b/contracts/mainnet/connectors/morpho-compound/main.sol @@ -0,0 +1,221 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; +import "./helpers.sol"; +import "./events.sol"; + +abstract contract MorphoCompound is Helpers, Events { + /** + * @dev Deposit ETH/ERC20_Token. + * @notice Deposit a token to Morpho Compound for lending / collaterization. + * @param _tokenAddress The address of underlying token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param _poolTokenAddress The address of cToken to deposit.(For ETH: cWETH address) + * @param _amount The amount of the token (in underlying) to deposit. (For max: `uint256(-1)`) + * @param _getId ID to retrieve amt. + * @param _setId ID stores the amount of tokens deposited. + */ + function deposit( + address _tokenAddress, + address _poolTokenAddress, + uint256 _amount, + // uint256 _maxGasForMatching, // optional + uint256 _getId, + uint256 _setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(_getId, _amount); + + bool _isETH = _tokenAddress == ethAddr; + + TokenInterface _tokenContract = _isETH + ? TokenInterface(wethAddr) + : TokenInterface(_tokenAddress); + + if (_amt == uint256(-1)) { + _amt = _isETH + ? address(this).balance + : _tokenContract.balanceOf(address(this)); + } + + if (_isETH) convertEthToWeth(_isETH, _tokenContract, _amt); + + approve(_tokenContract, address(morphoCompound), _amt); + morphoCompound.supply(_poolTokenAddress, address(this), _amt); + + setUint(_setId, _amt); + + _eventName = "LogDeposit(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode( + _tokenAddress, + _poolTokenAddress, + _amt, + // _maxGasForMatching, + _getId, + _setId + ); + } + + /** + * @dev Borrow ETH/ERC20_Token. + * @notice Borrow a token from Morpho Compound. + * @param _tokenAddress The address of underlying token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param _poolTokenAddress The address of cToken to borrow.(For ETH: cWETH address) + * @param _amount The amount of the token (in underlying) to borrow. + * @param _getId ID to retrieve amt. + * @param _setId ID stores the amount of tokens borrowed. + */ + function borrow( + address _tokenAddress, + address _poolTokenAddress, + uint256 _amount, + // uint256 _maxGasForMatching, + uint256 _getId, + uint256 _setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(_getId, _amount); + + bool _isETH = _tokenAddress == ethAddr; + + morphoCompound.borrow(_poolTokenAddress, _amt); + + if (_isETH) convertWethToEth(_isETH, TokenInterface(wethAddr), _amt); + + setUint(_setId, _amt); + + _eventName = "LogBorrow(bool,address,uint256,uint256,uint256)"; + _eventParam = abi.encode( + _isETH, + _poolTokenAddress, + _amt, + // _maxGasForMatching, + _getId, + _setId + ); + } + + /** + * @dev Withdraw ETH/ERC20_Token. + * @notice Withdraw a token from Morpho Compound. + * @param _tokenAddress The address of underlying token to withdraw.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param _poolTokenAddress The address of cToken to withdraw.(For ETH: cWETH address) + * @param _amount The amount of the token (in underlying) to withdraw. (For max: `uint256(-1)`) + * @param _getId ID to retrieve amt. + * @param _setId ID stores the amount of tokens withdrawed. + */ + function withdraw( + address _tokenAddress, + address _poolTokenAddress, + uint256 _amount, + uint256 _getId, + uint256 _setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + uint256 _amt = getUint(_getId, _amount); + bool _isETH = _tokenAddress == ethAddr; + address _token = _isETH ? wethAddr : _tokenAddress; + + if (_amt == uint256(-1)) + (, , _amt) = morphoCompoundLens.getCurrentSupplyBalanceInOf( + _poolTokenAddress, + address(this) + ); + + morphoCompound.withdraw(_poolTokenAddress, _amt); + + convertWethToEth(_isETH, TokenInterface(_token), _amt); + + setUint(_setId, _amt); + + _eventName = "LogWithdraw(bool,address,uint256,uint256,uint256)"; + _eventParam = abi.encode( + _isETH, + _poolTokenAddress, + _amt, + _getId, + _setId + ); + } + + /** + * @dev Payback ETH/ERC20_Token. + * @notice Payback a token to Morpho Compound. + * @param _tokenAddress The address of underlying token to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param _poolTokenAddress The address of cToken to payback.(For ETH: cWETH address) + * @param _amount The amount of the token (in underlying) to payback. (For max: `uint256(-1)`) + * @param _getId ID to retrieve amt. + * @param _setId ID stores the amount of tokens paid back. + */ + function payback( + address _tokenAddress, + address _poolTokenAddress, + uint256 _amount, + uint256 _getId, + uint256 _setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + bool _isETH = _tokenAddress == ethAddr; + uint256 _amt = getUint(_getId, _amount); + address _token = _isETH ? wethAddr : _tokenAddress; + + if (_amt == uint256(-1)) { + (, , _amt) = morphoCompoundLens.getCurrentBorrowBalanceInOf( + _poolTokenAddress, + address(this) + ); + } + + if (_isETH) convertEthToWeth(_isETH, TokenInterface(_token), _amt); + + approve(TokenInterface(_token), address(morphoCompound), _amt); + + morphoCompound.repay(_poolTokenAddress, address(this), _amt); + + setUint(_setId, _amt); + + _eventName = "LogPayback(bool,address,uint256,uint256,uint256)"; + _eventParam = abi.encode( + _isETH, + _poolTokenAddress, + _amt, + _getId, + _setId + ); + } + + /** + * @dev Claim rewards. + * @notice Claim rewards for the given assets from underlying protocol. + * @param _poolTokenAddresses The cToken addresses to claim rewards from..(For ETH: cToken address of WETH) + * @param _tradeForMorphoToken Whether or not to trade COMP tokens for MORPHO tokens. + */ + function claim( + address[] calldata _poolTokenAddresses, + bool _tradeForMorphoToken + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + morphoCompound.claimRewards(_poolTokenAddresses, _tradeForMorphoToken); + + _eventName = "LogClaimed(address[],bool)"; + _eventParam = abi.encode(_poolTokenAddresses, _tradeForMorphoToken); + } +} + +contract ConnectV2MorphoCompound is MorphoCompound { + string public constant name = "Morpho-Compound-v1.0"; +}