diff --git a/contracts/protocols/aave_v2_amm.sol b/contracts/protocols/aave_v2_amm.sol new file mode 100644 index 0000000..7b9f693 --- /dev/null +++ b/contracts/protocols/aave_v2_amm.sol @@ -0,0 +1,307 @@ +pragma solidity ^0.6.0; +pragma experimental ABIEncoderV2; + +interface AaveProtocolDataProvider { + function getUserReserveData(address asset, address user) external view returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); + + function getReserveConfigurationData(address asset) external view returns ( + uint256 decimals, + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus, + uint256 reserveFactor, + bool usageAsCollateralEnabled, + bool borrowingEnabled, + bool stableBorrowRateEnabled, + bool isActive, + bool isFrozen + ); + + function getReserveData(address asset) external view returns ( + uint256 availableLiquidity, + uint256 totalStableDebt, + uint256 totalVariableDebt, + uint256 liquidityRate, + uint256 variableBorrowRate, + uint256 stableBorrowRate, + uint256 averageStableBorrowRate, + uint256 liquidityIndex, + uint256 variableBorrowIndex, + uint40 lastUpdateTimestamp + ); +} + +interface AaveLendingPool { + function getUserAccountData(address user) external view returns ( + uint256 totalCollateralETH, + uint256 totalDebtETH, + uint256 availableBorrowsETH, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ); +} + +interface AaveAddressProvider { + function getLendingPool() external view returns (address); + function getPriceOracle() external view returns (address); +} + +interface AavePriceOracle { + function getAssetPrice(address _asset) external view returns(uint256); + function getAssetsPrices(address[] calldata _assets) external view returns(uint256[] memory); + function getSourceOfAsset(address _asset) external view returns(uint256); + function getFallbackOracle() external view returns(uint256); +} + +interface ChainLinkInterface { + function latestAnswer() external view returns (int256); + function decimals() external view returns (uint256); +} + +contract DSMath { + + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, "math-not-safe"); + } + + function sub(uint x, uint y) internal pure returns (uint z) { + z = x - y <= x ? x - y : 0; + } + + function mul(uint x, uint y) internal pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + } + + uint constant WAD = 10 ** 18; + uint constant RAY = 10 ** 27; + + function rmul(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, y), RAY / 2) / RAY; + } + + function wmul(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, y), WAD / 2) / WAD; + } + + function rdiv(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, RAY), y / 2) / y; + } + + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = add(mul(x, WAD), y / 2) / y; + } + +} + +contract AaveHelpers is DSMath { + /** + * @dev Return ethereum address + */ + function getEthAddr() internal pure returns (address) { + return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; // ETH Address + } + + /** + * @dev Return Weth address + */ + function getWethAddr() internal pure returns (address) { + return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // Mainnet WETH Address + // return 0xd0A1E359811322d97991E03f863a0C30C2cF029C; // Kovan WETH Address + } + + /** + * @dev get Aave Provider Address + */ + function getAaveAddressProvider() internal pure returns (address) { + return 0xAcc030EF66f9dFEAE9CbB0cd1B25654b82cFA8d5; // Mainnet + // return 0x652B2937Efd0B5beA1c8d54293FC1289672AFC6b; // Kovan + } + + /** + * @dev get Aave Protocol Data Provider + */ + function getAaveProtocolDataProvider() internal pure returns (address) { + return 0xc443AD9DDE3cecfB9dfC5736578f447aFE3590ba; // Mainnet + // return 0x744C1aaA95232EeF8A9994C4E0b3a89659D9AB79; // Kovan + } + + /** + * @dev get Chainlink ETH price feed Address + */ + function getChainlinkEthFeed() internal pure returns (address) { + return 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; //mainnet + // return 0x9326BFA02ADD2366b30bacB125260Af641031331; //kovan + } + + struct AaveUserTokenData { + uint tokenPriceInEth; + uint tokenPriceInUsd; + uint supplyBalance; + uint stableBorrowBalance; + uint variableBorrowBalance; + uint supplyRate; + uint stableBorrowRate; + uint userStableBorrowRate; + uint variableBorrowRate; + bool isCollateral; + AaveTokenData aaveTokenData; + } + + struct AaveUserData { + uint totalCollateralETH; + uint totalBorrowsETH; + uint availableBorrowsETH; + uint currentLiquidationThreshold; + uint ltv; + uint healthFactor; + uint ethPriceInUsd; + } + + struct AaveTokenData { + uint ltv; + uint threshold; + uint reserveFactor; + bool usageAsCollEnabled; + bool borrowEnabled; + bool stableBorrowEnabled; + bool isActive; + bool isFrozen; + uint availableLiquidity; + uint totalStableDebt; + uint totalVariableDebt; + } + + struct TokenPrice { + uint priceInEth; + uint priceInUsd; + } + + function getTokensPrices(AaveAddressProvider aaveAddressProvider, address[] memory tokens) + internal view returns(TokenPrice[] memory tokenPrices, uint ethPrice) { + uint[] memory _tokenPrices = AavePriceOracle(aaveAddressProvider.getPriceOracle()).getAssetsPrices(tokens); + ethPrice = uint(ChainLinkInterface(getChainlinkEthFeed()).latestAnswer()); + tokenPrices = new TokenPrice[](_tokenPrices.length); + for (uint i = 0; i < _tokenPrices.length; i++) { + tokenPrices[i] = TokenPrice( + _tokenPrices[i], + wmul(_tokenPrices[i], uint(ethPrice) * 10 ** 10) + ); + } + } + + function collateralData( + AaveProtocolDataProvider aaveData, + address token + ) internal view returns (AaveTokenData memory aaveTokenData) { + ( + , + aaveTokenData.ltv, + aaveTokenData.threshold, + , + aaveTokenData.reserveFactor, + aaveTokenData.usageAsCollEnabled, + aaveTokenData.borrowEnabled, + aaveTokenData.stableBorrowEnabled, + aaveTokenData.isActive, + aaveTokenData.isFrozen + ) = aaveData.getReserveConfigurationData(token); + } + + function getTokenData( + AaveProtocolDataProvider aaveData, + address user, + address token, + uint tokenPriceInEth, + uint tokenPriceInUsd + ) internal view returns(AaveUserTokenData memory tokenData) { + AaveTokenData memory aaveTokenData = collateralData(aaveData, token); + + ( + tokenData.supplyBalance, + tokenData.stableBorrowBalance, + tokenData.variableBorrowBalance, + ,, + tokenData.userStableBorrowRate, + ,, + tokenData.isCollateral + ) = aaveData.getUserReserveData(token, user); + + ( + aaveTokenData.availableLiquidity, + aaveTokenData.totalStableDebt, + aaveTokenData.totalVariableDebt, + tokenData.supplyRate, + tokenData.variableBorrowRate, + tokenData.stableBorrowRate, + ,,, + ) = aaveData.getReserveData(token); + + tokenData.tokenPriceInEth = tokenPriceInEth; + tokenData.tokenPriceInUsd = tokenPriceInUsd; + tokenData.aaveTokenData = aaveTokenData; + } + + function getUserData(AaveLendingPool aave, address user, uint ethPriceInUsd) + internal view returns (AaveUserData memory userData) { + ( + uint256 totalCollateralETH, + uint256 totalDebtETH, + uint256 availableBorrowsETH, + uint256 currentLiquidationThreshold, + uint256 ltv, + uint256 healthFactor + ) = aave.getUserAccountData(user); + + userData = AaveUserData( + totalCollateralETH, + totalDebtETH, + availableBorrowsETH, + currentLiquidationThreshold, + ltv, + healthFactor, + ethPriceInUsd + ); + } +} + +contract Resolver is AaveHelpers { + function getPosition(address user, address[] memory tokens) public view returns(AaveUserTokenData[] memory, AaveUserData memory) { + AaveAddressProvider addrProvider = AaveAddressProvider(getAaveAddressProvider()); + uint length = tokens.length; + address[] memory _tokens = new address[](length); + + for (uint i = 0; i < length; i++) { + _tokens[i] = tokens[i] == getEthAddr() ? getWethAddr() : tokens[i]; + } + + AaveUserTokenData[] memory tokensData = new AaveUserTokenData[](length); + (TokenPrice[] memory tokenPrices, uint ethPrice) = getTokensPrices(addrProvider, _tokens); + + for (uint i = 0; i < length; i++) { + tokensData[i] = getTokenData( + AaveProtocolDataProvider(getAaveProtocolDataProvider()), + user, + _tokens[i], + tokenPrices[i].priceInEth, + tokenPrices[i].priceInUsd + ); + } + + return (tokensData, getUserData(AaveLendingPool(addrProvider.getLendingPool()), user, ethPrice)); + } +} + +contract InstaAaveV2AMMResolver is Resolver { + string public constant name = "AaveV2-AMM-Resolver-v1"; +}