dsa-polygon-migration/contracts/senders/aave-v2-migrator/helpers.sol
2021-04-11 19:41:11 +05:30

177 lines
6.8 KiB
Solidity

pragma solidity >=0.7.0;
pragma experimental ABIEncoderV2;
import { DSMath } from "../../common/math.sol";
import { Stores } from "../../common/stores-mainnet.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Variables } from "./variables.sol";
import {
AaveLendingPoolProviderInterface,
AaveDataProviderInterface,
AaveInterface,
ATokenInterface,
StateSenderInterface,
ReserveConfigurationMap
} from "./interfaces.sol";
abstract contract Helpers is DSMath, Stores, Variables {
using SafeERC20 for IERC20;
/**
* @dev Aave reserve configuration bit masks
*/
uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF;
uint256 constant DECIMALS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF;
uint256 constant LIQUIDATION_THRESHOLD_START_BIT_POSITION = 16;
uint256 constant RESERVE_DECIMALS_START_BIT_POSITION = 48;
/**
* @dev Additional math helpers
*/
uint256 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals
uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2;
function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) {
if (value == 0 || percentage == 0) {
return 0;
}
require(
value <= (type(uint256).max - HALF_PERCENT) / percentage,
"percent-mul-overflow"
);
return (value * percentage + HALF_PERCENT) / PERCENTAGE_FACTOR;
}
function _paybackBehalfOne(AaveInterface aave, address token, uint amt, uint rateMode, address user) private {
address _token = token == ethAddr ? wethAddr : token;
aave.repay(_token, amt, rateMode, user);
}
function _PaybackStable(
uint _length,
AaveInterface aave,
address[] memory tokens,
uint256[] memory amts,
address user
) internal {
for (uint i = 0; i < _length; i++) {
if (amts[i] > 0) {
_paybackBehalfOne(aave, tokens[i], amts[i], 1, user);
}
}
}
function _PaybackVariable(
uint _length,
AaveInterface aave,
address[] memory tokens,
uint256[] memory amts,
address user
) internal {
for (uint i = 0; i < _length; i++) {
if (amts[i] > 0) {
_paybackBehalfOne(aave, tokens[i], amts[i], 2, user);
}
}
}
function _PaybackCalculate(AaveInterface aave, AaveDataRaw memory _data, address sourceDsa) internal returns (uint[] memory stableBorrow, uint[] memory variableBorrow, uint[] memory totalBorrow) {
for (uint i = 0; i < _data.borrowTokens.length; i++) {
require(isSupportedToken[_data.borrowTokens[i]], "token-not-enabled");
address _token = _data.borrowTokens[i] == ethAddr ? wethAddr : _data.borrowTokens[i];
_data.borrowTokens[i] = _token;
(
,
uint stableDebt,
uint variableDebt,
,,,,,
) = aaveData.getUserReserveData(_token, sourceDsa);
stableBorrow[i] = _data.stableBorrowAmts[i] == uint(-1) ? stableDebt : _data.stableBorrowAmts[i];
variableBorrow[i] = _data.variableBorrowAmts[i] == uint(-1) ? variableDebt : _data.variableBorrowAmts[i];
totalBorrow[i] = add(stableBorrow[i], variableBorrow[i]);
if (totalBorrow[i] > 0) {
IERC20(_token).safeApprove(address(aave), totalBorrow[i]);
}
aave.borrow(_token, totalBorrow[i], 2, 3288, address(this));
}
}
function _getAtokens(address dsa, AaveInterface aave, address[] memory supplyTokens, uint[] memory supplyAmts) internal returns (uint[] memory finalAmts) {
for (uint i = 0; i < supplyTokens.length; i++) {
require(isSupportedToken[supplyTokens[i]], "token-not-enabled");
address _token = supplyTokens[i] == ethAddr ? wethAddr : supplyTokens[i];
(address _aToken, ,) = aaveData.getReserveTokensAddresses(_token);
ATokenInterface aTokenContract = ATokenInterface(_aToken);
uint _finalAmt;
if (supplyAmts[i] == uint(-1)) {
_finalAmt = aTokenContract.balanceOf(dsa);
} else {
_finalAmt = supplyAmts[i];
}
aTokenContract.transferFrom(dsa, address(this), finalAmts[i]);
_finalAmt = wmul(_finalAmt, fee);
finalAmts[i] = _finalAmt;
}
}
function _getParams(uint config) internal returns (
uint liqudationThreshold, uint decimals
) {
liqudationThreshold = (config & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION;
decimals = (config & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;
}
function isPositionSafe() internal returns (bool isOk) {
AaveInterface aave = AaveInterface(aaveProvider.getLendingPool());
(,,,,,uint healthFactor) = aave.getUserAccountData(address(this));
uint minLimit = wdiv(1e18, safeRatioGap);
isOk = healthFactor > minLimit;
require(isOk, "position-at-risk");
}
function _checkRatio(AaveData memory data) public returns (bool isOk) {
uint totalCollateral;
uint totalDebt;
uint avgLiquidationThresold;
for(uint i = 0; i < data.supplyTokens.length; i++) {
address _token = data.supplyTokens[i] == ethAddr ? wethAddr : data.supplyTokens[i];
ReserveConfigurationMap memory config = aave.getConfiguration(_token);
(uint _liq, uint _dec) = _getParams(config.data);
uint assetPrice = aaveOracle.getAssetPrice(_token);
uint collateral = div(mul(assetPrice, data.supplyAmts[i]), 10**_dec);
totalCollateral += collateral;
avgLiquidationThresold += mul(collateral, _liq);
}
for(uint i = 0; data.borrowTokens.length; i++) {
address _token = data.supplyTokens[i] == ethAddr ? wethAddr : data.supplyTokens[i];
ReserveConfigurationMap memory config = aave.getConfiguration(_token);
(, uint _dec) = _getParams(config.data);
uint assetPrice = aaveOracle.getAssetPrice(_token);
uint debt = div(mul(assetPrice, data.borrowAmts[i]), 10**_dec);
totalDebt += debt;
}
if (totalCollateral > 0) {
avgLiquidationThresold = div(avgLiquidationThresold, totalCollateral);
}
uint healthFactor = wdiv(percentMul(totalCollateral, avgLiquidationThresold), totalDebt);
uint minLimit = wdiv(1e18, safeRatioGap);
isOk = healthFactor > minLimit;
require(isOk, "position-at-risk");
}
}