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 flashAmt ;
uint tokenLiq ;
bool isFlash ;
}
struct SpellHelperData {
address token ;
address atoken ;
uint tokenLiq ;
uint borrowAmt ;
uint flashAmt ;
bool isFlash ;
}
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-07 15:28:21 +00:00
function isPositionSafe ( ) internal 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 ) ;
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 ;
if ( data . tokenLiq < _reqAmt ) {
data . flashAmt = flashAmts [ data . token ] ;
if ( data . flashAmt > 0 ) {
aave . deposit ( data . token , data . flashAmt , address ( this ) , 3288 ) ; // TODO: what is our ID on Polygon?
data . tokenLiq += data . flashAmt ;
data . isFlash = true ;
2021-04-07 00:22:28 +00:00
}
}
2021-04-15 10:39:23 +00:00
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
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-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
if ( data . isFlash ) {
aave . withdraw ( data . token , data . flashAmt , address ( this ) ) ;
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-07 23:45:00 +00:00
function borrowAndTransferSpells ( AaveInterface aave , address dsa , 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 ] ;
if ( data . tokenLiq < data . borrowAmt ) {
data . flashAmt = flashAmts [ data . token ] ;
aave . deposit ( data . token , data . flashAmt , address ( this ) , 3288 ) ; // TODO: what is our ID on Polygon?
data . isFlash = true ;
data . tokenLiq += data . flashAmt ;
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
uint spellsAmt = ( 2 * num ) + 1 ;
string [ ] memory targets = new string [ ] ( spellsAmt ) ;
bytes [ ] memory castData = new bytes [ ] ( spellsAmt ) ;
for ( uint j = 0 ; j < num ; j ++ ) {
uint k = j * 2 ;
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-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 10:39:23 +00:00
if ( data . isFlash ) {
aave . withdraw ( data . token , data . flashAmt , address ( this ) ) ;
2021-04-07 23:45:00 +00:00
}
2021-04-07 00:22:28 +00:00
targets [ spellsAmt ] = " BASIC-A " ; // TODO: right spell?
2021-04-15 10:39:23 +00:00
castData [ spellsAmt ] = abi . encode ( " 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
}