Merge branch 'master' into feat/102-batch-delegation-allowance

This commit is contained in:
eboado 2020-10-30 16:04:31 +01:00
commit cba766d282
62 changed files with 8754 additions and 2935 deletions

View File

@ -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 || '';

View File

@ -19,16 +19,11 @@ contract LendingPoolAddressesProvider is Ownable, ILendingPoolAddressesProvider
mapping(bytes32 => address) private _addresses;
bytes32 private constant LENDING_POOL = 'LENDING_POOL';
bytes32 private constant LENDING_POOL_CORE = 'LENDING_POOL_CORE';
bytes32 private constant LENDING_POOL_CONFIGURATOR = 'LENDING_POOL_CONFIGURATOR';
bytes32 private constant AAVE_ADMIN = 'AAVE_ADMIN';
bytes32 private constant LENDING_POOL_COLLATERAL_MANAGER = 'COLLATERAL_MANAGER';
bytes32 private constant LENDING_POOL_FLASHLOAN_PROVIDER = 'FLASHLOAN_PROVIDER';
bytes32 private constant DATA_PROVIDER = 'DATA_PROVIDER';
bytes32 private constant ETHEREUM_ADDRESS = 'ETHEREUM_ADDRESS';
bytes32 private constant PRICE_ORACLE = 'PRICE_ORACLE';
bytes32 private constant LENDING_RATE_ORACLE = 'LENDING_RATE_ORACLE';
bytes32 private constant WALLET_BALANCE_PROVIDER = 'WALLET_BALANCE_PROVIDER';
/**
* @dev Sets an address for an id, allowing to cover it or not with a proxy

View File

@ -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]
);
}
}
}

View File

@ -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);
}
}

View File

@ -12,6 +12,7 @@ interface IFlashLoanReceiver {
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool);
}

View File

@ -27,9 +27,10 @@ interface ILendingPool {
* @dev emitted during a withdraw action.
* @param reserve the address of the reserve
* @param user the address of the user
* @param to address that will receive the underlying
* @param amount the amount to be withdrawn
**/
event Withdraw(address indexed reserve, address indexed user, uint256 amount);
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
event BorrowAllowanceDelegated(
address indexed fromUser,
@ -74,7 +75,7 @@ interface ILendingPool {
* @param reserve the address of the reserve
* @param user the address of the user executing the swap
**/
event Swap(address indexed reserve, address indexed user);
event Swap(address indexed reserve, address indexed user, uint256 rateMode);
/**
* @dev emitted when a user enables a reserve as collateral
@ -99,17 +100,18 @@ interface ILendingPool {
/**
* @dev emitted when a flashloan is executed
* @param target the address of the flashLoanReceiver
* @param assets the address of the assets being flashborrowed
* @param amounts the amount requested
* @param premiums the total fee on the amount
* @param initiator the address initiating the flash loan
* @param asset the address of the asset being flashborrowed
* @param amount the amount requested
* @param premium the total fee on the amount
* @param referralCode the referral code of the caller
**/
event FlashLoan(
address indexed target,
uint256 mode,
address[] assets,
uint256[] amounts,
uint256[] premiums,
address indexed initiator,
address indexed asset,
uint256 amount,
uint256 premium,
uint16 referralCode
);
@ -185,8 +187,13 @@ interface ILendingPool {
* @dev withdraws the assets of user.
* @param reserve the address of the reserve
* @param amount the underlying amount to be redeemed
* @param to address that will receive the underlying
**/
function withdraw(address reserve, uint256 amount) external;
function withdraw(
address reserve,
uint256 amount,
address to
) external;
/**
* @dev Sets allowance to borrow on a certain type of debt assets for a certain user address
@ -286,7 +293,7 @@ interface ILendingPool {
* @param receiver The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
* @param assets the address of the principal reserve
* @param amounts the amount requested for this flashloan
* @param mode the flashloan mode
* @param modes the flashloan borrow modes
* @param params a bytes array to be sent to the flashloan executor
* @param referralCode the referral code of the caller
**/
@ -294,7 +301,8 @@ interface ILendingPool {
address receiver,
address[] calldata assets,
uint256[] calldata amounts,
uint256 mode,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
@ -349,11 +357,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);

View File

@ -1,20 +0,0 @@
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
interface ISwapAdapter {
/**
* @dev Swaps an `amountToSwap` of an asset to another, approving a `fundsDestination` to pull the funds
* @param assetToSwapFrom Origin asset
* @param assetToSwapTo Destination asset
* @param amountToSwap How much `assetToSwapFrom` needs to be swapped
* @param fundsDestination Address that will be pulling the swapped funds
* @param params Additional variadic field to include extra params
*/
function executeOperation(
address assetToSwapFrom,
address assetToSwapTo,
uint256 amountToSwap,
address fundsDestination,
bytes calldata params
) external;
}

View File

@ -20,7 +20,6 @@ import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol'
import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol';
import {DebtTokenBase} from '../tokenization/base/DebtTokenBase.sol';
import {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol';
import {ISwapAdapter} from '../interfaces/ISwapAdapter.sol';
import {LendingPoolCollateralManager} from './LendingPoolCollateralManager.sol';
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol';
@ -120,8 +119,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @dev withdraws the _reserves of user.
* @param asset the address of the reserve
* @param amount the underlying amount to be redeemed
* @param to address that will receive the underlying
**/
function withdraw(address asset, uint256 amount) external override {
function withdraw(
address asset,
uint256 amount,
address to
) external override {
_whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
@ -155,9 +159,9 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, false);
}
IAToken(aToken).burn(msg.sender, msg.sender, amountToWithdraw, reserve.liquidityIndex);
IAToken(aToken).burn(msg.sender, to, amountToWithdraw, reserve.liquidityIndex);
emit Withdraw(asset, msg.sender, amountToWithdraw);
emit Withdraw(asset, msg.sender, to, amountToWithdraw);
}
/**
@ -361,7 +365,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0);
emit Swap(asset, msg.sender);
emit Swap(asset, msg.sender, rateMode);
}
/**
@ -495,13 +499,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
struct FlashLoanLocalVars {
IFlashLoanReceiver receiver;
address oracle;
ReserveLogic.InterestRateMode debtMode;
uint256 i;
address currentAsset;
address currentATokenAddress;
uint256 currentAmount;
uint256 currentPremium;
uint256 currentAmountPlusPremium;
address debtToken;
}
/**
@ -511,7 +515,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param receiverAddress The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
* @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 modes Types 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
**/
@ -519,7 +524,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256 mode,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external override {
@ -527,13 +533,12 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
FlashLoanLocalVars memory vars;
ValidationLogic.validateFlashloan(assets, amounts, mode);
ValidationLogic.validateFlashloan(assets, amounts);
address[] memory aTokenAddresses = new address[](assets.length);
uint256[] memory premiums = new uint256[](assets.length);
vars.receiver = IFlashLoanReceiver(receiverAddress);
vars.debtMode = ReserveLogic.InterestRateMode(mode);
for (vars.i = 0; vars.i < assets.length; vars.i++) {
aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress;
@ -546,7 +551,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
//execute action of the receiver
require(
vars.receiver.executeOperation(assets, amounts, premiums, params),
vars.receiver.executeOperation(assets, amounts, premiums, msg.sender, params),
Errors.INVALID_FLASH_LOAN_EXECUTOR_RETURN
);
@ -555,10 +560,9 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
vars.currentAmount = amounts[vars.i];
vars.currentPremium = premiums[vars.i];
vars.currentATokenAddress = aTokenAddresses[vars.i];
vars.currentAmountPlusPremium = vars.currentAmount.add(vars.currentPremium);
if (vars.debtMode == ReserveLogic.InterestRateMode.NONE) {
if (ReserveLogic.InterestRateMode(modes[vars.i]) == ReserveLogic.InterestRateMode.NONE) {
_reserves[vars.currentAsset].updateState();
_reserves[vars.currentAsset].cumulateToLiquidityIndex(
IERC20(vars.currentATokenAddress).totalSupply(),
@ -577,22 +581,37 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
vars.currentAmountPlusPremium
);
} else {
if (msg.sender != onBehalfOf) {
vars.debtToken = _reserves[vars.currentAsset].getDebtTokenAddress(modes[vars.i]);
_borrowAllowance[vars.debtToken][onBehalfOf][msg.sender] = _borrowAllowance[vars
.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,
modes[vars.i],
vars.currentATokenAddress,
referralCode,
false
)
);
}
emit FlashLoan(receiverAddress, mode, assets, amounts, premiums, referralCode);
emit FlashLoan(
receiverAddress,
msg.sender,
vars.currentAsset,
vars.currentAmount,
vars.currentPremium,
referralCode
);
}
}
@ -688,7 +707,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param asset the address of the reserve
* @return the reserve normalized income
*/
function getReserveNormalizedIncome(address asset) external override view returns (uint256) {
function getReserveNormalizedIncome(address asset)
external
virtual
override
view
returns (uint256)
{
return _reserves[asset].getNormalizedIncome();
}
@ -733,29 +758,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);
}
}
}
/**
@ -853,6 +897,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
);
ValidationLogic.validateBorrow(
vars.asset,
reserve,
vars.onBehalfOf,
vars.amount,
@ -866,34 +911,34 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
oracle
);
uint256 reserveId = reserve.id;
if (!userConfig.isBorrowing(reserveId)) {
userConfig.setBorrowing(reserveId, true);
}
reserve.updateState();
//caching the current stable borrow rate
uint256 currentStableRate = 0;
bool isFirstBorrowing = false;
if (
ReserveLogic.InterestRateMode(vars.interestRateMode) == ReserveLogic.InterestRateMode.STABLE
) {
currentStableRate = reserve.currentStableBorrowRate;
IStableDebtToken(reserve.stableDebtTokenAddress).mint(
isFirstBorrowing = IStableDebtToken(reserve.stableDebtTokenAddress).mint(
vars.onBehalfOf,
vars.amount,
currentStableRate
);
} else {
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
isFirstBorrowing = IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
vars.onBehalfOf,
vars.amount,
reserve.variableBorrowIndex
);
}
if (isFirstBorrowing) {
userConfig.setBorrowing(reserve.id, true);
}
reserve.updateInterestRates(
vars.asset,
vars.aTokenAddress,

View File

@ -15,7 +15,6 @@ import {Helpers} from '../libraries/helpers/Helpers.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol';
import {ISwapAdapter} from '../interfaces/ISwapAdapter.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
import {LendingPoolStorage} from './LendingPoolStorage.sol';

View File

@ -47,7 +47,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
* @param asset the address of the reserve
* @param stableRateEnabled true if stable rate borrowing is enabled, false otherwise
**/
event BorrowingEnabledOnReserve(address asset, bool stableRateEnabled);
event BorrowingEnabledOnReserve(address indexed asset, bool stableRateEnabled);
/**
* @dev emitted when borrowing is disabled on a reserve
@ -116,42 +116,42 @@ contract LendingPoolConfigurator is VersionedInitializable {
* @param asset the address of the reserve
* @param ltv the new value for the loan to value
**/
event ReserveBaseLtvChanged(address asset, uint256 ltv);
event ReserveBaseLtvChanged(address indexed asset, uint256 ltv);
/**
* @dev emitted when a reserve factor is updated
* @param asset the address of the reserve
* @param factor the new reserve factor
**/
event ReserveFactorChanged(address asset, uint256 factor);
event ReserveFactorChanged(address indexed asset, uint256 factor);
/**
* @dev emitted when a reserve liquidation threshold is updated
* @param asset the address of the reserve
* @param threshold the new value for the liquidation threshold
**/
event ReserveLiquidationThresholdChanged(address asset, uint256 threshold);
event ReserveLiquidationThresholdChanged(address indexed asset, uint256 threshold);
/**
* @dev emitted when a reserve liquidation bonus is updated
* @param asset the address of the reserve
* @param bonus the new value for the liquidation bonus
**/
event ReserveLiquidationBonusChanged(address asset, uint256 bonus);
event ReserveLiquidationBonusChanged(address indexed asset, uint256 bonus);
/**
* @dev emitted when the reserve decimals are updated
* @param asset the address of the reserve
* @param decimals the new decimals
**/
event ReserveDecimalsChanged(address asset, uint256 decimals);
event ReserveDecimalsChanged(address indexed asset, uint256 decimals);
/**
* @dev emitted when a reserve interest strategy contract is updated
* @param asset the address of the reserve
* @param strategy the new address of the interest strategy contract
**/
event ReserveInterestRateStrategyChanged(address asset, address strategy);
event ReserveInterestRateStrategyChanged(address indexed asset, address strategy);
/**
* @dev emitted when an aToken implementation is upgraded
@ -159,7 +159,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
* @param proxy the aToken proxy address
* @param implementation the new aToken implementation
**/
event ATokenUpgraded(address asset, address proxy, address implementation);
event ATokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
/**
* @dev emitted when the implementation of a stable debt token is upgraded
@ -167,7 +171,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
* @param proxy the stable debt token proxy address
* @param implementation the new aToken implementation
**/
event StableDebtTokenUpgraded(address asset, address proxy, address implementation);
event StableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
/**
* @dev emitted when the implementation of a variable debt token is upgraded
@ -175,7 +183,11 @@ contract LendingPoolConfigurator is VersionedInitializable {
* @param proxy the variable debt token proxy address
* @param implementation the new aToken implementation
**/
event VariableDebtTokenUpgraded(address asset, address proxy, address implementation);
event VariableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
ILendingPoolAddressesProvider internal addressesProvider;
ILendingPool internal pool;

View File

@ -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'
@ -100,7 +101,6 @@ library Errors {
// Credit delegation
string public constant INCONSISTENT_PARAMS_LENGTH = '75';
enum CollateralManagerErrors {
NO_ERROR,
NO_COLLATERAL_AVAILABLE,

View File

@ -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));
}
}

View File

@ -33,7 +33,7 @@ library ValidationLogic {
* @param reserve the reserve state on which the user is depositing
* @param amount the amount to be deposited
*/
function validateDeposit(ReserveLogic.ReserveData storage reserve, uint256 amount) internal view {
function validateDeposit(ReserveLogic.ReserveData storage reserve, uint256 amount) external view {
(bool isActive, bool isFreezed, , ) = reserve.configuration.getFlags();
require(amount > 0, Errors.AMOUNT_NOT_GREATER_THAN_0);
@ -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,
@ -56,7 +61,7 @@ library ValidationLogic {
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) internal view {
) external view {
require(amount > 0, Errors.AMOUNT_NOT_GREATER_THAN_0);
require(amount <= userBalance, Errors.NOT_ENOUGH_AVAILABLE_USER_BALANCE);
@ -99,6 +104,7 @@ library ValidationLogic {
/**
* @dev validates a borrow.
* @param asset the address of the asset to borrow
* @param reserve the reserve state from which the user is borrowing
* @param userAddress the address of the user
* @param amount the amount to be borrowed
@ -112,6 +118,7 @@ library ValidationLogic {
*/
function validateBorrow(
address asset,
ReserveLogic.ReserveData storage reserve,
address userAddress,
uint256 amount,
@ -198,6 +205,8 @@ library ValidationLogic {
Errors.CALLATERAL_SAME_AS_BORROWING_CURRENCY
);
vars.availableLiquidity = IERC20(asset).balanceOf(reserve.aTokenAddress);
//calculate the max available loan size in stable rate mode as a percentage of the
//available liquidity
uint256 maxLoanSizeStable = vars.availableLiquidity.percentMul(maxStableLoanPercent);
@ -246,15 +255,15 @@ library ValidationLogic {
* @dev validates a swap of borrow rate mode.
* @param reserve the reserve state on which the user is swapping the rate
* @param userConfig the user reserves configuration
* @param stableBorrowBalance the stable borrow balance of the user
* @param variableBorrowBalance the stable borrow balance of the user
* @param stableDebt the stable debt of the user
* @param variableDebt the variable debt of the user
* @param currentRateMode the rate mode of the borrow
*/
function validateSwapRateMode(
ReserveLogic.ReserveData storage reserve,
UserConfiguration.Map storage userConfig,
uint256 stableBorrowBalance,
uint256 variableBorrowBalance,
uint256 stableDebt,
uint256 variableDebt,
ReserveLogic.InterestRateMode currentRateMode
) external view {
(bool isActive, bool isFreezed, , bool stableRateEnabled) = reserve.configuration.getFlags();
@ -263,9 +272,9 @@ library ValidationLogic {
require(!isFreezed, Errors.NO_UNFREEZED_RESERVE);
if (currentRateMode == ReserveLogic.InterestRateMode.STABLE) {
require(stableBorrowBalance > 0, Errors.NO_STABLE_RATE_LOAN_IN_RESERVE);
require(stableDebt > 0, Errors.NO_STABLE_RATE_LOAN_IN_RESERVE);
} else if (currentRateMode == ReserveLogic.InterestRateMode.VARIABLE) {
require(variableBorrowBalance > 0, Errors.NO_VARIABLE_RATE_LOAN_IN_RESERVE);
require(variableDebt > 0, Errors.NO_VARIABLE_RATE_LOAN_IN_RESERVE);
/**
* user wants to swap to stable, before swapping we need to ensure that
* 1. stable borrow rate is enabled on the reserve
@ -278,8 +287,7 @@ library ValidationLogic {
require(
!userConfig.isUsingAsCollateral(reserve.id) ||
reserve.configuration.getLtv() == 0 ||
stableBorrowBalance.add(variableBorrowBalance) >
IERC20(reserve.aTokenAddress).balanceOf(msg.sender),
stableDebt.add(variableDebt) > IERC20(reserve.aTokenAddress).balanceOf(msg.sender),
Errors.CALLATERAL_SAME_AS_BORROWING_CURRENCY
);
} else {
@ -326,16 +334,10 @@ library ValidationLogic {
/**
* @dev validates a flashloan action
* @param mode the flashloan mode (0 = classic flashloan, 1 = open a stable rate loan, 2 = open a variable rate loan)
* @param assets the assets being flashborrowed
* @param amounts the amounts for each asset being borrowed
**/
function validateFlashloan(
address[] memory assets,
uint256[] memory amounts,
uint256 mode
) internal pure {
require(mode <= uint256(ReserveLogic.InterestRateMode.VARIABLE), Errors.INVALID_FLASHLOAN_MODE);
function validateFlashloan(address[] memory assets, uint256[] memory amounts) internal pure {
require(assets.length == amounts.length, Errors.INCONSISTENT_FLASHLOAN_PARAMS);
}
@ -389,4 +391,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
);
}
}

View File

@ -26,7 +26,10 @@ library PercentageMath {
return 0;
}
require(value <= (type(uint256).max - HALF_PERCENT)/percentage, Errors.MULTIPLICATION_OVERFLOW);
require(
value <= (type(uint256).max - HALF_PERCENT) / percentage,
Errors.MULTIPLICATION_OVERFLOW
);
return (value * percentage + HALF_PERCENT) / PERCENTAGE_FACTOR;
}
@ -41,7 +44,10 @@ library PercentageMath {
require(percentage != 0, Errors.DIVISION_BY_ZERO);
uint256 halfPercentage = percentage / 2;
require(value <= (type(uint256).max - halfPercentage)/PERCENTAGE_FACTOR, Errors.MULTIPLICATION_OVERFLOW);
require(
value <= (type(uint256).max - halfPercentage) / PERCENTAGE_FACTOR,
Errors.MULTIPLICATION_OVERFLOW
);
return (value * PERCENTAGE_FACTOR + halfPercentage) / percentage;
}

View File

@ -58,7 +58,7 @@ library WadRayMath {
return 0;
}
require(a <= (type(uint256).max-halfWAD)/b, Errors.MULTIPLICATION_OVERFLOW);
require(a <= (type(uint256).max - halfWAD) / b, Errors.MULTIPLICATION_OVERFLOW);
return (a * b + halfWAD) / WAD;
}
@ -73,7 +73,7 @@ library WadRayMath {
require(b != 0, Errors.DIVISION_BY_ZERO);
uint256 halfB = b / 2;
require(a <= (type(uint256).max-halfB)/WAD, Errors.MULTIPLICATION_OVERFLOW);
require(a <= (type(uint256).max - halfB) / WAD, Errors.MULTIPLICATION_OVERFLOW);
return (a * WAD + halfB) / b;
}
@ -89,10 +89,9 @@ library WadRayMath {
return 0;
}
require(a <= (type(uint256).max-halfRAY)/b, Errors.MULTIPLICATION_OVERFLOW);
require(a <= (type(uint256).max - halfRAY) / b, Errors.MULTIPLICATION_OVERFLOW);
return (a * b + halfRAY) / RAY;
}
/**
@ -105,7 +104,7 @@ library WadRayMath {
require(b != 0, Errors.DIVISION_BY_ZERO);
uint256 halfB = b / 2;
require(a <= (type(uint256).max-halfB)/RAY, Errors.MULTIPLICATION_OVERFLOW);
require(a <= (type(uint256).max - halfB) / RAY, Errors.MULTIPLICATION_OVERFLOW);
return (a * RAY + halfB) / b;
}

View File

@ -47,9 +47,11 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase {
address[] memory assets,
uint256[] memory amounts,
uint256[] memory premiums,
address initiator,
bytes memory params
) public override returns (bool) {
params;
initiator;
if (_failExecution) {
emit ExecutedWithFail(assets, amounts, premiums);

View File

@ -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);
}

View File

@ -97,7 +97,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
address user,
uint256 amount,
uint256 rate
) external override onlyLendingPool {
) external override onlyLendingPool returns (bool) {
MintLocalVars memory vars;
//cumulates the user debt
@ -148,6 +148,8 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
vars.newStableRate,
vars.currentAvgStableRate
);
return currentBalance == 0;
}
/**
@ -286,7 +288,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
* @param avgRate the average rate at which calculate the total supply
* @return The debt balance of the user since the last burn/mint action
**/
function _calcTotalSupply(uint256 avgRate) internal view returns (uint256) {
function _calcTotalSupply(uint256 avgRate) internal virtual view returns (uint256) {
uint256 principalSupply = super.totalSupply();
if (principalSupply == 0) {

View File

@ -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

View File

@ -62,7 +62,7 @@ interface IStableDebtToken {
address user,
uint256 amount,
uint256 rate
) external;
) external returns (bool);
/**
* @dev burns debt of the target user.

View File

@ -3,605 +3,30 @@
"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"
}
},
"FeeProvider": {
"buidlerevm": {
"address": "0xFAe0fd738dAbc8a0426F47437322b6d026A9FD95",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"localhost": {
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
}
},
"LendingPoolParametersProvider": {
"buidlerevm": {
"address": "0x2C4603396dE2F08642354A3A102760827FfFe113"
}
},
"LendingPoolCore": {
"buidlerevm": {
"address": "0xA10958a24032283FbE2D23cedf264d6eC9411CBA"
}
},
"LendingPoolConfigurator": {
"buidlerevm": {
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
},
"localhost": {
"address": "0xaca5aCeB6f44845d07Fd339a51F0bd52Bb3D8D1A",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"coverage": {
"address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"kovan": {
"address": "0x0EDc241FdA0dF39EB1B9eB1236217BBe72Ab911D",
"deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F"
}
},
"LendingPoolDataProvider": {
"buidlerevm": {
"address": "0x612719Ace03A8281188d61612A9f40D1da3ca420"
}
},
"LendingPool": {
"buidlerevm": {
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
},
"localhost": {
"address": "0x987223924D2DD6c6efB601756850f3886ECbceF6"
},
"coverage": {
"address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
},
"kovan": {
"address": "0xfF28b837352d9531bAb6dFF3650D7831192117F7",
"deployer": "0x85e4A467343c0dc4aDAB74Af84448D9c45D8ae6F"
}
},
"PriceOracle": {
"buidlerevm": {
"address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"localhost": {
"address": "0x9bD0Bec44106D8Ea8fFb6296d7A84742a290E064",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"MockAggregator": {
"buidlerevm": {
"address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"localhost": {
"address": "0xC452C5244F701108B4e8E8BCe693160046b30332",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"coverage": {
"address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"ChainlinkProxyPriceProvider": {
"buidlerevm": {
"address": "0x7B6C3e5486D9e6959441ab554A889099eed76290",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"kovan": {
"address": "0x293f5BcC66762c28a5d3Bd8512a799D457F5296D",
"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"
},
"coverage": {
"address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"kovan": {
"address": "0xf303Ae6F24C29D94E367fdb5C7aE04D32BEbF13E",
"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": "0x2A7BE996B8801ED21f2f45148791D402811A2106",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"coverage": {
"address": "0xEBAB67ee3ef604D5c250A53b4b8fcbBC6ec3007C",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"WalletBalanceProvider": {
"buidlerevm": {
"address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"coverage": {
"address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
},
"localhost": {
"address": "0x48FAde2E719B770E1783d03466dAEe98b5183538"
}
},
"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",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"USDC": {
"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",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"AToken": {
"buidlerevm": {
"address": "0x5f7134cd38C826a7649f9Cc47dda24d834DD2967",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"localhost": {
"address": "0x7436d6adaA697413F00cb63E1A2A854bF2Aec5A1",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"coverage": {
"address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"AaveProtocolTestHelpers": {
"buidlerevm": {
"address": "0xe7536f450378748E1BD4645D3c77ec38e0F3ba28"
}
},
"StableDebtToken": {
"buidlerevm": {
"address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"localhost": {
"address": "0xbF538F34cb100bAeEE55aa1F036D33F03b03d900",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"coverage": {
"address": "0x392E5355a0e88Bd394F717227c752670fb3a8020",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"VariableDebtToken": {
"buidlerevm": {
"address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"localhost": {
"address": "0xff1B1B810F5DCe853a9b1819DE220D532D1CFeF2",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
},
"coverage": {
"address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"MockFlashRepayAdapter": {
"buidlerevm": {
"address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10"
}
},
"MockFlashLiquiditySwapAdapter": {
"buidlerevm": {
"address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
}
},
"WETH": {
@ -610,21 +35,234 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"USDC": {
"buidlerevm": {
"address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"USDT": {
"buidlerevm": {
"address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"SUSD": {
"buidlerevm": {
"address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"ZRX": {
"buidlerevm": {
"address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"MKR": {
"buidlerevm": {
"address": "0xc4905364b78a742ccce7B890A89514061E47068D",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"WBTC": {
"buidlerevm": {
"address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"LINK": {
"buidlerevm": {
"address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"KNC": {
"buidlerevm": {
"address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"MANA": {
"buidlerevm": {
"address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"REP": {
"buidlerevm": {
"address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"SNX": {
"buidlerevm": {
"address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"BUSD": {
"buidlerevm": {
"address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"USD": {
"buidlerevm": {
"address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"UNI_DAI_ETH": {
"buidlerevm": {
"address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"UNI_USDC_ETH": {
"buidlerevm": {
"address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"UNI_SETH_ETH": {
"buidlerevm": {
"address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"UNI_LINK_ETH": {
"buidlerevm": {
"address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"UNI_MKR_ETH": {
"buidlerevm": {
"address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"UNI_LEND_ETH": {
"buidlerevm": {
"address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"LendingPoolAddressesProvider": {
"buidlerevm": {
"address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"LendingPoolAddressesProviderRegistry": {
"buidlerevm": {
"address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"ReserveLogic": {
"buidlerevm": {
"address": "0x78Ee8Fb9fE5abD5e347Fc94c2fb85596d1f60e3c",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"GenericLogic": {
"buidlerevm": {
"address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"ValidationLogic": {
"buidlerevm": {
"address": "0xA4765Ff72A9F3CfE73089bb2c3a41B838DF71574",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"LendingPool": {
"buidlerevm": {
"address": "0x35c1419Da7cf0Ff885B8Ef8EA9242FEF6800c99b",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"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": "0xf4830d6b1D70C8595d3BD8A63f9ed9F636DB9ef2"
}
},
"LendingPoolCollateralManager": {
"buidlerevm": {
"address": "0x8D0206fEBEB380486729b64bB4cfEDC5b354a6D6",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"MockFlashLoanReceiver": {
"buidlerevm": {
"address": "0xfC88832bac6AbdF216BC5A67be68E9DE94aD5ba2"
}
},
"WalletBalanceProvider": {
"buidlerevm": {
"address": "0x1256eBA4d0a7A38D10BaF4F61775ba491Ce7EE25",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"MockAToken": {
"buidlerevm": {
"address": "0x3bDA11B584dDff7F66E0cFe1da1562c92B45db60",
"address": "0x77B0b5636fEA30eA79BB65AeCCdb599997A849A8",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"MockStableDebtToken": {
"buidlerevm": {
"address": "0x392E5355a0e88Bd394F717227c752670fb3a8020",
"address": "0x78Ee8Fb9fE5abD5e347Fc94c2fb85596d1f60e3c",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
},
"MockVariableDebtToken": {
"buidlerevm": {
"address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460",
"address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}
}

View File

@ -0,0 +1,375 @@
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<LendingPoolLibraryAddresses> => {
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,
};
};
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<MintableERC20> =>
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 = (<any>protoConfigData)[tokenSymbol];
if (!configData) {
configData = (<any>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<IReserveParams>].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
);

View File

@ -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<Promise<MockTokenMap>>(
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<Promise<MockTokenMap>>(
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()
);

View File

@ -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,47 +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 {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;
@ -105,456 +73,26 @@ export const deployContract = async <ContractType extends Contract>(
return contract;
};
export const withSaveAndVerify = async <ContractType extends Contract>(
instance: ContractType,
id: string,
args: (string | string[])[],
verify?: boolean
): Promise<ContractType> => {
await waitForTx(instance.deployTransaction);
await registerContractInJsonDb(id, instance);
if (verify) {
await verifyContract(id, instance.address, args);
}
return instance;
};
export const getContract = async <ContractType extends Contract>(
contractName: string,
address: string
): Promise<ContractType> => (await BRE.ethers.getContractAt(contractName, address)) as ContractType;
export const deployLendingPoolAddressesProvider = async (verify?: boolean) => {
const instance = await deployContract<LendingPoolAddressesProvider>(
eContractid.LendingPoolAddressesProvider,
[]
);
if (verify) {
await verifyContract(eContractid.LendingPoolAddressesProvider, instance.address, []);
}
return instance;
};
export const deployLendingPoolAddressesProviderRegistry = async (verify?: boolean) => {
const instance = await deployContract<LendingPoolAddressesProviderRegistry>(
eContractid.LendingPoolAddressesProviderRegistry,
[]
);
if (verify) {
await verifyContract(eContractid.LendingPoolAddressesProviderRegistry, instance.address, []);
}
return instance;
};
export const deployLendingPoolConfigurator = async (verify?: boolean) => {
const instance = await deployContract<LendingPoolConfigurator>(
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<PriceOracle>(eContractid.PriceOracle, []);
if (verify) {
await verifyContract(eContractid.PriceOracle, instance.address, []);
}
return instance;
};
export const deployLendingRateOracle = async (verify?: boolean) => {
const instance = await deployContract<LendingRateOracle>(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<MockAggregator>(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<MockAggregator>(
eContractid.ChainlinkProxyPriceProvider,
args
);
if (verify) {
await verifyContract(eContractid.MockAggregator, instance.address, args);
}
return instance;
};
export const getChainlingProxyPriceProvider = async (address?: tEthereumAddress) =>
await getContract<MockAggregator>(
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<InitializableAdminUpgradeabilityProxy>(
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<MockFlashLoanReceiver>(
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<WalletBalanceProvider>(
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<AaveProtocolTestHelpers>(
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<MintableERC20>(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<DefaultReserveInterestRateStrategy>(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<StableDebtToken>(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<VariableDebtToken>(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<AToken>(id, args);
if (verify) {
await verifyContract(id, instance.address, args);
}
return instance;
};
export const getLendingPoolAddressesProvider = async (address?: tEthereumAddress) => {
return await getContract<LendingPoolAddressesProvider>(
eContractid.LendingPoolAddressesProvider,
address ||
(await getDb().get(`${eContractid.LendingPoolAddressesProvider}.${BRE.network.name}`).value())
.address
);
};
export const getLendingPoolConfiguratorProxy = async (address?: tEthereumAddress) => {
return await getContract<LendingPoolConfigurator>(
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 <LendingPool>(
await factory.attach(
address ||
(await getDb().get(`${eContractid.LendingPool}.${BRE.network.name}`).value()).address
)
);
};
export const getPriceOracle = async (address?: tEthereumAddress) => {
return await getContract<PriceOracle>(
eContractid.PriceOracle,
address || (await getDb().get(`${eContractid.PriceOracle}.${BRE.network.name}`).value()).address
);
};
export const getAToken = async (address?: tEthereumAddress) => {
return await getContract<AToken>(
eContractid.AToken,
address || (await getDb().get(`${eContractid.AToken}.${BRE.network.name}`).value()).address
);
};
export const getStableDebtToken = async (address?: tEthereumAddress) => {
return await getContract<AToken>(
eContractid.StableDebtToken,
address ||
(await getDb().get(`${eContractid.StableDebtToken}.${BRE.network.name}`).value()).address
);
};
export const getVariableDebtToken = async (address?: tEthereumAddress) => {
return await getContract<AToken>(
eContractid.VariableDebtToken,
address ||
(await getDb().get(`${eContractid.VariableDebtToken}.${BRE.network.name}`).value()).address
);
};
export const getMintableErc20 = async (address: tEthereumAddress) => {
return await getContract<MintableERC20>(
eContractid.MintableERC20,
address ||
(await getDb().get(`${eContractid.MintableERC20}.${BRE.network.name}`).value()).address
);
};
export const getIErc20Detailed = async (address: tEthereumAddress) => {
return await getContract<Ierc20Detailed>(
eContractid.IERC20Detailed,
address ||
(await getDb().get(`${eContractid.IERC20Detailed}.${BRE.network.name}`).value()).address
);
};
export const getAaveProtocolTestHelpers = async (address?: tEthereumAddress) => {
return await getContract<AaveProtocolTestHelpers>(
eContractid.AaveProtocolTestHelpers,
address ||
(await getDb().get(`${eContractid.AaveProtocolTestHelpers}.${BRE.network.name}`).value())
.address
);
};
export const getInterestRateStrategy = async (address?: tEthereumAddress) => {
return await getContract<DefaultReserveInterestRateStrategy>(
eContractid.DefaultReserveInterestRateStrategy,
address ||
(
await getDb()
.get(`${eContractid.DefaultReserveInterestRateStrategy}.${BRE.network.name}`)
.value()
).address
);
};
export const getMockFlashLoanReceiver = async (address?: tEthereumAddress) => {
return await getContract<MockFlashLoanReceiver>(
eContractid.MockFlashLoanReceiver,
address ||
(await getDb().get(`${eContractid.MockFlashLoanReceiver}.${BRE.network.name}`).value())
.address
);
};
export const getLendingRateOracle = async (address?: tEthereumAddress) => {
return await getContract<LendingRateOracle>(
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)) {
@ -623,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 = (<any>protoConfigData)[tokenSymbol];
if (!configData) {
configData = (<any>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<IReserveParams>].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<Promise<MockTokenMap>>(
async (acc, tokenSymbol) => {
const accumulator = await acc;
const address = db.get(`${tokenSymbol.toUpperCase()}.${BRE.network.name}`).value().address;
accumulator[tokenSymbol] = await getContract<MintableERC20>(
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<Promise<MockTokenMap>>(
async (acc, tokenSymbol) => {
const accumulator = await acc;
const address = db.get(`${tokenSymbol.toUpperCase()}.${BRE.network.name}`).value().address;
accumulator[tokenSymbol] = await getContract<MintableERC20>(
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<IReserveParams>,
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<LendingPoolAddressesProviderRegistry>(
eContractid.LendingPoolAddressesProviderRegistry,
address ||
(
await getDb()
.get(`${eContractid.LendingPoolAddressesProviderRegistry}.${BRE.network.name}`)
.value()
).address
);
};
export const buildPermitParams = (
chainId: number,
token: tEthereumAddress,

View File

@ -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<IReserveParams>,
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<IReserveParams>,
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<IReserveParams>,
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));
}
};

View File

@ -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 = <T>(arr: Array<T>, chunkSize: number): Array<Array<T>> => {
return arr.reduce(
(prevVal: any, currVal: any, currIndx: number, array: Array<T>) =>
!(currIndx % chunkSize)
? prevVal.concat([array.slice(currIndx, currIndx + chunkSize)])
: prevVal,
[]
);
};

View File

@ -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<IMarketRates>,
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 (

View File

@ -55,6 +55,8 @@ export enum eContractid {
VariableDebtToken = 'VariableDebtToken',
FeeProvider = 'FeeProvider',
TokenDistributor = 'TokenDistributor',
StableAndVariableTokensHelper = 'StableAndVariableTokensHelper',
ATokensAndRatesHelper = 'ATokensAndRatesHelper',
}
export enum ProtocolErrors {
@ -89,6 +91,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

7327
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
"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",
@ -37,8 +37,10 @@
"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",

1
runStableTokenCLI.sh Normal file
View File

@ -0,0 +1 @@
certoraRun specs/harness/StableDebtTokenHarness.sol:StableDebtTokenHarness --solc solc6.8 --verify StableDebtTokenHarness:specs/StableDebtToken.spec --settings -assumeUnwindCond --cache StableDebtToken --staging master

1
runUserConfigCLI.sh Normal file
View File

@ -0,0 +1 @@
certoraRun specs/harness/UserConfigurationHarness.sol --solc solc6.8 --verify UserConfigurationHarness:specs/UserConfiguration.spec --settings -useBitVectorTheory --staging master

1
runVariableTokenCLI.sh Normal file
View File

@ -0,0 +1 @@
certoraRun contracts/tokenization/VariableDebtToken.sol:VariableDebtToken specs/harness/LendingPoolHarnessForVariableDebtToken.sol --solc solc6.8 --link VariableDebtToken:POOL=LendingPoolHarnessForVariableDebtToken --verify VariableDebtToken:specs/VariableDebtToken.spec --settings -assumeUnwindCond,-useNonLinearArithmetic --cache VariableDebtToken --staging

155
specs/StableDebtToken.spec Normal file
View File

@ -0,0 +1,155 @@
methods {
getUserLastUpdated(address) returns uint40 envfree
}
rule integrityTimeStamp(address user, method f) {
env e;
require sinvoke getIncentivesController(e) == 0;
require getUserLastUpdated(user) <= e.block.timestamp;
calldataarg arg;
sinvoke f(e,arg);
assert getUserLastUpdated(user) <= e.block.timestamp;
}
/**
TotalSupply is the sum of all users balances
totalSupply(t) = Σaddress u. balanceOf(u,t)
Check that each possible opertaion changes the balance of at most one user
*/
rule balanceOfChange(address a, address b, method f )
{
env e;
require a!=b;
require sinvoke getIncentivesController(e) == 0;
uint256 balanceABefore = sinvoke balanceOf(e,a);
uint256 balanceBBefore = sinvoke balanceOf(e,b);
calldataarg arg;
sinvoke f(e, arg);
uint256 balanceAAfter = sinvoke balanceOf(e,a);
uint256 balanceBAfter = sinvoke balanceOf(e,b);
assert ( balanceABefore == balanceAAfter || balanceBBefore == balanceBAfter );
}
/**
Check that the change to total supply is coherent with the changes to balance
*/
rule integirtyBalanceOfTotalSupply(address a, method f )
{
env e;
require sinvoke getIncentivesController(e) == 0;
uint256 balanceABefore = sinvoke balanceOf(e,a);
uint256 totalSupplyBefore = sinvoke totalSupply(e);
calldataarg arg;
sinvoke f(e, arg);
require (f.selector != burn(address,uint256).selector );
uint256 balanceAAfter = sinvoke balanceOf(e,a);
uint256 totalSupplyAfter = sinvoke totalSupply(e);
assert (balanceAAfter != balanceABefore => ( balanceAAfter - balanceABefore == totalSupplyAfter - totalSupplyBefore));
}
/* Burn behaves differently and due to accumulation errors might have less total supply than the balance
*/
rule integirtyBalanceOfTotalSupplyOnBurn(address a, method f)
{
env e;
require sinvoke getIncentivesController(e) == 0;
uint256 balanceABefore = sinvoke balanceOf(e,a);
uint256 totalSupplyBefore = sinvoke totalSupply(e);
uint256 x;
sinvoke burn(e, a, x);
uint256 balanceAAfter = sinvoke balanceOf(e,a);
uint256 totalSupplyAfter = sinvoke totalSupply(e);
if (totalSupplyBefore > x)
assert (balanceAAfter != balanceABefore => ( balanceAAfter - balanceABefore == totalSupplyAfter - totalSupplyBefore));
else
assert (totalSupplyAfter == 0 );
}
/**
Mint inceases the balanceOf user a as expected
*/
rule integrityMint(address a, uint256 x) {
env e;
require sinvoke getIncentivesController(e) == 0;
uint256 index;
uint256 balancebefore = sinvoke balanceOf(e,a);
sinvoke mint(e,a,x,index);
uint256 balanceAfter = sinvoke balanceOf(e,a);
assert balanceAfter == balancebefore+x;
}
/**
Mint is additive, can performed either all at once or gradually
mint(u,x); mint(u,y) ~ mint(u,x+y) at the same timestamp
Note: We assume that the stable rate of the user is 0.
The case where the rate is non-zero takes much more time to prove,
and therefore it is currently excluded from the CI.
*/
rule additiveMint(address a, uint256 x, uint256 y) {
env e;
require sinvoke getIncentivesController(e) == 0;
require getUserStableRate(e,a) == 0;
uint256 index;
storage initialStorage = lastStorage;
sinvoke mint(e,a,x,index);
sinvoke mint(e,a,y,index);
uint256 balanceScenario1 = sinvoke balanceOf(e,a);
uint256 t = x + y;
sinvoke mint(e,a, t ,index) at initialStorage;
uint256 balanceScenario2 = sinvoke balanceOf(e,a);
assert balanceScenario1 == balanceScenario2, "mint is not additive";
}
rule integrityBurn(address a, uint256 x) {
env e;
require sinvoke getIncentivesController(e) == 0;
uint256 index;
uint256 balancebefore = sinvoke balanceOf(e,a);
sinvoke burn(e,a,x);
uint256 balanceAfter = sinvoke balanceOf(e,a);
assert balanceAfter == balancebefore - x;
}
rule additiveBurn(address a, uint256 x, uint256 y) {
env e;
require sinvoke getIncentivesController(e) == 0;
storage initialStorage = lastStorage;
sinvoke burn(e, a, x);
sinvoke burn(e, a, y);
uint256 balanceScenario1 = balanceOf(e, a);
uint256 t = x + y;
sinvoke burn(e, a, t) at initialStorage;
uint256 balanceScenario2 = balanceOf(e, a);
assert balanceScenario1 == balanceScenario2, "burn is not additive";
}
/**
mint and burn are inverse operations
Thus, totalSupply is back to initial state
BalanceOf user is back to initial state */
rule inverseMintBurn(address a, uint256 x) {
env e;
require sinvoke getIncentivesController(e) == 0;
uint256 index;
uint256 balancebefore = sinvoke balanceOf(e,a);
sinvoke mint(e,a,x,index);
sinvoke burn(e,a,x);
uint256 balanceAfter = sinvoke balanceOf(e,a);
assert balancebefore == balanceAfter, "burn is not inverse of mint";
}

View File

@ -0,0 +1,66 @@
methods {
setBorrowing(address, uint256, bool) envfree
setUsingAsCollateral(address, uint256, bool) envfree
isUsingAsCollateralOrBorrowing(address, uint256) returns bool envfree
isBorrowing(address, uint256) returns bool envfree
isUsingAsCollateral(address, uint256) returns bool envfree
isBorrowingAny(address ) returns bool envfree
isEmpty(address ) returns bool envfree
}
invariant empty(address user, uint256 reserveIndex )
isEmpty(user) => !isBorrowingAny(user) && !isUsingAsCollateralOrBorrowing(user, reserveIndex)
invariant notEmpty(address user, uint256 reserveIndex )
( isBorrowingAny(user) || isUsingAsCollateral(user, reserveIndex)) => !isEmpty(user)
invariant borrowing(address user, uint256 reserveIndex )
isBorrowing(user, reserveIndex) => isBorrowingAny(user)
invariant collateralOrBorrowing(address user, uint256 reserveIndex )
( isUsingAsCollateral(user, reserveIndex) || isBorrowing(user, reserveIndex) ) <=> isUsingAsCollateralOrBorrowing(user, reserveIndex)
rule setBorrowing(address user, uint256 reserveIndex, bool borrowing)
{
require reserveIndex < 128;
setBorrowing(user, reserveIndex, borrowing);
assert isBorrowing(user, reserveIndex) == borrowing, "unexpected result";
}
rule setBorrowingNoChangeToOther(address user, uint256 reserveIndex, uint256 reserveIndexOther, bool borrowing)
{
require reserveIndexOther != reserveIndex;
require reserveIndexOther < 128 && reserveIndex < 128;
bool otherReserveBorrowing = isBorrowing(user, reserveIndexOther);
bool otherReserveCollateral = isUsingAsCollateral(user,reserveIndexOther);
setBorrowing(user, reserveIndex, borrowing);
assert otherReserveBorrowing == isBorrowing(user, reserveIndexOther) &&
otherReserveCollateral == isUsingAsCollateral(user,reserveIndexOther), "changed to other reserve";
}
rule setUsingAsCollateral(address user, uint256 reserveIndex, bool usingAsCollateral)
{
require reserveIndex < 128;
setUsingAsCollateral(user, reserveIndex, usingAsCollateral);
assert isUsingAsCollateral(user, reserveIndex) == usingAsCollateral, "unexpected result";
}
rule setUsingAsCollateralNoChangeToOther(address user, uint256 reserveIndex, uint256 reserveIndexOther, bool usingAsCollateral)
{
require reserveIndexOther != reserveIndex;
require reserveIndexOther < 128 && reserveIndex < 128;
bool otherReserveBorrowing = isBorrowing(user, reserveIndexOther);
bool otherReserveCollateral = isUsingAsCollateral(user,reserveIndexOther);
setUsingAsCollateral(user, reserveIndex, usingAsCollateral);
assert otherReserveBorrowing == isBorrowing(user, reserveIndexOther) &&
otherReserveCollateral == isUsingAsCollateral(user,reserveIndexOther), "changed to other reserve";
}

View File

@ -0,0 +1,173 @@
using LendingPoolHarnessForVariableDebtToken as POOL
/**
TotalSupply is the sum of all users balances
totalSupply(t) = Σaddress u. balanceOf(u,t)
Check that each possible opertaion changes the balance of at most one user
*/
rule balanceOfChange(address a, address b, method f)
{
env e;
require a!=b ;
uint256 balanceABefore = sinvoke balanceOf(e, a);
uint256 balanceBBefore = sinvoke balanceOf(e, b);
calldataarg arg;
sinvoke f(e, arg);
uint256 balanceAAfter = sinvoke balanceOf(e, a);
uint256 balanceBAfter = sinvoke balanceOf(e, b);
assert ( balanceABefore == balanceAAfter || balanceBBefore == balanceBAfter );
}
/*
Check that the changed to total supply is coherent with the changes to balance
*/
rule integirtyBalanceOfTotalSupply(address a, method f )
{
env e;
uint256 balanceABefore = balanceOf(e, a);
uint256 totalSupplyBefore = totalSupply(e);
calldataarg arg;
sinvoke f(e, arg);
require (f.selector != burn(address, uint256, uint256).selector &&
f.selector != mint(address, uint256, uint256).selector ) ;
uint256 balanceAAfter = balanceOf(e, a);
uint256 totalSupplyAfter = totalSupply(e);
assert (balanceAAfter != balanceABefore => ( balanceAAfter - balanceABefore == totalSupplyAfter - totalSupplyBefore));
}
/* Burn behaves deferently and due to accumulation errors might hace less total supply then the balance
*/
rule integirtyBalanceOfTotalSupplyOnBurn(address a, method f )
{
env e;
uint256 balanceABefore = balanceOf(e, a);
uint256 totalSupplyBefore = totalSupply(e);
uint256 x;
address asset;
uint256 index = POOL.getReserveNormalizedVariableDebt(e, asset);
sinvoke burn(e, a, x, index);
uint256 balanceAAfter = balanceOf(e, a);
uint256 totalSupplyAfter = totalSupply(e);
assert (balanceAAfter != balanceABefore => ( balanceAAfter - balanceABefore == totalSupplyAfter - totalSupplyBefore));
}
rule integirtyBalanceOfTotalSupplyOnMint(address a, method f )
{
env e;
uint256 balanceABefore = balanceOf(e, a);
uint256 totalSupplyBefore = totalSupply(e);
uint256 x;
address asset;
uint256 index = POOL.getReserveNormalizedVariableDebt(e, asset);
sinvoke mint(e, a, x, index);
uint256 balanceAAfter = balanceOf(e, a);
uint256 totalSupplyAfter = totalSupply(e);
assert (balanceAAfter != balanceABefore => ( balanceAAfter - balanceABefore == totalSupplyAfter - totalSupplyBefore));
}
/**
Minting an amount of x tokens for user u increases their balance by x, up to rounding errors.
{ b= balanceOf(u,t) }
mint(u,x,index)
{ balanceOf(u,t) = b + x }
*/
rule integrityMint(address a, uint256 x) {
env e;
address asset;
uint256 index = POOL.getReserveNormalizedVariableDebt(e,asset);
uint256 balancebefore = balanceOf(e, a);
sinvoke mint(e, a, x, index);
uint256 balanceAfter = balanceOf(e, a);
assert balanceAfter == balancebefore+x;
}
/**
Mint is additive, can performed either all at once or gradually
mint(u,x); mint(u,y) ~ mint(u,x+y) at the same timestamp
*/
rule additiveMint(address a, uint256 x, uint256 y) {
env e;
address asset;
uint256 index = POOL.getReserveNormalizedVariableDebt(e, asset);
storage initialStorage = lastStorage;
sinvoke mint(e, a, x, index);
sinvoke mint(e, a, y, index);
uint256 balanceScenario1 = balanceOf(e, a);
uint t = x + y;
sinvoke mint(e, a, t ,index) at initialStorage;
uint256 balanceScenario2 = balanceOf(e, a);
assert balanceScenario1 == balanceScenario2, "mint is not additive";
}
/**
Transfer of x amount of tokens from user u where receiver is user u
{bu = balanceOf(u) }
burn(u, u, x)
{balanceOf(u) = bu - x }
*/
rule integrityBurn(address a, uint256 x) {
env e;
address asset;
uint256 index = POOL.getReserveNormalizedVariableDebt(e, asset);
uint256 balancebefore = balanceOf(e, a);
sinvoke burn(e, a, x, index);
uint256 balanceAfter = balanceOf(e, a);
assert balanceAfter == balancebefore - x;
}
/**
Minting is additive, i.e., it can be performed either all at once or in steps.
burn(u, u, x); burn(u, u, y) ~ burn(u, u, x+y)
*/
rule additiveBurn(address a, uint256 x, uint256 y) {
env e;
address asset;
uint256 index = POOL.getReserveNormalizedVariableDebt(e, asset);
storage initialStorage = lastStorage;
sinvoke burn(e, a, x, index);
sinvoke burn(e, a, y, index);
uint256 balanceScenario1 = balanceOf(e, a);
uint t = x + y;
sinvoke burn(e, a, t ,index) at initialStorage;
uint256 balanceScenario2 = balanceOf(e, a);
assert balanceScenario1 == balanceScenario2, "burn is not additive";
}
/**
Minting and burning are inverse operations.
{bu = balanceOf(u) }
mint(u,x); burn(u, u, x)
{balanceOf(u) = bu }
*/
rule inverseMintBurn(address a, uint256 x) {
env e;
address asset;
uint256 index = POOL.getReserveNormalizedVariableDebt(e, asset);
uint256 balancebefore = balanceOf(e, a);
sinvoke mint(e, a, x, index);
sinvoke burn(e, a, x, index);
uint256 balanceAfter = balanceOf(e, a);
assert balancebefore == balanceAfter, "burn is not inverse of mint";
}

View File

@ -0,0 +1,214 @@
pragma solidity ^0.6.8;
pragma experimental ABIEncoderV2;
import {
ReserveConfiguration
} from '../../contracts/libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../../contracts/libraries/configuration/UserConfiguration.sol';
import {ReserveLogic} from '../../contracts/libraries/logic/ReserveLogic.sol';
import {ILendingPool} from '../../contracts/interfaces/ILendingPool.sol';
import {LendingPool} from '../../contracts/lendingpool/LendingPool.sol';
/*
Certora: Harness that delegates calls to the original LendingPool.
Used for the verification of the VariableDebtToken contract.
*/
contract LendingPoolHarnessForVariableDebtToken is ILendingPool {
LendingPool private originalPool;
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external override {
originalPool.deposit(asset, amount, onBehalfOf, referralCode);
}
function withdraw(address asset, uint256 amount) external override {
originalPool.withdraw(asset, amount);
}
function getBorrowAllowance(
address fromUser,
address toUser,
address asset,
uint256 interestRateMode
) external override view returns (uint256) {
return originalPool.getBorrowAllowance(fromUser, toUser, asset, interestRateMode);
}
function delegateBorrowAllowance(
address asset,
address user,
uint256 interestRateMode,
uint256 amount
) external override {
originalPool.delegateBorrowAllowance(asset, user, interestRateMode, amount);
}
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
) external override {
originalPool.borrow(asset, amount, interestRateMode, referralCode, onBehalfOf);
}
function repay(
address asset,
uint256 amount,
uint256 rateMode,
address onBehalfOf
) external override {
originalPool.repay(asset, amount, rateMode, onBehalfOf);
}
function swapBorrowRateMode(address asset, uint256 rateMode) external override {
originalPool.swapBorrowRateMode(asset, rateMode);
}
function rebalanceStableBorrowRate(address asset, address user) external override {
originalPool.rebalanceStableBorrowRate(asset, user);
}
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external override {
originalPool.setUserUseReserveAsCollateral(asset, useAsCollateral);
}
function liquidationCall(
address collateral,
address asset,
address user,
uint256 purchaseAmount,
bool receiveAToken
) external override {
originalPool.liquidationCall(collateral, asset, user, purchaseAmount, receiveAToken);
}
function getReservesList() external override view returns (address[] memory) {
return originalPool.getReservesList();
}
function getReserveData(address asset)
external
override
view
returns (ReserveLogic.ReserveData memory)
{
return originalPool.getReserveData(asset);
}
function getUserConfiguration(address user)
external
override
view
returns (UserConfiguration.Map memory)
{
return originalPool.getUserConfiguration(user);
}
function getUserAccountData(address user)
external
override
view
returns (
uint256 totalCollateralETH,
uint256 totalBorrowsETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
)
{
return originalPool.getUserAccountData(user);
}
function initReserve(
address asset,
address aTokenAddress,
address stableDebtAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external override {
originalPool.initReserve(
asset,
aTokenAddress,
stableDebtAddress,
variableDebtAddress,
interestRateStrategyAddress
);
}
function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress)
external
override
{
originalPool.setReserveInterestRateStrategyAddress(asset, rateStrategyAddress);
}
function setConfiguration(address asset, uint256 configuration) external override {
originalPool.setConfiguration(asset, configuration);
}
function getConfiguration(address asset)
external
override
view
returns (ReserveConfiguration.Map memory)
{
return originalPool.getConfiguration(asset);
}
mapping(uint256 => uint256) private reserveNormalizedIncome;
function getReserveNormalizedIncome(address asset) external override view returns (uint256) {
require(reserveNormalizedIncome[block.timestamp] == 1e27);
return reserveNormalizedIncome[block.timestamp];
}
mapping(uint256 => uint256) private reserveNormalizedVariableDebt;
function getReserveNormalizedVariableDebt(address asset)
external
override
view
returns (uint256)
{
require(reserveNormalizedVariableDebt[block.timestamp] == 1e27);
return reserveNormalizedVariableDebt[block.timestamp];
}
function setPause(bool val) external override {
originalPool.setPause(val);
}
function paused() external override view returns (bool) {
return originalPool.paused();
}
function flashLoan(
address receiver,
address[] calldata assets,
uint256[] calldata amounts,
uint256 mode,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external override {
originalPool.flashLoan(receiver, assets, amounts, mode, onBehalfOf, params, referralCode);
}
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromAfter,
uint256 balanceToBefore
) external override {
originalPool.finalizeTransfer(asset, from, to, amount, balanceFromAfter, balanceToBefore);
}
}

View File

@ -0,0 +1,26 @@
pragma solidity ^0.6.8;
import {StableDebtToken} from '../../contracts/tokenization/StableDebtToken.sol';
import {IncentivizedERC20} from '../../contracts/tokenization/IncentivizedERC20.sol';
contract StableDebtTokenHarness is StableDebtToken {
constructor(
address pool,
address underlyingAsset,
string memory name,
string memory symbol,
address incentivesController
) public StableDebtToken(pool, underlyingAsset, name, symbol, incentivesController) {}
function balanceOf(address account) public override view returns (uint256) {
return IncentivizedERC20.balanceOf(account);
}
function _calcTotalSupply(uint256 avgRate) internal override view returns (uint256) {
return IncentivizedERC20.totalSupply();
}
function getIncentivesController() public view returns (address) {
return address(_incentivesController);
}
}

View File

@ -0,0 +1,56 @@
pragma solidity ^0.6.8;
pragma experimental ABIEncoderV2;
import {UserConfiguration} from '../../contracts/libraries/configuration/UserConfiguration.sol';
/*
A wrapper contract for calling functions from the library UserConfiguration.
*/
contract UserConfigurationHarness {
UserConfiguration.Map internal usersConfig;
function setBorrowing(
address user,
uint256 reserveIndex,
bool borrowing
) public {
UserConfiguration.setBorrowing(usersConfig, reserveIndex, borrowing);
}
function setUsingAsCollateral(
address user,
uint256 reserveIndex,
bool _usingAsCollateral
) public {
UserConfiguration.setUsingAsCollateral(usersConfig, reserveIndex, _usingAsCollateral);
}
function isUsingAsCollateralOrBorrowing(address user, uint256 reserveIndex)
public
view
returns (bool)
{
return UserConfiguration.isUsingAsCollateralOrBorrowing(usersConfig, reserveIndex);
}
function isBorrowing(address user, uint256 reserveIndex) public view returns (bool) {
return UserConfiguration.isBorrowing(usersConfig, reserveIndex);
}
function isUsingAsCollateral(address user, uint256 reserveIndex) public view returns (bool) {
return UserConfiguration.isUsingAsCollateral(usersConfig, reserveIndex);
}
function isBorrowingAny(address user) public view returns (bool) {
return UserConfiguration.isBorrowingAny(usersConfig);
}
function isEmpty(address user) public view returns (bool) {
return UserConfiguration.isEmpty(usersConfig);
}
/*
Mimics the original constructor of the contract.
*/
function init_state() public {}
}

View File

@ -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) => {

View File

@ -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)
);
});

View File

@ -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
);
});

View File

@ -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
);
});

View File

@ -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);

View File

@ -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',

View File

@ -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
);
});

View File

@ -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);

View File

@ -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 = <eEthereumNetwork>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);

View File

@ -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,36 +12,39 @@ import {
deployLendingPoolConfigurator,
deployLendingPool,
deployPriceOracle,
getLendingPoolConfiguratorProxy,
deployChainlinkProxyPriceProvider,
deployLendingPoolCollateralManager,
deployMockFlashLoanReceiver,
deployWalletBalancerProvider,
getLendingPool,
insertContractAddressInDb,
deployAaveProtocolTestHelpers,
getEthersSigners,
registerContractInJsonDb,
getPairsTokenAggregator,
initReserves,
deployLendingRateOracle,
} from '../helpers/contracts-helpers';
deployStableAndVariableTokensHelper,
deployATokensAndRatesHelper,
} 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;
@ -90,17 +98,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();
@ -115,6 +117,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(
@ -183,10 +193,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 {
@ -204,30 +215,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();

View File

@ -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');

View File

@ -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);
});

View File

@ -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,34 @@ 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());
});
});

View File

@ -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 () => {
@ -50,7 +48,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
0,
[0],
_mockFlashLoanReceiver.address,
'0x10',
'0'
);
@ -79,7 +78,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
['1000720000000000000'],
0,
[0],
_mockFlashLoanReceiver.address,
'0x10',
'0'
);
@ -110,7 +110,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
0,
[0],
caller.address,
'0x10',
'0'
)
@ -130,7 +131,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
0,
[0],
caller.address,
'0x10',
'0'
)
@ -150,11 +152,12 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
4,
[4],
caller.address,
'0x10',
'0'
)
).to.be.revertedWith(INVALID_FLASHLOAN_MODE);
).to.be.reverted;
});
it('Caller deposits 1000 DAI as collateral, Takes WETH flashloan with mode = 2, does not return the funds. A variable loan for caller is created', async () => {
@ -178,7 +181,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[weth.address],
[ethers.utils.parseEther('0.8')],
2,
[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,
[2],
caller.address,
'0x10',
'0'
),
@ -213,10 +219,19 @@ 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;
});
@ -244,7 +259,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[usdc.address],
[flashloanAmount],
0,
[0],
_mockFlashLoanReceiver.address,
'0x10',
'0'
);
@ -286,7 +302,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
_mockFlashLoanReceiver.address,
[usdc.address],
[flashloanAmount],
2,
[2],
caller.address,
'0x10',
'0'
)
@ -312,7 +329,15 @@ 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 +372,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 +395,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 +416,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<StableDebtToken>(
eContractid.VariableDebtToken,
stableDebtTokenAddress
);
const onBehalfOfDebt = await wethDebtToken.balanceOf(onBehalfOf.address);
expect(onBehalfOfDebt.toString()).to.be.equal(
'800000000000000000',
'Invalid onBehalfOf user debt'
);
});
});

View File

@ -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;
@ -235,7 +231,7 @@ export const withdraw = async (
if (expectedResult === 'success') {
const txResult = await waitForTx(
await pool.connect(user.signer).withdraw(reserve, amountToWithdraw)
await pool.connect(user.signer).withdraw(reserve, amountToWithdraw, user.address)
);
const {
@ -273,8 +269,10 @@ export const withdraw = async (
// );
// });
} else if (expectedResult === 'revert') {
await expect(pool.connect(user.signer).withdraw(reserve, amountToWithdraw), revertMessage).to.be
.reverted;
await expect(
pool.connect(user.signer).withdraw(reserve, amountToWithdraw, user.address),
revertMessage
).to.be.reverted;
}
};
@ -290,11 +288,15 @@ export const delegateBorrowAllowance = async (
) => {
const {pool} = testEnv;
const reserves : tEthereumAddress[] = []
const amountsToDelegate: tEthereumAddress[] = []
const reserves: tEthereumAddress[] = [];
const amountsToDelegate: tEthereumAddress[] = [];
for (const reserveSymbol of reserveSymbols) {
const newLength = reserves.push(await getReserveAddressFromSymbol(reserveSymbol))
amountsToDelegate.push(await (await convertToCurrencyDecimals(reserves[newLength-1], amounts[newLength-1])).toString())
const newLength = reserves.push(await getReserveAddressFromSymbol(reserveSymbol));
amountsToDelegate.push(
await (
await convertToCurrencyDecimals(reserves[newLength - 1], amounts[newLength - 1])
).toString()
);
}
const delegateAllowancePromise = pool
@ -307,10 +309,11 @@ export const delegateBorrowAllowance = async (
await delegateAllowancePromise;
for (const [i, reserve] of reserves.entries()) {
expect(
(await pool.getBorrowAllowance(user.address, receiver, reserve, interestRateModes[i])).toString()
(
await pool.getBorrowAllowance(user.address, receiver, reserve, interestRateModes[i])
).toString()
).to.be.equal(amountsToDelegate[i], 'borrowAllowance are set incorrectly');
}
}
};

View File

@ -1,7 +1,6 @@
import {evmRevert, evmSnapshot, BRE} from '../../helpers/misc-utils';
import {Signer} from 'ethers';
import {
getEthersSigners,
getLendingPool,
getLendingPoolAddressesProvider,
getAaveProtocolTestHelpers,
@ -10,7 +9,7 @@ import {
getLendingPoolConfiguratorProxy,
getPriceOracle,
getLendingPoolAddressesProviderRegistry,
} from '../../helpers/contracts-helpers';
} from '../../helpers/contracts-getters';
import {tEthereumAddress} from '../../helpers/types';
import {LendingPool} from '../../types/LendingPool';
import {AaveProtocolTestHelpers} from '../../types/AaveProtocolTestHelpers';
@ -25,6 +24,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';
chai.use(bignumberChai());
chai.use(almostEqual());
@ -40,7 +40,7 @@ export interface TestEnv {
oracle: PriceOracle;
helpersContract: AaveProtocolTestHelpers;
weth: MintableERC20;
aEth: AToken;
aWETH: AToken;
dai: MintableERC20;
aDai: AToken;
usdc: MintableERC20;
@ -64,7 +64,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,
@ -88,10 +88,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();
@ -99,13 +97,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();
@ -114,7 +110,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);
}
@ -124,7 +120,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);

View File

@ -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';

View File

@ -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();

View File

@ -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;

View File

@ -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');
@ -115,7 +116,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => {
// user tries to burn
await expect(
pool.connect(users[0].signer).withdraw(dai.address, amountDAItoDeposit)
pool.connect(users[0].signer).withdraw(dai.address, amountDAItoDeposit, users[0].address)
).to.revertedWith(IS_PAUSED);
// Configurator unpauses the pool
@ -186,7 +187,15 @@ 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

View File

@ -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

View File

@ -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
);

View File

@ -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;