mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Fix conflicts
This commit is contained in:
commit
1ac0a45394
|
@ -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
|
||||
|
|
|
@ -12,6 +12,7 @@ interface IFlashLoanReceiver {
|
|||
address[] calldata assets,
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata premiums,
|
||||
address initiator,
|
||||
bytes calldata params
|
||||
) external returns (bool);
|
||||
}
|
||||
|
|
|
@ -27,16 +27,17 @@ 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 asset,
|
||||
address indexed fromUser,
|
||||
address indexed toUser,
|
||||
uint256 interestRateMode,
|
||||
uint256 amount
|
||||
address[] assets,
|
||||
uint256[] interestRateModes,
|
||||
uint256[] amounts
|
||||
);
|
||||
/**
|
||||
* @dev emitted on borrow
|
||||
|
@ -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,20 +100,18 @@ interface ILendingPool {
|
|||
/**
|
||||
* @dev emitted when a flashloan is executed
|
||||
* @param target the address of the flashLoanReceiver
|
||||
* @param mode Type of the debt to open if the flash loan is not returned. 0 -> Don't open any debt, just revert, 1 -> stable, 2 -> variable
|
||||
* @param onBehalfOf the address incurring the debt, if borrow mode is not 0
|
||||
* @param assets the address of the assets being flashborrowed
|
||||
* @param amounts the amount requested
|
||||
* @param premiums the total fee on the amount
|
||||
* @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 indexed onBehalfOf,
|
||||
address[] assets,
|
||||
uint256[] amounts,
|
||||
uint256[] premiums,
|
||||
address indexed initiator,
|
||||
address indexed asset,
|
||||
uint256 amount,
|
||||
uint256 premium,
|
||||
uint16 referralCode
|
||||
);
|
||||
|
||||
|
@ -188,21 +187,26 @@ 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 asset for a certain user address
|
||||
* @param asset The underlying asset of the debt token
|
||||
* @dev Sets allowance to borrow on a certain type of debt assets for a certain user address
|
||||
* @param assets The underlying asset of each debt token
|
||||
* @param user The user to give allowance to
|
||||
* @param interestRateMode Type of debt: 1 for stable, 2 for variable
|
||||
* @param amount Allowance amount to borrow
|
||||
* @param interestRateModes Types of debt: 1 for stable, 2 for variable
|
||||
* @param amounts Allowance amounts to borrow
|
||||
**/
|
||||
function delegateBorrowAllowance(
|
||||
address asset,
|
||||
address[] calldata assets,
|
||||
address user,
|
||||
uint256 interestRateMode,
|
||||
uint256 amount
|
||||
uint256[] calldata interestRateModes,
|
||||
uint256[] calldata amounts
|
||||
) external;
|
||||
|
||||
function getBorrowAllowance(
|
||||
|
@ -289,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
|
||||
**/
|
||||
|
@ -297,7 +301,7 @@ interface ILendingPool {
|
|||
address receiver,
|
||||
address[] calldata assets,
|
||||
uint256[] calldata amounts,
|
||||
uint256 mode,
|
||||
uint256[] calldata modes,
|
||||
address onBehalfOf,
|
||||
bytes calldata params,
|
||||
uint16 referralCode
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,23 +183,32 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev Sets allowance to borrow on a certain type of debt asset for a certain user address
|
||||
* @param asset The underlying asset of the debt token
|
||||
* @dev Sets allowance to borrow on a certain type of debt assets for a certain user address
|
||||
* @param assets The underlying asset of each debt token
|
||||
* @param user The user to give allowance to
|
||||
* @param interestRateMode Type of debt: 1 for stable, 2 for variable
|
||||
* @param amount Allowance amount to borrow
|
||||
* @param interestRateModes Types of debt: 1 for stable, 2 for variable
|
||||
* @param amounts Allowance amounts to borrow
|
||||
**/
|
||||
function delegateBorrowAllowance(
|
||||
address asset,
|
||||
address[] calldata assets,
|
||||
address user,
|
||||
uint256 interestRateMode,
|
||||
uint256 amount
|
||||
uint256[] calldata interestRateModes,
|
||||
uint256[] calldata amounts
|
||||
) external override {
|
||||
_whenNotPaused();
|
||||
address debtToken = _reserves[asset].getDebtTokenAddress(interestRateMode);
|
||||
|
||||
_borrowAllowance[debtToken][msg.sender][user] = amount;
|
||||
emit BorrowAllowanceDelegated(asset, msg.sender, user, interestRateMode, amount);
|
||||
uint256 countAssets = assets.length;
|
||||
require(
|
||||
countAssets == interestRateModes.length && countAssets == amounts.length,
|
||||
Errors.LP_INCONSISTENT_PARAMS_LENGTH
|
||||
);
|
||||
|
||||
for (uint256 i = 0; i < countAssets; i++) {
|
||||
address debtToken = _reserves[assets[i]].getDebtTokenAddress(interestRateModes[i]);
|
||||
_borrowAllowance[debtToken][msg.sender][user] = amounts[i];
|
||||
}
|
||||
|
||||
emit BorrowAllowanceDelegated(msg.sender, user, assets, interestRateModes, amounts);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -352,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -486,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -502,7 +515,7 @@ 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
|
||||
|
@ -511,7 +524,7 @@ 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
|
||||
|
@ -520,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;
|
||||
|
@ -539,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.LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN
|
||||
);
|
||||
|
||||
|
@ -548,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(),
|
||||
|
@ -571,13 +582,11 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
);
|
||||
} else {
|
||||
if (msg.sender != onBehalfOf) {
|
||||
address debtToken = _reserves[vars.currentAsset].getDebtTokenAddress(mode);
|
||||
vars.debtToken = _reserves[vars.currentAsset].getDebtTokenAddress(modes[vars.i]);
|
||||
|
||||
_borrowAllowance[debtToken][onBehalfOf][msg
|
||||
.sender] = _borrowAllowance[debtToken][onBehalfOf][msg.sender].sub(
|
||||
vars.currentAmount,
|
||||
Errors.LP_BORROW_ALLOWANCE_ARE_NOT_ENOUGH
|
||||
);
|
||||
_borrowAllowance[vars.debtToken][onBehalfOf][msg.sender] = _borrowAllowance[vars
|
||||
.debtToken][onBehalfOf][msg.sender]
|
||||
.sub(vars.currentAmount, Errors.LP_BORROW_ALLOWANCE_ARE_NOT_ENOUGH);
|
||||
}
|
||||
|
||||
//if the user didn't choose to return the funds, the system checks if there
|
||||
|
@ -588,14 +597,21 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
msg.sender,
|
||||
onBehalfOf,
|
||||
vars.currentAmount,
|
||||
mode,
|
||||
modes[vars.i],
|
||||
vars.currentATokenAddress,
|
||||
referralCode,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
emit FlashLoan(receiverAddress, mode, onBehalfOf, assets, amounts, premiums, referralCode);
|
||||
emit FlashLoan(
|
||||
receiverAddress,
|
||||
msg.sender,
|
||||
vars.currentAsset,
|
||||
vars.currentAmount,
|
||||
vars.currentPremium,
|
||||
referralCode
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -691,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();
|
||||
}
|
||||
|
||||
|
@ -875,6 +897,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
);
|
||||
|
||||
ValidationLogic.validateBorrow(
|
||||
vars.asset,
|
||||
reserve,
|
||||
vars.onBehalfOf,
|
||||
vars.amount,
|
||||
|
@ -888,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,
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -89,6 +89,8 @@ library Errors {
|
|||
string public constant RC_INVALID_DECIMALS = '70';
|
||||
string public constant RC_INVALID_RESERVE_FACTOR = '71';
|
||||
string public constant LPAPR_INVALID_ADDRESSES_PROVIDER_ID = '72';
|
||||
string public constant VL_INCONSISTENT_FLASHLOAN_PARAMS = '73';
|
||||
string public constant LP_INCONSISTENT_PARAMS_LENGTH = '74';
|
||||
|
||||
enum CollateralManagerErrors {
|
||||
NO_ERROR,
|
||||
|
|
|
@ -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.VL_AMOUNT_NOT_GREATER_THAN_0);
|
||||
|
@ -61,7 +61,7 @@ library ValidationLogic {
|
|||
mapping(uint256 => address) storage reserves,
|
||||
uint256 reservesCount,
|
||||
address oracle
|
||||
) internal view {
|
||||
) external view {
|
||||
require(amount > 0, Errors.VL_AMOUNT_NOT_GREATER_THAN_0);
|
||||
|
||||
require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE);
|
||||
|
@ -104,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
|
||||
|
@ -117,6 +118,7 @@ library ValidationLogic {
|
|||
*/
|
||||
|
||||
function validateBorrow(
|
||||
address asset,
|
||||
ReserveLogic.ReserveData storage reserve,
|
||||
address userAddress,
|
||||
uint256 amount,
|
||||
|
@ -203,6 +205,8 @@ library ValidationLogic {
|
|||
Errors.VL_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);
|
||||
|
@ -251,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();
|
||||
|
@ -268,9 +272,9 @@ library ValidationLogic {
|
|||
require(!isFreezed, Errors.VL_NO_UNFREEZED_RESERVE);
|
||||
|
||||
if (currentRateMode == ReserveLogic.InterestRateMode.STABLE) {
|
||||
require(stableBorrowBalance > 0, Errors.VL_NO_STABLE_RATE_LOAN_IN_RESERVE);
|
||||
require(stableDebt > 0, Errors.VL_NO_STABLE_RATE_LOAN_IN_RESERVE);
|
||||
} else if (currentRateMode == ReserveLogic.InterestRateMode.VARIABLE) {
|
||||
require(variableBorrowBalance > 0, Errors.VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE);
|
||||
require(variableDebt > 0, Errors.VL_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
|
||||
|
@ -283,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.VL_CALLATERAL_SAME_AS_BORROWING_CURRENCY
|
||||
);
|
||||
} else {
|
||||
|
@ -331,20 +334,11 @@ 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.LP_INVALID_FLASHLOAN_MODE
|
||||
);
|
||||
require(assets.length == amounts.length, Errors.LP_INCONSISTENT_FLASHLOAN_PARAMS);
|
||||
function validateFlashloan(address[] memory assets, uint256[] memory amounts) internal pure {
|
||||
require(assets.length == amounts.length, Errors.VL_INCONSISTENT_FLASHLOAN_PARAMS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -62,7 +62,7 @@ interface IStableDebtToken {
|
|||
address user,
|
||||
uint256 amount,
|
||||
uint256 rate
|
||||
) external;
|
||||
) external returns (bool);
|
||||
|
||||
/**
|
||||
* @dev burns debt of the target user.
|
||||
|
|
|
@ -145,7 +145,6 @@ export const deployAaveLibraries = async (
|
|||
return {
|
||||
['__$5201a97c05ba6aa659e2f36a933dd51801$__']: validationLogic.address,
|
||||
['__$d3b4366daeb9cadc7528af6145b50b2183$__']: reserveLogic.address,
|
||||
['__$4c26be947d349222af871a3168b3fe584b$__']: genericLogic.address,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
1
runStableTokenCLI.sh
Normal file
1
runStableTokenCLI.sh
Normal 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
1
runUserConfigCLI.sh
Normal 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
1
runVariableTokenCLI.sh
Normal 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
155
specs/StableDebtToken.spec
Normal 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";
|
||||
}
|
||||
|
66
specs/UserConfiguration.spec
Normal file
66
specs/UserConfiguration.spec
Normal 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";
|
||||
}
|
173
specs/VariableDebtToken.spec
Normal file
173
specs/VariableDebtToken.spec
Normal 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";
|
||||
}
|
||||
|
||||
|
||||
|
214
specs/harness/LendingPoolHarnessForVariableDebtToken.sol
Normal file
214
specs/harness/LendingPoolHarnessForVariableDebtToken.sol
Normal 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);
|
||||
}
|
||||
}
|
26
specs/harness/StableDebtTokenHarness.sol
Normal file
26
specs/harness/StableDebtTokenHarness.sol
Normal 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);
|
||||
}
|
||||
}
|
56
specs/harness/UserConfigurationHarness.sol
Normal file
56
specs/harness/UserConfigurationHarness.sol
Normal 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 {}
|
||||
}
|
|
@ -50,7 +50,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
0,
|
||||
[0],
|
||||
_mockFlashLoanReceiver.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -80,7 +80,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
['1000720000000000000'],
|
||||
0,
|
||||
[0],
|
||||
_mockFlashLoanReceiver.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -112,7 +112,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
0,
|
||||
[0],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -133,7 +133,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
0,
|
||||
[0],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -154,12 +154,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(LP_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 () => {
|
||||
|
@ -183,7 +183,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
2,
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -208,7 +208,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
['1004415000000000000'], //slightly higher than the available liquidity
|
||||
2,
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -226,7 +226,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
deployer.address,
|
||||
[weth.address],
|
||||
['1000000000000000000'],
|
||||
2,
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -258,7 +258,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[usdc.address],
|
||||
[flashloanAmount],
|
||||
0,
|
||||
[0],
|
||||
_mockFlashLoanReceiver.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -301,7 +301,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[usdc.address],
|
||||
[flashloanAmount],
|
||||
2,
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -332,7 +332,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[usdc.address],
|
||||
[flashloanAmount],
|
||||
2,
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -372,7 +372,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
0,
|
||||
[0],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -395,7 +395,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
1,
|
||||
[1],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -438,7 +438,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
1,
|
||||
[1],
|
||||
onBehalfOf.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
@ -457,7 +457,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
// Deposited for onBehalfOf user already, delegate borrow allowance
|
||||
await pool
|
||||
.connect(onBehalfOf.signer)
|
||||
.delegateBorrowAllowance(weth.address, caller.address, 1, flashAmount);
|
||||
.delegateBorrowAllowance([weth.address], caller.address, [1], [flashAmount]);
|
||||
|
||||
await _mockFlashLoanReceiver.setFailExecutionTransfer(true);
|
||||
|
||||
|
@ -467,7 +467,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
1,
|
||||
[1],
|
||||
onBehalfOf.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
|
|
@ -231,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 {
|
||||
|
@ -269,15 +269,17 @@ 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;
|
||||
}
|
||||
};
|
||||
|
||||
export const delegateBorrowAllowance = async (
|
||||
reserveSymbol: string,
|
||||
amount: string,
|
||||
interestRateMode: string,
|
||||
reserveSymbols: string[],
|
||||
amounts: string[],
|
||||
interestRateModes: string[],
|
||||
user: SignerWithAddress,
|
||||
receiver: tEthereumAddress,
|
||||
expectedResult: string,
|
||||
|
@ -286,20 +288,32 @@ export const delegateBorrowAllowance = async (
|
|||
) => {
|
||||
const {pool} = testEnv;
|
||||
|
||||
const reserve = await getReserveAddressFromSymbol(reserveSymbol);
|
||||
const amountToDelegate = await convertToCurrencyDecimals(reserve, amount);
|
||||
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 delegateAllowancePromise = pool
|
||||
.connect(user.signer)
|
||||
.delegateBorrowAllowance(reserve, receiver, interestRateMode, amountToDelegate.toString());
|
||||
.delegateBorrowAllowance(reserves, receiver, interestRateModes, amountsToDelegate);
|
||||
if (expectedResult === 'revert') {
|
||||
await expect(delegateAllowancePromise, revertMessage).to.be.reverted;
|
||||
return;
|
||||
} else {
|
||||
await delegateAllowancePromise;
|
||||
expect(
|
||||
(await pool.getBorrowAllowance(user.address, receiver, reserve, interestRateMode)).toString()
|
||||
).to.be.equal(amountToDelegate.toString(), 'borrowAllowance are set incorrectly');
|
||||
for (const [i, reserve] of reserves.entries()) {
|
||||
expect(
|
||||
(
|
||||
await pool.getBorrowAllowance(user.address, receiver, reserve, interestRateModes[i])
|
||||
).toString()
|
||||
).to.be.equal(amountsToDelegate[i], 'borrowAllowance are set incorrectly');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -121,9 +121,9 @@ const executeAction = async (action: Action, users: SignerWithAddress[], testEnv
|
|||
}
|
||||
|
||||
await delegateBorrowAllowance(
|
||||
reserve,
|
||||
amount,
|
||||
rateMode,
|
||||
[reserve],
|
||||
[amount],
|
||||
[rateMode],
|
||||
user,
|
||||
toUser,
|
||||
expected,
|
||||
|
|
|
@ -115,7 +115,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(P_IS_PAUSED);
|
||||
|
||||
// Configurator unpauses the pool
|
||||
|
@ -132,7 +132,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => {
|
|||
|
||||
// Try to execute liquidation
|
||||
await expect(
|
||||
pool.connect(user.signer).delegateBorrowAllowance(dai.address, toUser.address, '1', '1')
|
||||
pool.connect(user.signer).delegateBorrowAllowance([dai.address], toUser.address, ['1'], ['1'])
|
||||
).revertedWith(P_IS_PAUSED);
|
||||
|
||||
// Unpause the pool
|
||||
|
@ -190,7 +190,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => {
|
|||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
1,
|
||||
[1],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
|
|
Loading…
Reference in New Issue
Block a user