1+ // SPDX-License-Identifier: agpl-3.0
2+ pragma solidity 0.6.12 ;
3+ pragma experimental ABIEncoderV2;
4+
5+ import {IERC20Detailed } from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol ' ;
6+ import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol ' ;
7+ import {IUiPoolDataProviderV2} from './interfaces/IUiPoolDataProviderV2.sol ' ;
8+ import {ILendingPool} from '../interfaces/ILendingPool.sol ' ;
9+ import {IAaveOracle} from './interfaces/IAaveOracle.sol ' ;
10+ import {IAToken} from '../interfaces/IAToken.sol ' ;
11+ import {IVariableDebtToken} from '../interfaces/IVariableDebtToken.sol ' ;
12+ import {IStableDebtToken} from '../interfaces/IStableDebtToken.sol ' ;
13+ import {WadRayMath} from '../protocol/libraries/math/WadRayMath.sol ' ;
14+ import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol ' ;
15+ import {UserConfiguration} from '../protocol/libraries/configuration/UserConfiguration.sol ' ;
16+ import {DataTypes} from '../protocol/libraries/types/DataTypes.sol ' ;
17+ import {IChainlinkAggregator} from '../interfaces/IChainlinkAggregator.sol ' ;
18+ import {DefaultReserveInterestRateStrategy} from '../protocol/lendingpool/DefaultReserveInterestRateStrategy.sol ' ;
19+ import {IERC20DetailedBytes } from './interfaces/IERC20DetailedBytes.sol ' ;
20+
21+ contract UiPoolDataProviderV2 is IUiPoolDataProviderV2 {
22+ using WadRayMath for uint256 ;
23+ using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
24+ using UserConfiguration for DataTypes.UserConfigurationMap;
25+
26+ IChainlinkAggregator public immutable networkBaseTokenPriceInUsdProxyAggregator;
27+ IChainlinkAggregator public immutable marketReferenceCurrencyPriceInUsdProxyAggregator;
28+ uint256 public constant ETH_CURRENCY_UNIT = 1 ether ;
29+ address public constant MKRAddress = 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2 ;
30+
31+ constructor (
32+ IChainlinkAggregator _networkBaseTokenPriceInUsdProxyAggregator ,
33+ IChainlinkAggregator _marketReferenceCurrencyPriceInUsdProxyAggregator
34+ ) public {
35+ networkBaseTokenPriceInUsdProxyAggregator = _networkBaseTokenPriceInUsdProxyAggregator;
36+ marketReferenceCurrencyPriceInUsdProxyAggregator = _marketReferenceCurrencyPriceInUsdProxyAggregator;
37+ }
38+
39+ function getInterestRateStrategySlopes (DefaultReserveInterestRateStrategy interestRateStrategy )
40+ internal
41+ view
42+ returns (
43+ uint256 ,
44+ uint256 ,
45+ uint256 ,
46+ uint256
47+ )
48+ {
49+ return (
50+ interestRateStrategy.variableRateSlope1 (),
51+ interestRateStrategy.variableRateSlope2 (),
52+ interestRateStrategy.stableRateSlope1 (),
53+ interestRateStrategy.stableRateSlope2 ()
54+ );
55+ }
56+
57+ function getReservesList (ILendingPoolAddressesProvider provider )
58+ public
59+ view
60+ override
61+ returns (address [] memory )
62+ {
63+ ILendingPool lendingPool = ILendingPool (provider.getLendingPool ());
64+ return lendingPool.getReservesList ();
65+ }
66+
67+ function getReservesData (ILendingPoolAddressesProvider provider )
68+ public
69+ view
70+ override
71+ returns (AggregatedReserveData[] memory , BaseCurrencyInfo memory )
72+ {
73+ IAaveOracle oracle = IAaveOracle (provider.getPriceOracle ());
74+ ILendingPool lendingPool = ILendingPool (provider.getLendingPool ());
75+ address [] memory reserves = lendingPool.getReservesList ();
76+ AggregatedReserveData[] memory reservesData = new AggregatedReserveData [](reserves.length );
77+
78+ for (uint256 i = 0 ; i < reserves.length ; i++ ) {
79+ AggregatedReserveData memory reserveData = reservesData[i];
80+ reserveData.underlyingAsset = reserves[i];
81+
82+ // reserve current state
83+ DataTypes.ReserveData memory baseData = lendingPool.getReserveData (
84+ reserveData.underlyingAsset
85+ );
86+ reserveData.liquidityIndex = baseData.liquidityIndex;
87+ reserveData.variableBorrowIndex = baseData.variableBorrowIndex;
88+ reserveData.liquidityRate = baseData.currentLiquidityRate;
89+ reserveData.variableBorrowRate = baseData.currentVariableBorrowRate;
90+ reserveData.stableBorrowRate = baseData.currentStableBorrowRate;
91+ reserveData.lastUpdateTimestamp = baseData.lastUpdateTimestamp;
92+ reserveData.aTokenAddress = baseData.aTokenAddress;
93+ reserveData.stableDebtTokenAddress = baseData.stableDebtTokenAddress;
94+ reserveData.variableDebtTokenAddress = baseData.variableDebtTokenAddress;
95+ reserveData.interestRateStrategyAddress = baseData.interestRateStrategyAddress;
96+ reserveData.priceInMarketReferenceCurrency = oracle.getAssetPrice (
97+ reserveData.underlyingAsset
98+ );
99+
100+ reserveData.availableLiquidity = IERC20Detailed (reserveData.underlyingAsset).balanceOf (
101+ reserveData.aTokenAddress
102+ );
103+ (
104+ reserveData.totalPrincipalStableDebt,
105+ ,
106+ reserveData.averageStableRate,
107+ reserveData.stableDebtLastUpdateTimestamp
108+ ) = IStableDebtToken (reserveData.stableDebtTokenAddress).getSupplyData ();
109+ reserveData.totalScaledVariableDebt = IVariableDebtToken (reserveData.variableDebtTokenAddress)
110+ .scaledTotalSupply ();
111+
112+ if (address (reserveData.underlyingAsset) == address (MKRAddress)) {
113+ bytes32 symbol = IERC20DetailedBytes (reserveData.underlyingAsset).symbol ();
114+ reserveData.symbol = bytes32ToString (symbol);
115+ } else {
116+ reserveData.symbol = IERC20Detailed (reserveData.underlyingAsset).symbol ();
117+ }
118+
119+ (
120+ reserveData.baseLTVasCollateral,
121+ reserveData.reserveLiquidationThreshold,
122+ reserveData.reserveLiquidationBonus,
123+ reserveData.decimals,
124+ reserveData.reserveFactor
125+ ) = baseData.configuration.getParamsMemory ();
126+ (
127+ reserveData.isActive,
128+ reserveData.isFrozen,
129+ reserveData.borrowingEnabled,
130+ reserveData.stableBorrowRateEnabled
131+ ) = baseData.configuration.getFlagsMemory ();
132+ reserveData.usageAsCollateralEnabled = reserveData.baseLTVasCollateral != 0 ;
133+ (
134+ reserveData.variableRateSlope1,
135+ reserveData.variableRateSlope2,
136+ reserveData.stableRateSlope1,
137+ reserveData.stableRateSlope2
138+ ) = getInterestRateStrategySlopes (
139+ DefaultReserveInterestRateStrategy (reserveData.interestRateStrategyAddress)
140+ );
141+ }
142+
143+ BaseCurrencyInfo memory baseCurrencyInfo;
144+ baseCurrencyInfo.networkBaseTokenPriceInUsd = networkBaseTokenPriceInUsdProxyAggregator
145+ .latestAnswer ();
146+ baseCurrencyInfo.networkBaseTokenPriceDecimals = networkBaseTokenPriceInUsdProxyAggregator
147+ .decimals ();
148+
149+ try oracle.BASE_CURRENCY_UNIT () returns (uint256 baseCurrencyUnit ) {
150+ if (ETH_CURRENCY_UNIT == baseCurrencyUnit) {
151+ baseCurrencyInfo.marketReferenceCurrencyUnit = ETH_CURRENCY_UNIT;
152+ baseCurrencyInfo
153+ .marketReferenceCurrencyPriceInUsd = marketReferenceCurrencyPriceInUsdProxyAggregator
154+ .latestAnswer ();
155+ } else {
156+ baseCurrencyInfo.marketReferenceCurrencyUnit = baseCurrencyUnit;
157+ baseCurrencyInfo.marketReferenceCurrencyPriceInUsd = int256 (baseCurrencyUnit);
158+ }
159+ } catch (
160+ bytes memory /*lowLevelData*/
161+ ) {
162+ baseCurrencyInfo.marketReferenceCurrencyUnit = ETH_CURRENCY_UNIT;
163+ baseCurrencyInfo
164+ .marketReferenceCurrencyPriceInUsd = marketReferenceCurrencyPriceInUsdProxyAggregator
165+ .latestAnswer ();
166+ }
167+
168+ return (reservesData, baseCurrencyInfo);
169+ }
170+
171+ function getUserReservesData (ILendingPoolAddressesProvider provider , address user )
172+ external
173+ view
174+ override
175+ returns (UserReserveData[] memory )
176+ {
177+ ILendingPool lendingPool = ILendingPool (provider.getLendingPool ());
178+ address [] memory reserves = lendingPool.getReservesList ();
179+ DataTypes.UserConfigurationMap memory userConfig = lendingPool.getUserConfiguration (user);
180+
181+ UserReserveData[] memory userReservesData = new UserReserveData [](
182+ user != address (0 ) ? reserves.length : 0
183+ );
184+
185+ for (uint256 i = 0 ; i < reserves.length ; i++ ) {
186+ DataTypes.ReserveData memory baseData = lendingPool.getReserveData (reserves[i]);
187+
188+ // user reserve data
189+ userReservesData[i].underlyingAsset = reserves[i];
190+ userReservesData[i].scaledATokenBalance = IAToken (baseData.aTokenAddress).scaledBalanceOf (
191+ user
192+ );
193+ userReservesData[i].usageAsCollateralEnabledOnUser = userConfig.isUsingAsCollateral (i);
194+
195+ if (userConfig.isBorrowing (i)) {
196+ userReservesData[i].scaledVariableDebt = IVariableDebtToken (
197+ baseData.variableDebtTokenAddress
198+ ).scaledBalanceOf (user);
199+ userReservesData[i].principalStableDebt = IStableDebtToken (baseData.stableDebtTokenAddress)
200+ .principalBalanceOf (user);
201+ if (userReservesData[i].principalStableDebt != 0 ) {
202+ userReservesData[i].stableBorrowRate = IStableDebtToken (baseData.stableDebtTokenAddress)
203+ .getUserStableRate (user);
204+ userReservesData[i].stableBorrowLastUpdateTimestamp = IStableDebtToken (
205+ baseData.stableDebtTokenAddress
206+ ).getUserLastUpdated (user);
207+ }
208+ }
209+ }
210+
211+ return (userReservesData);
212+ }
213+
214+ function bytes32ToString (bytes32 _bytes32 ) public pure returns (string memory ) {
215+ uint8 i = 0 ;
216+ while (i < 32 && _bytes32[i] != 0 ) {
217+ i++ ;
218+ }
219+ bytes memory bytesArray = new bytes (i);
220+ for (i = 0 ; i < 32 && _bytes32[i] != 0 ; i++ ) {
221+ bytesArray[i] = _bytes32[i];
222+ }
223+ return string (bytesArray);
224+ }
225+ }
0 commit comments