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?"
|
|
);
|
|
}
|
|
}
|