diff --git a/.gitignore b/.gitignore index 03a9d01b..626ee868 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,10 @@ build/ .idea types +deployed-contracts.json + coverage .coverage_artifacts .coverage_cache .coverage_contracts + diff --git a/buidler.config.ts b/buidler.config.ts index 878bc53f..79b1d670 100644 --- a/buidler.config.ts +++ b/buidler.config.ts @@ -14,7 +14,7 @@ usePlugin('@nomiclabs/buidler-etherscan'); usePlugin('buidler-gas-reporter'); const SKIP_LOAD = process.env.SKIP_LOAD === 'true'; -const DEFAULT_BLOCK_GAS_LIMIT = 10000000; +const DEFAULT_BLOCK_GAS_LIMIT = 12000000; const DEFAULT_GAS_PRICE = 10; const HARDFORK = 'istanbul'; const INFURA_KEY = process.env.INFURA_KEY || ''; @@ -90,6 +90,16 @@ const buidlerConfig: any = { balance, })), }, + buidlerevm_docker: { + hardfork: 'istanbul', + blockGasLimit: 9500000, + gas: 9500000, + gasPrice: 8000000000, + chainId: BUIDLEREVM_CHAINID, + throwOnTransactionFailures: true, + throwOnCallFailures: true, + url: 'http://localhost:8545', + }, ganache: { url: 'http://ganache:8545', accounts: { diff --git a/contracts/configuration/LendingPoolAddressesProviderRegistry.sol b/contracts/configuration/LendingPoolAddressesProviderRegistry.sol index 53ef4d10..bf15ef3d 100644 --- a/contracts/configuration/LendingPoolAddressesProviderRegistry.sol +++ b/contracts/configuration/LendingPoolAddressesProviderRegistry.sol @@ -20,7 +20,7 @@ contract LendingPoolAddressesProviderRegistry is Ownable, ILendingPoolAddressesP /** * @dev returns if an addressesProvider is registered or not * @param provider the addresses provider - * @return true if the addressesProvider is registered, false otherwise + * @return The id of the addresses provider or 0 if the addresses provider not registered **/ function isAddressesProviderRegistered(address provider) external @@ -33,7 +33,7 @@ contract LendingPoolAddressesProviderRegistry is Ownable, ILendingPoolAddressesP /** * @dev returns the list of active addressesProviders - * @return the list of addressesProviders + * @return the list of addressesProviders, potentially containing address(0) elements **/ function getAddressesProvidersList() external override view returns (address[] memory) { address[] memory addressesProvidersList = _addressesProvidersList; @@ -91,7 +91,7 @@ contract LendingPoolAddressesProviderRegistry is Ownable, ILendingPoolAddressesP /** * @dev Returns the id on an `addressesProvider` or address(0) if not registered - * @return The id or address(0) + * @return The id or 0 if the addresses provider is not registered */ function getAddressesProviderIdByAddress(address addressesProvider) external diff --git a/contracts/deployments/ATokensAndRatesHelper.sol b/contracts/deployments/ATokensAndRatesHelper.sol new file mode 100644 index 00000000..769b98fc --- /dev/null +++ b/contracts/deployments/ATokensAndRatesHelper.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; + +import {LendingPool} from '../lendingpool/LendingPool.sol'; +import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol'; +import {LendingPoolConfigurator} from '../lendingpool/LendingPoolConfigurator.sol'; +import {AToken} from '../tokenization/AToken.sol'; +import { + DefaultReserveInterestRateStrategy +} from '../lendingpool/DefaultReserveInterestRateStrategy.sol'; +import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol'; +import {StringLib} from '../libraries/helpers/StringLib.sol'; + +contract ATokensAndRatesHelper is Ownable { + address payable private pool; + address private addressesProvider; + address private poolConfigurator; + event deployedContracts(address aToken, address strategy); + + constructor( + address payable _pool, + address _addressesProvider, + address _poolConfigurator + ) public { + pool = _pool; + addressesProvider = _addressesProvider; + poolConfigurator = _poolConfigurator; + } + + function initDeployment( + address[] calldata tokens, + string[] calldata symbols, + uint256[5][] calldata rates, + address incentivesController + ) external onlyOwner { + require(tokens.length == symbols.length, 't Arrays not same length'); + require(rates.length == symbols.length, 'r Arrays not same length'); + + for (uint256 i = 0; i < tokens.length; i++) { + emit deployedContracts( + address( + new AToken( + LendingPool(pool), + tokens[i], + address(0), + StringLib.concat('Aave interest bearing ', symbols[i]), + StringLib.concat('a', symbols[i]), + incentivesController + ) + ), + address( + new DefaultReserveInterestRateStrategy( + LendingPoolAddressesProvider(addressesProvider), + rates[i][0], + rates[i][1], + rates[i][2], + rates[i][3], + rates[i][4] + ) + ) + ); + } + } + + function initReserve( + address[] calldata stables, + address[] calldata variables, + address[] calldata aTokens, + address[] calldata strategies, + uint8[] calldata reserveDecimals + ) external onlyOwner { + require(variables.length == stables.length); + require(aTokens.length == stables.length); + require(strategies.length == stables.length); + require(reserveDecimals.length == stables.length); + + for (uint256 i = 0; i < stables.length; i++) { + LendingPoolConfigurator(poolConfigurator).initReserve( + aTokens[i], + stables[i], + variables[i], + reserveDecimals[i], + strategies[i] + ); + } + } + + function enableReservesAsCollateral( + address[] calldata tokens, + uint256[] calldata baseLTVs, + uint256[] calldata liquidationThresholds, + uint256[] calldata liquidationBonuses + ) external onlyOwner { + require(baseLTVs.length == tokens.length); + require(liquidationThresholds.length == tokens.length); + require(liquidationBonuses.length == tokens.length); + + for (uint256 i = 0; i < tokens.length; i++) { + LendingPoolConfigurator(poolConfigurator).enableReserveAsCollateral( + tokens[i], + baseLTVs[i], + liquidationThresholds[i], + liquidationBonuses[i] + ); + } + } + + function enableBorrowingOnReserves(address[] calldata tokens, bool[] calldata stableBorrows) + external + onlyOwner + { + require(stableBorrows.length == tokens.length); + + for (uint256 i = 0; i < tokens.length; i++) { + LendingPoolConfigurator(poolConfigurator).enableBorrowingOnReserve( + tokens[i], + stableBorrows[i] + ); + } + } +} diff --git a/contracts/deployments/StableAndVariableTokensHelper.sol b/contracts/deployments/StableAndVariableTokensHelper.sol new file mode 100644 index 00000000..9722424e --- /dev/null +++ b/contracts/deployments/StableAndVariableTokensHelper.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; + +import {StableDebtToken} from '../tokenization/StableDebtToken.sol'; +import {VariableDebtToken} from '../tokenization/VariableDebtToken.sol'; +import {LendingRateOracle} from '../mocks/oracle/LendingRateOracle.sol'; +import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol'; +import {StringLib} from '../libraries/helpers/StringLib.sol'; + +contract StableAndVariableTokensHelper is Ownable { + address payable private pool; + address private addressesProvider; + event deployedContracts(address stableToken, address variableToken); + + constructor(address payable _pool, address _addressesProvider) public { + pool = _pool; + addressesProvider = _addressesProvider; + } + + function initDeployment( + address[] calldata tokens, + string[] calldata symbols, + address incentivesController + ) external onlyOwner { + require(tokens.length == symbols.length, 'Arrays not same length'); + require(pool != address(0), 'Pool can not be zero address'); + for (uint256 i = 0; i < tokens.length; i++) { + emit deployedContracts( + address( + new StableDebtToken( + pool, + tokens[i], + StringLib.concat('Aave stable debt bearing ', symbols[i]), + StringLib.concat('stableDebt', symbols[i]), + incentivesController + ) + ), + address( + new VariableDebtToken( + pool, + tokens[i], + StringLib.concat('Aave variable debt bearing ', symbols[i]), + StringLib.concat('variableDebt', symbols[i]), + incentivesController + ) + ) + ); + } + } + + function setOracleBorrowRates( + address[] calldata assets, + uint256[] calldata rates, + address oracle + ) external onlyOwner { + require(assets.length == rates.length, 'Arrays not same length'); + + for (uint256 i = 0; i < assets.length; i++) { + // LendingRateOracle owner must be this contract + LendingRateOracle(oracle).setMarketBorrowRate(assets[i], rates[i]); + } + } + + function setOracleOwnership(address oracle, address admin) external onlyOwner { + require(admin != address(0), 'owner can not be zero'); + require(LendingRateOracle(oracle).owner() == address(this), 'helper is not owner'); + LendingRateOracle(oracle).transferOwnership(admin); + } +} diff --git a/contracts/interfaces/ILendingPool.sol b/contracts/interfaces/ILendingPool.sol index 17e75fa6..450def2d 100644 --- a/contracts/interfaces/ILendingPool.sol +++ b/contracts/interfaces/ILendingPool.sol @@ -99,6 +99,8 @@ interface ILendingPool { /** * @dev emitted when a flashloan is executed * @param target the address of the flashLoanReceiver + * @param mode Type of the debt to open if the flash loan is not returned. 0 -> Don't open any debt, just revert, 1 -> stable, 2 -> variable + * @param onBehalfOf the address incurring the debt, if borrow mode is not 0 * @param assets the address of the assets being flashborrowed * @param amounts the amount requested * @param premiums the total fee on the amount @@ -107,6 +109,7 @@ interface ILendingPool { event FlashLoan( address indexed target, uint256 mode, + address indexed onBehalfOf, address[] assets, uint256[] amounts, uint256[] premiums, @@ -162,7 +165,6 @@ interface ILendingPool { address indexed reserve, uint256 liquidityRate, uint256 stableBorrowRate, - uint256 averageStableBorrowRate, uint256 variableBorrowRate, uint256 liquidityIndex, uint256 variableBorrowIndex @@ -296,6 +298,7 @@ interface ILendingPool { address[] calldata assets, uint256[] calldata amounts, uint256 mode, + address onBehalfOf, bytes calldata params, uint16 referralCode ) external; @@ -350,11 +353,14 @@ interface ILendingPool { function getReserveData(address asset) external view returns (ReserveLogic.ReserveData memory); - function balanceDecreaseAllowed( - address reserve, - address user, - uint256 amount - ) external view returns (bool); + function finalizeTransfer( + address asset, + address from, + address to, + uint256 amount, + uint256 balanceFromAfter, + uint256 balanceToBefore + ) external; function getReservesList() external view returns (address[] memory); diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index c63ff348..539b6ac6 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -503,6 +503,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage * @param assets The addresss of the assets being flashborrowed * @param amounts The amounts requested for this flashloan for each asset * @param mode Type of the debt to open if the flash loan is not returned. 0 -> Don't open any debt, just revert, 1 -> stable, 2 -> variable + * @param onBehalfOf If mode is not 0, then the address to take the debt onBehalfOf. The onBehalfOf address must already have approved `msg.sender` to incur the debt on their behalf. * @param params Variadic packed params to pass to the receiver as extra information * @param referralCode Referral code of the flash loan **/ @@ -511,6 +512,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage address[] calldata assets, uint256[] calldata amounts, uint256 mode, + address onBehalfOf, bytes calldata params, uint16 referralCode ) external override { @@ -568,13 +570,23 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage vars.currentAmountPlusPremium ); } else { + if (msg.sender != onBehalfOf) { + address debtToken = _reserves[vars.currentAsset].getDebtTokenAddress(mode); + + _borrowAllowance[debtToken][onBehalfOf][msg + .sender] = _borrowAllowance[debtToken][onBehalfOf][msg.sender].sub( + vars.currentAmount, + Errors.BORROW_ALLOWANCE_ARE_NOT_ENOUGH + ); + } + //if the user didn't choose to return the funds, the system checks if there //is enough collateral and eventually open a position _executeBorrow( ExecuteBorrowParams( vars.currentAsset, msg.sender, - msg.sender, + onBehalfOf, vars.currentAmount, mode, vars.currentATokenAddress, @@ -583,7 +595,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage ) ); } - emit FlashLoan(receiverAddress, mode, assets, amounts, premiums, referralCode); + emit FlashLoan(receiverAddress, mode, onBehalfOf, assets, amounts, premiums, referralCode); } } @@ -724,29 +736,48 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage } /** - * @dev validate if a balance decrease for an asset is allowed + * @dev validates and finalizes an aToken transfer * @param asset the address of the reserve - * @param user the user related to the balance decrease + * @param from the user from which the aTokens are transferred + * @param to the user receiving the aTokens * @param amount the amount being transferred/redeemed - * @return true if the balance decrease can be allowed, false otherwise + * @param balanceFromBefore the balance of the from user before the transfer + * @param balanceToBefore the balance of the to user before the transfer */ - function balanceDecreaseAllowed( + function finalizeTransfer( address asset, - address user, - uint256 amount - ) external override view returns (bool) { + address from, + address to, + uint256 amount, + uint256 balanceFromBefore, + uint256 balanceToBefore + ) external override { _whenNotPaused(); - return - GenericLogic.balanceDecreaseAllowed( - asset, - user, - amount, - _reserves, - _usersConfig[user], - _reservesList, - _reservesCount, - _addressesProvider.getPriceOracle() - ); + + require(msg.sender == _reserves[asset].aTokenAddress, Errors.CALLER_MUST_BE_AN_ATOKEN); + + ValidationLogic.validateTransfer( + from, + _reserves, + _usersConfig[from], + _reservesList, + _reservesCount, + _addressesProvider.getPriceOracle() + ); + + uint256 reserveId = _reserves[asset].id; + + if (from != to) { + if (balanceFromBefore.sub(amount) == 0) { + UserConfiguration.Map storage fromConfig = _usersConfig[from]; + fromConfig.setUsingAsCollateral(reserveId, false); + } + + if (balanceToBefore == 0 && amount != 0) { + UserConfiguration.Map storage toConfig = _usersConfig[to]; + toConfig.setUsingAsCollateral(reserveId, true); + } + } } /** @@ -913,13 +944,15 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage * @dev adds a reserve to the array of the _reserves address **/ function _addReserveToList(address asset) internal { - require(_reservesCount < MAX_NUMBER_RESERVES, Errors.NO_MORE_RESERVES_ALLOWED); + uint256 reservesCount = _reservesCount; + + require(reservesCount < MAX_NUMBER_RESERVES, Errors.NO_MORE_RESERVES_ALLOWED); bool reserveAlreadyAdded = _reserves[asset].id != 0 || _reservesList[0] == asset; if (!reserveAlreadyAdded) { - _reserves[asset].id = uint8(_reservesCount); - _reservesList[_reservesCount] = asset; + _reserves[asset].id = uint8(reservesCount); + _reservesList[reservesCount] = asset; _reservesCount++; } diff --git a/contracts/libraries/configuration/ReserveConfiguration.sol b/contracts/libraries/configuration/ReserveConfiguration.sol index 553cec66..ce4f722a 100644 --- a/contracts/libraries/configuration/ReserveConfiguration.sol +++ b/contracts/libraries/configuration/ReserveConfiguration.sol @@ -1,21 +1,23 @@ // SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.6.8; +import {Errors} from '../helpers/Errors.sol'; + /** * @title ReserveConfiguration library * @author Aave * @notice Implements the bitmap logic to handle the reserve configuration */ library ReserveConfiguration { - uint256 constant LTV_MASK = 0xFFFFFFFFFFFFFFFF0000; - uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFF0000FFFF; - uint256 constant LIQUIDATION_BONUS_MASK = 0xFFFFFFFF0000FFFFFFFF; - uint256 constant DECIMALS_MASK = 0xFFFFFF00FFFFFFFFFFFF; - uint256 constant ACTIVE_MASK = 0xFFFFFEFFFFFFFFFFFFFF; - uint256 constant FROZEN_MASK = 0xFFFFFDFFFFFFFFFFFFFF; - uint256 constant BORROWING_MASK = 0xFFFFFBFFFFFFFFFFFFFF; - uint256 constant STABLE_BORROWING_MASK = 0xFFFFF7FFFFFFFFFFFFFF; - uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFF; + uint256 constant LTV_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000; // prettier-ignore + uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF; // prettier-ignore + uint256 constant LIQUIDATION_BONUS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFF; // prettier-ignore + uint256 constant DECIMALS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF; // prettier-ignore + uint256 constant ACTIVE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF; // prettier-ignore + uint256 constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; // prettier-ignore + uint256 constant BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF; // prettier-ignore + uint256 constant STABLE_BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFF; // prettier-ignore + uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFF; // prettier-ignore /// @dev For the LTV, the start bit is 0 (up to 15), but we don't declare it as for 0 no bit movement is needed uint256 constant LIQUIDATION_THRESHOLD_START_BIT_POSITION = 16; @@ -27,6 +29,12 @@ library ReserveConfiguration { uint256 constant STABLE_BORROWING_ENABLED_START_BIT_POSITION = 59; uint256 constant RESERVE_FACTOR_START_BIT_POSITION = 64; + uint256 constant MAX_VALID_LTV = 65535; + uint256 constant MAX_VALID_LIQUIDATION_THRESHOLD = 65535; + uint256 constant MAX_VALID_LIQUIDATION_BONUS = 65535; + uint256 constant MAX_VALID_DECIMALS = 255; + uint256 constant MAX_VALID_RESERVE_FACTOR = 65535; + struct Map { //bit 0-15: LTV //bit 16-31: Liq. threshold @@ -47,6 +55,8 @@ library ReserveConfiguration { * @param ltv the new ltv **/ function setLtv(ReserveConfiguration.Map memory self, uint256 ltv) internal pure { + require(ltv <= MAX_VALID_LTV, Errors.INVALID_LTV); + self.data = (self.data & LTV_MASK) | ltv; } @@ -68,6 +78,8 @@ library ReserveConfiguration { internal pure { + require(threshold <= MAX_VALID_LIQUIDATION_THRESHOLD, Errors.INVALID_LIQ_THRESHOLD); + self.data = (self.data & LIQUIDATION_THRESHOLD_MASK) | (threshold << LIQUIDATION_THRESHOLD_START_BIT_POSITION); @@ -92,6 +104,8 @@ library ReserveConfiguration { * @param bonus the new liquidation bonus **/ function setLiquidationBonus(ReserveConfiguration.Map memory self, uint256 bonus) internal pure { + require(bonus <= MAX_VALID_LIQUIDATION_BONUS, Errors.INVALID_LIQ_BONUS); + self.data = (self.data & LIQUIDATION_BONUS_MASK) | (bonus << LIQUIDATION_BONUS_START_BIT_POSITION); @@ -116,6 +130,8 @@ library ReserveConfiguration { * @param decimals the decimals **/ function setDecimals(ReserveConfiguration.Map memory self, uint256 decimals) internal pure { + require(decimals <= MAX_VALID_DECIMALS, Errors.INVALID_DECIMALS); + self.data = (self.data & DECIMALS_MASK) | (decimals << RESERVE_DECIMALS_START_BIT_POSITION); } @@ -145,7 +161,7 @@ library ReserveConfiguration { * @return the active state **/ function getActive(ReserveConfiguration.Map storage self) internal view returns (bool) { - return ((self.data & ~ACTIVE_MASK) >> IS_ACTIVE_START_BIT_POSITION) != 0; + return (self.data & ~ACTIVE_MASK) != 0; } /** @@ -165,7 +181,7 @@ library ReserveConfiguration { * @return the frozen state **/ function getFrozen(ReserveConfiguration.Map storage self) internal view returns (bool) { - return ((self.data & ~FROZEN_MASK) >> IS_FROZEN_START_BIT_POSITION) != 0; + return (self.data & ~FROZEN_MASK) != 0; } /** @@ -185,7 +201,7 @@ library ReserveConfiguration { * @return the borrowing state **/ function getBorrowingEnabled(ReserveConfiguration.Map storage self) internal view returns (bool) { - return ((self.data & ~BORROWING_MASK) >> BORROWING_ENABLED_START_BIT_POSITION) != 0; + return (self.data & ~BORROWING_MASK) != 0; } /** @@ -212,8 +228,7 @@ library ReserveConfiguration { view returns (bool) { - return - ((self.data & ~STABLE_BORROWING_MASK) >> STABLE_BORROWING_ENABLED_START_BIT_POSITION) != 0; + return (self.data & ~STABLE_BORROWING_MASK) != 0; } /** @@ -225,6 +240,8 @@ library ReserveConfiguration { internal pure { + require(reserveFactor <= MAX_VALID_RESERVE_FACTOR, Errors.INVALID_RESERVE_FACTOR); + self.data = (self.data & RESERVE_FACTOR_MASK) | (reserveFactor << RESERVE_FACTOR_START_BIT_POSITION); @@ -257,10 +274,10 @@ library ReserveConfiguration { uint256 dataLocal = self.data; return ( - (dataLocal & ~ACTIVE_MASK) >> IS_ACTIVE_START_BIT_POSITION != 0, - (dataLocal & ~FROZEN_MASK) >> IS_FROZEN_START_BIT_POSITION != 0, - (dataLocal & ~BORROWING_MASK) >> BORROWING_ENABLED_START_BIT_POSITION != 0, - (dataLocal & ~STABLE_BORROWING_MASK) >> STABLE_BORROWING_ENABLED_START_BIT_POSITION != 0 + (dataLocal & ~ACTIVE_MASK) != 0, + (dataLocal & ~FROZEN_MASK) != 0, + (dataLocal & ~BORROWING_MASK) != 0, + (dataLocal & ~STABLE_BORROWING_MASK) != 0 ); } @@ -316,8 +333,7 @@ library ReserveConfiguration { ); } - - /** + /** * @dev gets the configuration flags of the reserve from a memory object * @param self the reserve configuration * @return the state flags representing active, freezed, borrowing enabled, stableRateBorrowing enabled @@ -333,10 +349,10 @@ library ReserveConfiguration { ) { return ( - (self.data & ~ACTIVE_MASK) >> IS_ACTIVE_START_BIT_POSITION != 0, - (self.data & ~FROZEN_MASK) >> IS_FROZEN_START_BIT_POSITION != 0, - (self.data & ~BORROWING_MASK) >> BORROWING_ENABLED_START_BIT_POSITION != 0, - (self.data & ~STABLE_BORROWING_MASK) >> STABLE_BORROWING_ENABLED_START_BIT_POSITION != 0 + (self.data & ~ACTIVE_MASK) != 0, + (self.data & ~FROZEN_MASK) != 0, + (self.data & ~BORROWING_MASK) != 0, + (self.data & ~STABLE_BORROWING_MASK) != 0 ); } } diff --git a/contracts/libraries/helpers/Errors.sol b/contracts/libraries/helpers/Errors.sol index 91dd385f..b515603f 100644 --- a/contracts/libraries/helpers/Errors.sol +++ b/contracts/libraries/helpers/Errors.sol @@ -46,6 +46,7 @@ library Errors { string public constant NO_MORE_RESERVES_ALLOWED = '59'; string public constant INVALID_FLASH_LOAN_EXECUTOR_RETURN = '60'; string public constant INCONSISTENT_FLASHLOAN_PARAMS = '69'; + string public constant CALLER_MUST_BE_AN_ATOKEN = '76'; // require error messages - aToken - DebtTokens string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool' @@ -89,6 +90,15 @@ library Errors { // pausable error message string public constant IS_PAUSED = '58'; // 'Pool is paused' + + // Reserve configuration + string public constant INVALID_LTV = '70'; + string public constant INVALID_LIQ_THRESHOLD = '71'; + string public constant INVALID_LIQ_BONUS = '72'; + string public constant INVALID_DECIMALS = '73'; + string public constant INVALID_RESERVE_FACTOR = '74'; + + enum CollateralManagerErrors { NO_ERROR, NO_COLLATERAL_AVAILABLE, diff --git a/contracts/libraries/helpers/StringLib.sol b/contracts/libraries/helpers/StringLib.sol new file mode 100644 index 00000000..fd4584a0 --- /dev/null +++ b/contracts/libraries/helpers/StringLib.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity ^0.6.8; + +library StringLib { + function concat(string memory a, string memory b) internal pure returns (string memory) { + return string(abi.encodePacked(a, b)); + } +} diff --git a/contracts/libraries/logic/GenericLogic.sol b/contracts/libraries/logic/GenericLogic.sol index a5801b9d..28d91927 100644 --- a/contracts/libraries/logic/GenericLogic.sol +++ b/contracts/libraries/logic/GenericLogic.sol @@ -33,7 +33,7 @@ library GenericLogic { uint256 borrowBalanceETH; uint256 avgLiquidationThreshold; uint256 amountToDecreaseETH; - uint256 collateralBalancefterDecrease; + uint256 collateralBalanceAfterDecrease; uint256 liquidationThresholdAfterDecrease; uint256 healthFactorAfterDecrease; bool reserveUsageAsCollateralEnabled; @@ -91,10 +91,10 @@ library GenericLogic { 10**vars.decimals ); - vars.collateralBalancefterDecrease = vars.collateralBalanceETH.sub(vars.amountToDecreaseETH); + vars.collateralBalanceAfterDecrease = vars.collateralBalanceETH.sub(vars.amountToDecreaseETH); //if there is a borrow, there can't be 0 collateral - if (vars.collateralBalancefterDecrease == 0) { + if (vars.collateralBalanceAfterDecrease == 0) { return false; } @@ -102,15 +102,15 @@ library GenericLogic { .collateralBalanceETH .mul(vars.avgLiquidationThreshold) .sub(vars.amountToDecreaseETH.mul(vars.liquidationThreshold)) - .div(vars.collateralBalancefterDecrease); + .div(vars.collateralBalanceAfterDecrease); uint256 healthFactorAfterDecrease = calculateHealthFactorFromBalances( - vars.collateralBalancefterDecrease, + vars.collateralBalanceAfterDecrease, vars.borrowBalanceETH, vars.liquidationThresholdAfterDecrease ); - return healthFactorAfterDecrease > GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD; + return healthFactorAfterDecrease >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD; } struct CalculateUserAccountDataVars { diff --git a/contracts/libraries/logic/ReserveLogic.sol b/contracts/libraries/logic/ReserveLogic.sol index ee6749da..1e4cba4c 100644 --- a/contracts/libraries/logic/ReserveLogic.sol +++ b/contracts/libraries/logic/ReserveLogic.sol @@ -151,12 +151,14 @@ library ReserveLogic { .scaledTotalSupply(); uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex; uint256 previousLiquidityIndex = reserve.liquidityIndex; + uint40 lastUpdatedTimestamp = reserve.lastUpdateTimestamp; (uint256 newLiquidityIndex, uint256 newVariableBorrowIndex) = _updateIndexes( reserve, scaledVariableDebt, previousLiquidityIndex, - previousVariableBorrowIndex + previousVariableBorrowIndex, + lastUpdatedTimestamp ); _mintToTreasury( @@ -164,7 +166,8 @@ library ReserveLogic { scaledVariableDebt, previousVariableBorrowIndex, newLiquidityIndex, - newVariableBorrowIndex + newVariableBorrowIndex, + lastUpdatedTimestamp ); } @@ -318,7 +321,8 @@ library ReserveLogic { uint256 scaledVariableDebt, uint256 previousVariableBorrowIndex, uint256 newLiquidityIndex, - uint256 newVariableBorrowIndex + uint256 newVariableBorrowIndex, + uint40 timestamp ) internal { MintToTreasuryLocalVars memory vars; @@ -345,7 +349,8 @@ library ReserveLogic { //calculate the stable debt until the last timestamp update vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest( vars.avgStableRate, - vars.stableSupplyUpdatedTimestamp + vars.stableSupplyUpdatedTimestamp, + timestamp ); vars.previousStableDebt = vars.principalStableDebt.rayMul(vars.cumulatedStableInterest); @@ -375,10 +380,9 @@ library ReserveLogic { ReserveData storage reserve, uint256 scaledVariableDebt, uint256 liquidityIndex, - uint256 variableBorrowIndex + uint256 variableBorrowIndex, + uint40 timestamp ) internal returns (uint256, uint256) { - uint40 timestamp = reserve.lastUpdateTimestamp; - uint256 currentLiquidityRate = reserve.currentLiquidityRate; uint256 newLiquidityIndex = liquidityIndex; diff --git a/contracts/libraries/logic/ValidationLogic.sol b/contracts/libraries/logic/ValidationLogic.sol index 947d84ea..78f74154 100644 --- a/contracts/libraries/logic/ValidationLogic.sol +++ b/contracts/libraries/logic/ValidationLogic.sol @@ -46,6 +46,11 @@ library ValidationLogic { * @param reserveAddress the address of the reserve * @param amount the amount to be withdrawn * @param userBalance the balance of the user + * @param reservesData the reserves state + * @param userConfig the user configuration + * @param reserves the addresses of the reserves + * @param reservesCount the number of reserves + * @param oracle the price oracle */ function validateWithdraw( address reserveAddress, @@ -389,4 +394,35 @@ library ValidationLogic { return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS); } + + /** + * @dev validates an aToken transfer. + * @param from the user from which the aTokens are being transferred + * @param reservesData the state of all the reserves + * @param userConfig the state of the user for the specific reserve + * @param reserves the addresses of all the active reserves + * @param oracle the price oracle + */ + function validateTransfer( + address from, + mapping(address => ReserveLogic.ReserveData) storage reservesData, + UserConfiguration.Map storage userConfig, + mapping(uint256 => address) storage reserves, + uint256 reservesCount, + address oracle + ) internal view { + (, , , , uint256 healthFactor) = GenericLogic.calculateUserAccountData( + from, + reservesData, + userConfig, + reserves, + reservesCount, + oracle + ); + + require( + healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, + Errors.TRANSFER_NOT_ALLOWED + ); + } } diff --git a/contracts/libraries/math/MathUtils.sol b/contracts/libraries/math/MathUtils.sol index e929e57c..e99a7ccc 100644 --- a/contracts/libraries/math/MathUtils.sol +++ b/contracts/libraries/math/MathUtils.sol @@ -42,13 +42,13 @@ library MathUtils { * @param lastUpdateTimestamp the timestamp of the last update of the interest * @return the interest rate compounded during the timeDelta, in ray **/ - function calculateCompoundedInterest(uint256 rate, uint40 lastUpdateTimestamp) - internal - view - returns (uint256) - { + function calculateCompoundedInterest( + uint256 rate, + uint40 lastUpdateTimestamp, + uint256 currentTimestamp + ) internal pure returns (uint256) { //solium-disable-next-line - uint256 exp = block.timestamp.sub(uint256(lastUpdateTimestamp)); + uint256 exp = currentTimestamp.sub(uint256(lastUpdateTimestamp)); if (exp == 0) { return WadRayMath.ray(); @@ -68,4 +68,17 @@ library MathUtils { return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm); } + + /** + * @dev calculates the compounded interest between the timestamp of the last update and the current block timestamp + * @param rate the interest rate (in ray) + * @param lastUpdateTimestamp the timestamp from which the interest accumulation needs to be calculated + **/ + function calculateCompoundedInterest(uint256 rate, uint40 lastUpdateTimestamp) + internal + view + returns (uint256) + { + return calculateCompoundedInterest(rate, lastUpdateTimestamp, block.timestamp); + } } diff --git a/contracts/libraries/math/PercentageMath.sol b/contracts/libraries/math/PercentageMath.sol index b853f1db..dda119f9 100644 --- a/contracts/libraries/math/PercentageMath.sol +++ b/contracts/libraries/math/PercentageMath.sol @@ -22,19 +22,16 @@ library PercentageMath { * @return the percentage of value **/ function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) { - if (value == 0) { + if (value == 0 || percentage == 0) { return 0; } - uint256 result = value * percentage; + require( + value <= (type(uint256).max - HALF_PERCENT) / percentage, + Errors.MULTIPLICATION_OVERFLOW + ); - require(result / value == percentage, Errors.MULTIPLICATION_OVERFLOW); - - result += HALF_PERCENT; - - require(result >= HALF_PERCENT, Errors.ADDITION_OVERFLOW); - - return result / PERCENTAGE_FACTOR; + return (value * percentage + HALF_PERCENT) / PERCENTAGE_FACTOR; } /** @@ -47,14 +44,11 @@ library PercentageMath { require(percentage != 0, Errors.DIVISION_BY_ZERO); uint256 halfPercentage = percentage / 2; - uint256 result = value * PERCENTAGE_FACTOR; + require( + value <= (type(uint256).max - halfPercentage) / PERCENTAGE_FACTOR, + Errors.MULTIPLICATION_OVERFLOW + ); - require(result / PERCENTAGE_FACTOR == value, Errors.MULTIPLICATION_OVERFLOW); - - result += halfPercentage; - - require(result >= halfPercentage, Errors.ADDITION_OVERFLOW); - - return result / percentage; + return (value * PERCENTAGE_FACTOR + halfPercentage) / percentage; } } diff --git a/contracts/libraries/math/WadRayMath.sol b/contracts/libraries/math/WadRayMath.sol index a1a8d8f4..2b4f989a 100644 --- a/contracts/libraries/math/WadRayMath.sol +++ b/contracts/libraries/math/WadRayMath.sol @@ -54,15 +54,13 @@ library WadRayMath { * @return the result of a*b, in wad **/ function wadMul(uint256 a, uint256 b) internal pure returns (uint256) { - if (a == 0) { + if (a == 0 || b == 0) { return 0; } - uint256 result = a * b + halfWAD; + require(a <= (type(uint256).max - halfWAD) / b, Errors.MULTIPLICATION_OVERFLOW); - require(result >= halfWAD && (result - halfWAD) / a == b, Errors.MULTIPLICATION_OVERFLOW); - - return result / WAD; + return (a * b + halfWAD) / WAD; } /** @@ -73,14 +71,11 @@ library WadRayMath { **/ function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, Errors.DIVISION_BY_ZERO); - uint256 halfB = b / 2; - uint256 result = a * WAD + halfB; + require(a <= (type(uint256).max - halfB) / WAD, Errors.MULTIPLICATION_OVERFLOW); - require(result >= halfB && (result - halfB) / WAD == a, Errors.MULTIPLICATION_OVERFLOW); - - return result / b; + return (a * WAD + halfB) / b; } /** @@ -90,15 +85,13 @@ library WadRayMath { * @return the result of a*b, in ray **/ function rayMul(uint256 a, uint256 b) internal pure returns (uint256) { - if (a == 0) { + if (a == 0 || b == 0) { return 0; } - uint256 result = a * b + halfRAY; + require(a <= (type(uint256).max - halfRAY) / b, Errors.MULTIPLICATION_OVERFLOW); - require(result >= halfRAY && (result - halfRAY) / a == b, Errors.MULTIPLICATION_OVERFLOW); - - return result / RAY; + return (a * b + halfRAY) / RAY; } /** @@ -109,14 +102,11 @@ library WadRayMath { **/ function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, Errors.DIVISION_BY_ZERO); - uint256 halfB = b / 2; - uint256 result = a * RAY + halfB; + require(a <= (type(uint256).max - halfB) / RAY, Errors.MULTIPLICATION_OVERFLOW); - require(result >= halfB && (result - halfB) / RAY == a, Errors.MULTIPLICATION_OVERFLOW); - - return result / b; + return (a * RAY + halfB) / b; } /** diff --git a/contracts/mocks/oracle/CLAggregators/MockAggregator.sol b/contracts/mocks/oracle/CLAggregators/MockAggregator.sol index 40188f7c..e0950e04 100644 --- a/contracts/mocks/oracle/CLAggregators/MockAggregator.sol +++ b/contracts/mocks/oracle/CLAggregators/MockAggregator.sol @@ -14,4 +14,13 @@ contract MockAggregator { function latestAnswer() external view returns (int256) { return _latestAnswer; } + + function getTokenType() external view returns (uint256) { + return 1; + } + + // function getSubTokens() external view returns (address[] memory) { + // TODO: implement mock for when multiple subtokens. Maybe we need to create diff mock contract + // to call it from the migration for this case?? + // } } diff --git a/contracts/mocks/tokens/MintableERC20.sol b/contracts/mocks/tokens/MintableERC20.sol index 394bcde2..2c79d971 100644 --- a/contracts/mocks/tokens/MintableERC20.sol +++ b/contracts/mocks/tokens/MintableERC20.sol @@ -22,7 +22,7 @@ contract MintableERC20 is ERC20 { * @return A boolean that indicates if the operation was successful. */ function mint(uint256 value) public returns (bool) { - _mint(msg.sender, value); + _mint(_msgSender(), value); return true; } } diff --git a/contracts/tokenization/AToken.sol b/contracts/tokenization/AToken.sol index bee1184d..adc1771b 100644 --- a/contracts/tokenization/AToken.sol +++ b/contracts/tokenization/AToken.sol @@ -40,7 +40,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken { bytes32 public DOMAIN_SEPARATOR; modifier onlyLendingPool { - require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL); + require(_msgSender() == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL); _; } @@ -108,7 +108,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken { //transfer event to track balances emit Transfer(user, address(0), amount); - emit Burn(msg.sender, receiverOfUnderlying, amount, index); + emit Burn(_msgSender(), receiverOfUnderlying, amount, index); } /** @@ -241,16 +241,6 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken { return super.totalSupply(); } - /** - * @dev Used to validate transfers before actually executing them. - * @param user address of the user to check - * @param amount the amount to check - * @return true if the user can transfer amount, false otherwise - **/ - function isTransferAllowed(address user, uint256 amount) public override view returns (bool) { - return POOL.balanceDecreaseAllowed(UNDERLYING_ASSET_ADDRESS, user, amount); - } - /** * @dev transfers the underlying asset to the target. Used by the lendingpool to transfer * assets in borrow(), redeem() and flashLoan() @@ -317,14 +307,24 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken { uint256 amount, bool validate ) internal { - if (validate) { - require(isTransferAllowed(from, amount), Errors.TRANSFER_NOT_ALLOWED); - } - uint256 index = POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS); + uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index); + uint256 toBalanceBefore = super.balanceOf(to).rayMul(index); + super._transfer(from, to, amount.rayDiv(index)); + if (validate) { + POOL.finalizeTransfer( + UNDERLYING_ASSET_ADDRESS, + from, + to, + amount, + fromBalanceBefore, + toBalanceBefore + ); + } + emit BalanceTransfer(from, to, amount, index); } diff --git a/contracts/tokenization/IncentivizedERC20.sol b/contracts/tokenization/IncentivizedERC20.sol index d97e9da2..097a298f 100644 --- a/contracts/tokenization/IncentivizedERC20.sol +++ b/contracts/tokenization/IncentivizedERC20.sol @@ -73,14 +73,14 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed { } /** - * @dev executes a transfer of tokens from msg.sender to recipient + * @dev executes a transfer of tokens from _msgSender() to recipient * @param recipient the recipient of the tokens * @param amount the amount of tokens being transferred * @return true if the transfer succeeds, false otherwise **/ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); - emit Transfer(msg.sender, recipient, amount); + emit Transfer(_msgSender(), recipient, amount); return true; } @@ -101,8 +101,8 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed { } /** - * @dev allows spender to spend the tokens owned by msg.sender - * @param spender the user allowed to spend msg.sender tokens + * @dev allows spender to spend the tokens owned by _msgSender() + * @param spender the user allowed to spend _msgSender() tokens * @return true **/ function approve(address spender, uint256 amount) public virtual override returns (bool) { @@ -111,7 +111,7 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed { } /** - * @dev executes a transfer of token from sender to recipient, if msg.sender is allowed to do so + * @dev executes a transfer of token from sender to recipient, if _msgSender() is allowed to do so * @param sender the owner of the tokens * @param recipient the recipient of the tokens * @param amount the amount of tokens being transferred @@ -133,8 +133,8 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed { } /** - * @dev increases the allowance of spender to spend msg.sender tokens - * @param spender the user allowed to spend on behalf of msg.sender + * @dev increases the allowance of spender to spend _msgSender() tokens + * @param spender the user allowed to spend on behalf of _msgSender() * @param addedValue the amount being added to the allowance * @return true **/ @@ -144,8 +144,8 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed { } /** - * @dev decreases the allowance of spender to spend msg.sender tokens - * @param spender the user allowed to spend on behalf of msg.sender + * @dev decreases the allowance of spender to spend _msgSender() tokens + * @param spender the user allowed to spend on behalf of _msgSender() * @param subtractedValue the amount being subtracted to the allowance * @return true **/ diff --git a/contracts/tokenization/base/DebtTokenBase.sol b/contracts/tokenization/base/DebtTokenBase.sol index fc43e770..0dddb431 100644 --- a/contracts/tokenization/base/DebtTokenBase.sol +++ b/contracts/tokenization/base/DebtTokenBase.sol @@ -23,7 +23,7 @@ abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable { * @dev Only lending pool can call functions marked by this modifier **/ modifier onlyLendingPool { - require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL); + require(_msgSender() == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL); _; } diff --git a/contracts/tokenization/interfaces/IAToken.sol b/contracts/tokenization/interfaces/IAToken.sol index 00f63b20..055e3f5d 100644 --- a/contracts/tokenization/interfaces/IAToken.sol +++ b/contracts/tokenization/interfaces/IAToken.sol @@ -54,8 +54,6 @@ interface IAToken is IERC20, IScaledBalanceToken { uint256 value ) external; - function isTransferAllowed(address user, uint256 amount) external view returns (bool); - /** * @dev transfer the amount of the underlying asset to the user * @param user address of the user diff --git a/deployed-contracts.json b/deployed-contracts.json index f924b450..9690522a 100644 --- a/deployed-contracts.json +++ b/deployed-contracts.json @@ -3,303 +3,35 @@ "buidlerevm": { "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "LendingPoolAddressesProvider": { - "buidlerevm": { - "address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x5191aA68c7dB195181Dd2441dBE23A48EA24b040", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "kovan": { - "address": "0xF9a2E6D57c691f3aa5269858178a13Ef06378579", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" - } - }, - "LendingPoolAddressesProviderRegistry": { - "buidlerevm": { - "address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xa89E20284Bd638F31b0011D0fC754Fc9d2fa73e3", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "kovan": { - "address": "0xf3266d89e6742fAE2C35D05eD549cd4e117300a7", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" - } - }, - "FeeProvider": { - "buidlerevm": { - "address": "0xFAe0fd738dAbc8a0426F47437322b6d026A9FD95", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e" - } - }, - "LendingPoolParametersProvider": { - "buidlerevm": { - "address": "0x2C4603396dE2F08642354A3A102760827FfFe113" - } - }, - "LendingPoolCore": { - "buidlerevm": { - "address": "0xA10958a24032283FbE2D23cedf264d6eC9411CBA" - } - }, - "LendingPoolConfigurator": { - "buidlerevm": { - "address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8" - }, - "localhost": { - "address": "0x9Ec55627757348b322c8dD0865D704649bFa0c7b" - }, - "kovan": { - "address": "0x1aae278bCcdb95817c7A546d752fC662F09b6DBa" - } - }, - "LendingPoolDataProvider": { - "buidlerevm": { - "address": "0x612719Ace03A8281188d61612A9f40D1da3ca420" - } - }, - "LendingPool": { - "buidlerevm": { - "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e" - }, - "localhost": { - "address": "0x3EE716e38f21e5FC16BFDB773db24D63C637A5d8" - }, - "kovan": { - "address": "0x8E05A3054cb736258FaF4638D07058cE6e294d2C" - } - }, - "PriceOracle": { - "buidlerevm": { - "address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x5889354f21A1C8D8D2f82669d778f6Dab778B519", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "MockAggregator": { - "buidlerevm": { - "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xC452C5244F701108B4e8E8BCe693160046b30332", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "ChainlinkProxyPriceProvider": { - "buidlerevm": { - "address": "0x7B6C3e5486D9e6959441ab554A889099eed76290", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x0B63c002cb44B2e5e580C3B3560a27F4101D95c0", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x7B6C3e5486D9e6959441ab554A889099eed76290", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "kovan": { - "address": "0x18a107d4fa249Efefd4DAf9A76EEE3b6366701AA", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" - } - }, - "LendingRateOracle": { - "buidlerevm": { - "address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xCeB290A2C6614BF23B2faa0f0B8067F29C48DB0F", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "kovan": { - "address": "0xac6Eb7B1083D39eC695a3898C2f782E7c7C64973", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" - } - }, - "DefaultReserveInterestRateStrategy": { - "buidlerevm": { - "address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x7C95b1ad025F0C9aB14192f87bF2aD53889bE4F7", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x626FdE749F9d499d3777320CAf29484B624ab84a", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "kovan": { - "address": "0x47341CE48FfE1cbD91991578B880a18c45cdB5CA", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" - } - }, - "LendingPoolLiquidationManager": { - "buidlerevm": { - "address": "0xFe230c227D3724015d0dE3dBEc831825f1ed1f59", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "MockOneSplit": { - "buidlerevm": { - "address": "0x4b2c297ba5be42610994974b9543D56B864CA011", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x4b2c297ba5be42610994974b9543D56B864CA011", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "OneSplitAdapter": { - "buidlerevm": { - "address": "0x24E420B42971372F060a93129846761F354Bc50B", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x24E420B42971372F060a93129846761F354Bc50B", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "TokenDistributor": { - "buidlerevm": { - "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4" - } - }, - "InitializableAdminUpgradeabilityProxy": { - "buidlerevm": { - "address": "0xC6bA6049F86d528698B5924B8fC2FE7289D38578", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "MockFlashLoanReceiver": { - "buidlerevm": { - "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2" - }, - "localhost": { - "address": "0x9c91aEaD98b1354C7B0EAfb8ff539d0796c79894" - }, - "coverage": { - "address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA" - } - }, - "WalletBalanceProvider": { - "buidlerevm": { - "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x145b7B6368Df63e7F3497b0A948B30fC1A4d5E55", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "DAI": { "buidlerevm": { "address": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x010e948B9B7D30771E23346C0B17a4D5Ff04e300", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "LEND": { "buidlerevm": { "address": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x79094eDB848047e87a4B8a64ab5Ee2f527791bC0", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "TUSD": { "buidlerevm": { "address": "0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xEE0A69d0Bb1312685870Dd7E20AcAD66b6f6264F", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "BAT": { "buidlerevm": { "address": "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x631B367fBE1dbB934bC039aAA0C9eC2EE5943fd5", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c", + } + }, + "WETH": { + "buidlerevm": { + "address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -307,412 +39,230 @@ "buidlerevm": { "address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xf55Af78B3f3059fACF166Aa338FFe059A14e75F6", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "USDT": { "buidlerevm": { "address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xD5A0587aAEB195028909E98930B391dFB3f9F589", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "SUSD": { "buidlerevm": { "address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xaD3AdbC18E4AD090034A6C74Eda61f4310dce313", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "ZRX": { "buidlerevm": { "address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x25a88BbA9c8D2a46e3Ff4bFe98712DF7A1044fB6", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "MKR": { "buidlerevm": { "address": "0xc4905364b78a742ccce7B890A89514061E47068D", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x16d1802cd7cfcb67955BBBa26bAae1cE559B5F5B", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xc4905364b78a742ccce7B890A89514061E47068D", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "WBTC": { "buidlerevm": { "address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xE58d8c88f5A670f16BE8F7864707170F43e943A6", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "LINK": { "buidlerevm": { "address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xfdAF4f6e47e854c05bE158993d32872e784F0502", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "KNC": { "buidlerevm": { "address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x92edC13A10036A3C50396f2B63148a3e9a8D589e", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "MANA": { "buidlerevm": { "address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xE5C277cDb7E10372918Ac54Ce54022910A24FE88", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "REP": { "buidlerevm": { "address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xF5742a599a0F4520089cbf2EBBa66Bb4F471B85F", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "SNX": { "buidlerevm": { "address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x380EF388e13D8cAdeACef6eF682C7B7D85865076", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "BUSD": { "buidlerevm": { "address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xC89577DED8441e52C17C13D527b85b225C5c8311", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "USD": { "buidlerevm": { "address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xD4b06774A717Ff5A7c20c8712e31c6BbfFcb1F01", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "UNI_DAI_ETH": { "buidlerevm": { "address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xbe66dC9DFEe580ED968403e35dF7b5159f873df8", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "UNI_USDC_ETH": { "buidlerevm": { "address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x93AfC6Df4bB8F62F2493B19e577f8382c0BA9EBC", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "UNI_SETH_ETH": { "buidlerevm": { "address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x75Ded61646B5945BdDd0CD9a9Db7c8288DA6F810", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "UNI_LINK_ETH": { "buidlerevm": { "address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xdE7c40e675bF1aA45c18cCbaEb9662B16b0Ddf7E", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "UNI_MKR_ETH": { "buidlerevm": { "address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xEcb928A3c079a1696Aa5244779eEc3dE1717fACd", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "UNI_LEND_ETH": { "buidlerevm": { "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544", + } + }, + "LendingPoolAddressesProvider": { + "buidlerevm": { + "address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22", + } + }, + "LendingPoolAddressesProviderRegistry": { + "buidlerevm": { + "address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "ReserveLogic": { + "buidlerevm": { + "address": "0xFAe0fd738dAbc8a0426F47437322b6d026A9FD95", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "GenericLogic": { + "buidlerevm": { + "address": "0x6082731fdAba4761277Fb31299ebC782AD3bCf24", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "ValidationLogic": { + "buidlerevm": { + "address": "0x8456161947DFc1fC159A0B26c025cD2b4bba0c3e", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "LendingPool": { + "buidlerevm": { + "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e" + } + }, + "LendingPoolConfigurator": { + "buidlerevm": { + "address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8" + } + }, + "StableAndVariableTokensHelper": { + "buidlerevm": { + "address": "0x0C6c3C47A1f650809B0D1048FDf9603e09473D7E", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "ATokensAndRatesHelper": { + "buidlerevm": { + "address": "0x06bA8d8af0dF898D0712DffFb0f862cC51AF45c2", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "PriceOracle": { + "buidlerevm": { + "address": "0xb682dEEf4f8e298d86bFc3e21f50c675151FB974", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "MockAggregator": { + "buidlerevm": { + "address": "0x3D8FFB457fedDFBc760F3F243283F52692b579B1", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "ChainlinkProxyPriceProvider": { + "buidlerevm": { + "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89", + "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + } + }, + "LendingRateOracle": { + "buidlerevm": { + "address": "0xAF6BA11790D1942625C0c2dA07da19AB63845cfF", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "AaveProtocolTestHelpers": { "buidlerevm": { - "address": "0xe7536f450378748E1BD4645D3c77ec38e0F3ba28" - }, - "localhost": { - "address": "0x987223924D2DD6c6efB601756850f3886ECbceF6" - }, - "coverage": { - "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4" - }, - "kovan": { - "address": "0xfF28b837352d9531bAb6dFF3650D7831192117F7", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" + "address": "0xf4830d6b1D70C8595d3BD8A63f9ed9F636DB9ef2" } }, - "StableDebtToken": { + "LendingPoolCollateralManager": { "buidlerevm": { - "address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d", + "address": "0x8D0206fEBEB380486729b64bB4cfEDC5b354a6D6", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xaca5aCeB6f44845d07Fd339a51F0bd52Bb3D8D1A", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "kovan": { - "address": "0x0EDc241FdA0dF39EB1B9eB1236217BBe72Ab911D", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" } }, - "VariableDebtToken": { + "MockFlashLoanReceiver": { "buidlerevm": { - "address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x9bD0Bec44106D8Ea8fFb6296d7A84742a290E064", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "kovan": { - "address": "0x293f5BcC66762c28a5d3Bd8512a799D457F5296D", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" + "address": "0xfC88832bac6AbdF216BC5A67be68E9DE94aD5ba2" } }, - "AToken": { - "localhost": { - "address": "0x00f126cCA2266bFb634Ed6DB17c4C74fb8cA5177", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, + "WalletBalanceProvider": { "buidlerevm": { - "address": "0x5f7134cd38C826a7649f9Cc47dda24d834DD2967", + "address": "0x1256eBA4d0a7A38D10BaF4F61775ba491Ce7EE25", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "kovan": { - "address": "0xf303Ae6F24C29D94E367fdb5C7aE04D32BEbF13E", - "deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F" } }, "MockAToken": { "buidlerevm": { - "address": "0x3bDA11B584dDff7F66E0cFe1da1562c92B45db60", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xbF538F34cb100bAeEE55aa1F036D33F03b03d900", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x392E5355a0e88Bd394F717227c752670fb3a8020", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "WETH": { - "buidlerevm": { - "address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0xff1B1B810F5DCe853a9b1819DE220D532D1CFeF2", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB", + "address": "0x77B0b5636fEA30eA79BB65AeCCdb599997A849A8", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "MockStableDebtToken": { "buidlerevm": { - "address": "0x392E5355a0e88Bd394F717227c752670fb3a8020", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x7436d6adaA697413F00cb63E1A2A854bF2Aec5A1", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460", + "address": "0x78Ee8Fb9fE5abD5e347Fc94c2fb85596d1f60e3c", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "MockVariableDebtToken": { "buidlerevm": { - "address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460", + "address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "localhost": { - "address": "0x2A7BE996B8801ED21f2f45148791D402811A2106", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - }, - "coverage": { - "address": "0xEBAB67ee3ef604D5c250A53b4b8fcbBC6ec3007C", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" - } - }, - "MockSwapAdapter": { - "buidlerevm": { - "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10" - }, - "coverage": { - "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2" - }, - "localhost": { - "address": "0x48FAde2E719B770E1783d03466dAEe98b5183538" - } - }, - "MockFlashRepayAdapter": { - "buidlerevm": { - "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10" - } - }, - "MockFlashLiquiditySwapAdapter": { - "buidlerevm": { - "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4" } } -} +} \ No newline at end of file diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts new file mode 100644 index 00000000..82ac2d97 --- /dev/null +++ b/helpers/contracts-deployments.ts @@ -0,0 +1,376 @@ +import {Contract} from 'ethers'; +import {BRE} from './misc-utils'; +import { + tEthereumAddress, + eContractid, + tStringTokenSmallUnits, + AavePools, + TokenContractId, + iMultiPoolsAssets, + IReserveParams, + PoolConfiguration, +} from './types'; + +import {MintableErc20 as MintableERC20} from '../types/MintableErc20'; +import {readArtifact} from '@nomiclabs/buidler/plugins'; +import {MockContract} from 'ethereum-waffle'; +import {getReservesConfigByPool} from './configuration'; +import {getFirstSigner} from './contracts-getters'; +import {ZERO_ADDRESS} from './constants'; +import { + AaveProtocolTestHelpersFactory, + ATokenFactory, + ATokensAndRatesHelperFactory, + ChainlinkProxyPriceProviderFactory, + DefaultReserveInterestRateStrategyFactory, + InitializableAdminUpgradeabilityProxyFactory, + LendingPoolAddressesProviderFactory, + LendingPoolAddressesProviderRegistryFactory, + LendingPoolCollateralManagerFactory, + LendingPoolConfiguratorFactory, + LendingPoolFactory, + LendingPoolLibraryAddresses, + LendingRateOracleFactory, + MintableErc20Factory, + MockAggregatorFactory, + MockFlashLoanReceiverFactory, + PriceOracleFactory, + ReserveLogicFactory, + StableDebtTokenFactory, + VariableDebtTokenFactory, + WalletBalanceProviderFactory, +} from '../types'; +import {withSaveAndVerify, registerContractInJsonDb, linkBytecode} from './contracts-helpers'; +import {StableAndVariableTokensHelperFactory} from '../types/StableAndVariableTokensHelperFactory'; + +export const deployLendingPoolAddressesProvider = async (verify?: boolean) => + withSaveAndVerify( + await new LendingPoolAddressesProviderFactory(await getFirstSigner()).deploy(), + eContractid.LendingPoolAddressesProvider, + [], + verify + ); + +export const deployLendingPoolAddressesProviderRegistry = async (verify?: boolean) => + withSaveAndVerify( + await new LendingPoolAddressesProviderRegistryFactory(await getFirstSigner()).deploy(), + eContractid.LendingPoolAddressesProviderRegistry, + [], + verify + ); + +export const deployLendingPoolConfigurator = async (verify?: boolean) => + withSaveAndVerify( + await new LendingPoolConfiguratorFactory(await getFirstSigner()).deploy(), + eContractid.LendingPoolConfigurator, + [], + verify + ); + +export const deployReserveLogicLibrary = async (verify?: boolean) => + withSaveAndVerify( + await new ReserveLogicFactory(await getFirstSigner()).deploy(), + eContractid.ReserveLogic, + [], + verify + ); + +export const deployGenericLogic = async (reserveLogic: Contract, verify?: boolean) => { + const genericLogicArtifact = await readArtifact( + BRE.config.paths.artifacts, + eContractid.GenericLogic + ); + + const linkedGenericLogicByteCode = linkBytecode(genericLogicArtifact, { + [eContractid.ReserveLogic]: reserveLogic.address, + }); + + const genericLogicFactory = await BRE.ethers.getContractFactory( + genericLogicArtifact.abi, + linkedGenericLogicByteCode + ); + + const genericLogic = await (await genericLogicFactory.deploy()).deployed(); + return withSaveAndVerify(genericLogic, eContractid.GenericLogic, [], verify); +}; + +export const deployValidationLogic = async ( + reserveLogic: Contract, + genericLogic: Contract, + verify?: boolean +) => { + const validationLogicArtifact = await readArtifact( + BRE.config.paths.artifacts, + eContractid.ValidationLogic + ); + + const linkedValidationLogicByteCode = linkBytecode(validationLogicArtifact, { + [eContractid.ReserveLogic]: reserveLogic.address, + [eContractid.GenericLogic]: genericLogic.address, + }); + + const validationLogicFactory = await BRE.ethers.getContractFactory( + validationLogicArtifact.abi, + linkedValidationLogicByteCode + ); + + const validationLogic = await (await validationLogicFactory.deploy()).deployed(); + + return withSaveAndVerify(validationLogic, eContractid.ValidationLogic, [], verify); +}; + +export const deployAaveLibraries = async ( + verify?: boolean +): Promise => { + const reserveLogic = await deployReserveLogicLibrary(verify); + const genericLogic = await deployGenericLogic(reserveLogic, verify); + const validationLogic = await deployValidationLogic(reserveLogic, genericLogic, verify); + + // Hardcoded solidity placeholders, if any library changes path this will fail. + // The '__$PLACEHOLDER$__ can be calculated via solidity keccak, but the LendingPoolLibraryAddresses Type seems to + // require a hardcoded string. + // + // how-to: + // 1. PLACEHOLDER = solidityKeccak256(['string'], `${libPath}:${libName}`).slice(2, 36) + // 2. LIB_PLACEHOLDER = `__$${PLACEHOLDER}$__` + // or grab placeholdes from LendingPoolLibraryAddresses at Typechain generation. + // + // libPath example: contracts/libraries/logic/GenericLogic.sol + // libName example: GenericLogic + return { + ['__$5201a97c05ba6aa659e2f36a933dd51801$__']: validationLogic.address, + ['__$d3b4366daeb9cadc7528af6145b50b2183$__']: reserveLogic.address, + ['__$4c26be947d349222af871a3168b3fe584b$__']: genericLogic.address, + }; +}; + +export const deployLendingPool = async (verify?: boolean) => { + const libraries = await deployAaveLibraries(verify); + return withSaveAndVerify( + await new LendingPoolFactory(libraries, await getFirstSigner()).deploy(), + eContractid.LendingPool, + [], + verify + ); +}; + +export const deployPriceOracle = async (verify?: boolean) => + withSaveAndVerify( + await new PriceOracleFactory(await getFirstSigner()).deploy(), + eContractid.PriceOracle, + [], + verify + ); + +export const deployLendingRateOracle = async (verify?: boolean) => + withSaveAndVerify( + await new LendingRateOracleFactory(await getFirstSigner()).deploy(), + eContractid.LendingRateOracle, + [], + verify + ); + +export const deployMockAggregator = async (price: tStringTokenSmallUnits, verify?: boolean) => + withSaveAndVerify( + await new MockAggregatorFactory(await getFirstSigner()).deploy(price), + eContractid.MockAggregator, + [price], + verify + ); + +export const deployChainlinkProxyPriceProvider = async ( + args: [tEthereumAddress[], tEthereumAddress[], tEthereumAddress], + verify?: boolean +) => + withSaveAndVerify( + await new ChainlinkProxyPriceProviderFactory(await getFirstSigner()).deploy(...args), + eContractid.ChainlinkProxyPriceProvider, + args, + verify + ); + +export const deployLendingPoolCollateralManager = async (verify?: boolean) => { + return withSaveAndVerify( + await new LendingPoolCollateralManagerFactory(await getFirstSigner()).deploy(), + eContractid.LendingPoolCollateralManager, + [], + verify + ); +}; + +export const deployInitializableAdminUpgradeabilityProxy = async (verify?: boolean) => + withSaveAndVerify( + await new InitializableAdminUpgradeabilityProxyFactory(await getFirstSigner()).deploy(), + eContractid.InitializableAdminUpgradeabilityProxy, + [], + verify + ); + +export const deployMockFlashLoanReceiver = async ( + addressesProvider: tEthereumAddress, + verify?: boolean +) => + withSaveAndVerify( + await new MockFlashLoanReceiverFactory(await getFirstSigner()).deploy(addressesProvider), + eContractid.MockFlashLoanReceiver, + [addressesProvider], + verify + ); + +export const deployWalletBalancerProvider = async ( + addressesProvider: tEthereumAddress, + verify?: boolean +) => + withSaveAndVerify( + await new WalletBalanceProviderFactory(await getFirstSigner()).deploy(addressesProvider), + eContractid.WalletBalanceProvider, + [addressesProvider], + verify + ); + +export const deployAaveProtocolTestHelpers = async ( + addressesProvider: tEthereumAddress, + verify?: boolean +) => + withSaveAndVerify( + await new AaveProtocolTestHelpersFactory(await getFirstSigner()).deploy(addressesProvider), + eContractid.AaveProtocolTestHelpers, + [addressesProvider], + verify + ); + +export const deployMintableERC20 = async ( + args: [string, string, string], + verify?: boolean +): Promise => + withSaveAndVerify( + await new MintableErc20Factory(await getFirstSigner()).deploy(...args), + eContractid.MintableERC20, + args, + verify + ); + +export const deployDefaultReserveInterestRateStrategy = async ( + args: [tEthereumAddress, string, string, string, string, string], + verify: boolean +) => + withSaveAndVerify( + await new DefaultReserveInterestRateStrategyFactory(await getFirstSigner()).deploy(...args), + eContractid.DefaultReserveInterestRateStrategy, + args, + verify + ); + +export const deployStableDebtToken = async ( + args: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress], + verify: boolean +) => + withSaveAndVerify( + await new StableDebtTokenFactory(await getFirstSigner()).deploy(...args), + eContractid.StableDebtToken, + args, + verify + ); + +export const deployVariableDebtToken = async ( + args: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress], + verify: boolean +) => + withSaveAndVerify( + await new VariableDebtTokenFactory(await getFirstSigner()).deploy(...args), + eContractid.VariableDebtToken, + args, + verify + ); + +export const deployGenericAToken = async ( + [poolAddress, underlyingAssetAddress, name, symbol, incentivesController]: [ + tEthereumAddress, + tEthereumAddress, + string, + string, + tEthereumAddress + ], + verify: boolean +) => { + const args: [ + tEthereumAddress, + tEthereumAddress, + tEthereumAddress, + string, + string, + tEthereumAddress + ] = [poolAddress, underlyingAssetAddress, ZERO_ADDRESS, name, symbol, incentivesController]; + return withSaveAndVerify( + await new ATokenFactory(await getFirstSigner()).deploy(...args), + eContractid.AToken, + args, + verify + ); +}; + +export const deployAllMockTokens = async (verify?: boolean) => { + const tokens: {[symbol: string]: MockContract | MintableERC20} = {}; + + const protoConfigData = getReservesConfigByPool(AavePools.proto); + const secondaryConfigData = getReservesConfigByPool(AavePools.secondary); + + for (const tokenSymbol of Object.keys(TokenContractId)) { + let decimals = '18'; + + let configData = (protoConfigData)[tokenSymbol]; + + if (!configData) { + configData = (secondaryConfigData)[tokenSymbol]; + } + + tokens[tokenSymbol] = await deployMintableERC20( + [tokenSymbol, tokenSymbol, configData ? configData.reserveDecimals : decimals], + verify + ); + } + return tokens; +}; + +export const deployMockTokens = async (config: PoolConfiguration, verify?: boolean) => { + const tokens: {[symbol: string]: MockContract | MintableERC20} = {}; + const defaultDecimals = 18; + + const configData = config.ReservesConfig; + + for (const tokenSymbol of Object.keys(config.ReserveSymbols)) { + tokens[tokenSymbol] = await deployMintableERC20( + [ + tokenSymbol, + tokenSymbol, + configData[tokenSymbol as keyof iMultiPoolsAssets].reserveDecimals || + defaultDecimals.toString(), + ], + verify + ); + await registerContractInJsonDb(tokenSymbol.toUpperCase(), tokens[tokenSymbol]); + } + return tokens; +}; + +export const deployStableAndVariableTokensHelper = async ( + args: [tEthereumAddress, tEthereumAddress], + verify?: boolean +) => + withSaveAndVerify( + await new StableAndVariableTokensHelperFactory(await getFirstSigner()).deploy(...args), + eContractid.StableAndVariableTokensHelper, + args, + verify + ); + +export const deployATokensAndRatesHelper = async ( + args: [tEthereumAddress, tEthereumAddress, tEthereumAddress], + verify?: boolean +) => + withSaveAndVerify( + await new ATokensAndRatesHelperFactory(await getFirstSigner()).deploy(...args), + eContractid.ATokensAndRatesHelper, + args, + verify + ); diff --git a/helpers/contracts-getters.ts b/helpers/contracts-getters.ts index e69de29b..0b03cb63 100644 --- a/helpers/contracts-getters.ts +++ b/helpers/contracts-getters.ts @@ -0,0 +1,224 @@ +import { + AaveProtocolTestHelpersFactory, + ATokenFactory, + ATokensAndRatesHelperFactory, + DefaultReserveInterestRateStrategyFactory, + GenericLogicFactory, + LendingPoolAddressesProviderFactory, + LendingPoolAddressesProviderRegistryFactory, + LendingPoolConfiguratorFactory, + LendingPoolFactory, + LendingRateOracleFactory, + MintableErc20Factory, + MockFlashLoanReceiverFactory, + PriceOracleFactory, + ReserveLogicFactory, + StableAndVariableTokensHelperFactory, + StableDebtTokenFactory, + VariableDebtTokenFactory, +} from '../types'; +import {Ierc20DetailedFactory} from '../types/Ierc20DetailedFactory'; +import {MockTokenMap} from './contracts-helpers'; +import {BRE, getDb} from './misc-utils'; +import {eContractid, PoolConfiguration, tEthereumAddress, TokenContractId} from './types'; + +export const getFirstSigner = async () => (await BRE.ethers.getSigners())[0]; + +export const getLendingPoolAddressesProvider = async (address?: tEthereumAddress) => + await LendingPoolAddressesProviderFactory.connect( + address || + (await getDb().get(`${eContractid.LendingPoolAddressesProvider}.${BRE.network.name}`).value()) + .address, + await getFirstSigner() + ); + +export const getLendingPoolConfiguratorProxy = async (address?: tEthereumAddress) => { + return await LendingPoolConfiguratorFactory.connect( + address || + (await getDb().get(`${eContractid.LendingPoolConfigurator}.${BRE.network.name}`).value()) + .address, + await getFirstSigner() + ); +}; + +export const getLendingPool = async (address?: tEthereumAddress) => + await LendingPoolFactory.connect( + address || + (await getDb().get(`${eContractid.LendingPool}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getPriceOracle = async (address?: tEthereumAddress) => + await PriceOracleFactory.connect( + address || + (await getDb().get(`${eContractid.PriceOracle}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getAToken = async (address?: tEthereumAddress) => + await ATokenFactory.connect( + address || (await getDb().get(`${eContractid.AToken}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getStableDebtToken = async (address?: tEthereumAddress) => + await StableDebtTokenFactory.connect( + address || + (await getDb().get(`${eContractid.StableDebtToken}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getVariableDebtToken = async (address?: tEthereumAddress) => + await VariableDebtTokenFactory.connect( + address || + (await getDb().get(`${eContractid.VariableDebtToken}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getMintableErc20 = async (address: tEthereumAddress) => + await MintableErc20Factory.connect( + address || + (await getDb().get(`${eContractid.MintableERC20}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getIErc20Detailed = async (address: tEthereumAddress) => + await Ierc20DetailedFactory.connect( + address || + (await getDb().get(`${eContractid.IERC20Detailed}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getAaveProtocolTestHelpers = async (address?: tEthereumAddress) => + await AaveProtocolTestHelpersFactory.connect( + address || + (await getDb().get(`${eContractid.AaveProtocolTestHelpers}.${BRE.network.name}`).value()) + .address, + await getFirstSigner() + ); + +export const getInterestRateStrategy = async (address?: tEthereumAddress) => + await DefaultReserveInterestRateStrategyFactory.connect( + address || + ( + await getDb() + .get(`${eContractid.DefaultReserveInterestRateStrategy}.${BRE.network.name}`) + .value() + ).address, + await getFirstSigner() + ); + +export const getMockFlashLoanReceiver = async (address?: tEthereumAddress) => + await MockFlashLoanReceiverFactory.connect( + address || + (await getDb().get(`${eContractid.MockFlashLoanReceiver}.${BRE.network.name}`).value()) + .address, + await getFirstSigner() + ); + +export const getLendingRateOracle = async (address?: tEthereumAddress) => + await LendingRateOracleFactory.connect( + address || + (await getDb().get(`${eContractid.LendingRateOracle}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getMockedTokens = async (config: PoolConfiguration) => { + const tokenSymbols = config.ReserveSymbols; + const db = getDb(); + const tokens: MockTokenMap = await tokenSymbols.reduce>( + async (acc, tokenSymbol) => { + const accumulator = await acc; + const address = db.get(`${tokenSymbol.toUpperCase()}.${BRE.network.name}`).value().address; + accumulator[tokenSymbol] = await getMintableErc20(address); + return Promise.resolve(acc); + }, + Promise.resolve({}) + ); + return tokens; +}; + +export const getAllMockedTokens = async () => { + const db = getDb(); + const tokens: MockTokenMap = await Object.keys(TokenContractId).reduce>( + async (acc, tokenSymbol) => { + const accumulator = await acc; + const address = db.get(`${tokenSymbol.toUpperCase()}.${BRE.network.name}`).value().address; + accumulator[tokenSymbol] = await getMintableErc20(address); + return Promise.resolve(acc); + }, + Promise.resolve({}) + ); + return tokens; +}; + +export const getPairsTokenAggregator = ( + allAssetsAddresses: { + [tokenSymbol: string]: tEthereumAddress; + }, + aggregatorsAddresses: {[tokenSymbol: string]: tEthereumAddress} +): [string[], string[]] => { + const {ETH, USD, WETH, ...assetsAddressesWithoutEth} = allAssetsAddresses; + + const pairs = Object.entries(assetsAddressesWithoutEth).map(([tokenSymbol, tokenAddress]) => { + if (tokenSymbol !== 'WETH' && tokenSymbol !== 'ETH') { + const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex( + (value) => value === tokenSymbol + ); + const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [ + string, + tEthereumAddress + ][])[aggregatorAddressIndex]; + return [tokenAddress, aggregatorAddress]; + } + }) as [string, string][]; + + const mappedPairs = pairs.map(([asset]) => asset); + const mappedAggregators = pairs.map(([, source]) => source); + + return [mappedPairs, mappedAggregators]; +}; + +export const getLendingPoolAddressesProviderRegistry = async (address?: tEthereumAddress) => + await LendingPoolAddressesProviderRegistryFactory.connect( + address || + ( + await getDb() + .get(`${eContractid.LendingPoolAddressesProviderRegistry}.${BRE.network.name}`) + .value() + ).address, + await getFirstSigner() + ); + +export const getReserveLogic = async (address?: tEthereumAddress) => + await ReserveLogicFactory.connect( + address || + (await getDb().get(`${eContractid.ReserveLogic}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getGenericLogic = async (address?: tEthereumAddress) => + await GenericLogicFactory.connect( + address || + (await getDb().get(`${eContractid.GenericLogic}.${BRE.network.name}`).value()).address, + await getFirstSigner() + ); + +export const getStableAndVariableTokensHelper = async (address?: tEthereumAddress) => + await StableAndVariableTokensHelperFactory.connect( + address || + ( + await getDb() + .get(`${eContractid.StableAndVariableTokensHelper}.${BRE.network.name}`) + .value() + ).address, + await getFirstSigner() + ); + +export const getATokensAndRatesHelper = async (address?: tEthereumAddress) => + await ATokensAndRatesHelperFactory.connect( + address || + (await getDb().get(`${eContractid.ATokensAndRatesHelper}.${BRE.network.name}`).value()) + .address, + await getFirstSigner() + ); diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index 073ffeca..cbe2b69c 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -1,5 +1,7 @@ import {Contract, Signer, utils, ethers} from 'ethers'; -import {CommonsConfig} from '../config/commons'; +import {signTypedData_v4} from 'eth-sig-util'; +import {fromRpcSig, ECDSASignature} from 'ethereumjs-util'; +import BigNumber from 'bignumber.js'; import {getDb, BRE, waitForTx} from './misc-utils'; import { tEthereumAddress, @@ -9,50 +11,13 @@ import { AavePools, iParamsPerNetwork, iParamsPerPool, - TokenContractId, - iMultiPoolsAssets, - IReserveParams, - ICommonConfiguration, - PoolConfiguration, } from './types'; - -import {LendingPoolAddressesProvider} from '../types/LendingPoolAddressesProvider'; import {MintableErc20 as MintableERC20} from '../types/MintableErc20'; -import {LendingPoolAddressesProviderRegistry} from '../types/LendingPoolAddressesProviderRegistry'; -import {LendingPoolConfigurator} from '../types/LendingPoolConfigurator'; -import {readArtifact} from '@nomiclabs/buidler/plugins'; import {Artifact} from '@nomiclabs/buidler/types'; -import {LendingPool} from '../types/LendingPool'; -import {PriceOracle} from '../types/PriceOracle'; -import {MockAggregator} from '../types/MockAggregator'; -import {LendingRateOracle} from '../types/LendingRateOracle'; -import {DefaultReserveInterestRateStrategy} from '../types/DefaultReserveInterestRateStrategy'; -import {LendingPoolCollateralManager} from '../types/LendingPoolCollateralManager'; -import {InitializableAdminUpgradeabilityProxy} from '../types/InitializableAdminUpgradeabilityProxy'; -import {MockFlashLoanReceiver} from '../types/MockFlashLoanReceiver'; -import {WalletBalanceProvider} from '../types/WalletBalanceProvider'; -import {AToken} from '../types/AToken'; -import {AaveProtocolTestHelpers} from '../types/AaveProtocolTestHelpers'; -import BigNumber from 'bignumber.js'; -import {Ierc20Detailed} from '../types/Ierc20Detailed'; -import {StableDebtToken} from '../types/StableDebtToken'; -import {VariableDebtToken} from '../types/VariableDebtToken'; -import {MockUniswapV2Router02} from '../types/MockUniswapV2Router02'; -import {UniswapLiquiditySwapAdapter} from '../types/UniswapLiquiditySwapAdapter'; -import {UniswapRepayAdapter} from '../types/UniswapRepayAdapter'; -import {MockContract} from 'ethereum-waffle'; -import {getReservesConfigByPool} from './configuration'; import {verifyContract} from './etherscan-verification'; - -const { - ProtocolGlobalParams: {UsdAddress}, -} = CommonsConfig; +import {getIErc20Detailed} from './contracts-getters'; export type MockTokenMap = {[symbol: string]: MintableERC20}; -import {ZERO_ADDRESS} from './constants'; -import {signTypedData_v4, TypedData} from 'eth-sig-util'; -import {fromRpcSig, ECDSASignature} from 'ethereumjs-util'; -import {SignerWithAddress} from '../test/helpers/make-suite'; export const registerContractInJsonDb = async (contractId: string, contractInstance: Contract) => { const currentNetwork = BRE.network.name; @@ -108,503 +73,26 @@ export const deployContract = async ( return contract; }; +export const withSaveAndVerify = async ( + instance: ContractType, + id: string, + args: (string | string[])[], + verify?: boolean +): Promise => { + await waitForTx(instance.deployTransaction); + await registerContractInJsonDb(id, instance); + if (verify) { + await verifyContract(id, instance.address, args); + } + return instance; +}; + export const getContract = async ( contractName: string, address: string ): Promise => (await BRE.ethers.getContractAt(contractName, address)) as ContractType; -export const deployLendingPoolAddressesProvider = async (verify?: boolean) => { - const instance = await deployContract( - eContractid.LendingPoolAddressesProvider, - [] - ); - if (verify) { - await verifyContract(eContractid.LendingPoolAddressesProvider, instance.address, []); - } - return instance; -}; - -export const deployLendingPoolAddressesProviderRegistry = async (verify?: boolean) => { - const instance = await deployContract( - eContractid.LendingPoolAddressesProviderRegistry, - [] - ); - if (verify) { - await verifyContract(eContractid.LendingPoolAddressesProviderRegistry, instance.address, []); - } - return instance; -}; - -export const deployLendingPoolConfigurator = async (verify?: boolean) => { - const instance = await deployContract( - eContractid.LendingPoolConfigurator, - [] - ); - if (verify) { - await verifyContract(eContractid.LendingPoolConfigurator, instance.address, []); - } - return instance; -}; - -const deployLibrary = async (libraryId: eContractid) => { - const factory = await BRE.ethers.getContractFactory(libraryId); - const library = await factory.deploy(); - await library.deployed(); - - return library; -}; - -export const linkLibrariesToArtifact = async (artifact: Artifact) => { - const reserveLogic = await deployLibrary(eContractid.ReserveLogic); - - const genericLogicArtifact = await readArtifact( - BRE.config.paths.artifacts, - eContractid.GenericLogic - ); - - const linkedGenericLogicByteCode = linkBytecode(genericLogicArtifact, { - [eContractid.ReserveLogic]: reserveLogic.address, - }); - - const genericLogicFactory = await BRE.ethers.getContractFactory( - genericLogicArtifact.abi, - linkedGenericLogicByteCode - ); - - const genericLogic = await (await genericLogicFactory.deploy()).deployed(); - - const validationLogicArtifact = await readArtifact( - BRE.config.paths.artifacts, - eContractid.ValidationLogic - ); - - const linkedValidationLogicByteCode = linkBytecode(validationLogicArtifact, { - [eContractid.ReserveLogic]: reserveLogic.address, - [eContractid.GenericLogic]: genericLogic.address, - }); - - const validationLogicFactory = await BRE.ethers.getContractFactory( - validationLogicArtifact.abi, - linkedValidationLogicByteCode - ); - - const validationLogic = await (await validationLogicFactory.deploy()).deployed(); - - const linkedBytecode = linkBytecode(artifact, { - [eContractid.ReserveLogic]: reserveLogic.address, - [eContractid.GenericLogic]: genericLogic.address, - [eContractid.ValidationLogic]: validationLogic.address, - }); - const factory = await BRE.ethers.getContractFactory(artifact.abi, linkedBytecode); - - return factory; -}; - -export const deployLendingPool = async (verify?: boolean) => { - const lendingPoolArtifact = await readArtifact( - BRE.config.paths.artifacts, - eContractid.LendingPool - ); - const factory = await linkLibrariesToArtifact(lendingPoolArtifact); - const lendingPool = await factory.deploy(); - await waitForTx(lendingPool.deployTransaction); - const instance = (await lendingPool.deployed()) as LendingPool; - if (verify) { - await verifyContract(eContractid.LendingPool, instance.address, []); - } - return instance; -}; - -export const deployPriceOracle = async (verify?: boolean) => { - const instance = await deployContract(eContractid.PriceOracle, []); - if (verify) { - await verifyContract(eContractid.PriceOracle, instance.address, []); - } - return instance; -}; - -export const deployLendingRateOracle = async (verify?: boolean) => { - const instance = await deployContract(eContractid.LendingRateOracle, []); - if (verify) { - await verifyContract(eContractid.LendingRateOracle, instance.address, []); - } - return instance; -}; - -export const deployMockAggregator = async (price: tStringTokenSmallUnits, verify?: boolean) => { - const args = [price]; - const instance = await deployContract(eContractid.MockAggregator, args); - if (verify) { - await verifyContract(eContractid.MockAggregator, instance.address, args); - } - return instance; -}; - -export const deployChainlinkProxyPriceProvider = async ( - [assetsAddresses, sourcesAddresses, fallbackOracleAddress]: [ - tEthereumAddress[], - tEthereumAddress[], - tEthereumAddress - ], - verify?: boolean -) => { - const args = [assetsAddresses, sourcesAddresses, fallbackOracleAddress]; - const instance = await deployContract( - eContractid.ChainlinkProxyPriceProvider, - args - ); - if (verify) { - await verifyContract(eContractid.MockAggregator, instance.address, args); - } - return instance; -}; - -export const deployMockUniswapRouter = async () => - await deployContract(eContractid.MockUniswapV2Router02, []); - -export const deployUniswapLiquiditySwapAdapter = async ( - addressesProvider: tEthereumAddress, - uniswapRouter: tEthereumAddress -) => - await deployContract(eContractid.UniswapLiquiditySwapAdapter, [ - addressesProvider, - uniswapRouter, - ]); - -export const deployUniswapRepayAdapter = async ( - addressesProvider: tEthereumAddress, - uniswapRouter: tEthereumAddress -) => - await deployContract(eContractid.UniswapRepayAdapter, [ - addressesProvider, - uniswapRouter, - ]); - -export const getChainlingProxyPriceProvider = async (address?: tEthereumAddress) => - await getContract( - eContractid.ChainlinkProxyPriceProvider, - address || - (await getDb().get(`${eContractid.ChainlinkProxyPriceProvider}.${BRE.network.name}`).value()) - .address - ); - -export const deployLendingPoolCollateralManager = async (verify?: boolean) => { - const collateralManagerArtifact = await readArtifact( - BRE.config.paths.artifacts, - eContractid.LendingPoolCollateralManager - ); - - const factory = await linkLibrariesToArtifact(collateralManagerArtifact); - const args: string[] = []; - const collateralManager = await factory.deploy(args); - const instance = (await collateralManager.deployed()) as LendingPoolCollateralManager; - - if (verify) { - await verifyContract(eContractid.LendingPoolCollateralManager, instance.address, args); - } - return instance; -}; - -export const deployInitializableAdminUpgradeabilityProxy = async (verify?: boolean) => { - const instance = await deployContract( - eContractid.InitializableAdminUpgradeabilityProxy, - [] - ); - if (verify) { - await verifyContract(eContractid.InitializableAdminUpgradeabilityProxy, instance.address, []); - } - return instance; -}; - -export const deployMockFlashLoanReceiver = async ( - addressesProvider: tEthereumAddress, - verify?: boolean -) => { - const args = [addressesProvider]; - const instance = await deployContract( - eContractid.MockFlashLoanReceiver, - args - ); - if (verify) { - await verifyContract(eContractid.MockFlashLoanReceiver, instance.address, args); - } - return instance; -}; - -export const deployWalletBalancerProvider = async ( - addressesProvider: tEthereumAddress, - verify?: boolean -) => { - const args = [addressesProvider]; - const instance = await deployContract( - eContractid.WalletBalanceProvider, - args - ); - if (verify) { - await verifyContract(eContractid.WalletBalanceProvider, instance.address, args); - } - return instance; -}; - -export const deployAaveProtocolTestHelpers = async ( - addressesProvider: tEthereumAddress, - verify?: boolean -) => { - const args = [addressesProvider]; - const instance = await deployContract( - eContractid.AaveProtocolTestHelpers, - args - ); - - if (verify) { - await verifyContract(eContractid.AaveProtocolTestHelpers, instance.address, args); - } - return instance; -}; - -export const deployMintableERC20 = async ([name, symbol, decimals]: [string, string, number]) => - await deployContract(eContractid.MintableERC20, [name, symbol, decimals]); - -export const deployDefaultReserveInterestRateStrategy = async ( - [ - addressesProvider, - baseVariableBorrowRate, - variableSlope1, - variableSlope2, - stableSlope1, - stableSlope2, - ]: [tEthereumAddress, string, string, string, string, string], - verify: boolean -) => { - const id = eContractid.DefaultReserveInterestRateStrategy; - const args = [ - addressesProvider, - baseVariableBorrowRate, - variableSlope1, - variableSlope2, - stableSlope1, - stableSlope2, - ]; - const instance = await deployContract(id, args); - - if (verify) { - await verifyContract(id, instance.address, args); - } - return instance; -}; - -export const deployStableDebtToken = async ( - [name, symbol, underlyingAsset, poolAddress, incentivesController]: [ - string, - string, - tEthereumAddress, - tEthereumAddress, - tEthereumAddress - ], - verify: boolean -) => { - const id = eContractid.StableDebtToken; - const args = [poolAddress, underlyingAsset, name, symbol, incentivesController]; - const instance = await deployContract(id, args); - - if (verify) { - await verifyContract(id, instance.address, args); - } - return instance; -}; - -export const deployVariableDebtToken = async ( - [name, symbol, underlyingAsset, poolAddress, incentivesController]: [ - string, - string, - tEthereumAddress, - tEthereumAddress, - tEthereumAddress - ], - verify: boolean -) => { - const id = eContractid.VariableDebtToken; - const args = [poolAddress, underlyingAsset, name, symbol, incentivesController]; - const instance = await deployContract(id, args); - - if (verify) { - await verifyContract(id, instance.address, args); - } - return instance; -}; - -export const deployGenericAToken = async ( - [poolAddress, underlyingAssetAddress, name, symbol, incentivesController]: [ - tEthereumAddress, - tEthereumAddress, - string, - string, - tEthereumAddress - ], - verify: boolean -) => { - const id = eContractid.AToken; - const args = [ - poolAddress, - underlyingAssetAddress, - ZERO_ADDRESS, - name, - symbol, - incentivesController, - ]; - const instance = await deployContract(id, args); - - if (verify) { - await verifyContract(id, instance.address, args); - } - return instance; -}; - -export const getLendingPoolAddressesProvider = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.LendingPoolAddressesProvider, - address || - (await getDb().get(`${eContractid.LendingPoolAddressesProvider}.${BRE.network.name}`).value()) - .address - ); -}; - -export const getLendingPoolConfiguratorProxy = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.LendingPoolConfigurator, - address || - (await getDb().get(`${eContractid.LendingPoolConfigurator}.${BRE.network.name}`).value()) - .address - ); -}; - -export const getLendingPool = async (address?: tEthereumAddress) => { - const lendingPoolArtifact = await readArtifact( - BRE.config.paths.artifacts, - eContractid.LendingPool - ); - - const factory = await linkLibrariesToArtifact(lendingPoolArtifact); - - return ( - await factory.attach( - address || - (await getDb().get(`${eContractid.LendingPool}.${BRE.network.name}`).value()).address - ) - ); -}; - -export const getPriceOracle = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.PriceOracle, - address || (await getDb().get(`${eContractid.PriceOracle}.${BRE.network.name}`).value()).address - ); -}; - -export const getAToken = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.AToken, - address || (await getDb().get(`${eContractid.AToken}.${BRE.network.name}`).value()).address - ); -}; - -export const getStableDebtToken = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.StableDebtToken, - address || - (await getDb().get(`${eContractid.StableDebtToken}.${BRE.network.name}`).value()).address - ); -}; - -export const getVariableDebtToken = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.VariableDebtToken, - address || - (await getDb().get(`${eContractid.VariableDebtToken}.${BRE.network.name}`).value()).address - ); -}; - -export const getMintableErc20 = async (address: tEthereumAddress) => { - return await getContract( - eContractid.MintableERC20, - address || - (await getDb().get(`${eContractid.MintableERC20}.${BRE.network.name}`).value()).address - ); -}; - -export const getIErc20Detailed = async (address: tEthereumAddress) => { - return await getContract( - eContractid.IERC20Detailed, - address || - (await getDb().get(`${eContractid.IERC20Detailed}.${BRE.network.name}`).value()).address - ); -}; - -export const getAaveProtocolTestHelpers = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.AaveProtocolTestHelpers, - address || - (await getDb().get(`${eContractid.AaveProtocolTestHelpers}.${BRE.network.name}`).value()) - .address - ); -}; - -export const getInterestRateStrategy = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.DefaultReserveInterestRateStrategy, - address || - ( - await getDb() - .get(`${eContractid.DefaultReserveInterestRateStrategy}.${BRE.network.name}`) - .value() - ).address - ); -}; - -export const getMockFlashLoanReceiver = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.MockFlashLoanReceiver, - address || - (await getDb().get(`${eContractid.MockFlashLoanReceiver}.${BRE.network.name}`).value()) - .address - ); -}; - -export const getMockUniswapRouter = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.MockUniswapV2Router02, - address || - (await getDb().get(`${eContractid.MockUniswapV2Router02}.${BRE.network.name}`).value()) - .address - ); -}; - -export const getUniswapLiquiditySwapAdapter = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.UniswapLiquiditySwapAdapter, - address || - (await getDb().get(`${eContractid.UniswapLiquiditySwapAdapter}.${BRE.network.name}`).value()) - .address - ); -}; - -export const getUniswapRepayAdapter = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.UniswapRepayAdapter, - address || - (await getDb().get(`${eContractid.UniswapRepayAdapter}.${BRE.network.name}`).value()).address - ); -}; - -export const getLendingRateOracle = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.LendingRateOracle, - address || - (await getDb().get(`${eContractid.LendingRateOracle}.${BRE.network.name}`).value()).address - ); -}; - -const linkBytecode = (artifact: Artifact, libraries: any) => { +export const linkBytecode = (artifact: Artifact, libraries: any) => { let bytecode = artifact.bytecode; for (const [fileName, fileReferences] of Object.entries(artifact.linkReferences)) { @@ -673,254 +161,6 @@ export const convertToCurrencyUnits = async (tokenAddress: string, amount: strin return amountInCurrencyUnits.toFixed(); }; -export const deployAllMockTokens = async (verify?: boolean) => { - const tokens: {[symbol: string]: MockContract | MintableERC20} = {}; - - const protoConfigData = getReservesConfigByPool(AavePools.proto); - const secondaryConfigData = getReservesConfigByPool(AavePools.secondary); - - for (const tokenSymbol of Object.keys(TokenContractId)) { - let decimals = 18; - - let configData = (protoConfigData)[tokenSymbol]; - - if (!configData) { - configData = (secondaryConfigData)[tokenSymbol]; - } - - if (!configData) { - decimals = 18; - } - - tokens[tokenSymbol] = await deployMintableERC20([ - tokenSymbol, - tokenSymbol, - configData ? configData.reserveDecimals : 18, - ]); - await registerContractInJsonDb(tokenSymbol.toUpperCase(), tokens[tokenSymbol]); - - if (verify) { - await verifyContract(eContractid.MintableERC20, tokens[tokenSymbol].address, []); - } - } - return tokens; -}; - -export const deployMockTokens = async (config: PoolConfiguration, verify?: boolean) => { - const tokens: {[symbol: string]: MockContract | MintableERC20} = {}; - const defaultDecimals = 18; - - const configData = config.ReservesConfig; - - for (const tokenSymbol of Object.keys(config.ReserveSymbols)) { - tokens[tokenSymbol] = await deployMintableERC20([ - tokenSymbol, - tokenSymbol, - Number(configData[tokenSymbol as keyof iMultiPoolsAssets].reserveDecimals) || - defaultDecimals, - ]); - await registerContractInJsonDb(tokenSymbol.toUpperCase(), tokens[tokenSymbol]); - - if (verify) { - await verifyContract(eContractid.MintableERC20, tokens[tokenSymbol].address, []); - } - } - return tokens; -}; - -export const getMockedTokens = async (config: PoolConfiguration) => { - const tokenSymbols = config.ReserveSymbols; - const db = getDb(); - const tokens: MockTokenMap = await tokenSymbols.reduce>( - async (acc, tokenSymbol) => { - const accumulator = await acc; - const address = db.get(`${tokenSymbol.toUpperCase()}.${BRE.network.name}`).value().address; - accumulator[tokenSymbol] = await getContract( - eContractid.MintableERC20, - address - ); - return Promise.resolve(acc); - }, - Promise.resolve({}) - ); - return tokens; -}; - -export const getAllMockedTokens = async () => { - const db = getDb(); - const tokens: MockTokenMap = await Object.keys(TokenContractId).reduce>( - async (acc, tokenSymbol) => { - const accumulator = await acc; - const address = db.get(`${tokenSymbol.toUpperCase()}.${BRE.network.name}`).value().address; - accumulator[tokenSymbol] = await getContract( - eContractid.MintableERC20, - address - ); - return Promise.resolve(acc); - }, - Promise.resolve({}) - ); - return tokens; -}; - -export const getPairsTokenAggregator = ( - allAssetsAddresses: { - [tokenSymbol: string]: tEthereumAddress; - }, - aggregatorsAddresses: {[tokenSymbol: string]: tEthereumAddress} -): [string[], string[]] => { - const {ETH, USD, WETH, ...assetsAddressesWithoutEth} = allAssetsAddresses; - - const pairs = Object.entries(assetsAddressesWithoutEth).map(([tokenSymbol, tokenAddress]) => { - if (tokenSymbol !== 'WETH' && tokenSymbol !== 'ETH') { - const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex( - (value) => value === tokenSymbol - ); - const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [ - string, - tEthereumAddress - ][])[aggregatorAddressIndex]; - return [tokenAddress, aggregatorAddress]; - } - }) as [string, string][]; - - const mappedPairs = pairs.map(([asset]) => asset); - const mappedAggregators = pairs.map(([, source]) => source); - - return [mappedPairs, mappedAggregators]; -}; - -export const initReserves = async ( - reservesParams: iMultiPoolsAssets, - tokenAddresses: {[symbol: string]: tEthereumAddress}, - lendingPoolAddressesProvider: LendingPoolAddressesProvider, - lendingPool: LendingPool, - helpers: AaveProtocolTestHelpers, - lendingPoolConfigurator: LendingPoolConfigurator, - aavePool: AavePools, - incentivesController: tEthereumAddress, - verify: boolean -) => { - if (aavePool !== AavePools.proto && aavePool !== AavePools.secondary) { - console.log(`Invalid Aave pool ${aavePool}`); - process.exit(1); - } - - for (let [assetSymbol, {reserveDecimals}] of Object.entries(reservesParams) as [ - string, - IReserveParams - ][]) { - const assetAddressIndex = Object.keys(tokenAddresses).findIndex( - (value) => value === assetSymbol - ); - const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[ - assetAddressIndex - ]; - - const {isActive: reserveInitialized} = await helpers.getReserveConfigurationData(tokenAddress); - - if (reserveInitialized) { - console.log(`Reserve ${assetSymbol} is already active, skipping configuration`); - continue; - } - - try { - const reserveParamIndex = Object.keys(reservesParams).findIndex( - (value) => value === assetSymbol - ); - const [ - , - { - baseVariableBorrowRate, - variableRateSlope1, - variableRateSlope2, - stableRateSlope1, - stableRateSlope2, - }, - ] = (Object.entries(reservesParams) as [string, IReserveParams][])[reserveParamIndex]; - console.log('deploy the interest rate strategy for ', assetSymbol); - const rateStrategyContract = await deployDefaultReserveInterestRateStrategy( - [ - lendingPoolAddressesProvider.address, - baseVariableBorrowRate, - variableRateSlope1, - variableRateSlope2, - stableRateSlope1, - stableRateSlope2, - ], - verify - ); - - console.log('deploy the stable debt totken for ', assetSymbol); - const stableDebtToken = await deployStableDebtToken( - [ - `Aave stable debt bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`, - `stableDebt${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`, - tokenAddress, - lendingPool.address, - incentivesController, - ], - verify - ); - - console.log('deploy the variable debt totken for ', assetSymbol); - const variableDebtToken = await deployVariableDebtToken( - [ - `Aave variable debt bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`, - `variableDebt${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`, - tokenAddress, - lendingPool.address, - incentivesController, - ], - verify - ); - - console.log('deploy the aToken for ', assetSymbol); - const aToken = await deployGenericAToken( - [ - lendingPool.address, - tokenAddress, - `Aave interest bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`, - `a${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`, - incentivesController, - ], - verify - ); - - if (process.env.POOL === AavePools.secondary) { - if (assetSymbol.search('UNI') === -1) { - assetSymbol = `Uni${assetSymbol}`; - } else { - assetSymbol = assetSymbol.replace(/_/g, '').replace('UNI', 'Uni'); - } - } - - console.log('initialize the reserve ', assetSymbol); - await lendingPoolConfigurator.initReserve( - aToken.address, - stableDebtToken.address, - variableDebtToken.address, - reserveDecimals, - rateStrategyContract.address - ); - } catch (e) { - console.log(`Reserve initialization for ${assetSymbol} failed with error ${e}. Skipped.`); - } - } -}; - -export const getLendingPoolAddressesProviderRegistry = async (address?: tEthereumAddress) => { - return await getContract( - eContractid.LendingPoolAddressesProviderRegistry, - address || - ( - await getDb() - .get(`${eContractid.LendingPoolAddressesProviderRegistry}.${BRE.network.name}`) - .value() - ).address - ); -}; - export const buildPermitParams = ( chainId: number, token: tEthereumAddress, diff --git a/helpers/init-helpers.ts b/helpers/init-helpers.ts index 599fc7ff..b33e3b9a 100644 --- a/helpers/init-helpers.ts +++ b/helpers/init-helpers.ts @@ -1,57 +1,256 @@ import {iMultiPoolsAssets, IReserveParams, tEthereumAddress} from './types'; -import {LendingPool} from '../types/LendingPool'; import {LendingPoolConfigurator} from '../types/LendingPoolConfigurator'; import {AaveProtocolTestHelpers} from '../types/AaveProtocolTestHelpers'; -import {waitForTx} from './misc-utils'; +import { + deployATokensAndRatesHelper, + deployStableAndVariableTokensHelper, +} from './contracts-deployments'; +import {chunk, waitForTx} from './misc-utils'; +import { + getATokensAndRatesHelper, + getLendingPoolAddressesProvider, + getStableAndVariableTokensHelper, +} from './contracts-getters'; -export const enableReservesToBorrow = async ( +export const initReservesByHelper = async ( reservesParams: iMultiPoolsAssets, tokenAddresses: {[symbol: string]: tEthereumAddress}, - helpers: AaveProtocolTestHelpers, - lendingPoolConfigurator: LendingPoolConfigurator + admin: tEthereumAddress, + incentivesController: tEthereumAddress ) => { - for (const [assetSymbol, {borrowingEnabled, stableBorrowRateEnabled}] of Object.entries( - reservesParams - ) as [string, IReserveParams][]) { - if (!borrowingEnabled) continue; - try { + const stableAndVariableDeployer = await getStableAndVariableTokensHelper(); + const atokenAndRatesDeployer = await getATokensAndRatesHelper(); + + const addressProvider = await getLendingPoolAddressesProvider(); + + // Set aTokenAndRatesDeployer as temporal admin + await waitForTx(await addressProvider.setAaveAdmin(atokenAndRatesDeployer.address)); + + // CHUNK CONFIGURATION + const tokensChunks = 4; + const initChunks = 6; + + // Deploy tokens and rates in chunks + const reservesChunks = chunk( + Object.entries(reservesParams) as [string, IReserveParams][], + tokensChunks + ); + // Initialize variables for future reserves initialization + let deployedStableTokens: string[] = []; + let deployedVariableTokens: string[] = []; + let deployedATokens: string[] = []; + let deployedRates: string[] = []; + let reserveTokens: string[] = []; + let reserveInitDecimals: string[] = []; + + console.log( + `- Token deployments in ${reservesChunks.length * 2} txs instead of ${ + Object.entries(reservesParams).length * 4 + } txs` + ); + for (let reservesChunk of reservesChunks) { + // Prepare data + const tokens: string[] = []; + const symbols: string[] = []; + const strategyRates: string[][] = []; + const reservesDecimals: string[] = []; + + for (let [assetSymbol, {reserveDecimals}] of reservesChunk) { const assetAddressIndex = Object.keys(tokenAddresses).findIndex( (value) => value === assetSymbol ); const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[ assetAddressIndex ]; - const {borrowingEnabled: borrowingAlreadyEnabled} = await helpers.getReserveConfigurationData( - tokenAddress - ); - if (borrowingAlreadyEnabled) { - console.log(`Reserve ${assetSymbol} is already enabled for borrowing, skipping`); - continue; - } - - console.log('Enabling borrowing on reserve ', assetSymbol); - - await waitForTx( - await lendingPoolConfigurator.enableBorrowingOnReserve( - tokenAddress, - stableBorrowRateEnabled - ) - ); - } catch (e) { - console.log( - `Enabling reserve for borrowings for ${assetSymbol} failed with error ${e}. Skipped.` + const reserveParamIndex = Object.keys(reservesParams).findIndex( + (value) => value === assetSymbol ); + const [ + , + { + baseVariableBorrowRate, + variableRateSlope1, + variableRateSlope2, + stableRateSlope1, + stableRateSlope2, + }, + ] = (Object.entries(reservesParams) as [string, IReserveParams][])[reserveParamIndex]; + // Add to lists + tokens.push(tokenAddress); + symbols.push(assetSymbol); + strategyRates.push([ + baseVariableBorrowRate, + variableRateSlope1, + variableRateSlope2, + stableRateSlope1, + stableRateSlope2, + ]); + reservesDecimals.push(reserveDecimals); } + + // Deploy stable and variable deployers + const tx1 = await waitForTx( + await stableAndVariableDeployer.initDeployment(tokens, symbols, incentivesController) + ); + + // Deploy atokens and rate strategies + const tx2 = await waitForTx( + await atokenAndRatesDeployer.initDeployment( + tokens, + symbols, + strategyRates, + incentivesController + ) + ); + console.log(` - Deployed aToken, DebtTokens and Strategy for: ${symbols.join(', ')} `); + const stableTokens: string[] = tx1.events?.map((e) => e.args?.stableToken) || []; + const variableTokens: string[] = tx1.events?.map((e) => e.args?.variableToken) || []; + const aTokens: string[] = tx2.events?.map((e) => e.args?.aToken) || []; + const strategies: string[] = tx2.events?.map((e) => e.args?.strategy) || []; + + deployedStableTokens = [...deployedStableTokens, ...stableTokens]; + deployedVariableTokens = [...deployedVariableTokens, ...variableTokens]; + deployedATokens = [...deployedATokens, ...aTokens]; + deployedRates = [...deployedRates, ...strategies]; + reserveInitDecimals = [...reserveInitDecimals, ...reservesDecimals]; + reserveTokens = [...reserveTokens, ...tokens]; } + + // Deploy init reserves per chunks + const chunkedStableTokens = chunk(deployedStableTokens, initChunks); + const chunkedVariableTokens = chunk(deployedVariableTokens, initChunks); + const chunkedAtokens = chunk(deployedATokens, initChunks); + const chunkedRates = chunk(deployedRates, initChunks); + const chunkedDecimals = chunk(reserveInitDecimals, initChunks); + const chunkedSymbols = chunk(Object.keys(tokenAddresses), initChunks); + + console.log(`- Reserves initialization in ${chunkedStableTokens.length} txs`); + for (let chunkIndex = 0; chunkIndex < chunkedDecimals.length; chunkIndex++) { + const tx3 = await waitForTx( + await atokenAndRatesDeployer.initReserve( + chunkedStableTokens[chunkIndex], + chunkedVariableTokens[chunkIndex], + chunkedAtokens[chunkIndex], + chunkedRates[chunkIndex], + chunkedDecimals[chunkIndex] + ) + ); + console.log(` - Reserve ready for: ${chunkedSymbols[chunkIndex].join(', ')}`); + } + + // Set deployer back as admin + await waitForTx(await addressProvider.setAaveAdmin(admin)); }; -export const enableReservesAsCollateral = async ( +export const getPairsTokenAggregator = ( + allAssetsAddresses: { + [tokenSymbol: string]: tEthereumAddress; + }, + aggregatorsAddresses: {[tokenSymbol: string]: tEthereumAddress} +): [string[], string[]] => { + const {ETH, USD, WETH, ...assetsAddressesWithoutEth} = allAssetsAddresses; + + const pairs = Object.entries(assetsAddressesWithoutEth).map(([tokenSymbol, tokenAddress]) => { + if (tokenSymbol !== 'WETH' && tokenSymbol !== 'ETH') { + const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex( + (value) => value === tokenSymbol + ); + const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [ + string, + tEthereumAddress + ][])[aggregatorAddressIndex]; + return [tokenAddress, aggregatorAddress]; + } + }) as [string, string][]; + + const mappedPairs = pairs.map(([asset]) => asset); + const mappedAggregators = pairs.map(([, source]) => source); + + return [mappedPairs, mappedAggregators]; +}; + +export const enableReservesToBorrowByHelper = async ( reservesParams: iMultiPoolsAssets, tokenAddresses: {[symbol: string]: tEthereumAddress}, helpers: AaveProtocolTestHelpers, - lendingPoolConfigurator: LendingPoolConfigurator + admin: tEthereumAddress ) => { + const addressProvider = await getLendingPoolAddressesProvider(); + const atokenAndRatesDeployer = await getATokensAndRatesHelper(); + const tokens: string[] = []; + const symbols: string[] = []; + const stableEnabled: boolean[] = []; + + // Prepare data + for (const [assetSymbol, {borrowingEnabled, stableBorrowRateEnabled}] of Object.entries( + reservesParams + ) as [string, IReserveParams][]) { + if (!borrowingEnabled) continue; + const assetAddressIndex = Object.keys(tokenAddresses).findIndex( + (value) => value === assetSymbol + ); + const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[ + assetAddressIndex + ]; + const {borrowingEnabled: borrowingAlreadyEnabled} = await helpers.getReserveConfigurationData( + tokenAddress + ); + + if (borrowingAlreadyEnabled) { + console.log(`Reserve ${assetSymbol} is already enabled for borrowing, skipping`); + continue; + } + tokens.push(tokenAddress); + stableEnabled.push(stableBorrowRateEnabled); + symbols.push(assetSymbol); + } + if (tokens.length) { + // Set aTokenAndRatesDeployer as temporal admin + await waitForTx(await addressProvider.setAaveAdmin(atokenAndRatesDeployer.address)); + + // Deploy init per chunks + const stableChunks = 20; + const chunkedTokens = chunk(tokens, stableChunks); + const chunkedSymbols = chunk(symbols, stableChunks); + const chunkedStableEnabled = chunk(stableEnabled, stableChunks); + + console.log(`- Borrow stable initialization in ${chunkedTokens.length} txs`); + for (let chunkIndex = 0; chunkIndex < chunkedTokens.length; chunkIndex++) { + try { + await waitForTx( + await atokenAndRatesDeployer.enableBorrowingOnReserves( + chunkedTokens[chunkIndex], + chunkedStableEnabled[chunkIndex], + {gasLimit: 12000000} + ) + ); + } catch (error) { + console.error(error); + throw error; + } + + console.log(` - Init for: ${chunkedSymbols[chunkIndex].join(', ')}`); + } + // Set deployer back as admin + await waitForTx(await addressProvider.setAaveAdmin(admin)); + } +}; + +export const enableReservesAsCollateralByHelper = async ( + reservesParams: iMultiPoolsAssets, + tokenAddresses: {[symbol: string]: tEthereumAddress}, + helpers: AaveProtocolTestHelpers, + admin: tEthereumAddress +) => { + const addressProvider = await getLendingPoolAddressesProvider(); + const atokenAndRatesDeployer = await getATokensAndRatesHelper(); + const tokens: string[] = []; + const symbols: string[] = []; + const baseLTVA: string[] = []; + const liquidationThresholds: string[] = []; + const liquidationBonuses: string[] = []; + for (const [ assetSymbol, {baseLTVAsCollateral, liquidationBonus, liquidationThreshold}, @@ -69,25 +268,42 @@ export const enableReservesAsCollateral = async ( ); if (alreadyEnabled) { - console.log(`Reserve ${assetSymbol} is already enabled as collateral, skipping`); + console.log(`- Reserve ${assetSymbol} is already enabled as collateral, skipping`); continue; } + // Push data + tokens.push(tokenAddress); + symbols.push(assetSymbol); + baseLTVA.push(baseLTVAsCollateral); + liquidationThresholds.push(liquidationThreshold); + liquidationBonuses.push(liquidationBonus); + } + if (tokens.length) { + // Set aTokenAndRatesDeployer as temporal admin + await waitForTx(await addressProvider.setAaveAdmin(atokenAndRatesDeployer.address)); - try { - console.log(`Enabling reserve ${assetSymbol} as collateral`); + // Deploy init per chunks + const enableChunks = 20; + const chunkedTokens = chunk(tokens, enableChunks); + const chunkedSymbols = chunk(symbols, enableChunks); + const chunkedBase = chunk(baseLTVA, enableChunks); + const chunkedliquidationThresholds = chunk(liquidationThresholds, enableChunks); + const chunkedliquidationBonuses = chunk(liquidationBonuses, enableChunks); + console.log(`- Enable reserve as collateral in ${chunkedTokens.length} txs`); + for (let chunkIndex = 0; chunkIndex < chunkedTokens.length; chunkIndex++) { await waitForTx( - await lendingPoolConfigurator.enableReserveAsCollateral( - tokenAddress, - baseLTVAsCollateral, - liquidationThreshold, - liquidationBonus + await atokenAndRatesDeployer.enableReservesAsCollateral( + chunkedTokens[chunkIndex], + chunkedBase[chunkIndex], + chunkedliquidationThresholds[chunkIndex], + chunkedliquidationBonuses[chunkIndex], + {gasLimit: 12000000} ) ); - } catch (e) { - console.log( - `Enabling reserve as collateral for ${assetSymbol} failed with error ${e}. Skipped.` - ); + console.log(` - Init for: ${chunkedSymbols[chunkIndex].join(', ')}`); } + // Set deployer back as admin + await waitForTx(await addressProvider.setAaveAdmin(admin)); } }; diff --git a/helpers/misc-utils.ts b/helpers/misc-utils.ts index 8bf0c416..3df0e7d8 100644 --- a/helpers/misc-utils.ts +++ b/helpers/misc-utils.ts @@ -5,6 +5,8 @@ import FileSync from 'lowdb/adapters/FileSync'; import {WAD} from './constants'; import {Wallet, ContractTransaction} from 'ethers'; import {BuidlerRuntimeEnvironment} from '@nomiclabs/buidler/types'; +import path from 'path'; +import fs from 'fs'; export const toWad = (value: string | number) => new BigNumber(value).times(WAD).toFixed(); @@ -50,3 +52,13 @@ export const filterMapBy = (raw: {[key: string]: any}, fn: (key: string) => bool obj[key] = raw[key]; return obj; }, {}); + +export const chunk = (arr: Array, chunkSize: number): Array> => { + return arr.reduce( + (prevVal: any, currVal: any, currIndx: number, array: Array) => + !(currIndx % chunkSize) + ? prevVal.concat([array.slice(currIndx, currIndx + chunkSize)]) + : prevVal, + [] + ); +}; diff --git a/helpers/oracles-helpers.ts b/helpers/oracles-helpers.ts index f5b5941d..45cec5e2 100644 --- a/helpers/oracles-helpers.ts +++ b/helpers/oracles-helpers.ts @@ -4,22 +4,26 @@ import { IMarketRates, iAssetBase, iAssetAggregatorBase, - eContractid, SymbolMap, } from './types'; import {LendingRateOracle} from '../types/LendingRateOracle'; import {PriceOracle} from '../types/PriceOracle'; import {MockAggregator} from '../types/MockAggregator'; -import {deployMockAggregator, getContract, MockTokenMap} from './contracts-helpers'; -import {waitForTx} from './misc-utils'; -import {verifyContract} from './etherscan-verification'; +import {deployMockAggregator} from './contracts-deployments'; +import {chunk, waitForTx} from './misc-utils'; +import {getStableAndVariableTokensHelper} from './contracts-getters'; -export const setInitialMarketRatesInRatesOracle = async ( +export const setInitialMarketRatesInRatesOracleByHelper = async ( marketRates: iMultiPoolsAssets, assetsAddresses: {[x: string]: tEthereumAddress}, - lendingRateOracleInstance: LendingRateOracle + lendingRateOracleInstance: LendingRateOracle, + admin: tEthereumAddress ) => { + const stableAndVariableTokenHelper = await getStableAndVariableTokensHelper(); + const assetAddresses: string[] = []; + const borrowRates: string[] = []; + const symbols: string[] = []; for (const [assetSymbol, {borrowRate}] of Object.entries(marketRates) as [ string, IMarketRates @@ -30,9 +34,36 @@ export const setInitialMarketRatesInRatesOracle = async ( const [, assetAddress] = (Object.entries(assetsAddresses) as [string, string][])[ assetAddressIndex ]; - await waitForTx(await lendingRateOracleInstance.setMarketBorrowRate(assetAddress, borrowRate)); - console.log('added Market Borrow Rate for: ', assetSymbol); + assetAddresses.push(assetAddress); + borrowRates.push(borrowRate); + symbols.push(assetSymbol); } + // Set borrow rates per chunks + const ratesChunks = 20; + const chunkedTokens = chunk(assetAddresses, ratesChunks); + const chunkedRates = chunk(borrowRates, ratesChunks); + const chunkedSymbols = chunk(symbols, ratesChunks); + + // Set helper as owner + await waitForTx( + await lendingRateOracleInstance.transferOwnership(stableAndVariableTokenHelper.address) + ); + + console.log(`- Oracle borrow initalization in ${chunkedTokens.length} txs`); + for (let chunkIndex = 0; chunkIndex < chunkedTokens.length; chunkIndex++) { + const tx3 = await waitForTx( + await stableAndVariableTokenHelper.setOracleBorrowRates( + chunkedTokens[chunkIndex], + chunkedRates[chunkIndex], + lendingRateOracleInstance.address + ) + ); + console.log(` - Setted Oracle Borrow Rates for: ${chunkedSymbols[chunkIndex].join(', ')}`); + } + // Set back ownership + await waitForTx( + await stableAndVariableTokenHelper.setOracleOwnership(lendingRateOracleInstance.address, admin) + ); }; export const setInitialAssetPricesInOracle = async ( diff --git a/helpers/types.ts b/helpers/types.ts index 38b04fcd..36588ad8 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -55,6 +55,8 @@ export enum eContractid { VariableDebtToken = 'VariableDebtToken', FeeProvider = 'FeeProvider', TokenDistributor = 'TokenDistributor', + StableAndVariableTokensHelper = 'StableAndVariableTokensHelper', + ATokensAndRatesHelper = 'ATokensAndRatesHelper', MockUniswapV2Router02 = 'MockUniswapV2Router02', UniswapLiquiditySwapAdapter = 'UniswapLiquiditySwapAdapter', UniswapRepayAdapter = 'UniswapRepayAdapter', @@ -92,6 +94,7 @@ export enum ProtocolErrors { REQUESTED_AMOUNT_TOO_SMALL = '25', // 'The requested amount is too small for a FlashLoan.' INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26', // 'The actual balance of the protocol is inconsistent' CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27', // 'The actual balance of the protocol is inconsistent' + BORROW_ALLOWANCE_ARE_NOT_ENOUGH = '54', // User borrows on behalf, but allowance are too small INVALID_FLASH_LOAN_EXECUTOR_RETURN = '60', // The flash loan received returned 0 (EOA) // require error messages - aToken @@ -120,6 +123,12 @@ export enum ProtocolErrors { IS_PAUSED = '58', // Pool is paused + INVALID_LTV = '70', + INVALID_LIQ_THRESHOLD = '71', + INVALID_LIQ_BONUS = '72', + INVALID_DECIMALS = '73', + INVALID_RESERVE_FACTOR = '74', + // old INVALID_FROM_BALANCE_AFTER_TRANSFER = 'Invalid from balance after transfer', diff --git a/package-lock.json b/package-lock.json index b44b0962..5b9d2c4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5268,13 +5268,13 @@ "dependencies": { "ansi-regex": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "ansi-styles": { "version": "3.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { @@ -5283,7 +5283,7 @@ }, "bindings": { "version": "1.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, "requires": { @@ -5292,7 +5292,7 @@ }, "bip66": { "version": "1.1.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", "dev": true, "requires": { @@ -5301,19 +5301,19 @@ }, "bn.js": { "version": "4.11.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", "dev": true }, "brorand": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, "browserify-aes": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -5327,25 +5327,25 @@ }, "buffer-from": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, "buffer-xor": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "dev": true }, "camelcase": { "version": "5.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "cipher-base": { "version": "1.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { @@ -5355,7 +5355,7 @@ }, "cliui": { "version": "5.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { @@ -5366,7 +5366,7 @@ }, "color-convert": { "version": "1.9.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { @@ -5375,13 +5375,13 @@ }, "color-name": { "version": "1.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "create-hash": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -5394,7 +5394,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -5408,7 +5408,7 @@ }, "cross-spawn": { "version": "6.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { @@ -5421,13 +5421,13 @@ }, "decamelize": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "drbg.js": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", "dev": true, "requires": { @@ -5438,7 +5438,7 @@ }, "elliptic": { "version": "6.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", "dev": true, "requires": { @@ -5453,13 +5453,13 @@ }, "emoji-regex": { "version": "7.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "end-of-stream": { "version": "1.4.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { @@ -5468,7 +5468,7 @@ }, "ethereumjs-util": { "version": "6.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", "dev": true, "requires": { @@ -5483,7 +5483,7 @@ }, "ethjs-util": { "version": "0.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", "dev": true, "requires": { @@ -5493,7 +5493,7 @@ }, "evp_bytestokey": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { @@ -5503,7 +5503,7 @@ }, "execa": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { @@ -5518,13 +5518,13 @@ }, "file-uri-to-path": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "dev": true }, "find-up": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { @@ -5533,13 +5533,13 @@ }, "get-caller-file": { "version": "2.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, "get-stream": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { @@ -5548,7 +5548,7 @@ }, "hash-base": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { @@ -5558,7 +5558,7 @@ }, "hash.js": { "version": "1.1.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { @@ -5568,7 +5568,7 @@ }, "hmac-drbg": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { @@ -5579,43 +5579,43 @@ }, "inherits": { "version": "2.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "invert-kv": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-hex-prefixed": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=", "dev": true }, "is-stream": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "isexe": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "keccak": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", "dev": true, "requires": { @@ -5627,7 +5627,7 @@ }, "lcid": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { @@ -5636,7 +5636,7 @@ }, "locate-path": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { @@ -5646,7 +5646,7 @@ }, "map-age-cleaner": { "version": "0.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "dev": true, "requires": { @@ -5655,7 +5655,7 @@ }, "md5.js": { "version": "1.3.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { @@ -5666,7 +5666,7 @@ }, "mem": { "version": "4.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", "dev": true, "requires": { @@ -5677,37 +5677,37 @@ }, "mimic-fn": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, "minimalistic-assert": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, "minimalistic-crypto-utils": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", "dev": true }, "nan": { "version": "2.14.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true }, "nice-try": { "version": "1.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "npm-run-path": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { @@ -5716,7 +5716,7 @@ }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { @@ -5725,7 +5725,7 @@ }, "os-locale": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { @@ -5736,25 +5736,25 @@ }, "p-defer": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, "p-finally": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-is-promise": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", "dev": true }, "p-limit": { "version": "2.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { @@ -5763,7 +5763,7 @@ }, "p-locate": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { @@ -5772,25 +5772,25 @@ }, "p-try": { "version": "2.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "path-exists": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-key": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "pump": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { @@ -5800,19 +5800,19 @@ }, "require-directory": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, "ripemd160": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { @@ -5822,7 +5822,7 @@ }, "rlp": { "version": "2.2.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.3.tgz", "integrity": "sha512-l6YVrI7+d2vpW6D6rS05x2Xrmq8oW7v3pieZOJKBEdjuTF4Kz/iwk55Zyh1Zaz+KOB2kC8+2jZlp2u9L4tTzCQ==", "dev": true, "requires": { @@ -5832,13 +5832,13 @@ }, "safe-buffer": { "version": "5.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", "dev": true }, "secp256k1": { "version": "3.7.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz", "integrity": "sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==", "dev": true, "requires": { @@ -5854,19 +5854,19 @@ }, "semver": { "version": "5.7.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "sha.js": { "version": "2.4.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -5876,7 +5876,7 @@ }, "shebang-command": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { @@ -5885,25 +5885,25 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "source-map-support": { "version": "0.5.12", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", "dev": true, "requires": { @@ -5913,7 +5913,7 @@ }, "string-width": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { @@ -5924,7 +5924,7 @@ }, "strip-ansi": { "version": "5.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { @@ -5933,13 +5933,13 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "strip-hex-prefix": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", "dev": true, "requires": { @@ -5948,7 +5948,7 @@ }, "which": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { @@ -5957,13 +5957,13 @@ }, "which-module": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "wrap-ansi": { "version": "5.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { @@ -5974,19 +5974,19 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "y18n": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, "yargs": { "version": "13.2.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", "dev": true, "requires": { @@ -6005,7 +6005,7 @@ }, "yargs-parser": { "version": "13.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { @@ -15177,7 +15177,6 @@ "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", - "fsevents": "~2.1.1", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -15216,12 +15215,6 @@ "locate-path": "^3.0.0" } }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "optional": true - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -17305,16 +17298,6 @@ "ajv-keywords": "^3.4.1" } }, - "scrypt": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/scrypt/-/scrypt-6.0.3.tgz", - "integrity": "sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0=", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.0.8" - } - }, "scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", @@ -19211,7 +19194,6 @@ "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", - "fsevents": "~2.1.2", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -19228,12 +19210,6 @@ "to-regex-range": "^5.0.1" } }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "optional": true - }, "glob-parent": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", @@ -21256,9 +21232,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.43.tgz", - "integrity": "sha512-F7xV2kxZGb3seVP3UQt3msHcoDCtDi8WNO/UCzNLhRwaYVT4yJO1ndcV+vCTnY+jiAVqyLZq/VJbRE/AhwqEag==", + "version": "10.17.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.42.tgz", + "integrity": "sha512-HElxYF7C/MSkuvlaHB2c+82zhXiuO49Cq056Dol8AQuTph7oJtduo2n6J8rFa+YhJyNgQ/Lm20ZaxqD0vxU0+Q==", "dev": true } } @@ -23928,6 +23904,16 @@ } } }, + "scrypt": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/scrypt/-/scrypt-6.0.3.tgz", + "integrity": "sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0=", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.0.8" + } + }, "scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", diff --git a/package.json b/package.json index 4a64a417..931b1186 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,16 @@ "buidler:kovan": "buidler --network kovan", "buidler:ropsten": "buidler--network ropsten", "buidler:main": "buidler --network main", + "buidler:docker": "buidler --network buidlerevm_docker", "buidler help": "buidler help", "compile": "SKIP_LOAD=true buidler compile", - "types-gen": "typechain --target ethers-v5 --outDir ./types './artifacts/*.json'", + "types-gen": "npm run compile -- --force && typechain --target ethers-v5 --outDir ./types './artifacts/*.json'", "test": "buidler test", "test-scenarios": "buidler test test/__setup.spec.ts test/scenario.spec.ts", "aave:evm:dev:migration": "buidler aave:dev", "aave:evm:full:migration": "buidler aave:full", + "aave:docker:dev:migration": "npm run buidler:docker -- aave:dev", + "aave:docker:full:migration": "npm run buidler:docker -- aave:full", "aave:kovan:dev:migration": "npm run buidler:kovan -- aave:dev --verify", "aave:kovan:full:migration": "npm run buidler:kovan -- aave:full --verify", "aave:ropsten:dev:migration": "npm run buidler:ropsten -- aave:dev --verify", @@ -34,8 +37,11 @@ "test-transfers": "buidler test test/__setup.spec.ts test/atoken-transfer.spec.ts", "test-flash": "buidler test test/__setup.spec.ts test/flashloan.spec.ts", "test-liquidate": "buidler test test/__setup.spec.ts test/liquidation-atoken.spec.ts", + "test-deploy": "buidler test test/__setup.spec.ts test/test-init.spec.ts", "test-pausable": "buidler test test/__setup.spec.ts test/pausable-functions.spec.ts", "test-permit": "buidler test test/__setup.spec.ts test/atoken-permit.spec.ts", + "test-stable-and-atokens": "buidler test test/__setup.spec.ts test/atoken-transfer.spec.ts test/stable-token.spec.ts", + "test-subgraph:scenarios": "buidler --network buidlerevm_docker test test/__setup.spec.ts test/subgraph-scenarios.spec.ts", "dev:coverage": "buidler coverage --network coverage", "dev:deployment": "buidler dev-deployment", "dev:deployExample": "buidler deploy-Example", diff --git a/tasks/dev/1_mock_tokens.ts b/tasks/dev/1_mock_tokens.ts index 617071ce..efa3ca04 100644 --- a/tasks/dev/1_mock_tokens.ts +++ b/tasks/dev/1_mock_tokens.ts @@ -1,5 +1,5 @@ import {task} from '@nomiclabs/buidler/config'; -import {deployAllMockTokens} from '../../helpers/contracts-helpers'; +import {deployAllMockTokens} from '../../helpers/contracts-deployments'; task('dev:deploy-mock-tokens', 'Deploy mock tokens for dev enviroment') .addOptionalParam('verify', 'Verify contracts at Etherscan') .setAction(async ({verify}, localBRE) => { diff --git a/tasks/dev/2_address_provider_registry.ts b/tasks/dev/2_address_provider_registry.ts index 078b56c5..1c3da96d 100644 --- a/tasks/dev/2_address_provider_registry.ts +++ b/tasks/dev/2_address_provider_registry.ts @@ -2,7 +2,7 @@ import {task} from '@nomiclabs/buidler/config'; import { deployLendingPoolAddressesProvider, deployLendingPoolAddressesProviderRegistry, -} from '../../helpers/contracts-helpers'; +} from '../../helpers/contracts-deployments'; import {waitForTx} from '../../helpers/misc-utils'; task( @@ -20,6 +20,6 @@ task( const addressesProviderRegistry = await deployLendingPoolAddressesProviderRegistry(verify); await waitForTx( - await addressesProviderRegistry.registerAddressesProvider(addressesProvider.address, 0) + await addressesProviderRegistry.registerAddressesProvider(addressesProvider.address, 1) ); }); diff --git a/tasks/dev/3_lending_pool.ts b/tasks/dev/3_lending_pool.ts index b7c88a19..866bd6b7 100644 --- a/tasks/dev/3_lending_pool.ts +++ b/tasks/dev/3_lending_pool.ts @@ -1,14 +1,18 @@ import {task} from '@nomiclabs/buidler/config'; import { + deployATokensAndRatesHelper, deployLendingPool, - getLendingPoolAddressesProvider, - getLendingPool, - insertContractAddressInDb, deployLendingPoolConfigurator, - getLendingPoolConfiguratorProxy, -} from '../../helpers/contracts-helpers'; + deployStableAndVariableTokensHelper, +} from '../../helpers/contracts-deployments'; import {eContractid} from '../../helpers/types'; import {waitForTx} from '../../helpers/misc-utils'; +import { + getLendingPoolAddressesProvider, + getLendingPool, + getLendingPoolConfiguratorProxy, +} from '../../helpers/contracts-getters'; +import {insertContractAddressInDb} from '../../helpers/contracts-helpers'; task('dev:deploy-lending-pool', 'Deploy lending pool for dev enviroment') .addOptionalParam('verify', 'Verify contracts at Etherscan') @@ -41,4 +45,14 @@ task('dev:deploy-lending-pool', 'Deploy lending pool for dev enviroment') eContractid.LendingPoolConfigurator, lendingPoolConfiguratorProxy.address ); + + // Deploy deployment helpers + await deployStableAndVariableTokensHelper( + [lendingPoolProxy.address, addressesProvider.address], + verify + ); + await deployATokensAndRatesHelper( + [lendingPoolProxy.address, addressesProvider.address, lendingPoolConfiguratorProxy.address], + verify + ); }); diff --git a/tasks/dev/4_oracles.ts b/tasks/dev/4_oracles.ts index 0e2d8ef5..a20e2381 100644 --- a/tasks/dev/4_oracles.ts +++ b/tasks/dev/4_oracles.ts @@ -1,23 +1,24 @@ import {task} from '@nomiclabs/buidler/config'; import { - getLendingPoolAddressesProvider, deployPriceOracle, - getMockedTokens, - getPairsTokenAggregator, deployChainlinkProxyPriceProvider, deployLendingRateOracle, - getAllMockedTokens, -} from '../../helpers/contracts-helpers'; +} from '../../helpers/contracts-deployments'; import { setInitialAssetPricesInOracle, - setInitialMarketRatesInRatesOracle, deployAllMockAggregators, + setInitialMarketRatesInRatesOracleByHelper, } from '../../helpers/oracles-helpers'; import {ICommonConfiguration, iAssetBase, TokenContractId} from '../../helpers/types'; import {waitForTx} from '../../helpers/misc-utils'; import {getAllAggregatorsAddresses, getAllTokenAddresses} from '../../helpers/mock-helpers'; import {ConfigNames, loadPoolConfig} from '../../helpers/configuration'; +import { + getAllMockedTokens, + getLendingPoolAddressesProvider, + getPairsTokenAggregator, +} from '../../helpers/contracts-getters'; task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') .addOptionalParam('verify', 'Verify contracts at Etherscan') @@ -41,6 +42,7 @@ task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') return prev; }, defaultTokenList); const addressesProvider = await getLendingPoolAddressesProvider(); + const admin = await addressesProvider.getAaveAdmin(); const fallbackOracle = await deployPriceOracle(verify); await waitForTx(await fallbackOracle.setEthUsdPrice(MockUsdPriceInWei)); @@ -66,9 +68,10 @@ task('dev:deploy-oracles', 'Deploy oracles for dev enviroment') const allReservesAddresses = { ...tokensAddressesWithoutUsd, }; - await setInitialMarketRatesInRatesOracle( + await setInitialMarketRatesInRatesOracleByHelper( LendingRateOracleRatesCommon, allReservesAddresses, - lendingRateOracle + lendingRateOracle, + admin ); }); diff --git a/tasks/dev/5_initialize.ts b/tasks/dev/5_initialize.ts index 6333247c..d4ce0c5d 100644 --- a/tasks/dev/5_initialize.ts +++ b/tasks/dev/5_initialize.ts @@ -1,23 +1,28 @@ import {task} from '@nomiclabs/buidler/config'; import { - getLendingPoolAddressesProvider, - initReserves, deployLendingPoolCollateralManager, - insertContractAddressInDb, deployMockFlashLoanReceiver, deployWalletBalancerProvider, deployAaveProtocolTestHelpers, - getLendingPool, - getLendingPoolConfiguratorProxy, - getAllMockedTokens, -} from '../../helpers/contracts-helpers'; +} from '../../helpers/contracts-deployments'; import {getReservesConfigByPool} from '../../helpers/configuration'; import {tEthereumAddress, AavePools, eContractid} from '../../helpers/types'; import {waitForTx, filterMapBy} from '../../helpers/misc-utils'; -import {enableReservesToBorrow, enableReservesAsCollateral} from '../../helpers/init-helpers'; +import { + enableReservesToBorrowByHelper, + enableReservesAsCollateralByHelper, + initReservesByHelper, +} from '../../helpers/init-helpers'; import {getAllTokenAddresses} from '../../helpers/mock-helpers'; import {ZERO_ADDRESS} from '../../helpers/constants'; +import { + getAllMockedTokens, + getLendingPool, + getLendingPoolConfiguratorProxy, + getLendingPoolAddressesProvider, +} from '../../helpers/contracts-getters'; +import {insertContractAddressInDb} from '../../helpers/contracts-helpers'; task('dev:initialize-lending-pool', 'Initialize lending pool configuration.') .addOptionalParam('verify', 'Verify contracts at Etherscan') @@ -39,28 +44,20 @@ task('dev:initialize-lending-pool', 'Initialize lending pool configuration.') const reservesParams = getReservesConfigByPool(AavePools.proto); - await initReserves( + const admin = await addressesProvider.getAaveAdmin(); + + await initReservesByHelper(reservesParams, protoPoolReservesAddresses, admin, ZERO_ADDRESS); + await enableReservesToBorrowByHelper( reservesParams, protoPoolReservesAddresses, - addressesProvider, - lendingPoolProxy, testHelpers, - lendingPoolConfiguratorProxy, - AavePools.proto, - ZERO_ADDRESS, - verify + admin ); - await enableReservesToBorrow( + await enableReservesAsCollateralByHelper( reservesParams, protoPoolReservesAddresses, testHelpers, - lendingPoolConfiguratorProxy - ); - await enableReservesAsCollateral( - reservesParams, - protoPoolReservesAddresses, - testHelpers, - lendingPoolConfiguratorProxy + admin ); const collateralManager = await deployLendingPoolCollateralManager(verify); diff --git a/tasks/full/1_address_provider_registry.ts b/tasks/full/1_address_provider_registry.ts index 85ead901..4dd84f08 100644 --- a/tasks/full/1_address_provider_registry.ts +++ b/tasks/full/1_address_provider_registry.ts @@ -1,13 +1,13 @@ import {task} from '@nomiclabs/buidler/config'; +import {getParamPerNetwork} from '../../helpers/contracts-helpers'; import { deployLendingPoolAddressesProvider, deployLendingPoolAddressesProviderRegistry, - getParamPerNetwork, - getLendingPoolAddressesProviderRegistry, -} from '../../helpers/contracts-helpers'; +} from '../../helpers/contracts-deployments'; import {waitForTx} from '../../helpers/misc-utils'; import {ConfigNames, loadPoolConfig, getGenesisAaveAdmin} from '../../helpers/configuration'; import {eEthereumNetwork} from '../../helpers/types'; +import {getLendingPoolAddressesProviderRegistry} from '../../helpers/contracts-getters'; task( 'full:deploy-address-provider', diff --git a/tasks/full/2_lending_pool.ts b/tasks/full/2_lending_pool.ts index a4f919ce..4a10b30c 100644 --- a/tasks/full/2_lending_pool.ts +++ b/tasks/full/2_lending_pool.ts @@ -1,14 +1,18 @@ import {task} from '@nomiclabs/buidler/config'; +import {insertContractAddressInDb} from '../../helpers/contracts-helpers'; import { + deployATokensAndRatesHelper, deployLendingPool, - getLendingPoolAddressesProvider, - getLendingPool, - insertContractAddressInDb, deployLendingPoolConfigurator, - getLendingPoolConfiguratorProxy, -} from '../../helpers/contracts-helpers'; + deployStableAndVariableTokensHelper, +} from '../../helpers/contracts-deployments'; import {eContractid} from '../../helpers/types'; import {waitForTx} from '../../helpers/misc-utils'; +import { + getLendingPoolAddressesProvider, + getLendingPool, + getLendingPoolConfiguratorProxy, +} from '../../helpers/contracts-getters'; task('full:deploy-lending-pool', 'Deploy lending pool for dev enviroment') .addFlag('verify', 'Verify contracts at Etherscan') @@ -44,4 +48,13 @@ task('full:deploy-lending-pool', 'Deploy lending pool for dev enviroment') eContractid.LendingPoolConfigurator, lendingPoolConfiguratorProxy.address ); + // Deploy deployment helpers + await deployStableAndVariableTokensHelper( + [lendingPoolProxy.address, addressesProvider.address], + verify + ); + await deployATokensAndRatesHelper( + [lendingPoolProxy.address, addressesProvider.address, lendingPoolConfiguratorProxy.address], + verify + ); }); diff --git a/tasks/full/3_oracles.ts b/tasks/full/3_oracles.ts index 3121b008..a7a39a8c 100644 --- a/tasks/full/3_oracles.ts +++ b/tasks/full/3_oracles.ts @@ -1,17 +1,18 @@ import {task} from '@nomiclabs/buidler/config'; +import {getParamPerNetwork} from '../../helpers/contracts-helpers'; import { - getLendingPoolAddressesProvider, - getPairsTokenAggregator, deployChainlinkProxyPriceProvider, deployLendingRateOracle, - getParamPerNetwork, -} from '../../helpers/contracts-helpers'; - -import {setInitialMarketRatesInRatesOracle} from '../../helpers/oracles-helpers'; +} from '../../helpers/contracts-deployments'; +import {setInitialMarketRatesInRatesOracleByHelper} from '../../helpers/oracles-helpers'; import {ICommonConfiguration, eEthereumNetwork, SymbolMap} from '../../helpers/types'; import {waitForTx, filterMapBy} from '../../helpers/misc-utils'; import {ConfigNames, loadPoolConfig} from '../../helpers/configuration'; import {exit} from 'process'; +import { + getLendingPoolAddressesProvider, + getPairsTokenAggregator, +} from '../../helpers/contracts-getters'; task('full:deploy-oracles', 'Deploy oracles for dev enviroment') .addFlag('verify', 'Verify contracts at Etherscan') @@ -29,11 +30,11 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') FallbackOracle, ChainlinkAggregator, } = poolConfig as ICommonConfiguration; - const lendingRateOracles = filterMapBy(LendingRateOracleRatesCommon, (key) => ReserveSymbols.includes(key) ); const addressesProvider = await getLendingPoolAddressesProvider(); + const admin = await addressesProvider.getAaveAdmin(); const fallbackOracle = await getParamPerNetwork(FallbackOracle, network); const reserveAssets = await getParamPerNetwork(ReserveAssets, network); @@ -57,10 +58,11 @@ task('full:deploy-oracles', 'Deploy oracles for dev enviroment') await waitForTx(await addressesProvider.setLendingRateOracle(lendingRateOracle.address)); const {USD, ...tokensAddressesWithoutUsd} = tokensToWatch; - await setInitialMarketRatesInRatesOracle( + await setInitialMarketRatesInRatesOracleByHelper( lendingRateOracles, tokensAddressesWithoutUsd, - lendingRateOracle + lendingRateOracle, + admin ); } catch (err) { console.error(err); diff --git a/tasks/full/5_initialize.ts b/tasks/full/5_initialize.ts index 31900897..ddc789d1 100644 --- a/tasks/full/5_initialize.ts +++ b/tasks/full/5_initialize.ts @@ -1,22 +1,25 @@ import {task} from '@nomiclabs/buidler/config'; +import {getParamPerNetwork} from '../../helpers/contracts-helpers'; import { - getLendingPoolAddressesProvider, - initReserves, deployLendingPoolCollateralManager, - insertContractAddressInDb, deployWalletBalancerProvider, deployAaveProtocolTestHelpers, +} from '../../helpers/contracts-deployments'; +import {loadPoolConfig, ConfigNames} from '../../helpers/configuration'; +import {eEthereumNetwork, ICommonConfiguration} from '../../helpers/types'; +import {waitForTx} from '../../helpers/misc-utils'; +import { + initReservesByHelper, + enableReservesToBorrowByHelper, + enableReservesAsCollateralByHelper, +} from '../../helpers/init-helpers'; +import {exit} from 'process'; +import { getLendingPool, getLendingPoolConfiguratorProxy, - getParamPerNetwork, -} from '../../helpers/contracts-helpers'; -import {loadPoolConfig, ConfigNames} from '../../helpers/configuration'; - -import {AavePools, eContractid, eEthereumNetwork, ICommonConfiguration} from '../../helpers/types'; -import {waitForTx} from '../../helpers/misc-utils'; -import {enableReservesToBorrow, enableReservesAsCollateral} from '../../helpers/init-helpers'; + getLendingPoolAddressesProvider, +} from '../../helpers/contracts-getters'; import {ZERO_ADDRESS} from '../../helpers/constants'; -import {exit} from 'process'; task('full:initialize-lending-pool', 'Initialize lending pool configuration.') .addFlag('verify', 'Verify contracts at Etherscan') @@ -24,7 +27,6 @@ task('full:initialize-lending-pool', 'Initialize lending pool configuration.') .setAction(async ({verify, pool}, localBRE) => { try { await localBRE.run('set-bre'); - console.log('init'); const network = localBRE.network.name; const poolConfig = loadPoolConfig(pool); const {ReserveAssets, ReservesConfig} = poolConfig as ICommonConfiguration; @@ -37,40 +39,20 @@ task('full:initialize-lending-pool', 'Initialize lending pool configuration.') const testHelpers = await deployAaveProtocolTestHelpers(addressesProvider.address, verify); - console.log('init reserves'); - await initReserves( - ReservesConfig, - reserveAssets, - addressesProvider, - lendingPoolProxy, - testHelpers, - lendingPoolConfiguratorProxy, - AavePools.proto, - ZERO_ADDRESS, - verify - ); - console.log('enable reserves'); - await enableReservesToBorrow( - ReservesConfig, - reserveAssets, - testHelpers, - lendingPoolConfiguratorProxy - ); - console.log('enable reserves as collateral'); - await enableReservesAsCollateral( - ReservesConfig, - reserveAssets, - testHelpers, - lendingPoolConfiguratorProxy - ); + const admin = await addressesProvider.getAaveAdmin(); + if (!reserveAssets) { + throw 'Reserve assets is undefined. Check ReserveAssets configuration at config directory'; + } + + await initReservesByHelper(ReservesConfig, reserveAssets, admin, ZERO_ADDRESS); + await enableReservesToBorrowByHelper(ReservesConfig, reserveAssets, testHelpers, admin); + await enableReservesAsCollateralByHelper(ReservesConfig, reserveAssets, testHelpers, admin); - console.log('deploy coll manager'); const collateralManager = await deployLendingPoolCollateralManager(verify); await waitForTx( await addressesProvider.setLendingPoolCollateralManager(collateralManager.address) ); - console.log('deploy bal provicer'); await deployWalletBalancerProvider(addressesProvider.address, verify); } catch (err) { console.error(err); diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts index 40ed2ced..f9047181 100644 --- a/test/__setup.spec.ts +++ b/test/__setup.spec.ts @@ -1,5 +1,10 @@ import rawBRE from '@nomiclabs/buidler'; import {MockContract} from 'ethereum-waffle'; +import { + insertContractAddressInDb, + getEthersSigners, + registerContractInJsonDb, +} from '../helpers/contracts-helpers'; import { deployLendingPoolAddressesProvider, deployMintableERC20, @@ -7,39 +12,42 @@ import { deployLendingPoolConfigurator, deployLendingPool, deployPriceOracle, - getLendingPoolConfiguratorProxy, deployChainlinkProxyPriceProvider, deployLendingPoolCollateralManager, deployMockFlashLoanReceiver, deployWalletBalancerProvider, - getLendingPool, - insertContractAddressInDb, deployAaveProtocolTestHelpers, - getEthersSigners, - registerContractInJsonDb, - getPairsTokenAggregator, - initReserves, deployLendingRateOracle, + deployStableAndVariableTokensHelper, + deployATokensAndRatesHelper, deployMockUniswapRouter, deployUniswapLiquiditySwapAdapter, deployUniswapRepayAdapter, -} from '../helpers/contracts-helpers'; +} from '../helpers/contracts-deployments'; import {Signer} from 'ethers'; import {TokenContractId, eContractid, tEthereumAddress, AavePools} from '../helpers/types'; import {MintableErc20 as MintableERC20} from '../types/MintableErc20'; import {getReservesConfigByPool} from '../helpers/configuration'; import {initializeMakeSuite} from './helpers/make-suite'; -import {AaveProtocolTestHelpers} from '../types/AaveProtocolTestHelpers'; import { setInitialAssetPricesInOracle, - setInitialMarketRatesInRatesOracle, deployAllMockAggregators, + setInitialMarketRatesInRatesOracleByHelper, } from '../helpers/oracles-helpers'; import {waitForTx} from '../helpers/misc-utils'; -import {enableReservesToBorrow, enableReservesAsCollateral} from '../helpers/init-helpers'; +import { + initReservesByHelper, + enableReservesToBorrowByHelper, + enableReservesAsCollateralByHelper, +} from '../helpers/init-helpers'; import {AaveConfig} from '../config/aave'; import {ZERO_ADDRESS} from '../helpers/constants'; +import { + getLendingPool, + getLendingPoolConfiguratorProxy, + getPairsTokenAggregator, +} from '../helpers/contracts-getters'; const MOCK_USD_PRICE_IN_WEI = AaveConfig.ProtocolGlobalParams.MockUsdPriceInWei; const ALL_ASSETS_INITIAL_PRICES = AaveConfig.Mocks.AllAssetsInitialPrices; @@ -93,17 +101,11 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { const lendingPoolImpl = await deployLendingPool(); - console.log('Deployed lending pool, address:', lendingPoolImpl.address); await waitForTx(await addressesProvider.setLendingPoolImpl(lendingPoolImpl.address)); - console.log('Added pool to addresses provider'); - const address = await addressesProvider.getLendingPool(); - console.log('Address is ', address); const lendingPoolProxy = await getLendingPool(address); - console.log('implementation set, address:', lendingPoolProxy.address); - await insertContractAddressInDb(eContractid.LendingPool, lendingPoolProxy.address); const lendingPoolConfiguratorImpl = await deployLendingPoolConfigurator(); @@ -118,6 +120,14 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { lendingPoolConfiguratorProxy.address ); + // Deploy deployment helpers + await deployStableAndVariableTokensHelper([lendingPoolProxy.address, addressesProvider.address]); + await deployATokensAndRatesHelper([ + lendingPoolProxy.address, + addressesProvider.address, + lendingPoolConfiguratorProxy.address, + ]); + const fallbackOracle = await deployPriceOracle(); await waitForTx(await fallbackOracle.setEthUsdPrice(MOCK_USD_PRICE_IN_WEI)); await setInitialAssetPricesInOracle( @@ -186,10 +196,11 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { const allReservesAddresses = { ...tokensAddressesWithoutUsd, }; - await setInitialMarketRatesInRatesOracle( + await setInitialMarketRatesInRatesOracleByHelper( LENDING_RATE_ORACLE_RATES_COMMON, allReservesAddresses, - lendingRateOracle + lendingRateOracle, + aaveAdmin ); const { @@ -207,30 +218,21 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { const testHelpers = await deployAaveProtocolTestHelpers(addressesProvider.address); await insertContractAddressInDb(eContractid.AaveProtocolTestHelpers, testHelpers.address); + const admin = await deployer.getAddress(); console.log('Initialize configuration'); - await initReserves( + await initReservesByHelper(reservesParams, protoPoolReservesAddresses, admin, ZERO_ADDRESS); + await enableReservesToBorrowByHelper( reservesParams, protoPoolReservesAddresses, - addressesProvider, - lendingPoolProxy, testHelpers, - lendingPoolConfiguratorProxy, - AavePools.proto, - ZERO_ADDRESS, - false + admin ); - await enableReservesToBorrow( + await enableReservesAsCollateralByHelper( reservesParams, protoPoolReservesAddresses, testHelpers, - lendingPoolConfiguratorProxy - ); - await enableReservesAsCollateral( - reservesParams, - protoPoolReservesAddresses, - testHelpers, - lendingPoolConfiguratorProxy + admin ); const collateralManager = await deployLendingPoolCollateralManager(); diff --git a/test/addresses-provider-registry.spec.ts b/test/addresses-provider-registry.spec.ts index 5630591d..d7b148e7 100644 --- a/test/addresses-provider-registry.spec.ts +++ b/test/addresses-provider-registry.spec.ts @@ -1,6 +1,5 @@ import {TestEnv, makeSuite} from './helpers/make-suite'; -import {RAY, APPROVAL_AMOUNT_LENDING_POOL, ZERO_ADDRESS} from '../helpers/constants'; -import {convertToCurrencyDecimals} from '../helpers/contracts-helpers'; +import {ZERO_ADDRESS} from '../helpers/constants'; import {ProtocolErrors} from '../helpers/types'; const {expect} = require('chai'); diff --git a/test/atoken-permit.spec.ts b/test/atoken-permit.spec.ts index 91e438f3..44c90008 100644 --- a/test/atoken-permit.spec.ts +++ b/test/atoken-permit.spec.ts @@ -32,10 +32,11 @@ makeSuite('AToken: Permit', (testEnv: TestEnv) => { }); it('Get aDAI for tests', async () => { - const {dai, deployer, pool} = testEnv; + const {dai, pool, deployer} = testEnv; await dai.mint(parseEther('20000')); await dai.approve(pool.address, parseEther('20000')); + await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); }); diff --git a/test/atoken-transfer.spec.ts b/test/atoken-transfer.spec.ts index 0e207e17..ca92e086 100644 --- a/test/atoken-transfer.spec.ts +++ b/test/atoken-transfer.spec.ts @@ -36,6 +36,10 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { await aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit); + const name = await aDai.name(); + + expect(name).to.be.equal('Aave interest bearing DAI'); + const fromBalance = await aDai.balanceOf(users[0].address); const toBalance = await aDai.balanceOf(users[1].address); @@ -46,8 +50,8 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { ); }); - it('User 0 deposits 1 WETH and user 1 tries to borrow, but the aTokens received as a transfer are not available as collateral (revert expected)', async () => { - const {users, pool, weth} = testEnv; + it('User 0 deposits 1 WETH and user 1 tries to borrow the WETH with the received DAI as collateral', async () => { + const {users, pool, weth, helpersContract} = testEnv; const userAddress = await pool.signer.getAddress(); await weth.connect(users[0].signer).mint(await convertToCurrencyDecimals(weth.address, '1')); @@ -57,26 +61,6 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { await pool .connect(users[0].signer) .deposit(weth.address, ethers.utils.parseEther('1.0'), userAddress, '0'); - await expect( - pool - .connect(users[1].signer) - .borrow( - weth.address, - ethers.utils.parseEther('0.1'), - RateMode.Stable, - AAVE_REFERRAL, - users[1].address - ), - COLLATERAL_BALANCE_IS_0 - ).to.be.revertedWith(COLLATERAL_BALANCE_IS_0); - }); - - it('User 1 sets the DAI as collateral and borrows, tries to transfer everything back to user 0 (revert expected)', async () => { - const {users, pool, aDai, dai, weth} = testEnv; - await pool.connect(users[1].signer).setUserUseReserveAsCollateral(dai.address, true); - - const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '1000'); - await pool .connect(users[1].signer) .borrow( @@ -87,9 +71,32 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { users[1].address ); + const userReserveData = await helpersContract.getUserReserveData(weth.address, users[1].address); + + expect(userReserveData.currentStableDebt.toString()).to.be.eq(ethers.utils.parseEther('0.1')); + }); + + it('User 1 tries to transfer all the DAI used as collateral back to user 0 (revert expected)', async () => { + const {users, pool, aDai, dai, weth} = testEnv; + + const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '1000'); + await expect( aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer), TRANSFER_NOT_ALLOWED ).to.be.revertedWith(TRANSFER_NOT_ALLOWED); }); + + it('User 1 tries to transfer a small amount of DAI used as collateral back to user 0', async () => { + + const {users, pool, aDai, dai, weth} = testEnv; + + const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '100'); + + await aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer); + + const user0Balance = await aDai.balanceOf(users[0].address); + + expect(user0Balance.toString()).to.be.eq(aDAItoTransfer.toString()); + }); }); diff --git a/test/configurator.spec.ts b/test/configurator.spec.ts index 891c88dc..788add5c 100644 --- a/test/configurator.spec.ts +++ b/test/configurator.spec.ts @@ -10,7 +10,63 @@ const APPROVAL_AMOUNT_LENDING_POOL = const {expect} = require('chai'); makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { - const {CALLER_NOT_AAVE_ADMIN, RESERVE_LIQUIDITY_NOT_0} = ProtocolErrors; + const { + CALLER_NOT_AAVE_ADMIN, + RESERVE_LIQUIDITY_NOT_0, + INVALID_LTV, + INVALID_LIQ_THRESHOLD, + INVALID_LIQ_BONUS, + INVALID_DECIMALS, + INVALID_RESERVE_FACTOR, + } = ProtocolErrors; + + it('Reverts trying to set an invalid LTV', async () => { + const {configurator, weth} = testEnv; + + const invalidLtv = 65536; + + await expect(configurator.setLtv(weth.address, invalidLtv)).to.be.revertedWith(INVALID_LTV); + }); + + it('Reverts trying to set an invalid liquidation threshold', async () => { + const {configurator, weth} = testEnv; + + const invalidLiqThreshold = 65536; + + await expect( + configurator.setLiquidationThreshold(weth.address, invalidLiqThreshold) + ).to.be.revertedWith(INVALID_LIQ_THRESHOLD); + }); + + it('Reverts trying to set an invalid liquidation bonus', async () => { + const {configurator, weth} = testEnv; + + const invalidLiqBonus = 65536; + + await expect( + configurator.setLiquidationBonus(weth.address, invalidLiqBonus) + ).to.be.revertedWith(INVALID_LIQ_BONUS); + }); + + it('Reverts trying to set an invalid reserve decimals', async () => { + const {configurator, weth} = testEnv; + + const invalidDecimals = 256; + + await expect(configurator.setReserveDecimals(weth.address, invalidDecimals)).to.be.revertedWith( + INVALID_DECIMALS + ); + }); + + it('Reverts trying to set an invalid reserve factor', async () => { + const {configurator, weth} = testEnv; + + const invalidReserveFactor = 65536; + + await expect( + configurator.setReserveFactor(weth.address, invalidReserveFactor) + ).to.be.revertedWith(INVALID_RESERVE_FACTOR); + }); it('Deactivates the ETH reserve', async () => { const {configurator, weth, helpersContract} = testEnv; diff --git a/test/flashloan.spec.ts b/test/flashloan.spec.ts index 4edd4848..fc977fcf 100644 --- a/test/flashloan.spec.ts +++ b/test/flashloan.spec.ts @@ -2,16 +2,13 @@ import BigNumber from 'bignumber.js'; import {TestEnv, makeSuite} from './helpers/make-suite'; import {APPROVAL_AMOUNT_LENDING_POOL, oneRay} from '../helpers/constants'; -import { - convertToCurrencyDecimals, - getMockFlashLoanReceiver, - getContract, -} from '../helpers/contracts-helpers'; +import {convertToCurrencyDecimals, getContract} from '../helpers/contracts-helpers'; import {ethers} from 'ethers'; import {MockFlashLoanReceiver} from '../types/MockFlashLoanReceiver'; import {ProtocolErrors, eContractid} from '../helpers/types'; import {VariableDebtToken} from '../types/VariableDebtToken'; import {StableDebtToken} from '../types/StableDebtToken'; +import {getMockFlashLoanReceiver} from '../helpers/contracts-getters'; const {expect} = require('chai'); @@ -25,6 +22,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { SAFEERC20_LOWLEVEL_CALL, IS_PAUSED, INVALID_FLASH_LOAN_EXECUTOR_RETURN, + BORROW_ALLOWANCE_ARE_NOT_ENOUGH, } = ProtocolErrors; before(async () => { @@ -51,6 +49,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { [weth.address], [ethers.utils.parseEther('0.8')], 0, + _mockFlashLoanReceiver.address, '0x10', '0' ); @@ -80,6 +79,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { [weth.address], ['1000720000000000000'], 0, + _mockFlashLoanReceiver.address, '0x10', '0' ); @@ -111,6 +111,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { [weth.address], [ethers.utils.parseEther('0.8')], 0, + caller.address, '0x10', '0' ) @@ -131,6 +132,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { [weth.address], [ethers.utils.parseEther('0.8')], 0, + caller.address, '0x10', '0' ) @@ -151,6 +153,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { [weth.address], [ethers.utils.parseEther('0.8')], 4, + caller.address, '0x10', '0' ) @@ -179,6 +182,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { [weth.address], [ethers.utils.parseEther('0.8')], 2, + caller.address, '0x10', '0' ); @@ -197,14 +201,16 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { }); it('tries to take a flashloan that is bigger than the available liquidity (revert expected)', async () => { - const {pool, weth} = testEnv; + const {pool, weth, users} = testEnv; + const caller = users[1]; await expect( - pool.flashLoan( + pool.connect(caller.signer).flashLoan( _mockFlashLoanReceiver.address, [weth.address], ['1004415000000000000'], //slightly higher than the available liquidity 2, + caller.address, '0x10', '0' ), @@ -213,10 +219,11 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { }); it('tries to take a flashloan using a non contract address as receiver (revert expected)', async () => { - const {pool, deployer, weth} = testEnv; + const {pool, deployer, weth, users} = testEnv; + const caller = users[1]; await expect( - pool.flashLoan(deployer.address, [weth.address], ['1000000000000000000'], 2, '0x10', '0') + pool.flashLoan(deployer.address, [weth.address], ['1000000000000000000'], 2, caller.address, '0x10', '0') ).to.be.reverted; }); @@ -245,6 +252,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { [usdc.address], [flashloanAmount], 0, + _mockFlashLoanReceiver.address, '0x10', '0' ); @@ -287,6 +295,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { [usdc.address], [flashloanAmount], 2, + caller.address, '0x10', '0' ) @@ -312,7 +321,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { await pool .connect(caller.signer) - .flashLoan(_mockFlashLoanReceiver.address, [usdc.address], [flashloanAmount], 2, '0x10', '0'); + .flashLoan(_mockFlashLoanReceiver.address, [usdc.address], [flashloanAmount], 2, caller.address, '0x10', '0'); const {variableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses( usdc.address ); @@ -347,7 +356,15 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { await expect( pool .connect(caller.signer) - .flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], 0, '0x10', '0') + .flashLoan( + _mockFlashLoanReceiver.address, + [weth.address], + [flashAmount], + 0, + caller.address, + '0x10', + '0' + ) ).to.be.revertedWith(SAFEERC20_LOWLEVEL_CALL); }); @@ -362,7 +379,15 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { await pool .connect(caller.signer) - .flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], 1, '0x10', '0'); + .flashLoan( + _mockFlashLoanReceiver.address, + [weth.address], + [flashAmount], + 1, + caller.address, + '0x10', + '0' + ); const {stableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(weth.address); @@ -375,4 +400,82 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { expect(callerDebt.toString()).to.be.equal('800000000000000000', 'Invalid user debt'); }); + + it('Caller takes a WETH flashloan with mode = 1 onBehalfOf user without allowance', async () => { + const {dai, pool, weth, users, helpersContract} = testEnv; + + const caller = users[5]; + const onBehalfOf = users[4]; + + // Deposit 1000 dai for onBehalfOf user + await dai.connect(onBehalfOf.signer).mint(await convertToCurrencyDecimals(dai.address, '1000')); + + await dai.connect(onBehalfOf.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); + + const amountToDeposit = await convertToCurrencyDecimals(dai.address, '1000'); + + await pool + .connect(onBehalfOf.signer) + .deposit(dai.address, amountToDeposit, onBehalfOf.address, '0'); + + const flashAmount = ethers.utils.parseEther('0.8'); + + await _mockFlashLoanReceiver.setFailExecutionTransfer(true); + + await expect( + pool + .connect(caller.signer) + .flashLoan( + _mockFlashLoanReceiver.address, + [weth.address], + [flashAmount], + 1, + onBehalfOf.address, + '0x10', + '0' + ) + ).to.be.revertedWith(BORROW_ALLOWANCE_ARE_NOT_ENOUGH); + }); + + it('Caller takes a WETH flashloan with mode = 1 onBehalfOf user with allowance. A loan for onBehalfOf is creatd.', async () => { + const {dai, pool, weth, users, helpersContract} = testEnv; + + const caller = users[5]; + const onBehalfOf = users[4]; + + const flashAmount = ethers.utils.parseEther('0.8'); + + // Deposited for onBehalfOf user already, delegate borrow allowance + await pool + .connect(onBehalfOf.signer) + .delegateBorrowAllowance(weth.address, caller.address, 1, flashAmount); + + await _mockFlashLoanReceiver.setFailExecutionTransfer(true); + + await pool + .connect(caller.signer) + .flashLoan( + _mockFlashLoanReceiver.address, + [weth.address], + [flashAmount], + 1, + onBehalfOf.address, + '0x10', + '0' + ); + + const {stableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(weth.address); + + const wethDebtToken = await getContract( + eContractid.VariableDebtToken, + stableDebtTokenAddress + ); + + const onBehalfOfDebt = await wethDebtToken.balanceOf(onBehalfOf.address); + + expect(onBehalfOfDebt.toString()).to.be.equal( + '800000000000000000', + 'Invalid onBehalfOf user debt' + ); + }); }); diff --git a/test/helpers/actions.ts b/test/helpers/actions.ts index 85d3eb00..422b0455 100644 --- a/test/helpers/actions.ts +++ b/test/helpers/actions.ts @@ -17,11 +17,8 @@ import { } from './utils/calculations'; import {getReserveAddressFromSymbol, getReserveData, getUserData} from './utils/helpers'; -import { - convertToCurrencyDecimals, - getAToken, - getMintableErc20, -} from '../../helpers/contracts-helpers'; +import {convertToCurrencyDecimals} from '../../helpers/contracts-helpers'; +import {getAToken, getMintableErc20} from '../../helpers/contracts-getters'; import {MAX_UINT_AMOUNT, ONE_YEAR} from '../../helpers/constants'; import {SignerWithAddress, TestEnv} from './make-suite'; import {BRE, increaseTime, timeLatest, waitForTx} from '../../helpers/misc-utils'; @@ -31,7 +28,6 @@ import {ReserveData, UserReserveData} from './utils/interfaces'; import {ContractReceipt} from 'ethers'; import {AToken} from '../../types/AToken'; import {RateMode, tEthereumAddress} from '../../helpers/types'; -import {time} from 'console'; const {expect} = chai; diff --git a/test/helpers/make-suite.ts b/test/helpers/make-suite.ts index de9cfb13..5c2cf1ff 100644 --- a/test/helpers/make-suite.ts +++ b/test/helpers/make-suite.ts @@ -1,7 +1,6 @@ import {evmRevert, evmSnapshot, BRE} from '../../helpers/misc-utils'; import {Signer} from 'ethers'; import { - getEthersSigners, getLendingPool, getLendingPoolAddressesProvider, getAaveProtocolTestHelpers, @@ -12,7 +11,7 @@ import { getLendingPoolAddressesProviderRegistry, getUniswapLiquiditySwapAdapter, getUniswapRepayAdapter, -} from '../../helpers/contracts-helpers'; +} from '../../helpers/contracts-getters'; import {tEthereumAddress} from '../../helpers/types'; import {LendingPool} from '../../types/LendingPool'; import {AaveProtocolTestHelpers} from '../../types/AaveProtocolTestHelpers'; @@ -27,6 +26,7 @@ import {almostEqual} from './almost-equal'; import {PriceOracle} from '../../types/PriceOracle'; import {LendingPoolAddressesProvider} from '../../types/LendingPoolAddressesProvider'; import {LendingPoolAddressesProviderRegistry} from '../../types/LendingPoolAddressesProviderRegistry'; +import {getEthersSigners} from '../../helpers/contracts-helpers'; import {UniswapLiquiditySwapAdapter} from '../../types/UniswapLiquiditySwapAdapter'; import {UniswapRepayAdapter} from '../../types/UniswapRepayAdapter'; chai.use(bignumberChai()); @@ -44,7 +44,7 @@ export interface TestEnv { oracle: PriceOracle; helpersContract: AaveProtocolTestHelpers; weth: MintableERC20; - aEth: AToken; + aWETH: AToken; dai: MintableERC20; aDai: AToken; usdc: MintableERC20; @@ -70,7 +70,7 @@ const testEnv: TestEnv = { helpersContract: {} as AaveProtocolTestHelpers, oracle: {} as PriceOracle, weth: {} as MintableERC20, - aEth: {} as AToken, + aWETH: {} as AToken, dai: {} as MintableERC20, aDai: {} as AToken, usdc: {} as MintableERC20, @@ -96,10 +96,8 @@ export async function initializeMakeSuite() { } testEnv.deployer = deployer; testEnv.pool = await getLendingPool(); - console.log('Pool loaded'); testEnv.configurator = await getLendingPoolConfiguratorProxy(); - console.log('Configurator loaded'); testEnv.oracle = await getPriceOracle(); testEnv.addressesProvider = await getLendingPoolAddressesProvider(); @@ -107,13 +105,11 @@ export async function initializeMakeSuite() { testEnv.helpersContract = await getAaveProtocolTestHelpers(); - const aDaiAddress = (await testEnv.helpersContract.getAllATokens()).find( - (aToken) => aToken.symbol === 'aDAI' - )?.tokenAddress; + const allTokens = await testEnv.helpersContract.getAllATokens(); - const aEthAddress = (await testEnv.helpersContract.getAllATokens()).find( - (aToken) => aToken.symbol === 'aETH' - )?.tokenAddress; + const aDaiAddress = allTokens.find((aToken) => aToken.symbol === 'aDAI')?.tokenAddress; + + const aWEthAddress = allTokens.find((aToken) => aToken.symbol === 'aWETH')?.tokenAddress; const reservesTokens = await testEnv.helpersContract.getAllReservesTokens(); @@ -122,7 +118,7 @@ export async function initializeMakeSuite() { const lendAddress = reservesTokens.find((token) => token.symbol === 'LEND')?.tokenAddress; const wethAddress = reservesTokens.find((token) => token.symbol === 'WETH')?.tokenAddress; - if (!aDaiAddress || !aEthAddress) { + if (!aDaiAddress || !aWEthAddress) { console.log(`atoken-modifiers.spec: aTokens not correctly initialized`); process.exit(1); } @@ -132,7 +128,7 @@ export async function initializeMakeSuite() { } testEnv.aDai = await getAToken(aDaiAddress); - testEnv.aEth = await getAToken(aEthAddress); + testEnv.aWETH = await getAToken(aWEthAddress); testEnv.dai = await getMintableErc20(daiAddress); testEnv.usdc = await getMintableErc20(usdcAddress); diff --git a/test/helpers/utils/calculations.ts b/test/helpers/utils/calculations.ts index 7bffad2d..ae787e1d 100644 --- a/test/helpers/utils/calculations.ts +++ b/test/helpers/utils/calculations.ts @@ -5,7 +5,6 @@ import { MAX_UINT_AMOUNT, OPTIMAL_UTILIZATION_RATE, EXCESS_UTILIZATION_RATE, - ZERO_ADDRESS, } from '../../../helpers/constants'; import {IReserveParams, iAavePoolAssets, RateMode, tEthereumAddress} from '../../../helpers/types'; import './math'; diff --git a/test/helpers/utils/helpers.ts b/test/helpers/utils/helpers.ts index d729d327..7a909c20 100644 --- a/test/helpers/utils/helpers.ts +++ b/test/helpers/utils/helpers.ts @@ -7,7 +7,7 @@ import { getAToken, getStableDebtToken, getVariableDebtToken, -} from '../../../helpers/contracts-helpers'; +} from '../../../helpers/contracts-getters'; import {tEthereumAddress} from '../../../helpers/types'; import BigNumber from 'bignumber.js'; import {getDb, BRE} from '../../../helpers/misc-utils'; @@ -27,7 +27,7 @@ export const getReserveData = async ( const stableDebtToken = await getStableDebtToken(tokenAddresses.stableDebtTokenAddress); const variableDebtToken = await getVariableDebtToken(tokenAddresses.variableDebtTokenAddress); - const [principalStableDebt] = await stableDebtToken.getSupplyData(); + const {0: principalStableDebt} = await stableDebtToken.getSupplyData(); const totalStableDebtLastUpdated = await stableDebtToken.getTotalSupplyLastUpdated(); const scaledVariableDebt = await variableDebtToken.scaledTotalSupply(); diff --git a/test/lending-pool-addresses-provider.spec.ts b/test/lending-pool-addresses-provider.spec.ts index ed283c46..4858531a 100644 --- a/test/lending-pool-addresses-provider.spec.ts +++ b/test/lending-pool-addresses-provider.spec.ts @@ -5,7 +5,7 @@ import {ProtocolErrors} from '../helpers/types'; import {ethers} from 'ethers'; import {ZERO_ADDRESS} from '../helpers/constants'; import {waitForTx} from '../helpers/misc-utils'; -import {deployLendingPool} from '../helpers/contracts-helpers'; +import {deployLendingPool} from '../helpers/contracts-deployments'; const {utils} = ethers; diff --git a/test/pausable-functions.spec.ts b/test/pausable-functions.spec.ts index 48c50ee2..7a24da2d 100644 --- a/test/pausable-functions.spec.ts +++ b/test/pausable-functions.spec.ts @@ -1,10 +1,11 @@ import {makeSuite, TestEnv} from './helpers/make-suite'; import {ProtocolErrors, RateMode} from '../helpers/types'; import {APPROVAL_AMOUNT_LENDING_POOL, oneEther} from '../helpers/constants'; -import {convertToCurrencyDecimals, getMockFlashLoanReceiver} from '../helpers/contracts-helpers'; +import {convertToCurrencyDecimals} from '../helpers/contracts-helpers'; import {parseEther, parseUnits} from 'ethers/lib/utils'; import {BigNumber} from 'bignumber.js'; import {MockFlashLoanReceiver} from '../types/MockFlashLoanReceiver'; +import {getMockFlashLoanReceiver} from '../helpers/contracts-getters'; const {expect} = require('chai'); @@ -186,7 +187,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { await expect( pool .connect(caller.signer) - .flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], 1, '0x10', '0') + .flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], 1, caller.address, '0x10', '0') ).revertedWith(IS_PAUSED); // Unpause pool diff --git a/test/pool-modifiers.spec.ts b/test/pool-modifiers.spec.ts index fafd5783..fb915b15 100644 --- a/test/pool-modifiers.spec.ts +++ b/test/pool-modifiers.spec.ts @@ -152,7 +152,7 @@ // }); // it('unfreezes the reserve, user deposits 1 ETH, freezes the reserve, check that the user can redeem', async () => { -// const {aETH} = _aTokenInstances; +// const {aWETH} = _aTokenInstances; // //unfreezes the reserve // await _lendingPoolConfiguratorInstance.unfreezeReserve(ETHEREUM_ADDRESS); @@ -165,13 +165,13 @@ // //freezes the reserve // await _lendingPoolConfiguratorInstance.freezeReserve(ETHEREUM_ADDRESS); -// const balance = await aETH.balanceOf(deployer); +// const balance = await aWETH.balanceOf(deployer); -// await aETH.redeem(balance); +// await aWETH.redeem(balance); // }); // it('unfreezes the reserve, user 0 deposits 100 DAI, user 1 deposits 1 ETH and borrows 50 DAI, freezes the reserve, checks that the user 1 can repay', async () => { -// const {aETH, aDAI} = _aTokenInstances; +// const {aWETH, aDAI} = _aTokenInstances; // const {DAI} = _tokenInstances; // //unfreezes the reserve @@ -209,7 +209,7 @@ // }); // it('Check that liquidationCall can be executed on a freezed reserve', async () => { -// const {aETH, aDAI} = _aTokenInstances; +// const {aWETH, aDAI} = _aTokenInstances; // const {DAI} = _tokenInstances; // //user 2 tries to liquidate @@ -228,7 +228,7 @@ // }); // it('Check that rebalanceStableBorrowRate can be executed on a freezed reserve', async () => { -// const {aETH, aDAI} = _aTokenInstances; +// const {aWETH, aDAI} = _aTokenInstances; // const {DAI} = _tokenInstances; // //user 2 tries to liquidate diff --git a/test/stable-token.spec.ts b/test/stable-token.spec.ts index 422cb352..fea265c6 100644 --- a/test/stable-token.spec.ts +++ b/test/stable-token.spec.ts @@ -34,6 +34,9 @@ makeSuite('Stable debt token tests', (testEnv: TestEnv) => { daiStableDebtTokenAddress ); + const name = await stableDebtContract.name(); + + expect(name).to.be.equal('Aave stable debt bearing DAI'); await expect(stableDebtContract.burn(deployer.address, '1')).to.be.revertedWith( CALLER_MUST_BE_LENDING_POOL ); diff --git a/test/subgraph-scenarios.spec.ts b/test/subgraph-scenarios.spec.ts new file mode 100644 index 00000000..c756ce50 --- /dev/null +++ b/test/subgraph-scenarios.spec.ts @@ -0,0 +1,32 @@ +import {configuration as actionsConfiguration} from './helpers/actions'; +import {configuration as calculationsConfiguration} from './helpers/utils/calculations'; + +import BigNumber from 'bignumber.js'; +import {makeSuite} from './helpers/make-suite'; +import {getReservesConfigByPool} from '../helpers/configuration'; +import {AavePools, iAavePoolAssets, IReserveParams} from '../helpers/types'; +import {executeStory} from './helpers/scenario-engine'; + +makeSuite('Subgraph scenario tests', async (testEnv) => { + let story: any; + let scenario; + before('Initializing configuration', async () => { + const scenario = require(`./helpers/scenarios/borrow-repay-stable`); + story = scenario.stories[0]; + // Sets BigNumber for this suite, instead of globally + BigNumber.config({DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_DOWN}); + + actionsConfiguration.skipIntegrityCheck = false; //set this to true to execute solidity-coverage + + calculationsConfiguration.reservesParams = >( + getReservesConfigByPool(AavePools.proto) + ); + }); + after('Reset', () => { + // Reset BigNumber + BigNumber.config({DECIMAL_PLACES: 20, ROUNDING_MODE: BigNumber.ROUND_HALF_UP}); + }); + it('deposit-borrow', async () => { + await executeStory(story, testEnv); + }); +}); diff --git a/test/upgradeability.spec.ts b/test/upgradeability.spec.ts index 45beb11c..72d818d7 100644 --- a/test/upgradeability.spec.ts +++ b/test/upgradeability.spec.ts @@ -1,16 +1,12 @@ import {expect} from 'chai'; import {makeSuite, TestEnv} from './helpers/make-suite'; import {ProtocolErrors, eContractid} from '../helpers/types'; -import { - deployGenericAToken, - getAToken, - deployContract, - getContract, -} from '../helpers/contracts-helpers'; +import {deployContract, getContract} from '../helpers/contracts-helpers'; import {MockAToken} from '../types/MockAToken'; import {MockStableDebtToken} from '../types/MockStableDebtToken'; import {MockVariableDebtToken} from '../types/MockVariableDebtToken'; import {ZERO_ADDRESS} from '../helpers/constants'; +import {getAToken} from '../helpers/contracts-getters'; makeSuite('Upgradeability', (testEnv: TestEnv) => { const {CALLER_NOT_AAVE_ADMIN} = ProtocolErrors;