Merge branch 'feat/data-helpers' into 'master'

UI data helpers

See merge request aave-tech/protocol-v2!131
This commit is contained in:
Ernesto Boado 2020-11-06 12:57:32 +00:00
commit d599dee431
10 changed files with 3577 additions and 5650 deletions

View File

@ -7,6 +7,8 @@ import {eEthereumNetwork} from './helpers/types';
import {BUIDLEREVM_CHAINID, COVERAGE_CHAINID} from './helpers/buidler-constants';
import {setDRE} from './helpers/misc-utils';
require('dotenv').config();
usePlugin('@nomiclabs/buidler-ethers');
usePlugin('buidler-typechain');
usePlugin('solidity-coverage');

View File

@ -0,0 +1,94 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
pragma experimental ABIEncoderV2;
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
interface IUiPoolDataProvider {
struct AggregatedReserveData {
address underlyingAsset;
string name;
string symbol;
uint256 decimals;
uint256 baseLTVasCollateral;
uint256 reserveLiquidationThreshold;
uint256 reserveLiquidationBonus;
uint256 reserveFactor;
bool usageAsCollateralEnabled;
bool borrowingEnabled;
bool stableBorrowRateEnabled;
bool isActive;
bool isFrozen;
// base data
uint128 liquidityIndex;
uint128 variableBorrowIndex;
uint128 liquidityRate;
uint128 variableBorrowRate;
uint128 stableBorrowRate;
uint40 lastUpdateTimestamp;
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
address interestRateStrategyAddress;
//
uint256 availableLiquidity;
uint256 totalPrincipalStableDebt;
uint256 averageStableRate;
uint256 stableDebtLastUpdateTimestamp;
uint256 totalScaledVariableDebt;
uint256 priceInEth;
uint256 variableRateSlope1;
uint256 variableRateSlope2;
uint256 stableRateSlope1;
uint256 stableRateSlope2;
}
//
// struct ReserveData {
// uint256 averageStableBorrowRate;
// uint256 totalLiquidity;
// }
struct UserReserveData {
address underlyingAsset;
uint256 scaledATokenBalance;
bool usageAsCollateralEnabledOnUser;
uint256 stableBorrowRate;
uint256 scaledVariableDebt;
uint256 principalStableDebt;
uint256 stableBorrowLastUpdateTimestamp;
}
//
// struct ATokenSupplyData {
// string name;
// string symbol;
// uint8 decimals;
// uint256 totalSupply;
// address aTokenAddress;
// }
function getReservesData(ILendingPoolAddressesProvider provider, address user)
external
view
returns (
AggregatedReserveData[] memory,
UserReserveData[] memory,
uint256
);
// function getUserReservesData(ILendingPoolAddressesProvider provider, address user)
// external
// view
// returns (UserReserveData[] memory);
//
// function getAllATokenSupply(ILendingPoolAddressesProvider provider)
// external
// view
// returns (ATokenSupplyData[] memory);
//
// function getATokenSupply(address[] calldata aTokens)
// external
// view
// returns (ATokenSupplyData[] memory);
}

View File

@ -0,0 +1,163 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
pragma experimental ABIEncoderV2;
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {IUiPoolDataProvider} from './IUiPoolDataProvider.sol';
import {ILendingPool} from '../interfaces/ILendingPool.sol';
import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
import {IAToken} from '../tokenization/interfaces/IAToken.sol';
import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol';
import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
import {
DefaultReserveInterestRateStrategy
} from '../lendingpool/DefaultReserveInterestRateStrategy.sol';
contract UiPoolDataProvider is IUiPoolDataProvider {
using WadRayMath for uint256;
using ReserveConfiguration for ReserveConfiguration.Map;
using UserConfiguration for UserConfiguration.Map;
address public constant MOCK_USD_ADDRESS = 0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96;
function getInterestRateStrategySlopes(DefaultReserveInterestRateStrategy interestRateStrategy)
internal
view
returns (
uint256,
uint256,
uint256,
uint256
)
{
return (
interestRateStrategy.variableRateSlope1(),
interestRateStrategy.variableRateSlope2(),
interestRateStrategy.stableRateSlope1(),
interestRateStrategy.stableRateSlope2()
);
}
function getReservesData(ILendingPoolAddressesProvider provider, address user)
external
override
view
returns (
AggregatedReserveData[] memory,
UserReserveData[] memory,
uint256
)
{
ILendingPool lendingPool = ILendingPool(provider.getLendingPool());
IPriceOracleGetter oracle = IPriceOracleGetter(provider.getPriceOracle());
address[] memory reserves = lendingPool.getReservesList();
UserConfiguration.Map memory userConfig = lendingPool.getUserConfiguration(user);
AggregatedReserveData[] memory reservesData = new AggregatedReserveData[](reserves.length);
UserReserveData[] memory userReservesData = new UserReserveData[](
user != address(0) ? reserves.length : 0
);
for (uint256 i = 0; i < reserves.length; i++) {
AggregatedReserveData memory reserveData = reservesData[i];
reserveData.underlyingAsset = reserves[i];
// reserve current state
ReserveLogic.ReserveData memory baseData = lendingPool.getReserveData(
reserveData.underlyingAsset
);
reserveData.liquidityIndex = baseData.liquidityIndex;
reserveData.variableBorrowIndex = baseData.variableBorrowIndex;
reserveData.liquidityRate = baseData.currentLiquidityRate;
reserveData.variableBorrowRate = baseData.currentVariableBorrowRate;
reserveData.stableBorrowRate = baseData.currentStableBorrowRate;
reserveData.lastUpdateTimestamp = baseData.lastUpdateTimestamp;
reserveData.aTokenAddress = baseData.aTokenAddress;
reserveData.stableDebtTokenAddress = baseData.stableDebtTokenAddress;
reserveData.variableDebtTokenAddress = baseData.variableDebtTokenAddress;
reserveData.interestRateStrategyAddress = baseData.interestRateStrategyAddress;
reserveData.priceInEth = oracle.getAssetPrice(reserveData.underlyingAsset);
reserveData.availableLiquidity = IERC20Detailed(reserveData.underlyingAsset).balanceOf(
reserveData.aTokenAddress
);
(
reserveData.totalPrincipalStableDebt,
,
reserveData.averageStableRate,
reserveData.stableDebtLastUpdateTimestamp
) = IStableDebtToken(reserveData.stableDebtTokenAddress).getSupplyData();
reserveData.totalScaledVariableDebt = IVariableDebtToken(reserveData.variableDebtTokenAddress)
.scaledTotalSupply();
// reserve configuration
// we're getting this info from the aToken, because some of assets can be not compliant with ETC20Detailed
reserveData.symbol = IERC20Detailed(reserveData.aTokenAddress).symbol();
reserveData.name = '';
(
reserveData.baseLTVasCollateral,
reserveData.reserveLiquidationThreshold,
reserveData.reserveLiquidationBonus,
reserveData.decimals,
reserveData.reserveFactor
) = baseData.configuration.getParamsMemory();
(
reserveData.isActive,
reserveData.isFrozen,
reserveData.borrowingEnabled,
reserveData.stableBorrowRateEnabled
) = baseData.configuration.getFlagsMemory();
reserveData.usageAsCollateralEnabled = reserveData.baseLTVasCollateral != 0;
(
reserveData.variableRateSlope1,
reserveData.variableRateSlope2,
reserveData.stableRateSlope1,
reserveData.stableRateSlope2
) = getInterestRateStrategySlopes(
DefaultReserveInterestRateStrategy(reserveData.interestRateStrategyAddress)
);
if (user != address(0)) {
// user reserve data
userReservesData[i].underlyingAsset = reserveData.underlyingAsset;
userReservesData[i].scaledATokenBalance = IAToken(reserveData.aTokenAddress)
.scaledBalanceOf(user);
userReservesData[i].usageAsCollateralEnabledOnUser = userConfig.isUsingAsCollateral(i);
if (userConfig.isBorrowing(i)) {
userReservesData[i].scaledVariableDebt = IVariableDebtToken(
reserveData
.variableDebtTokenAddress
)
.scaledBalanceOf(user);
userReservesData[i].principalStableDebt = IStableDebtToken(
reserveData
.stableDebtTokenAddress
)
.principalBalanceOf(user);
if (userReservesData[i].principalStableDebt != 0) {
userReservesData[i].stableBorrowRate = IStableDebtToken(
reserveData
.stableDebtTokenAddress
)
.getUserStableRate(user);
userReservesData[i].stableBorrowLastUpdateTimestamp = IStableDebtToken(
reserveData
.stableDebtTokenAddress
)
.getUserLastUpdated(user);
}
}
}
}
return (reservesData, userReservesData, oracle.getAssetPrice(MOCK_USD_ADDRESS));
}
}

View File

@ -25,6 +25,7 @@ contract WalletBalanceProvider {
using ReserveConfiguration for ReserveConfiguration.Map;
LendingPoolAddressesProvider internal immutable _provider;
address constant MOCK_ETH_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
constructor(LendingPoolAddressesProvider provider) public {
_provider = provider;
@ -91,11 +92,16 @@ contract WalletBalanceProvider {
ILendingPool pool = ILendingPool(_provider.getLendingPool());
address[] memory reserves = pool.getReservesList();
address[] memory reservesWithEth = new address[](reserves.length + 1);
for (uint256 i = 0; i < reserves.length; i++) {
reservesWithEth[i] = reserves[i];
}
reservesWithEth[reserves.length] = MOCK_ETH_ADDRESS;
uint256[] memory balances = new uint256[](reserves.length);
uint256[] memory balances = new uint256[](reservesWithEth.length);
for (uint256 j = 0; j < reserves.length; j++) {
ReserveConfiguration.Map memory configuration = pool.getConfiguration(reserves[j]);
for (uint256 j = 0; j < reservesWithEth.length; j++) {
ReserveConfiguration.Map memory configuration = pool.getConfiguration(reservesWithEth[j]);
(bool isActive, , , ) = configuration.getFlagsMemory();

View File

@ -584,4 +584,4 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
}
}
}

View File

@ -1,5 +1,6 @@
import BigNumber from 'bignumber.js';
import {MockTokenMap} from './contracts-helpers';
import {UiPoolDataProviderFactory} from '../types';
export interface SymbolMap<T> {
[symbol: string]: T;
@ -60,6 +61,7 @@ export enum eContractid {
TokenDistributor = 'TokenDistributor',
StableAndVariableTokensHelper = 'StableAndVariableTokensHelper',
ATokensAndRatesHelper = 'ATokensAndRatesHelper',
UiPoolDataProvider = 'UiPoolDataProvider',
WETHGateway = 'WETHGateway',
WETH = 'WETH',
WETHMocked = 'WETHMocked',

8919
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,8 @@
"ci:clean": "rm -rf ./artifacts ./cache ./types",
"print-contracts:kovan": "npm run hardhat:kovan -- print-contracts",
"print-contracts:main": "npm run hardhat:main -- print-contracts",
"print-contracts:ropsten": "npm run hardhat:main -- print-contracts"
"print-contracts:ropsten": "npm run hardhat:main -- print-contracts",
"dev:deployUIProvider": "npm run buidler:kovan deploy-UiPoolDataProvider"
},
"devDependencies": {
"@nomiclabs/buidler": "^1.4.7",
@ -78,6 +79,7 @@
"chai": "4.2.0",
"chai-bignumber": "3.0.0",
"chai-bn": "^0.2.1",
"dotenv": "^8.2.0",
"eth-sig-util": "2.5.3",
"ethereum-waffle": "3.0.2",
"ethereumjs-util": "7.0.2",

View File

@ -0,0 +1,27 @@
import {task} from '@nomiclabs/buidler/config';
import {UiPoolDataProviderFactory} from '../../types';
import {verifyContract} from '../../helpers/etherscan-verification';
import {eContractid} from '../../helpers/types';
task(`deploy-${eContractid.UiPoolDataProvider}`, `Deploys the UiPoolDataProvider contract`)
.addFlag('verify', 'Verify UiPoolDataProvider contract via Etherscan API.')
.setAction(async ({verify}, localBRE) => {
await localBRE.run('set-bre');
if (!localBRE.network.config.chainId) {
throw new Error('INVALID_CHAIN_ID');
}
console.log(`\n- UiPoolDataProvider deployment`);
console.log(`\tDeploying UiPoolDataProvider implementation ...`);
const uiPoolDataProvider = await new UiPoolDataProviderFactory(
await localBRE.ethers.provider.getSigner()
).deploy();
await uiPoolDataProvider.deployTransaction.wait();
console.log('uiPoolDataProvider.address', uiPoolDataProvider.address);
await verifyContract(eContractid.UiPoolDataProvider, uiPoolDataProvider.address, []);
console.log(`\tFinished UiPoolDataProvider proxy and implementation deployment`);
});

View File

@ -205,7 +205,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
tokens,
aggregators,
fallbackOracle.address,
mockTokens.WETH.address
mockTokens.WETH.address,
]);
await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address));