2021-04-05 00:33:23 +00:00
pragma solidity >= 0 . 7 . 0 ;
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 ;
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-12 06:02:42 +00:00
address _token = supplyTokens [ i ] == maticAddr ? wmaticAddr : supplyTokens [ i ] ;
( address _aToken , , ) = aaveData . getReserveTokensAddresses ( _token ) ;
IERC20 _atokenContract = IERC20 ( _aToken ) ;
2021-04-07 00:22:28 +00:00
uint _atokenBal = _atokenContract . balanceOf ( address ( this ) ) ;
uint _supplyAmt = supplyAmts [ i ] ;
bool isFlash ;
uint _flashAmt ;
2021-04-12 06:02:42 +00:00
( uint tokenLiq , , , , , , , , , ) = aaveData . getReserveData ( _token ) ;
2021-04-07 00:22:28 +00:00
if ( _atokenBal < _supplyAmt ) {
uint _reqAmt = _supplyAmt - _atokenBal ;
if ( tokenLiq < _reqAmt ) {
_flashAmt = flashAmts [ _token ] ;
if ( _flashAmt > 0 ) {
2021-04-07 23:45:00 +00:00
aave . deposit ( _token , _flashAmt , address ( this ) , 3288 ) ; // TODO: what is our ID on Polygon?
2021-04-07 00:22:28 +00:00
tokenLiq += _flashAmt ;
isFlash = true ;
}
}
uint num = _reqAmt / tokenLiq + 1 ; // TODO: Is this right
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 ) {
aave . borrow ( _token , splitAmt , 2 , 3288 , address ( this ) ) ;
2021-04-07 00:22:28 +00:00
aave . deposit ( _token , splitAmt , address ( this ) , 3288 ) ;
} else {
2021-04-12 06:02:42 +00:00
aave . borrow ( _token , finalSplit , 2 , 3288 , address ( this ) ) ;
2021-04-07 00:22:28 +00:00
aave . deposit ( _token , finalSplit , address ( this ) , 3288 ) ;
}
}
}
if ( isFlash ) {
aave . withdraw ( _token , _flashAmt , address ( this ) ) ;
}
_atokenContract . safeTransfer ( dsa , _supplyAmt ) ;
}
}
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-14 20:14:33 +00:00
address _token = borrowTokens [ i ] == maticAddr ? wmaticAddr : borrowTokens [ i ] ;
2021-04-12 06:02:42 +00:00
( address _atoken , , ) = aaveData . getReserveTokensAddresses ( _token ) ;
( uint tokenLiq , , , , , , , , , ) = aaveData . getReserveData ( _token ) ;
2021-04-07 00:22:28 +00:00
uint _borrowAmt = borrowAmts [ i ] ;
2021-04-07 23:45:00 +00:00
uint _flashAmt ;
bool isFlash ;
2021-04-07 00:22:28 +00:00
if ( tokenLiq < _borrowAmt ) {
2021-04-07 23:45:00 +00:00
_flashAmt = flashAmts [ _token ] ;
aave . deposit ( _token , _flashAmt , address ( this ) , 3288 ) ; // TODO: what is our ID on Polygon?
isFlash = true ;
2021-04-07 00:22:28 +00:00
tokenLiq += _flashAmt ;
}
// TODO: Check number of loops needed. Borrow and supply on user's account.
uint num = _borrowAmt / tokenLiq + 1 ; // TODO: Is this right
uint splitAmt = _borrowAmt / num ; // TODO: Check decimal
uint finalSplit = _borrowAmt - ( splitAmt * ( num - 1 ) ) ; // TODO: to resolve upper decimal error
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-13 23:08:56 +00:00
castData [ k ] = abi . encodeWithSignature ( " borrow(address,uint256,uint256,uint256,uint256) " , _token , splitAmt , 2 , 0 , 0 ) ;
2021-04-13 23:10:01 +00:00
targets [ k + 1 ] = " AAVE-V2-A " ;
2021-04-13 23:31:59 +00:00
castData [ k + 1 ] = abi . encodeWithSignature ( " deposit(address,uint256,uint256,uint256) " , _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-13 23:08:56 +00:00
castData [ k ] = abi . encodeWithSignature ( " borrow(address,uint256,uint256,uint256,uint256) " , _token , finalSplit , 2 , 0 , 0 ) ;
2021-04-13 23:10:01 +00:00
targets [ k + 1 ] = " AAVE-V2-A " ;
2021-04-13 23:31:59 +00:00
castData [ k + 1 ] = abi . encodeWithSignature ( " deposit(address,uint256,uint256,uint256) " , _token , finalSplit , 0 , 0 ) ;
2021-04-07 00:22:28 +00:00
}
}
2021-04-07 23:45:00 +00:00
if ( isFlash ) {
aave . withdraw ( _token , _flashAmt , address ( this ) ) ;
}
2021-04-07 00:22:28 +00:00
targets [ spellsAmt ] = " BASIC-A " ; // TODO: right spell?
2021-04-13 23:30:02 +00:00
castData [ spellsAmt ] = abi . encode ( " withdraw(address,uint256,address,uint256,uint256) " , _atoken , _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
}