mirror of
				https://github.com/Instadapp/dsa-connectors.git
				synced 2024-07-29 22:37:00 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			223 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
| // SPDX-License-Identifier: MIT
 | |
| pragma solidity ^0.7.6;
 | |
| 
 | |
| import { DSMath } from "../../common/math.sol";
 | |
| import { Basic } from "../../common/basic.sol";
 | |
| import { TokenInterface, AccountInterface } from "../../common/interfaces.sol";
 | |
| import { ComptrollerInterface, CompoundMappingInterface, CETHInterface, CTokenInterface } from "./interface.sol";
 | |
| 
 | |
| abstract contract Helpers is DSMath, Basic {
 | |
| 	/**
 | |
| 	 * @dev Compound CEth
 | |
| 	 */
 | |
| 	CETHInterface internal constant cEth =
 | |
| 		CETHInterface(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5);
 | |
| 
 | |
| 	/**
 | |
| 	 * @dev Compound Comptroller
 | |
| 	 */
 | |
| 	ComptrollerInterface internal constant troller =
 | |
| 		ComptrollerInterface(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);
 | |
| 
 | |
| 	/**
 | |
| 	 * @dev Compound Mapping
 | |
| 	 */
 | |
| 	CompoundMappingInterface internal constant compMapping =
 | |
| 		CompoundMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88);
 | |
| 
 | |
| 	struct ImportData {
 | |
| 		address[] cTokens; // is the list of all tokens the user has interacted with (supply/borrow) -> used to enter markets
 | |
| 		uint256[] borrowAmts;
 | |
| 		uint256[] supplyAmts;
 | |
| 		address[] borrowTokens;
 | |
| 		address[] supplyTokens;
 | |
| 		CTokenInterface[] borrowCtokens;
 | |
| 		CTokenInterface[] supplyCtokens;
 | |
| 		address[] supplyCtokensAddr;
 | |
| 		address[] borrowCtokensAddr;
 | |
| 	}
 | |
| 
 | |
| 	struct ImportInputData {
 | |
| 		address userAccount;
 | |
| 		string[] supplyIds;
 | |
| 		string[] borrowIds;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @dev enter compound market
 | |
| 	 * @param _cotkens array of ctoken addresses to enter compound market
 | |
| 	 */
 | |
| 	function _enterMarkets(address[] memory _cotkens) internal {
 | |
| 		troller.enterMarkets(_cotkens);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| contract CompoundHelper is Helpers {
 | |
| 	/**
 | |
| 	 * @notice fetch the borrow details of the user
 | |
| 	 * @dev approve the cToken to spend (borrowed amount of) tokens to allow for repaying later
 | |
| 	 * @param _importInputData the struct containing borrowIds of the users borrowed tokens
 | |
| 	 * @param data struct used to store the final data on which the CompoundHelper contract functions operate
 | |
| 	 * @return ImportData the final value of param data
 | |
| 	 */
 | |
| 	function getBorrowAmounts(
 | |
| 		ImportInputData memory _importInputData,
 | |
| 		ImportData memory data
 | |
| 	) internal returns (ImportData memory) {
 | |
| 		if (_importInputData.borrowIds.length > 0) {
 | |
| 			// initialize arrays for borrow data
 | |
| 			uint256 _length = _importInputData.borrowIds.length;
 | |
| 			data.borrowTokens = new address[](_length);
 | |
| 			data.borrowCtokens = new CTokenInterface[](_length);
 | |
| 			data.borrowCtokensAddr = new address[](_length);
 | |
| 			data.borrowAmts = new uint256[](_length);
 | |
| 
 | |
| 			// populate the arrays with borrow tokens, cToken addresses and instances, and borrow amounts
 | |
| 			for (uint256 i; i < _length; i++) {
 | |
| 				(address _token, address _cToken) = compMapping.getMapping(
 | |
| 					_importInputData.borrowIds[i]
 | |
| 				);
 | |
| 
 | |
| 				require(
 | |
| 					_token != address(0) && _cToken != address(0),
 | |
| 					"ctoken mapping not found"
 | |
| 				);
 | |
| 
 | |
| 				data.cTokens[i] = _cToken;
 | |
| 
 | |
| 				data.borrowTokens[i] = _token;
 | |
| 				data.borrowCtokens[i] = CTokenInterface(_cToken);
 | |
| 				data.borrowCtokensAddr[i] = _cToken;
 | |
| 				data.borrowAmts[i] = data.borrowCtokens[i].borrowBalanceCurrent(
 | |
| 					_importInputData.userAccount
 | |
| 				);
 | |
| 
 | |
| 				// give the resp. cToken address approval to spend tokens
 | |
| 				if (_token != ethAddr && data.borrowAmts[i] > 0) {
 | |
| 					// will be required when repaying the borrow amount on behalf of the user
 | |
| 					TokenInterface(_token).approve(_cToken, data.borrowAmts[i]);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		return data;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @notice fetch the supply details of the user
 | |
| 	 * @dev only reads data from blockchain hence view
 | |
| 	 * @param _importInputData the struct containing supplyIds of the users supplied tokens
 | |
| 	 * @param data struct used to store the final data on which the CompoundHelper contract functions operate
 | |
| 	 * @return ImportData the final value of param data
 | |
| 	 */
 | |
| 	function getSupplyAmounts(
 | |
| 		ImportInputData memory _importInputData,
 | |
| 		ImportData memory data
 | |
| 	) internal view returns (ImportData memory) {
 | |
| 		// initialize arrays for supply data
 | |
| 		uint256 _length = _importInputData.supplyIds.length;
 | |
| 		data.supplyTokens = new address[](_length);
 | |
| 		data.supplyCtokens = new CTokenInterface[](_length);
 | |
| 		data.supplyCtokensAddr = new address[](_length);
 | |
| 		data.supplyAmts = new uint256[](_length);
 | |
| 
 | |
| 		// populate arrays with supply data (supply tokens address, cToken addresses, cToken instances and supply amounts)
 | |
| 		for (uint256 i; i < _length; i++) {
 | |
| 			(address _token, address _cToken) = compMapping.getMapping(
 | |
| 				_importInputData.supplyIds[i]
 | |
| 			);
 | |
| 
 | |
| 			require(
 | |
| 				_token != address(0) && _cToken != address(0),
 | |
| 				"ctoken mapping not found"
 | |
| 			);
 | |
| 
 | |
| 			uint256 _supplyIndex = add(i, _importInputData.borrowIds.length);
 | |
| 			data.cTokens[_supplyIndex] = _cToken;
 | |
| 
 | |
| 			data.supplyTokens[i] = _token;
 | |
| 			data.supplyCtokens[i] = CTokenInterface(_cToken);
 | |
| 			data.supplyCtokensAddr[i] = (_cToken);
 | |
| 			data.supplyAmts[i] = data.supplyCtokens[i].balanceOf(
 | |
| 				_importInputData.userAccount
 | |
| 			);
 | |
| 		}
 | |
| 		return data;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @notice repays the debt taken by user on Compound on its behalf to free its collateral for transfer
 | |
| 	 * @dev uses the cEth contract for ETH repays, otherwise the general cToken interface
 | |
| 	 * @param _userAccount the user address for which debt is to be repayed
 | |
| 	 * @param _cTokenContracts array containing all interfaces to the cToken contracts in which the user has debt positions
 | |
| 	 * @param _borrowAmts array containing the amount borrowed for each token
 | |
| 	 */
 | |
| 	function _repayUserDebt(
 | |
| 		address _userAccount,
 | |
| 		CTokenInterface[] memory _cTokenContracts,
 | |
| 		uint256[] memory _borrowAmts
 | |
| 	) internal {
 | |
| 		for (uint256 i; i < _cTokenContracts.length; i++) {
 | |
| 			if (_borrowAmts[i] > 0) {
 | |
| 				if (address(_cTokenContracts[i]) == address(cEth))
 | |
| 					cEth.repayBorrowBehalf{ value: _borrowAmts[i] }(
 | |
| 						_userAccount
 | |
| 					);
 | |
| 				else
 | |
| 					require(
 | |
| 						_cTokenContracts[i].repayBorrowBehalf(
 | |
| 							_userAccount,
 | |
| 							_borrowAmts[i]
 | |
| 						) == 0,
 | |
| 						"repayOnBehalf-failed"
 | |
| 					);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @notice used to transfer user's supply position on Compound to DSA
 | |
| 	 * @dev uses the transferFrom token in cToken contracts to transfer positions, requires approval from user first
 | |
| 	 * @param _userAccount address of the user account whose position is to be transferred
 | |
| 	 * @param _cTokenContracts array containing all interfaces to the cToken contracts in which the user has supply positions
 | |
| 	 * @param _amts array containing the amount supplied for each token
 | |
| 	 */
 | |
| 	function _transferTokensToDsa(
 | |
| 		address _userAccount,
 | |
| 		CTokenInterface[] memory _cTokenContracts,
 | |
| 		uint256[] memory _amts
 | |
| 	) internal {
 | |
| 		for (uint256 i; i < _cTokenContracts.length; i++)
 | |
| 			if (_amts[i] > 0)
 | |
| 				require(
 | |
| 					_cTokenContracts[i].transferFrom(
 | |
| 						_userAccount,
 | |
| 						address(this),
 | |
| 						_amts[i]
 | |
| 					),
 | |
| 					"ctoken-transfer-failed-allowance?"
 | |
| 				);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @notice borrows the user's debt positions from Compound via DSA, so that its debt positions get imported to DSA
 | |
| 	 * @dev actually borrow some extra amount than the original position to cover the flash loan fee
 | |
| 	 * @param _cTokenContracts array containing all interfaces to the cToken contracts in which the user has debt positions
 | |
| 	 * @param _amts array containing the amounts the user had borrowed originally from Compound plus the flash loan fee
 | |
| 	 * @param _flashLoanFees flash loan fee (in percentage and scaled up to 10**2)
 | |
| 	 */
 | |
| 	function _borrowDebtPosition(
 | |
| 		CTokenInterface[] memory _cTokenContracts,
 | |
| 		uint256[] memory _amts,
 | |
| 		uint256[] memory _flashLoanFees
 | |
| 	) internal {
 | |
| 		for (uint256 i; i < _cTokenContracts.length; i++)
 | |
| 			if (_amts[i] > 0)
 | |
| 				require(
 | |
| 					_cTokenContracts[i].borrow(
 | |
| 						add(_amts[i], _flashLoanFees[i])
 | |
| 					) == 0,
 | |
| 					"borrow-failed-collateral?"
 | |
| 				);
 | |
| 	}
 | |
| }
 | 
