Merge branch 'master' into feat/pei-integration

This commit is contained in:
andyk 2020-09-15 18:43:55 +03:00
commit 125644cc54
26 changed files with 807 additions and 249 deletions

View File

@ -10,7 +10,6 @@ usePlugin('solidity-coverage');
usePlugin('@nomiclabs/buidler-waffle');
usePlugin('@nomiclabs/buidler-etherscan');
//usePlugin('buidler-gas-reporter');
const DEFAULT_BLOCK_GAS_LIMIT = 10000000;
const DEFAULT_GAS_PRICE = 10;
const HARDFORK = 'istanbul';

View File

@ -137,6 +137,15 @@ interface ILendingPool {
address liquidator,
bool receiveAToken
);
/**
* @dev Emitted when the pause is triggered.
*/
event Paused();
/**
* @dev Emitted when the pause is lifted.
*/
event Unpaused();
/**
* @dev deposits The underlying asset into the reserve. A corresponding amount of the overlying asset (aTokens)
@ -420,4 +429,15 @@ interface ILendingPool {
) external view returns (bool);
function getReserves() external view returns (address[] memory);
/**
* @dev Set the _pause state
* @param val the boolean value to set the current pause state of LendingPool
*/
function setPause(bool val) external;
/**
* @dev Returns if the LendingPool is paused
*/
function paused() external view returns(bool);
}

View File

@ -2,20 +2,19 @@
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;
/**
* @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

@ -55,16 +55,27 @@ contract LendingPool is VersionedInitializable, ILendingPool {
address[] internal _reservesList;
bool internal _flashLiquidationLocked;
bool internal _paused;
/**
* @dev only lending pools configurator can use functions affected by this modifier
**/
modifier onlyLendingPoolConfigurator {
function onlyLendingPoolConfigurator() internal view {
require(
_addressesProvider.getLendingPoolConfigurator() == msg.sender,
Errors.CALLER_NOT_LENDING_POOL_CONFIGURATOR
);
_;
}
/**
* @dev Function to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
function whenNotPaused() internal view {
require(!_paused, Errors.IS_PAUSED);
}
uint256 public constant UINT_MAX_VALUE = uint256(-1);
@ -97,6 +108,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
address onBehalfOf,
uint16 referralCode
) external override {
whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateDeposit(reserve, amount);
@ -125,6 +137,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
* @param amount the underlying amount to be redeemed
**/
function withdraw(address asset, uint256 amount) external override {
whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
address aToken = reserve.aTokenAddress;
@ -185,6 +198,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 interestRateMode,
uint256 amount
) external override {
whenNotPaused();
address debtToken = _reserves[asset].getDebtTokenAddress(interestRateMode);
_borrowAllowance[debtToken][msg.sender][user] = amount;
@ -207,6 +221,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint16 referralCode,
address onBehalfOf
) external override {
whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
if (onBehalfOf != msg.sender) {
@ -246,6 +261,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 rateMode,
address onBehalfOf
) external override {
whenNotPaused();
_executeRepay(asset, msg.sender, amount, rateMode, onBehalfOf);
}
@ -307,6 +323,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
* @param rateMode the rate mode that the user wants to swap
**/
function swapBorrowRateMode(address asset, uint256 rateMode) external override {
whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
@ -350,6 +367,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
* @param user the address of the user to be rebalanced
**/
function rebalanceStableBorrowRate(address asset, address user) external override {
whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
IStableDebtToken stableDebtToken = IStableDebtToken(reserve.stableDebtTokenAddress);
@ -395,6 +413,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
* @param useAsCollateral true if the user wants to user the deposit as collateral, false otherwise.
**/
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external override {
whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateSetUseReserveAsCollateral(
@ -431,7 +450,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 purchaseAmount,
bool receiveAToken
) external override {
whenNotPaused();
address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
//solium-disable-next-line
@ -488,6 +507,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
address receiver,
bytes calldata params
) external override {
whenNotPaused();
require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED);
_flashLiquidationLocked = true;
@ -535,6 +555,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
bytes calldata params,
uint16 referralCode
) external override {
whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset];
FlashLoanLocalVars memory vars;
@ -596,6 +617,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 amountToSwap,
bytes calldata params
) external override {
whenNotPaused();
address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
//solium-disable-next-line
@ -791,7 +813,8 @@ contract LendingPool is VersionedInitializable, ILendingPool {
address stableDebtAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external override onlyLendingPoolConfigurator {
) external override {
onlyLendingPoolConfigurator();
_reserves[asset].init(
aTokenAddress,
stableDebtAddress,
@ -810,16 +833,13 @@ contract LendingPool is VersionedInitializable, ILendingPool {
function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress)
external
override
onlyLendingPoolConfigurator
{
onlyLendingPoolConfigurator();
_reserves[asset].interestRateStrategyAddress = rateStrategyAddress;
}
function setConfiguration(address asset, uint256 configuration)
external
override
onlyLendingPoolConfigurator
{
function setConfiguration(address asset, uint256 configuration) external override {
onlyLendingPoolConfigurator();
_reserves[asset].configuration.data = configuration;
}
@ -970,6 +990,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
address user,
uint256 amount
) external override view returns (bool) {
whenNotPaused();
return
GenericLogic.balanceDecreaseAllowed(
asset,
@ -995,4 +1016,26 @@ contract LendingPool is VersionedInitializable, ILendingPool {
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
return _addressesProvider;
}
/**
* @dev Set the _pause state
* @param val the boolean value to set the current pause state of LendingPool
*/
function setPause(bool val) external override {
onlyLendingPoolConfigurator();
_paused = val;
if (_paused) {
emit Paused();
} else {
emit Unpaused();
}
}
/**
* @dev Returns if the LendingPool is paused
*/
function paused() external view override returns(bool) {
return _paused;
}
}

View File

@ -582,4 +582,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
proxy.upgradeToAndCall(implementation, params);
}
/**
* @dev pauses or unpauses LendingPool actions
* @param val the boolean value to set the current pause state of LendingPool
**/
function setPoolPause(bool val) external onlyLendingPoolManager {
pool.setPause(val);
}
}

View File

@ -27,6 +27,7 @@ import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
* @title LendingPoolLiquidationManager contract
* @author Aave
* @notice Implements the liquidation function.
* @dev LendingPoolLiquidationManager inherits Pausable from OpenZeppelin to have the same storage layout as LendingPool
**/
contract LendingPoolLiquidationManager is VersionedInitializable {
using SafeERC20 for IERC20;
@ -49,6 +50,7 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
address[] internal reservesList;
bool internal _flashLiquidationLocked;
bool public _paused;
uint256 internal constant LIQUIDATION_CLOSE_FACTOR_PERCENT = 5000;

View File

@ -49,8 +49,8 @@ library Errors {
string public constant CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = '30'; // 'User cannot give allowance to himself'
string public constant TRANSFER_AMOUNT_NOT_GT_0 = '31'; // 'Transferred amount needs to be greater than zero'
string public constant INVALID_ATOKEN_BALANCE = '52'; // balance on burning is invalid
// require error messages - ReserveLogic
// require error messages - ReserveLogic
string public constant RESERVE_ALREADY_INITIALIZED = '34'; // 'Reserve has already been initialized'
string public constant LIQUIDITY_INDEX_OVERFLOW = '47'; // Liquidity index overflows uint128
string public constant VARIABLE_BORROW_INDEX_OVERFLOW = '48'; // Variable borrow index overflows uint128
@ -77,6 +77,8 @@ library Errors {
string public constant ADDITION_OVERFLOW = '45';
string public constant DIVISION_BY_ZERO = '46';
// pausable error message
string public constant IS_PAUSED = '58'; // 'Pool is paused'
enum LiquidationErrors {
NO_ERROR,
NO_COLLATERAL_AVAILABLE,

View File

@ -62,14 +62,11 @@ library ReserveLogic {
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
//tokens addresses
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
address interestRateStrategyAddress;
//the id of the reserve. Represents the position in the list of the active reserves
uint8 id;
}

View File

@ -4,57 +4,56 @@ pragma solidity ^0.6.8;
import {MintableERC20} from '../tokens/MintableERC20.sol';
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
import {ISwapAdapter} from '../../interfaces/ISwapAdapter.sol';
import {ILendingPool} from "../../interfaces/ILendingPool.sol";
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
contract MockSwapAdapter is ISwapAdapter {
uint256 internal _amountToReturn;
bool internal _tryReentrancy;
ILendingPoolAddressesProvider public addressesProvider;
uint256 internal _amountToReturn;
bool internal _tryReentrancy;
ILendingPoolAddressesProvider public addressesProvider;
event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
constructor(ILendingPoolAddressesProvider provider) public {
addressesProvider = provider;
}
constructor(ILendingPoolAddressesProvider provider) public {
addressesProvider = provider;
function setAmountToReturn(uint256 amount) public {
_amountToReturn = amount;
}
function setTryReentrancy(bool tryReentrancy) public {
_tryReentrancy = tryReentrancy;
}
function executeOperation(
address assetToSwapFrom,
address assetToSwapTo,
uint256 amountToSwap,
address fundsDestination,
bytes calldata params
) external override {
params;
IERC20(assetToSwapFrom).transfer(address(1), amountToSwap); // We don't want to keep funds here
MintableERC20(assetToSwapTo).mint(_amountToReturn);
IERC20(assetToSwapTo).approve(fundsDestination, _amountToReturn);
if (_tryReentrancy) {
ILendingPool(fundsDestination).repayWithCollateral(
assetToSwapFrom,
assetToSwapTo,
address(1), // Doesn't matter, we just want to test the reentrancy
1 ether, // Same
address(1), // Same
'0x'
);
}
function setAmountToReturn(uint256 amount) public {
_amountToReturn = amount;
}
emit Swapped(assetToSwapFrom, assetToSwapTo, amountToSwap, _amountToReturn);
}
function setTryReentrancy(bool tryReentrancy) public {
_tryReentrancy = tryReentrancy;
}
function executeOperation(
address assetToSwapFrom,
address assetToSwapTo,
uint256 amountToSwap,
address fundsDestination,
bytes calldata params
) external override {
params;
IERC20(assetToSwapFrom).transfer(address(1), amountToSwap); // We don't want to keep funds here
MintableERC20(assetToSwapTo).mint(_amountToReturn);
IERC20(assetToSwapTo).approve(fundsDestination, _amountToReturn);
if (_tryReentrancy) {
ILendingPool(fundsDestination).repayWithCollateral(
assetToSwapFrom,
assetToSwapTo,
address(1), // Doesn't matter, we just want to test the reentrancy
1 ether, // Same
address(1), // Same
"0x"
);
}
emit Swapped(assetToSwapFrom, assetToSwapTo, amountToSwap, _amountToReturn);
}
function burnAsset(IERC20 asset, uint256 amount) public {
uint256 amountToBurn = (amount == type(uint256).max) ? asset.balanceOf(address(this)) : amount;
asset.transfer(address(0), amountToBurn);
}
function burnAsset(IERC20 asset, uint256 amount) public {
uint256 amountToBurn = (amount == type(uint256).max) ? asset.balanceOf(address(this)) : amount;
asset.transfer(address(0), amountToBurn);
}
}

View File

@ -27,14 +27,18 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
LendingPool public immutable POOL;
/// @dev owner => next valid nonce to submit with permit()
mapping (address => uint256) public _nonces;
mapping(address => uint256) public _nonces;
uint256 public constant ATOKEN_REVISION = 0x1;
bytes32 public DOMAIN_SEPARATOR;
bytes public constant EIP712_REVISION = bytes("1");
bytes32 internal constant EIP712_DOMAIN = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes public constant EIP712_REVISION = bytes('1');
bytes32 internal constant EIP712_DOMAIN = keccak256(
'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
);
bytes32 public constant PERMIT_TYPEHASH = keccak256(
'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'
);
modifier onlyLendingPool {
require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL);
@ -65,16 +69,18 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
//solium-disable-next-line
assembly {
chainId := chainid()
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(abi.encode(
DOMAIN_SEPARATOR = keccak256(
abi.encode(
EIP712_DOMAIN,
keccak256(bytes(tokenName)),
keccak256(EIP712_REVISION),
chainId,
address(this)
));
)
);
_setName(tokenName);
_setSymbol(tokenSymbol);
@ -92,7 +98,6 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
uint256 amount,
uint256 index
) external override onlyLendingPool {
uint256 currentBalance = balanceOf(user);
require(amount <= currentBalance, Errors.INVALID_ATOKEN_BALANCE);
@ -104,6 +109,9 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
//transfers the underlying to the target
IncentivizedERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(receiverOfUnderlying, amount);
//transfer event to track balances
emit Transfer(user, address(0), amount);
emit Burn(msg.sender, receiverOfUnderlying, amount, index);
}
@ -113,14 +121,18 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
* @param user the address receiving the minted tokens
* @param amount the amount of tokens to mint
*/
function mint(address user, uint256 amount, uint256 index) external override onlyLendingPool {
function mint(
address user,
uint256 amount,
uint256 index
) external override onlyLendingPool {
uint256 scaledAmount = amount.rayDiv(index);
//mint an equivalent amount of tokens to cover the new deposit
_mint(user,scaledAmount);
//mint an equivalent amount of tokens to cover the new deposit
_mint(user, scaledAmount);
//transfer event to track balances
emit Transfer(address(0), user, amount);
emit Mint(user, amount, index);
}
@ -208,12 +220,12 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
}
/**
* @dev transfers the underlying asset to the target. Used by the lendingpool to transfer
* assets in borrow(), redeem() and flashLoan()
* @param target the target of the transfer
* @param amount the amount to transfer
* @return the amount transferred
**/
* @dev transfers the underlying asset to the target. Used by the lendingpool to transfer
* assets in borrow(), redeem() and flashLoan()
* @param target the target of the transfer
* @param amount the amount to transfer
* @return the amount transferred
**/
function transferUnderlyingTo(address target, uint256 amount)
external
override
@ -225,39 +237,38 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
}
/**
* @dev implements the permit function as for https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
* @param owner the owner of the funds
* @param spender the spender
* @param value the amount
* @param deadline the deadline timestamp, type(uint256).max for max deadline
* @param v signature param
* @param s signature param
* @param r signature param
*/
* @dev implements the permit function as for https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
* @param owner the owner of the funds
* @param spender the spender
* @param value the amount
* @param deadline the deadline timestamp, type(uint256).max for max deadline
* @param v signature param
* @param s signature param
* @param r signature param
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(owner != address(0), "INVALID_OWNER");
//solium-disable-next-line
require(block.timestamp <= deadline, "INVALID_EXPIRATION");
uint256 currentValidNonce = _nonces[owner];
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(
abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
)
);
require(owner == ecrecover(digest, v, r, s), "INVALID_SIGNATURE");
_nonces[owner] = currentValidNonce.add(1);
_approve(owner, spender, value);
require(owner != address(0), 'INVALID_OWNER');
//solium-disable-next-line
require(block.timestamp <= deadline, 'INVALID_EXPIRATION');
uint256 currentValidNonce = _nonces[owner];
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
)
);
require(owner == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE');
_nonces[owner] = currentValidNonce.add(1);
_approve(owner, spender, value);
}
function _transfer(
@ -265,8 +276,8 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
address to,
uint256 amount,
bool validate
) internal {
if(validate){
) internal {
if (validate) {
require(isTransferAllowed(from, amount), Errors.TRANSFER_NOT_ALLOWED);
}
@ -277,17 +288,16 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
super._transfer(from, to, scaledAmount);
emit BalanceTransfer(from, to, amount, index);
}
function _transfer(
address from,
address to,
uint256 amount
) internal override {
_transfer(from, to, amount, true);
) internal override {
_transfer(from, to, amount, true);
}
/**
* @dev aTokens should not receive ETH
**/

View File

@ -10,16 +10,17 @@ import {IAaveIncentivesController} from '../interfaces/IAaveIncentivesController
/**
* @title ERC20
* @notice Basic ERC20 implementation
* @author Aave
* @author Aave, inspired by the Openzeppelin ERC20 implementation
**/
contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
using SafeMath for uint256;
IAaveIncentivesController internal immutable _incentivesController;
mapping(address => uint256) private _balances;
mapping(address => uint256) internal _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
uint256 internal _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
@ -79,6 +80,7 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
**/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
emit Transfer(msg.sender, recipient, amount);
return true;
}
@ -126,6 +128,7 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
_msgSender(),
_allowances[sender][_msgSender()].sub(amount, 'ERC20: transfer amount exceeds allowance')
);
emit Transfer(sender, recipient, amount);
return true;
}
@ -184,7 +187,6 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
_incentivesController.handleAction(recipient, totalSupply, oldRecipientBalance);
}
}
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
@ -201,8 +203,6 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
if (address(_incentivesController) != address(0)) {
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
}
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
@ -219,8 +219,6 @@ contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
if (address(_incentivesController) != address(0)) {
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
}
emit Transfer(account, address(0), amount);
}
function _approve(

View File

@ -133,6 +133,9 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
_mint(user, amount.add(balanceIncrease));
// transfer event to track balances
emit Transfer(address(0), user, amount);
emit MintDebt(
user,
amount,
@ -181,6 +184,9 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
_burn(user, amount.sub(balanceIncrease));
}
// transfer event to track balances
emit Transfer(user, address(0), amount);
emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease);
}
}

View File

@ -80,6 +80,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
require(newUserIndex < (1 << 128), 'Debt token: Index overflow');
_usersData[user] = newUserIndex;
emit Transfer(address(0), user, amount);
emit MintDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
}
@ -109,6 +110,8 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
}
_usersData[user] = newUserIndex;
// transfer event to track the balances
emit Transfer(user, address(0), amount);
emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
}
}

View File

@ -495,4 +495,4 @@
"address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
}
}
}
}

View File

@ -5,7 +5,7 @@ export enum eEthereumNetwork {
kovan = 'kovan',
ropsten = 'ropsten',
main = 'main',
coverage = 'coverage'
coverage = 'coverage',
}
export enum AavePools {
@ -42,7 +42,7 @@ export enum eContractid {
AaveProtocolTestHelpers = 'AaveProtocolTestHelpers',
IERC20Detailed = 'IERC20Detailed',
StableDebtToken = 'StableDebtToken',
VariableDebtToken = 'VariableDebtToken'
VariableDebtToken = 'VariableDebtToken',
}
export enum ProtocolErrors {
@ -100,6 +100,8 @@ export enum ProtocolErrors {
NO_ERRORS = '42', // 'No errors'
INVALID_FLASHLOAN_MODE = '43', //Invalid flashloan mode
IS_PAUSED = '58', // Pool is paused
// old
INVALID_FROM_BALANCE_AFTER_TRANSFER = 'Invalid from balance after transfer',

261
package-lock.json generated
View File

@ -5138,12 +5138,14 @@
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
@ -5151,7 +5153,8 @@
},
"bindings": {
"version": "1.5.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dev": true,
"requires": {
"file-uri-to-path": "1.0.0"
@ -5159,7 +5162,8 @@
},
"bip66": {
"version": "1.1.5",
"bundled": true,
"resolved": false,
"integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=",
"dev": true,
"requires": {
"safe-buffer": "^5.0.1"
@ -5167,17 +5171,20 @@
},
"bn.js": {
"version": "4.11.8",
"bundled": true,
"resolved": false,
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
"dev": true
},
"brorand": {
"version": "1.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
"dev": true
},
"browserify-aes": {
"version": "1.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"dev": true,
"requires": {
"buffer-xor": "^1.0.3",
@ -5190,22 +5197,26 @@
},
"buffer-from": {
"version": "1.1.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"buffer-xor": {
"version": "1.0.3",
"bundled": true,
"resolved": false,
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
"dev": true
},
"camelcase": {
"version": "5.3.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"cipher-base": {
"version": "1.0.4",
"bundled": true,
"resolved": false,
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
"dev": true,
"requires": {
"inherits": "^2.0.1",
@ -5214,7 +5225,8 @@
},
"cliui": {
"version": "5.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"requires": {
"string-width": "^3.1.0",
@ -5224,7 +5236,8 @@
},
"color-convert": {
"version": "1.9.3",
"bundled": true,
"resolved": false,
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
@ -5232,12 +5245,14 @@
},
"color-name": {
"version": "1.1.3",
"bundled": true,
"resolved": false,
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"create-hash": {
"version": "1.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"dev": true,
"requires": {
"cipher-base": "^1.0.1",
@ -5249,7 +5264,8 @@
},
"create-hmac": {
"version": "1.1.7",
"bundled": true,
"resolved": false,
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true,
"requires": {
"cipher-base": "^1.0.3",
@ -5262,7 +5278,8 @@
},
"cross-spawn": {
"version": "6.0.5",
"bundled": true,
"resolved": false,
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"requires": {
"nice-try": "^1.0.4",
@ -5274,12 +5291,14 @@
},
"decamelize": {
"version": "1.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
"drbg.js": {
"version": "1.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=",
"dev": true,
"requires": {
"browserify-aes": "^1.0.6",
@ -5289,7 +5308,8 @@
},
"elliptic": {
"version": "6.5.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==",
"dev": true,
"requires": {
"bn.js": "^4.4.0",
@ -5303,12 +5323,14 @@
},
"emoji-regex": {
"version": "7.0.3",
"bundled": true,
"resolved": false,
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true
},
"end-of-stream": {
"version": "1.4.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"dev": true,
"requires": {
"once": "^1.4.0"
@ -5316,7 +5338,8 @@
},
"ethereumjs-util": {
"version": "6.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==",
"dev": true,
"requires": {
"bn.js": "^4.11.0",
@ -5330,7 +5353,8 @@
},
"ethjs-util": {
"version": "0.1.6",
"bundled": true,
"resolved": false,
"integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==",
"dev": true,
"requires": {
"is-hex-prefixed": "1.0.0",
@ -5339,7 +5363,8 @@
},
"evp_bytestokey": {
"version": "1.0.3",
"bundled": true,
"resolved": false,
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
"dev": true,
"requires": {
"md5.js": "^1.3.4",
@ -5348,7 +5373,8 @@
},
"execa": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"dev": true,
"requires": {
"cross-spawn": "^6.0.0",
@ -5362,12 +5388,14 @@
},
"file-uri-to-path": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true
},
"find-up": {
"version": "3.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
@ -5375,12 +5403,14 @@
},
"get-caller-file": {
"version": "2.0.5",
"bundled": true,
"resolved": false,
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"get-stream": {
"version": "4.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true,
"requires": {
"pump": "^3.0.0"
@ -5388,7 +5418,8 @@
},
"hash-base": {
"version": "3.0.4",
"bundled": true,
"resolved": false,
"integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
"dev": true,
"requires": {
"inherits": "^2.0.1",
@ -5397,7 +5428,8 @@
},
"hash.js": {
"version": "1.1.7",
"bundled": true,
"resolved": false,
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
@ -5406,7 +5438,8 @@
},
"hmac-drbg": {
"version": "1.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
"dev": true,
"requires": {
"hash.js": "^1.0.3",
@ -5416,37 +5449,44 @@
},
"inherits": {
"version": "2.0.4",
"bundled": true,
"resolved": false,
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"invert-kv": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"is-hex-prefixed": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=",
"dev": true
},
"is-stream": {
"version": "1.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"dev": true
},
"isexe": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"keccak": {
"version": "1.4.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==",
"dev": true,
"requires": {
"bindings": "^1.2.1",
@ -5457,7 +5497,8 @@
},
"lcid": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"requires": {
"invert-kv": "^2.0.0"
@ -5465,7 +5506,8 @@
},
"locate-path": {
"version": "3.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
"p-locate": "^3.0.0",
@ -5474,7 +5516,8 @@
},
"map-age-cleaner": {
"version": "0.1.3",
"bundled": true,
"resolved": false,
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"dev": true,
"requires": {
"p-defer": "^1.0.0"
@ -5482,7 +5525,8 @@
},
"md5.js": {
"version": "1.3.5",
"bundled": true,
"resolved": false,
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
"dev": true,
"requires": {
"hash-base": "^3.0.0",
@ -5492,7 +5536,8 @@
},
"mem": {
"version": "4.3.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
"dev": true,
"requires": {
"map-age-cleaner": "^0.1.1",
@ -5502,32 +5547,38 @@
},
"mimic-fn": {
"version": "2.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
"minimalistic-assert": {
"version": "1.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
"dev": true
},
"minimalistic-crypto-utils": {
"version": "1.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
"dev": true
},
"nan": {
"version": "2.14.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
"dev": true
},
"nice-try": {
"version": "1.0.5",
"bundled": true,
"resolved": false,
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"npm-run-path": {
"version": "2.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
"dev": true,
"requires": {
"path-key": "^2.0.0"
@ -5535,7 +5586,8 @@
},
"once": {
"version": "1.4.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
@ -5543,7 +5595,8 @@
},
"os-locale": {
"version": "3.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true,
"requires": {
"execa": "^1.0.0",
@ -5553,22 +5606,26 @@
},
"p-defer": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
"dev": true
},
"p-finally": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
"dev": true
},
"p-is-promise": {
"version": "2.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
"dev": true
},
"p-limit": {
"version": "2.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
@ -5576,7 +5633,8 @@
},
"p-locate": {
"version": "3.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
"p-limit": "^2.0.0"
@ -5584,22 +5642,26 @@
},
"p-try": {
"version": "2.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"path-exists": {
"version": "3.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
"dev": true
},
"path-key": {
"version": "2.0.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true
},
"pump": {
"version": "3.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
"end-of-stream": "^1.1.0",
@ -5608,17 +5670,20 @@
},
"require-directory": {
"version": "2.1.1",
"bundled": true,
"resolved": false,
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
"require-main-filename": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
"ripemd160": {
"version": "2.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
"dev": true,
"requires": {
"hash-base": "^3.0.0",
@ -5627,7 +5692,8 @@
},
"rlp": {
"version": "2.2.3",
"bundled": true,
"resolved": false,
"integrity": "sha512-l6YVrI7+d2vpW6D6rS05x2Xrmq8oW7v3pieZOJKBEdjuTF4Kz/iwk55Zyh1Zaz+KOB2kC8+2jZlp2u9L4tTzCQ==",
"dev": true,
"requires": {
"bn.js": "^4.11.1",
@ -5636,12 +5702,14 @@
},
"safe-buffer": {
"version": "5.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
"dev": true
},
"secp256k1": {
"version": "3.7.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==",
"dev": true,
"requires": {
"bindings": "^1.5.0",
@ -5656,17 +5724,20 @@
},
"semver": {
"version": "5.7.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"dev": true
},
"set-blocking": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true
},
"sha.js": {
"version": "2.4.11",
"bundled": true,
"resolved": false,
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true,
"requires": {
"inherits": "^2.0.1",
@ -5675,7 +5746,8 @@
},
"shebang-command": {
"version": "1.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true,
"requires": {
"shebang-regex": "^1.0.0"
@ -5683,22 +5755,26 @@
},
"shebang-regex": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
"signal-exit": {
"version": "3.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
"source-map": {
"version": "0.6.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.12",
"bundled": true,
"resolved": false,
"integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
@ -5707,7 +5783,8 @@
},
"string-width": {
"version": "3.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"requires": {
"emoji-regex": "^7.0.1",
@ -5717,7 +5794,8 @@
},
"strip-ansi": {
"version": "5.2.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
@ -5725,12 +5803,14 @@
},
"strip-eof": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
"dev": true
},
"strip-hex-prefix": {
"version": "1.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=",
"dev": true,
"requires": {
"is-hex-prefixed": "1.0.0"
@ -5738,7 +5818,8 @@
},
"which": {
"version": "1.3.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
@ -5746,12 +5827,14 @@
},
"which-module": {
"version": "2.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"wrap-ansi": {
"version": "5.1.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
@ -5761,17 +5844,20 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true,
"resolved": false,
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"y18n": {
"version": "4.0.0",
"bundled": true,
"resolved": false,
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true
},
"yargs": {
"version": "13.2.4",
"bundled": true,
"resolved": false,
"integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
"dev": true,
"requires": {
"cliui": "^5.0.0",
@ -5789,7 +5875,8 @@
},
"yargs-parser": {
"version": "13.1.1",
"bundled": true,
"resolved": false,
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",

View File

@ -15,7 +15,10 @@
"test-scenarios": "buidler test test/__setup.spec.ts test/scenario.spec.ts",
"test-repay-with-collateral": "buidler test test/__setup.spec.ts test/repay-with-collateral.spec.ts",
"test-liquidate-with-collateral": "buidler test test/__setup.spec.ts test/flash-liquidation-with-collateral.spec.ts",
"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-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",
"dev:coverage": "buidler coverage --network coverage",
"dev:deployment": "buidler dev-deployment",

View File

@ -17,6 +17,7 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
// ZERO_COLLATERAL,
COLLATERAL_BALANCE_IS_0,
TRANSFER_NOT_ALLOWED,
IS_PAUSED,
} = ProtocolErrors;
it('User 0 deposits 1000 DAI, transfers to user 1', async () => {
@ -45,7 +46,6 @@ 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;
const userAddress = await pool.signer.getAddress();
@ -92,5 +92,4 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
TRANSFER_NOT_ALLOWED
).to.be.revertedWith(TRANSFER_NOT_ALLOWED);
});
});

View File

@ -17,7 +17,7 @@ const {expect} = require('chai');
const {parseUnits, parseEther} = ethers.utils;
makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEnv) => {
const {INVALID_HF, COLLATERAL_CANNOT_BE_LIQUIDATED} = ProtocolErrors;
const {INVALID_HF, COLLATERAL_CANNOT_BE_LIQUIDATED, IS_PAUSED} = ProtocolErrors;
it('User 1 provides some liquidity for others to borrow', async () => {
const {pool, weth, dai, usdc, deployer} = testEnv;
@ -736,7 +736,9 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
await pool.connect(user.signer).deposit(weth.address, amountToDepositWeth, user.address, '0');
await pool.connect(user.signer).deposit(dai.address, amountToDepositDAI, user.address, '0');
await pool.connect(user.signer).borrow(usdc.address, amountToBorrowVariable, 2, 0, user.address);
await pool
.connect(user.signer)
.borrow(usdc.address, amountToBorrowVariable, 2, 0, user.address);
const amountToRepay = amountToBorrowVariable;

View File

@ -23,6 +23,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
TRANSFER_AMOUNT_EXCEEDS_BALANCE,
INVALID_FLASHLOAN_MODE,
SAFEERC20_LOWLEVEL_CALL,
IS_PAUSED,
} = ProtocolErrors;
before(async () => {

View File

@ -54,7 +54,6 @@ const almostEqualOrEqual = function (
return;
}
this.assert(actual[key] != undefined, `Property ${key} is undefined in the actual data`);
expect(expected[key] != undefined, `Property ${key} is undefined in the expected data`);
@ -63,10 +62,9 @@ const almostEqualOrEqual = function (
}
if (actual[key] instanceof BigNumber) {
const actualValue = (<BigNumber>actual[key]).decimalPlaces(0, BigNumber.ROUND_DOWN);
const expectedValue = (<BigNumber>expected[key]).decimalPlaces(0, BigNumber.ROUND_DOWN);
this.assert(
actualValue.eq(expectedValue) ||
actualValue.plus(1).eq(expectedValue) ||

View File

@ -230,7 +230,7 @@ const executeAction = async (action: Action, users: SignerWithAddress[], testEnv
await rebalanceStableBorrowRate(reserve, user, target, expected, testEnv, revertMessage);
}
break;
default:
throw `Invalid action requested: ${name}`;
}

View File

@ -539,7 +539,7 @@ export const calcExpectedUserDataAfterBorrow = (
currentTimestamp
);
expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance;
expectedUserData.walletBalance = userDataBeforeAction.walletBalance.plus(amountBorrowed);
return expectedUserData;
@ -623,7 +623,7 @@ export const calcExpectedUserDataAfterRepay = (
txTimestamp
);
expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance;
if (user === onBehalfOf) {
expectedUserData.walletBalance = userDataBeforeAction.walletBalance.minus(totalRepaid);
} else {
@ -926,9 +926,7 @@ export const calcExpectedATokenBalance = (
) => {
const index = calcExpectedReserveNormalizedIncome(reserveDataBeforeAction, currentTimestamp);
const {
scaledATokenBalance: scaledBalanceBeforeAction,
} = userDataBeforeAction;
const {scaledATokenBalance: scaledBalanceBeforeAction} = userDataBeforeAction;
return scaledBalanceBeforeAction.rayMul(index);
};

View File

@ -17,6 +17,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
INVALID_HF,
SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER,
COLLATERAL_CANNOT_BE_LIQUIDATED,
IS_PAUSED,
} = ProtocolErrors;
it('LIQUIDATION - Deposits WETH, borrows DAI/Check liquidation fails because health factor is above 1', async () => {

View File

@ -0,0 +1,378 @@
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 {parseEther, parseUnits} from 'ethers/lib/utils';
import {BigNumber} from 'bignumber.js';
import {MockFlashLoanReceiver} from '../types/MockFlashLoanReceiver';
const {expect} = require('chai');
makeSuite('Pausable Pool', (testEnv: TestEnv) => {
let _mockFlashLoanReceiver = {} as MockFlashLoanReceiver;
const {
IS_PAUSED,
TRANSFER_NOT_ALLOWED,
INVALID_FROM_BALANCE_AFTER_TRANSFER,
INVALID_TO_BALANCE_AFTER_TRANSFER,
} = ProtocolErrors;
before(async () => {
_mockFlashLoanReceiver = await getMockFlashLoanReceiver();
});
it('User 0 deposits 1000 DAI. Configurator pauses pool. Transfers to user 1 reverts. Configurator unpauses the network and next transfer succees', async () => {
const {users, pool, dai, aDai, configurator} = testEnv;
const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
await dai.connect(users[0].signer).mint(amountDAItoDeposit);
// user 0 deposits 1000 DAI
await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool
.connect(users[0].signer)
.deposit(dai.address, amountDAItoDeposit, users[0].address, '0');
const user0Balance = await aDai.balanceOf(users[0].address);
const user1Balance = await aDai.balanceOf(users[1].address);
// Configurator pauses the pool
await configurator.setPoolPause(true);
// User 0 tries the transfer to User 1
await expect(
aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit)
).to.revertedWith(IS_PAUSED);
const pausedFromBalance = await aDai.balanceOf(users[0].address);
const pausedToBalance = await aDai.balanceOf(users[1].address);
expect(pausedFromBalance).to.be.equal(
user0Balance.toString(),
INVALID_TO_BALANCE_AFTER_TRANSFER
);
expect(pausedToBalance.toString()).to.be.equal(
user1Balance.toString(),
INVALID_FROM_BALANCE_AFTER_TRANSFER
);
// Configurator unpauses the pool
await configurator.setPoolPause(false);
// User 0 succeeds transfer to User 1
await aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit);
const fromBalance = await aDai.balanceOf(users[0].address);
const toBalance = await aDai.balanceOf(users[1].address);
expect(fromBalance.toString()).to.be.equal(
user0Balance.sub(amountDAItoDeposit),
INVALID_FROM_BALANCE_AFTER_TRANSFER
);
expect(toBalance.toString()).to.be.equal(
user1Balance.add(amountDAItoDeposit),
INVALID_TO_BALANCE_AFTER_TRANSFER
);
});
it('Deposit', async () => {
const {users, pool, dai, aDai, configurator} = testEnv;
const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
await dai.connect(users[0].signer).mint(amountDAItoDeposit);
// user 0 deposits 1000 DAI
await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
// Configurator pauses the pool
await configurator.setPoolPause(true);
await expect(
pool.connect(users[0].signer).deposit(dai.address, amountDAItoDeposit, users[0].address, '0')
).to.revertedWith(IS_PAUSED);
// Configurator unpauses the pool
await configurator.setPoolPause(false);
});
it('Withdraw', async () => {
const {users, pool, dai, aDai, configurator} = testEnv;
const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
await dai.connect(users[0].signer).mint(amountDAItoDeposit);
// user 0 deposits 1000 DAI
await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool
.connect(users[0].signer)
.deposit(dai.address, amountDAItoDeposit, users[0].address, '0');
// Configurator pauses the pool
await configurator.setPoolPause(true);
// user tries to burn
await expect(
pool.connect(users[0].signer).withdraw(dai.address, amountDAItoDeposit)
).to.revertedWith(IS_PAUSED);
// Configurator unpauses the pool
await configurator.setPoolPause(false);
});
it('DelegateBorrowAllowance', async () => {
const {pool, dai, users, configurator} = testEnv;
const user = users[1];
const toUser = users[2];
// Pause the pool
await configurator.setPoolPause(true);
// Try to execute liquidation
await expect(
pool.connect(user.signer).delegateBorrowAllowance(dai.address, toUser.address, '1', '1')
).revertedWith(IS_PAUSED);
// Unpause the pool
await configurator.setPoolPause(false);
});
it('Borrow', async () => {
const {pool, dai, users, configurator} = testEnv;
const user = users[1];
// Pause the pool
await configurator.setPoolPause(true);
// Try to execute liquidation
await expect(
pool.connect(user.signer).borrow(dai.address, '1', '1', '0', user.address)
).revertedWith(IS_PAUSED);
// Unpause the pool
await configurator.setPoolPause(false);
});
it('Swap liquidity', async () => {
const {pool, dai, weth, users, configurator} = testEnv;
const user = users[1];
// Pause the pool
await configurator.setPoolPause(true);
// Try to execute liquidation
await expect(
pool.connect(user.signer).swapLiquidity(user.address, dai.address, weth.address, '1', '0x')
).revertedWith(IS_PAUSED);
// Unpause the pool
await configurator.setPoolPause(false);
});
it('Repay', async () => {
const {pool, dai, users, configurator} = testEnv;
const user = users[1];
// Pause the pool
await configurator.setPoolPause(true);
// Try to execute liquidation
await expect(pool.connect(user.signer).repay(dai.address, '1', '1', user.address)).revertedWith(
IS_PAUSED
);
// Unpause the pool
await configurator.setPoolPause(false);
});
it('Repay with collateral', async () => {
const {pool, weth, dai, usdc, users, mockSwapAdapter, oracle, configurator} = testEnv;
const user = users[6];
const liquidator = users[5];
// Pause the pool
await configurator.setPoolPause(true);
// Try to execute liquidation
await expect(
pool
.connect(liquidator.signer)
.repayWithCollateral(
weth.address,
usdc.address,
user.address,
'1',
mockSwapAdapter.address,
'0x'
)
).revertedWith(IS_PAUSED);
// Unpause the pool
await configurator.setPoolPause(false);
});
it('Flash loan', async () => {
const {dai, pool, weth, users, configurator} = testEnv;
const caller = users[3];
const flashAmount = parseEther('0.8');
await _mockFlashLoanReceiver.setFailExecutionTransfer(true);
// Pause pool
await configurator.setPoolPause(true);
await expect(
pool
.connect(caller.signer)
.flashLoan(_mockFlashLoanReceiver.address, weth.address, flashAmount, 1, '0x10', '0')
).revertedWith(IS_PAUSED);
// Unpause pool
await configurator.setPoolPause(false);
});
it('Liquidation call', async () => {
const {users, pool, usdc, oracle, weth, configurator} = testEnv;
const depositor = users[3];
const borrower = users[4];
//mints USDC to depositor
await usdc
.connect(depositor.signer)
.mint(await convertToCurrencyDecimals(usdc.address, '1000'));
//approve protocol to access depositor wallet
await usdc.connect(depositor.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
//user 3 deposits 1000 USDC
const amountUSDCtoDeposit = await convertToCurrencyDecimals(usdc.address, '1000');
await pool
.connect(depositor.signer)
.deposit(usdc.address, amountUSDCtoDeposit, depositor.address, '0');
//user 4 deposits 1 ETH
const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1');
//mints WETH to borrower
await weth.connect(borrower.signer).mint(amountETHtoDeposit);
//approve protocol to access borrower wallet
await weth.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool
.connect(borrower.signer)
.deposit(weth.address, amountETHtoDeposit, borrower.address, '0');
//user 4 borrows
const userGlobalData = await pool.getUserAccountData(borrower.address);
const usdcPrice = await oracle.getAssetPrice(usdc.address);
const amountUSDCToBorrow = await convertToCurrencyDecimals(
usdc.address,
new BigNumber(userGlobalData.availableBorrowsETH.toString())
.div(usdcPrice.toString())
.multipliedBy(0.9502)
.toFixed(0)
);
await pool
.connect(borrower.signer)
.borrow(usdc.address, amountUSDCToBorrow, RateMode.Stable, '0', borrower.address);
// Drops HF below 1
await oracle.setAssetPrice(
usdc.address,
new BigNumber(usdcPrice.toString()).multipliedBy(1.2).toFixed(0)
);
//mints dai to the liquidator
await usdc.mint(await convertToCurrencyDecimals(usdc.address, '1000'));
await usdc.approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
const userReserveDataBefore = await pool.getUserReserveData(usdc.address, borrower.address);
const amountToLiquidate = new BigNumber(userReserveDataBefore.currentStableDebt.toString())
.multipliedBy(0.5)
.toFixed(0);
// Pause pool
await configurator.setPoolPause(true);
// Do liquidation
expect(
pool.liquidationCall(weth.address, usdc.address, borrower.address, amountToLiquidate, true)
).revertedWith(IS_PAUSED);
// Unpause pool
await configurator.setPoolPause(false);
});
it('SwapBorrowRateMode', async () => {
const {pool, weth, dai, usdc, users, configurator, mockSwapAdapter} = testEnv;
const user = users[1];
const amountWETHToDeposit = parseEther('10');
const amountDAIToDeposit = parseEther('120');
const amountToBorrow = parseUnits('65', 6);
await weth.connect(user.signer).mint(amountWETHToDeposit);
await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0');
await dai.connect(user.signer).mint(amountDAIToDeposit);
await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool.connect(user.signer).deposit(dai.address, amountDAIToDeposit, user.address, '0');
await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address);
// Pause pool
await configurator.setPoolPause(true);
// Try to repay
await expect(
pool.connect(user.signer).swapBorrowRateMode(usdc.address, RateMode.Stable)
).revertedWith(IS_PAUSED);
// Unpause pool
await configurator.setPoolPause(false);
});
it('RebalanceStableBorrowRate', async () => {
const {pool, dai, users, configurator} = testEnv;
const user = users[1];
// Pause pool
await configurator.setPoolPause(true);
await expect(
pool.connect(user.signer).rebalanceStableBorrowRate(dai.address, user.address)
).revertedWith(IS_PAUSED);
// Unpause pool
await configurator.setPoolPause(false);
});
it('setUserUseReserveAsCollateral', async () => {
const {pool, weth, users, configurator} = testEnv;
const user = users[1];
const amountWETHToDeposit = parseEther('1');
await weth.connect(user.signer).mint(amountWETHToDeposit);
await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0');
// Pause pool
await configurator.setPoolPause(true);
await expect(
pool.connect(user.signer).setUserUseReserveAsCollateral(weth.address, false)
).revertedWith(IS_PAUSED);
// Unpause pool
await configurator.setPoolPause(false);
});
});

View File

@ -9,7 +9,7 @@ import {
import {getContractsData} from './helpers/actions';
import {waitForTx} from './__setup.spec';
import {timeLatest} from '../helpers/misc-utils';
import {tEthereumAddress} from '../helpers/types';
import {ProtocolErrors, tEthereumAddress} from '../helpers/types';
import {parse} from 'path';
const {expect} = require('chai');
@ -39,6 +39,7 @@ export const expectRepayWithCollateralEvent = (
};
makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => {
const {IS_PAUSED} = ProtocolErrors;
it("It's not possible to repayWithCollateral() on a non-active collateral or a non active principal", async () => {
const {configurator, weth, pool, users, dai, mockSwapAdapter} = testEnv;
const user = users[1];
@ -347,7 +348,9 @@ makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => {
await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0');
await pool.connect(user.signer).borrow(usdc.address, amountToBorrowVariable, 2, 0, user.address);
await pool
.connect(user.signer)
.borrow(usdc.address, amountToBorrowVariable, 2, 0, user.address);
await pool.connect(user.signer).borrow(usdc.address, amountToBorrowStable, 1, 0, user.address);