2021-04-05 00:33:23 +00:00
pragma solidity >= 0 . 7 . 0 ;
2021-04-15 10:39:23 +00:00
pragma experimental ABIEncoderV2 ;
2021-04-05 00:33:23 +00:00
import { DSMath } from " ../../common/math.sol " ;
2021-04-07 00:22:28 +00:00
import { SafeERC20 } from " @openzeppelin/contracts/token/ERC20/SafeERC20.sol " ;
import { IERC20 } from " @openzeppelin/contracts/token/ERC20/IERC20.sol " ;
2021-04-07 23:45:00 +00:00
import { Stores } from " ../../common/stores-polygon.sol " ;
import { Variables } from " ./variables.sol " ;
2021-04-07 00:22:28 +00:00
import {
TokenMappingInterface ,
AaveData ,
AaveDataProviderInterface ,
2021-04-12 06:02:42 +00:00
AaveInterface ,
AccountInterface
2021-04-07 00:22:28 +00:00
} from " ./interfaces.sol " ;
2021-04-05 00:33:23 +00:00
2021-04-07 23:45:00 +00:00
abstract contract Helpers is Stores , DSMath , Variables {
2021-04-07 00:22:28 +00:00
using SafeERC20 for IERC20 ;
2021-04-15 10:39:23 +00:00
struct TransferHelperData {
address token ;
address atoken ;
uint atokenBal ;
uint supplyAmt ;
uint tokenLiq ;
}
struct SpellHelperData {
address token ;
address atoken ;
uint tokenLiq ;
uint borrowAmt ;
}
2021-04-07 00:22:28 +00:00
function remapTokens ( AaveData memory data ) internal view returns ( AaveData memory ) {
2021-04-05 00:33:23 +00:00
for ( uint i = 0 ; i < data . supplyTokens . length ; i ++ ) {
data . supplyTokens [ i ] = tokenMapping . getMapping ( data . supplyTokens [ i ] ) ;
}
for ( uint i = 0 ; i < data . borrowTokens . length ; i ++ ) {
data . borrowTokens [ i ] = tokenMapping . getMapping ( data . borrowTokens [ i ] ) ;
}
return data ;
}
2021-04-07 00:22:28 +00:00
2021-04-15 22:38:01 +00:00
function getCollateralStatus ( address token , address user ) internal view returns ( bool enabled ) {
( uint bal , , , , , , , , bool isCol ) = aaveData . getUserReserveData ( token , user ) ;
enabled = bal > 0 && ! isCol ;
}
function isPositionSafe ( ) internal view returns ( bool isOk ) {
2021-04-12 06:02:42 +00:00
AaveInterface aave = AaveInterface ( aaveProvider . getLendingPool ( ) ) ;
( , , , , , uint healthFactor ) = aave . getUserAccountData ( address ( this ) ) ;
uint minLimit = wdiv ( 1 e18 , safeRatioGap ) ;
isOk = healthFactor > minLimit ;
2021-04-07 15:28:21 +00:00
require ( isOk , " position-at-risk " ) ;
}
2021-04-07 23:45:00 +00:00
function transferAtokens ( AaveInterface aave , address dsa , address [ ] memory supplyTokens , uint [ ] memory supplyAmts ) internal {
2021-04-07 00:22:28 +00:00
for ( uint i = 0 ; i < supplyTokens . length ; i ++ ) {
2021-04-15 10:39:23 +00:00
TransferHelperData memory data ;
data . token = supplyTokens [ i ] == maticAddr ? wmaticAddr : supplyTokens [ i ] ;
( data . atoken , , ) = aaveData . getReserveTokensAddresses ( data . token ) ;
IERC20 _atokenContract = IERC20 ( data . atoken ) ;
2021-04-15 20:41:39 +00:00
IERC20 _tokenContract = IERC20 ( data . token ) ;
2021-04-15 10:39:23 +00:00
data . atokenBal = _atokenContract . balanceOf ( address ( this ) ) ;
data . supplyAmt = supplyAmts [ i ] ;
( data . tokenLiq , , , , , , , , , ) = aaveData . getReserveData ( data . token ) ;
if ( data . atokenBal < data . supplyAmt ) {
uint _reqAmt = data . supplyAmt - data . atokenBal ;
uint num = _reqAmt / data . tokenLiq + 1 ; // TODO: Is this right
2021-04-07 00:22:28 +00:00
uint splitAmt = _reqAmt / num ; // TODO: Check decimal
uint finalSplit = _reqAmt - ( splitAmt * ( num - 1 ) ) ; // TODO: to resolve upper decimal error
2021-04-15 20:41:39 +00:00
_tokenContract . approve ( address ( aave ) , _reqAmt ) ;
2021-04-07 00:22:28 +00:00
for ( uint j = 0 ; j < num ; j ++ ) {
2021-04-12 06:02:42 +00:00
if ( j < num - 1 ) {
2021-04-15 10:39:23 +00:00
aave . borrow ( data . token , splitAmt , 2 , 3288 , address ( this ) ) ;
aave . deposit ( data . token , splitAmt , address ( this ) , 3288 ) ;
2021-04-15 22:38:01 +00:00
if ( j == 0 ) aave . setUserUseReserveAsCollateral ( data . token , true ) ;
2021-04-07 00:22:28 +00:00
} else {
2021-04-15 10:39:23 +00:00
aave . borrow ( data . token , finalSplit , 2 , 3288 , address ( this ) ) ;
aave . deposit ( data . token , finalSplit , address ( this ) , 3288 ) ;
2021-04-07 00:22:28 +00:00
}
}
}
2021-04-15 10:39:23 +00:00
_atokenContract . safeTransfer ( dsa , data . supplyAmt ) ;
2021-04-07 00:22:28 +00:00
}
}
2021-04-15 22:58:59 +00:00
function borrowAndTransferSpells ( address dsa , address [ ] memory supplyTokens , address [ ] memory borrowTokens , uint [ ] memory borrowAmts ) internal {
2021-04-07 00:22:28 +00:00
for ( uint i = 0 ; i < borrowTokens . length ; i ++ ) {
2021-04-15 10:39:23 +00:00
SpellHelperData memory data ;
data . token = borrowTokens [ i ] == maticAddr ? wmaticAddr : borrowTokens [ i ] ;
( data . atoken , , ) = aaveData . getReserveTokensAddresses ( data . token ) ;
( data . tokenLiq , , , , , , , , , ) = aaveData . getReserveData ( data . token ) ;
data . borrowAmt = borrowAmts [ i ] ;
2021-04-07 00:22:28 +00:00
// TODO: Check number of loops needed. Borrow and supply on user's account.
2021-04-15 10:39:23 +00:00
uint num = data . borrowAmt / data . tokenLiq + 1 ; // TODO: Is this right
uint splitAmt = data . borrowAmt / num ; // TODO: Check decimal
uint finalSplit = data . borrowAmt - ( splitAmt * ( num - 1 ) ) ; // TODO: to resolve upper decimal error
2021-04-07 00:22:28 +00:00
2021-04-15 22:48:05 +00:00
uint spellsAmt = num <= 1 ? ( 2 * ( num + 1 ) ) : ( 2 * ( num + 1 ) ) + 1 ;
2021-04-07 00:22:28 +00:00
string [ ] memory targets = new string [ ] ( spellsAmt ) ;
bytes [ ] memory castData = new bytes [ ] ( spellsAmt ) ;
2021-04-15 22:38:01 +00:00
targets [ 0 ] = " AAVE-V2-A " ;
castData [ 0 ] = abi . encodeWithSignature ( " enableCollateral(address[]) " , supplyTokens ) ;
2021-04-07 00:22:28 +00:00
for ( uint j = 0 ; j < num ; j ++ ) {
2021-04-15 22:48:05 +00:00
uint skip = 0 ;
uint k = j * 2 + 1 + skip ;
2021-04-07 00:22:28 +00:00
if ( i < num - 1 ) {
2021-04-13 23:10:01 +00:00
targets [ k ] = " AAVE-V2-A " ;
2021-04-15 10:39:23 +00:00
castData [ k ] = abi . encodeWithSignature ( " borrow(address,uint256,uint256,uint256,uint256) " , data . token , splitAmt , 2 , 0 , 0 ) ;
2021-04-13 23:10:01 +00:00
targets [ k + 1 ] = " AAVE-V2-A " ;
2021-04-15 10:39:23 +00:00
castData [ k + 1 ] = abi . encodeWithSignature ( " deposit(address,uint256,uint256,uint256) " , data . token , splitAmt , 0 , 0 ) ;
2021-04-15 22:48:05 +00:00
if ( j == 0 ) {
skip = 1 ;
2021-04-15 23:13:43 +00:00
targets [ k + 1 ] = " AAVE-V2-A " ;
address [ ] memory tokenArr = new address [ ] ( 1 ) ;
tokenArr [ i ] = data . token ;
castData [ k + 1 ] = abi . encodeWithSignature ( " enableCollateral(address[]) " , tokenArr ) ;
2021-04-15 22:48:05 +00:00
}
2021-04-07 00:22:28 +00:00
} else {
2021-04-13 23:10:01 +00:00
targets [ k ] = " AAVE-V2-A " ;
2021-04-15 10:39:23 +00:00
castData [ k ] = abi . encodeWithSignature ( " borrow(address,uint256,uint256,uint256,uint256) " , data . token , finalSplit , 2 , 0 , 0 ) ;
2021-04-13 23:10:01 +00:00
targets [ k + 1 ] = " AAVE-V2-A " ;
2021-04-15 10:39:23 +00:00
castData [ k + 1 ] = abi . encodeWithSignature ( " deposit(address,uint256,uint256,uint256) " , data . token , finalSplit , 0 , 0 ) ;
2021-04-07 00:22:28 +00:00
}
}
2021-04-07 23:45:00 +00:00
2021-04-15 23:13:43 +00:00
targets [ spellsAmt - 1 ] = " BASIC-A " ;
2021-04-15 22:52:33 +00:00
castData [ spellsAmt - 1 ] = abi . encodeWithSignature ( " withdraw(address,uint256,address,uint256,uint256) " , data . atoken , data . borrowAmt , address ( this ) , 0 , 0 ) ; // encode the data of atoken withdrawal
2021-04-12 06:02:42 +00:00
AccountInterface ( dsa ) . castMigrate ( targets , castData , address ( this ) ) ;
2021-04-07 00:22:28 +00:00
}
2021-04-07 23:45:00 +00:00
2021-04-07 00:22:28 +00:00
}
2021-04-05 00:33:23 +00:00
}