mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Merge branch 'master' of gitlab.com:aave-tech/protocol-v2
This commit is contained in:
commit
d06e3a39fc
|
@ -2,6 +2,7 @@ import {usePlugin} from '@nomiclabs/buidler/config';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import {accounts} from './test-wallets.js';
|
import {accounts} from './test-wallets.js';
|
||||||
import {eEthereumNetwork} from './helpers/types';
|
import {eEthereumNetwork} from './helpers/types';
|
||||||
|
import {BUIDLEREVM_CHAINID, COVERAGE_CHAINID} from './helpers/buidler-constants';
|
||||||
|
|
||||||
usePlugin('@nomiclabs/buidler-ethers');
|
usePlugin('@nomiclabs/buidler-ethers');
|
||||||
usePlugin('buidler-typechain');
|
usePlugin('buidler-typechain');
|
||||||
|
@ -9,9 +10,6 @@ usePlugin('solidity-coverage');
|
||||||
usePlugin('@nomiclabs/buidler-waffle');
|
usePlugin('@nomiclabs/buidler-waffle');
|
||||||
usePlugin('@nomiclabs/buidler-etherscan');
|
usePlugin('@nomiclabs/buidler-etherscan');
|
||||||
//usePlugin('buidler-gas-reporter');
|
//usePlugin('buidler-gas-reporter');
|
||||||
|
|
||||||
const BUIDLEREVM_CHAINID = 31337;
|
|
||||||
const COVERAGE_CHAINID = 1337;
|
|
||||||
const DEFAULT_BLOCK_GAS_LIMIT = 10000000;
|
const DEFAULT_BLOCK_GAS_LIMIT = 10000000;
|
||||||
const DEFAULT_GAS_PRICE = 10;
|
const DEFAULT_GAS_PRICE = 10;
|
||||||
const HARDFORK = 'istanbul';
|
const HARDFORK = 'istanbul';
|
||||||
|
|
11
contracts/interfaces/IAaveIncentivesController.sol
Normal file
11
contracts/interfaces/IAaveIncentivesController.sol
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
|
pragma solidity 0.6.8;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
interface IAaveIncentivesController {
|
||||||
|
function handleAction(
|
||||||
|
address user,
|
||||||
|
uint256 userBalance,
|
||||||
|
uint256 totalSupply
|
||||||
|
) external;
|
||||||
|
}
|
|
@ -137,6 +137,15 @@ interface ILendingPool {
|
||||||
address liquidator,
|
address liquidator,
|
||||||
bool receiveAToken
|
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)
|
* @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);
|
) external view returns (bool);
|
||||||
|
|
||||||
function getReserves() external view returns (address[] memory);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,20 +2,19 @@
|
||||||
pragma solidity ^0.6.8;
|
pragma solidity ^0.6.8;
|
||||||
|
|
||||||
interface ISwapAdapter {
|
interface ISwapAdapter {
|
||||||
|
/**
|
||||||
/**
|
* @dev Swaps an `amountToSwap` of an asset to another, approving a `fundsDestination` to pull the funds
|
||||||
* @dev Swaps an `amountToSwap` of an asset to another, approving a `fundsDestination` to pull the funds
|
* @param assetToSwapFrom Origin asset
|
||||||
* @param assetToSwapFrom Origin asset
|
* @param assetToSwapTo Destination asset
|
||||||
* @param assetToSwapTo Destination asset
|
* @param amountToSwap How much `assetToSwapFrom` needs to be swapped
|
||||||
* @param amountToSwap How much `assetToSwapFrom` needs to be swapped
|
* @param fundsDestination Address that will be pulling the swapped funds
|
||||||
* @param fundsDestination Address that will be pulling the swapped funds
|
* @param params Additional variadic field to include extra params
|
||||||
* @param params Additional variadic field to include extra params
|
*/
|
||||||
*/
|
function executeOperation(
|
||||||
function executeOperation(
|
address assetToSwapFrom,
|
||||||
address assetToSwapFrom,
|
address assetToSwapTo,
|
||||||
address assetToSwapTo,
|
uint256 amountToSwap,
|
||||||
uint256 amountToSwap,
|
address fundsDestination,
|
||||||
address fundsDestination,
|
bytes calldata params
|
||||||
bytes calldata params
|
) external;
|
||||||
) external;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
address[] internal _reservesList;
|
address[] internal _reservesList;
|
||||||
|
|
||||||
bool internal _flashLiquidationLocked;
|
bool internal _flashLiquidationLocked;
|
||||||
|
bool internal _paused;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev only lending pools configurator can use functions affected by this modifier
|
* @dev only lending pools configurator can use functions affected by this modifier
|
||||||
|
@ -66,6 +67,17 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
||||||
|
|
||||||
uint256 public constant LENDINGPOOL_REVISION = 0x2;
|
uint256 public constant LENDINGPOOL_REVISION = 0x2;
|
||||||
|
@ -96,6 +108,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
address onBehalfOf,
|
address onBehalfOf,
|
||||||
uint16 referralCode
|
uint16 referralCode
|
||||||
) external override {
|
) external override {
|
||||||
|
whenNotPaused();
|
||||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||||
|
|
||||||
ValidationLogic.validateDeposit(reserve, amount);
|
ValidationLogic.validateDeposit(reserve, amount);
|
||||||
|
@ -124,6 +137,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
* @param amount the underlying amount to be redeemed
|
* @param amount the underlying amount to be redeemed
|
||||||
**/
|
**/
|
||||||
function withdraw(address asset, uint256 amount) external override {
|
function withdraw(address asset, uint256 amount) external override {
|
||||||
|
whenNotPaused();
|
||||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||||
|
|
||||||
address aToken = reserve.aTokenAddress;
|
address aToken = reserve.aTokenAddress;
|
||||||
|
@ -184,6 +198,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
uint256 interestRateMode,
|
uint256 interestRateMode,
|
||||||
uint256 amount
|
uint256 amount
|
||||||
) external override {
|
) external override {
|
||||||
|
whenNotPaused();
|
||||||
address debtToken = _reserves[asset].getDebtTokenAddress(interestRateMode);
|
address debtToken = _reserves[asset].getDebtTokenAddress(interestRateMode);
|
||||||
|
|
||||||
_borrowAllowance[debtToken][msg.sender][user] = amount;
|
_borrowAllowance[debtToken][msg.sender][user] = amount;
|
||||||
|
@ -206,6 +221,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
uint16 referralCode,
|
uint16 referralCode,
|
||||||
address onBehalfOf
|
address onBehalfOf
|
||||||
) external override {
|
) external override {
|
||||||
|
whenNotPaused();
|
||||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||||
|
|
||||||
if (onBehalfOf != msg.sender) {
|
if (onBehalfOf != msg.sender) {
|
||||||
|
@ -245,6 +261,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
uint256 rateMode,
|
uint256 rateMode,
|
||||||
address onBehalfOf
|
address onBehalfOf
|
||||||
) external override {
|
) external override {
|
||||||
|
whenNotPaused();
|
||||||
_executeRepay(asset, msg.sender, amount, rateMode, onBehalfOf);
|
_executeRepay(asset, msg.sender, amount, rateMode, onBehalfOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +323,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
* @param rateMode the rate mode that the user wants to swap
|
* @param rateMode the rate mode that the user wants to swap
|
||||||
**/
|
**/
|
||||||
function swapBorrowRateMode(address asset, uint256 rateMode) external override {
|
function swapBorrowRateMode(address asset, uint256 rateMode) external override {
|
||||||
|
whenNotPaused();
|
||||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||||
|
|
||||||
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
|
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
|
||||||
|
@ -349,6 +367,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
* @param user the address of the user to be rebalanced
|
* @param user the address of the user to be rebalanced
|
||||||
**/
|
**/
|
||||||
function rebalanceStableBorrowRate(address asset, address user) external override {
|
function rebalanceStableBorrowRate(address asset, address user) external override {
|
||||||
|
whenNotPaused();
|
||||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||||
|
|
||||||
IStableDebtToken stableDebtToken = IStableDebtToken(reserve.stableDebtTokenAddress);
|
IStableDebtToken stableDebtToken = IStableDebtToken(reserve.stableDebtTokenAddress);
|
||||||
|
@ -394,6 +413,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
* @param useAsCollateral true if the user wants to user the deposit as collateral, false otherwise.
|
* @param useAsCollateral true if the user wants to user the deposit as collateral, false otherwise.
|
||||||
**/
|
**/
|
||||||
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external override {
|
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external override {
|
||||||
|
whenNotPaused();
|
||||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||||
|
|
||||||
ValidationLogic.validateSetUseReserveAsCollateral(
|
ValidationLogic.validateSetUseReserveAsCollateral(
|
||||||
|
@ -430,6 +450,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
uint256 purchaseAmount,
|
uint256 purchaseAmount,
|
||||||
bool receiveAToken
|
bool receiveAToken
|
||||||
) external override {
|
) external override {
|
||||||
|
whenNotPaused();
|
||||||
address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
|
address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
|
@ -473,6 +494,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
address receiver,
|
address receiver,
|
||||||
bytes calldata params
|
bytes calldata params
|
||||||
) external override {
|
) external override {
|
||||||
|
whenNotPaused();
|
||||||
require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED);
|
require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED);
|
||||||
_flashLiquidationLocked = true;
|
_flashLiquidationLocked = true;
|
||||||
|
|
||||||
|
@ -528,6 +550,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
bytes calldata params,
|
bytes calldata params,
|
||||||
uint16 referralCode
|
uint16 referralCode
|
||||||
) external override {
|
) external override {
|
||||||
|
whenNotPaused();
|
||||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||||
FlashLoanLocalVars memory vars;
|
FlashLoanLocalVars memory vars;
|
||||||
|
|
||||||
|
@ -589,6 +612,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
uint256 amountToSwap,
|
uint256 amountToSwap,
|
||||||
bytes calldata params
|
bytes calldata params
|
||||||
) external override {
|
) external override {
|
||||||
|
whenNotPaused();
|
||||||
address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
|
address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
|
@ -961,6 +985,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
address user,
|
address user,
|
||||||
uint256 amount
|
uint256 amount
|
||||||
) external override view returns (bool) {
|
) external override view returns (bool) {
|
||||||
|
whenNotPaused();
|
||||||
return
|
return
|
||||||
GenericLogic.balanceDecreaseAllowed(
|
GenericLogic.balanceDecreaseAllowed(
|
||||||
asset,
|
asset,
|
||||||
|
@ -986,4 +1011,26 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
|
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
|
||||||
return _addressesProvider;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -582,4 +582,12 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
||||||
|
|
||||||
proxy.upgradeToAndCall(implementation, params);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
|
||||||
* @title LendingPoolLiquidationManager contract
|
* @title LendingPoolLiquidationManager contract
|
||||||
* @author Aave
|
* @author Aave
|
||||||
* @notice Implements the liquidation function.
|
* @notice Implements the liquidation function.
|
||||||
|
* @dev LendingPoolLiquidationManager inherits Pausable from OpenZeppelin to have the same storage layout as LendingPool
|
||||||
**/
|
**/
|
||||||
contract LendingPoolLiquidationManager is VersionedInitializable {
|
contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
@ -49,6 +50,7 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
address[] internal reservesList;
|
address[] internal reservesList;
|
||||||
|
|
||||||
bool internal _flashLiquidationLocked;
|
bool internal _flashLiquidationLocked;
|
||||||
|
bool public _paused;
|
||||||
|
|
||||||
uint256 internal constant LIQUIDATION_CLOSE_FACTOR_PERCENT = 5000;
|
uint256 internal constant LIQUIDATION_CLOSE_FACTOR_PERCENT = 5000;
|
||||||
|
|
||||||
|
@ -512,6 +514,11 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
|
||||||
address(vars.toReserveAToken),
|
address(vars.toReserveAToken),
|
||||||
vars.amountToReceive
|
vars.amountToReceive
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (vars.toReserveAToken.balanceOf(msg.sender) == 0) {
|
||||||
|
usersConfig[msg.sender].setUsingAsCollateral(toReserve.id, true);
|
||||||
|
}
|
||||||
|
|
||||||
vars.toReserveAToken.mint(msg.sender, vars.amountToReceive, toReserve.liquidityIndex);
|
vars.toReserveAToken.mint(msg.sender, vars.amountToReceive, toReserve.liquidityIndex);
|
||||||
toReserve.updateInterestRates(
|
toReserve.updateInterestRates(
|
||||||
toAsset,
|
toAsset,
|
||||||
|
|
|
@ -49,8 +49,8 @@ library Errors {
|
||||||
string public constant CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = '30'; // 'User cannot give allowance to himself'
|
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 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
|
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 RESERVE_ALREADY_INITIALIZED = '34'; // 'Reserve has already been initialized'
|
||||||
string public constant LIQUIDITY_INDEX_OVERFLOW = '47'; // Liquidity index overflows uint128
|
string public constant LIQUIDITY_INDEX_OVERFLOW = '47'; // Liquidity index overflows uint128
|
||||||
string public constant VARIABLE_BORROW_INDEX_OVERFLOW = '48'; // Variable borrow 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 ADDITION_OVERFLOW = '45';
|
||||||
string public constant DIVISION_BY_ZERO = '46';
|
string public constant DIVISION_BY_ZERO = '46';
|
||||||
|
|
||||||
|
// pausable error message
|
||||||
|
string public constant IS_PAUSED = '58'; // 'Pool is paused'
|
||||||
enum LiquidationErrors {
|
enum LiquidationErrors {
|
||||||
NO_ERROR,
|
NO_ERROR,
|
||||||
NO_COLLATERAL_AVAILABLE,
|
NO_COLLATERAL_AVAILABLE,
|
||||||
|
@ -86,6 +88,7 @@ library Errors {
|
||||||
NOT_ENOUGH_LIQUIDITY,
|
NOT_ENOUGH_LIQUIDITY,
|
||||||
NO_ACTIVE_RESERVE,
|
NO_ACTIVE_RESERVE,
|
||||||
HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,
|
HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,
|
||||||
INVALID_EQUAL_ASSETS_TO_SWAP
|
INVALID_EQUAL_ASSETS_TO_SWAP,
|
||||||
|
NO_UNFREEZED_RESERVE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,14 +62,11 @@ library ReserveLogic {
|
||||||
//the current stable borrow rate. Expressed in ray
|
//the current stable borrow rate. Expressed in ray
|
||||||
uint128 currentStableBorrowRate;
|
uint128 currentStableBorrowRate;
|
||||||
uint40 lastUpdateTimestamp;
|
uint40 lastUpdateTimestamp;
|
||||||
|
|
||||||
//tokens addresses
|
//tokens addresses
|
||||||
address aTokenAddress;
|
address aTokenAddress;
|
||||||
address stableDebtTokenAddress;
|
address stableDebtTokenAddress;
|
||||||
address variableDebtTokenAddress;
|
address variableDebtTokenAddress;
|
||||||
|
|
||||||
address interestRateStrategyAddress;
|
address interestRateStrategyAddress;
|
||||||
|
|
||||||
//the id of the reserve. Represents the position in the list of the active reserves
|
//the id of the reserve. Represents the position in the list of the active reserves
|
||||||
uint8 id;
|
uint8 id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,16 +452,19 @@ library ValidationLogic {
|
||||||
address fromAsset,
|
address fromAsset,
|
||||||
address toAsset
|
address toAsset
|
||||||
) internal view returns (uint256, string memory) {
|
) internal view returns (uint256, string memory) {
|
||||||
if (!fromReserve.configuration.getActive() || !toReserve.configuration.getActive()) {
|
|
||||||
return (uint256(Errors.LiquidationErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fromAsset == toAsset) {
|
if (fromAsset == toAsset) {
|
||||||
return (
|
return (
|
||||||
uint256(Errors.LiquidationErrors.INVALID_EQUAL_ASSETS_TO_SWAP),
|
uint256(Errors.LiquidationErrors.INVALID_EQUAL_ASSETS_TO_SWAP),
|
||||||
Errors.INVALID_EQUAL_ASSETS_TO_SWAP
|
Errors.INVALID_EQUAL_ASSETS_TO_SWAP
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
(bool isToActive, bool isToFreezed, , ) = toReserve.configuration.getFlags();
|
||||||
|
if (!fromReserve.configuration.getActive() || !isToActive) {
|
||||||
|
return (uint256(Errors.LiquidationErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE);
|
||||||
|
}
|
||||||
|
if (isToFreezed) {
|
||||||
|
return (uint256(Errors.LiquidationErrors.NO_UNFREEZED_RESERVE), Errors.NO_UNFREEZED_RESERVE);
|
||||||
|
}
|
||||||
|
|
||||||
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
return (uint256(Errors.LiquidationErrors.NO_ERROR), Errors.NO_ERRORS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,57 +4,56 @@ pragma solidity ^0.6.8;
|
||||||
import {MintableERC20} from '../tokens/MintableERC20.sol';
|
import {MintableERC20} from '../tokens/MintableERC20.sol';
|
||||||
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
|
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
|
||||||
import {ISwapAdapter} from '../../interfaces/ISwapAdapter.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';
|
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
|
||||||
|
|
||||||
contract MockSwapAdapter is ISwapAdapter {
|
contract MockSwapAdapter is ISwapAdapter {
|
||||||
|
uint256 internal _amountToReturn;
|
||||||
|
bool internal _tryReentrancy;
|
||||||
|
ILendingPoolAddressesProvider public addressesProvider;
|
||||||
|
|
||||||
uint256 internal _amountToReturn;
|
event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
|
||||||
bool internal _tryReentrancy;
|
|
||||||
ILendingPoolAddressesProvider public addressesProvider;
|
|
||||||
|
|
||||||
event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
|
constructor(ILendingPoolAddressesProvider provider) public {
|
||||||
|
addressesProvider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(ILendingPoolAddressesProvider provider) public {
|
function setAmountToReturn(uint256 amount) public {
|
||||||
addressesProvider = provider;
|
_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 {
|
emit Swapped(assetToSwapFrom, assetToSwapTo, amountToSwap, _amountToReturn);
|
||||||
_amountToReturn = amount;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function setTryReentrancy(bool tryReentrancy) public {
|
function burnAsset(IERC20 asset, uint256 amount) public {
|
||||||
_tryReentrancy = tryReentrancy;
|
uint256 amountToBurn = (amount == type(uint256).max) ? asset.balanceOf(address(this)) : amount;
|
||||||
}
|
asset.transfer(address(0), amountToBurn);
|
||||||
|
}
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@ contract MockAToken is AToken {
|
||||||
LendingPool _pool,
|
LendingPool _pool,
|
||||||
address _underlyingAssetAddress,
|
address _underlyingAssetAddress,
|
||||||
string memory _tokenName,
|
string memory _tokenName,
|
||||||
string memory _tokenSymbol
|
string memory _tokenSymbol,
|
||||||
) public AToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol) {}
|
address incentivesController
|
||||||
|
) public AToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol, incentivesController) {}
|
||||||
|
|
||||||
function getRevision() internal override pure returns (uint256) {
|
function getRevision() internal override pure returns (uint256) {
|
||||||
return 0x2;
|
return 0x2;
|
||||||
|
|
|
@ -9,8 +9,12 @@ contract MockStableDebtToken is StableDebtToken {
|
||||||
address _pool,
|
address _pool,
|
||||||
address _underlyingAssetAddress,
|
address _underlyingAssetAddress,
|
||||||
string memory _tokenName,
|
string memory _tokenName,
|
||||||
string memory _tokenSymbol
|
string memory _tokenSymbol,
|
||||||
) public StableDebtToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol) {}
|
address incentivesController
|
||||||
|
)
|
||||||
|
public
|
||||||
|
StableDebtToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol, incentivesController)
|
||||||
|
{}
|
||||||
|
|
||||||
function getRevision() internal override pure returns (uint256) {
|
function getRevision() internal override pure returns (uint256) {
|
||||||
return 0x2;
|
return 0x2;
|
||||||
|
|
|
@ -9,8 +9,18 @@ contract MockVariableDebtToken is VariableDebtToken {
|
||||||
address _pool,
|
address _pool,
|
||||||
address _underlyingAssetAddress,
|
address _underlyingAssetAddress,
|
||||||
string memory _tokenName,
|
string memory _tokenName,
|
||||||
string memory _tokenSymbol
|
string memory _tokenSymbol,
|
||||||
) public VariableDebtToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol) {}
|
address incentivesController
|
||||||
|
)
|
||||||
|
public
|
||||||
|
VariableDebtToken(
|
||||||
|
_pool,
|
||||||
|
_underlyingAssetAddress,
|
||||||
|
_tokenName,
|
||||||
|
_tokenSymbol,
|
||||||
|
incentivesController
|
||||||
|
)
|
||||||
|
{}
|
||||||
|
|
||||||
function getRevision() internal override pure returns (uint256) {
|
function getRevision() internal override pure returns (uint256) {
|
||||||
return 0x2;
|
return 0x2;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-License-Identifier: agpl-3.0
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
pragma solidity ^0.6.8;
|
pragma solidity ^0.6.8;
|
||||||
|
|
||||||
import {ERC20} from './ERC20.sol';
|
import {IncentivizedERC20} from './IncentivizedERC20.sol';
|
||||||
import {LendingPool} from '../lendingpool/LendingPool.sol';
|
import {LendingPool} from '../lendingpool/LendingPool.sol';
|
||||||
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
||||||
import {Errors} from '../libraries/helpers/Errors.sol';
|
import {Errors} from '../libraries/helpers/Errors.sol';
|
||||||
|
@ -18,23 +18,27 @@ import {SafeERC20} from '../misc/SafeERC20.sol';
|
||||||
* @dev Implementation of the interest bearing token for the DLP protocol.
|
* @dev Implementation of the interest bearing token for the DLP protocol.
|
||||||
* @author Aave
|
* @author Aave
|
||||||
*/
|
*/
|
||||||
contract AToken is VersionedInitializable, ERC20, IAToken {
|
contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
||||||
using WadRayMath for uint256;
|
using WadRayMath for uint256;
|
||||||
using SafeERC20 for ERC20;
|
using SafeERC20 for IncentivizedERC20;
|
||||||
|
|
||||||
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
||||||
address public immutable UNDERLYING_ASSET_ADDRESS;
|
address public immutable UNDERLYING_ASSET_ADDRESS;
|
||||||
LendingPool public immutable POOL;
|
LendingPool public immutable POOL;
|
||||||
|
|
||||||
/// @dev owner => next valid nonce to submit with permit()
|
/// @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;
|
uint256 public constant ATOKEN_REVISION = 0x1;
|
||||||
|
|
||||||
bytes32 public DOMAIN_SEPARATOR;
|
bytes32 public DOMAIN_SEPARATOR;
|
||||||
bytes public constant EIP712_REVISION = bytes("1");
|
bytes public constant EIP712_REVISION = bytes('1');
|
||||||
bytes32 internal constant EIP712_DOMAIN = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
|
bytes32 internal constant EIP712_DOMAIN = keccak256(
|
||||||
bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
|
'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 {
|
modifier onlyLendingPool {
|
||||||
require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL);
|
require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL);
|
||||||
|
@ -45,8 +49,9 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
LendingPool pool,
|
LendingPool pool,
|
||||||
address underlyingAssetAddress,
|
address underlyingAssetAddress,
|
||||||
string memory tokenName,
|
string memory tokenName,
|
||||||
string memory tokenSymbol
|
string memory tokenSymbol,
|
||||||
) public ERC20(tokenName, tokenSymbol, 18) {
|
address incentivesController
|
||||||
|
) public IncentivizedERC20(tokenName, tokenSymbol, 18, incentivesController) {
|
||||||
POOL = pool;
|
POOL = pool;
|
||||||
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
|
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
|
||||||
}
|
}
|
||||||
|
@ -64,16 +69,18 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
assembly {
|
assembly {
|
||||||
chainId := chainid()
|
chainId := chainid()
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMAIN_SEPARATOR = keccak256(abi.encode(
|
DOMAIN_SEPARATOR = keccak256(
|
||||||
|
abi.encode(
|
||||||
EIP712_DOMAIN,
|
EIP712_DOMAIN,
|
||||||
keccak256(bytes(tokenName)),
|
keccak256(bytes(tokenName)),
|
||||||
keccak256(EIP712_REVISION),
|
keccak256(EIP712_REVISION),
|
||||||
chainId,
|
chainId,
|
||||||
address(this)
|
address(this)
|
||||||
));
|
)
|
||||||
|
);
|
||||||
|
|
||||||
_setName(tokenName);
|
_setName(tokenName);
|
||||||
_setSymbol(tokenSymbol);
|
_setSymbol(tokenSymbol);
|
||||||
|
@ -91,7 +98,6 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
uint256 amount,
|
uint256 amount,
|
||||||
uint256 index
|
uint256 index
|
||||||
) external override onlyLendingPool {
|
) external override onlyLendingPool {
|
||||||
|
|
||||||
uint256 currentBalance = balanceOf(user);
|
uint256 currentBalance = balanceOf(user);
|
||||||
|
|
||||||
require(amount <= currentBalance, Errors.INVALID_ATOKEN_BALANCE);
|
require(amount <= currentBalance, Errors.INVALID_ATOKEN_BALANCE);
|
||||||
|
@ -101,7 +107,7 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
_burn(user, scaledAmount);
|
_burn(user, scaledAmount);
|
||||||
|
|
||||||
//transfers the underlying to the target
|
//transfers the underlying to the target
|
||||||
ERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(receiverOfUnderlying, amount);
|
IncentivizedERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(receiverOfUnderlying, amount);
|
||||||
|
|
||||||
//transfer event to track balances
|
//transfer event to track balances
|
||||||
emit Transfer(user, address(0), amount);
|
emit Transfer(user, address(0), amount);
|
||||||
|
@ -115,13 +121,15 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
* @param user the address receiving the minted tokens
|
* @param user the address receiving the minted tokens
|
||||||
* @param amount the amount of tokens to mint
|
* @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);
|
uint256 scaledAmount = amount.rayDiv(index);
|
||||||
|
|
||||||
//mint an equivalent amount of tokens to cover the new deposit
|
//mint an equivalent amount of tokens to cover the new deposit
|
||||||
_mint(user,scaledAmount);
|
_mint(user, scaledAmount);
|
||||||
|
|
||||||
//transfer event to track balances
|
//transfer event to track balances
|
||||||
emit Transfer(address(0), user, amount);
|
emit Transfer(address(0), user, amount);
|
||||||
|
@ -147,11 +155,16 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev calculates the balance of the user, which is the
|
* @dev calculates the balance of the user, which is the
|
||||||
* principal balance + interest generated by the principal balance
|
* principal balance + interest generated by the principal balance
|
||||||
* @param user the user for which the balance is being calculated
|
* @param user the user for which the balance is being calculated
|
||||||
* @return the total balance of the user
|
* @return the total balance of the user
|
||||||
**/
|
**/
|
||||||
function balanceOf(address user) public override(ERC20, IERC20) view returns (uint256) {
|
function balanceOf(address user)
|
||||||
|
public
|
||||||
|
override(IncentivizedERC20, IERC20)
|
||||||
|
view
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
return super.balanceOf(user).rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
return super.balanceOf(user).rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,22 +178,35 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
return super.balanceOf(user);
|
return super.balanceOf(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev returns the principal balance of the user and principal total supply.
|
||||||
|
* @param user the address of the user
|
||||||
|
* @return the principal balance of the user
|
||||||
|
* @return the principal total supply
|
||||||
|
**/
|
||||||
|
function getScaledUserBalanceAndSupply(address user)
|
||||||
|
external
|
||||||
|
override
|
||||||
|
view
|
||||||
|
returns (uint256, uint256)
|
||||||
|
{
|
||||||
|
return (super.balanceOf(user), super.totalSupply());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev calculates the total supply of the specific aToken
|
* @dev calculates the total supply of the specific aToken
|
||||||
* since the balance of every single user increases over time, the total supply
|
* since the balance of every single user increases over time, the total supply
|
||||||
* does that too.
|
* does that too.
|
||||||
* @return the current total supply
|
* @return the current total supply
|
||||||
**/
|
**/
|
||||||
function totalSupply() public override(ERC20, IERC20) view returns (uint256) {
|
function totalSupply() public override(IncentivizedERC20, IERC20) view returns (uint256) {
|
||||||
uint256 currentSupplyScaled = super.totalSupply();
|
uint256 currentSupplyScaled = super.totalSupply();
|
||||||
|
|
||||||
if (currentSupplyScaled == 0) {
|
if (currentSupplyScaled == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return currentSupplyScaled.rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
||||||
currentSupplyScaled
|
|
||||||
.rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -194,56 +220,55 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev transfers the underlying asset to the target. Used by the lendingpool to transfer
|
* @dev transfers the underlying asset to the target. Used by the lendingpool to transfer
|
||||||
* assets in borrow(), redeem() and flashLoan()
|
* assets in borrow(), redeem() and flashLoan()
|
||||||
* @param target the target of the transfer
|
* @param target the target of the transfer
|
||||||
* @param amount the amount to transfer
|
* @param amount the amount to transfer
|
||||||
* @return the amount transferred
|
* @return the amount transferred
|
||||||
**/
|
**/
|
||||||
function transferUnderlyingTo(address target, uint256 amount)
|
function transferUnderlyingTo(address target, uint256 amount)
|
||||||
external
|
external
|
||||||
override
|
override
|
||||||
onlyLendingPool
|
onlyLendingPool
|
||||||
returns (uint256)
|
returns (uint256)
|
||||||
{
|
{
|
||||||
ERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
|
IncentivizedERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev implements the permit function as for https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
|
* @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 owner the owner of the funds
|
||||||
* @param spender the spender
|
* @param spender the spender
|
||||||
* @param value the amount
|
* @param value the amount
|
||||||
* @param deadline the deadline timestamp, type(uint256).max for max deadline
|
* @param deadline the deadline timestamp, type(uint256).max for max deadline
|
||||||
* @param v signature param
|
* @param v signature param
|
||||||
* @param s signature param
|
* @param s signature param
|
||||||
* @param r signature param
|
* @param r signature param
|
||||||
*/
|
*/
|
||||||
function permit(
|
function permit(
|
||||||
address owner,
|
address owner,
|
||||||
address spender,
|
address spender,
|
||||||
uint256 value,
|
uint256 value,
|
||||||
uint256 deadline,
|
uint256 deadline,
|
||||||
uint8 v,
|
uint8 v,
|
||||||
bytes32 r,
|
bytes32 r,
|
||||||
bytes32 s
|
bytes32 s
|
||||||
) external {
|
) external {
|
||||||
require(owner != address(0), "INVALID_OWNER");
|
require(owner != address(0), 'INVALID_OWNER');
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
require(block.timestamp <= deadline, "INVALID_EXPIRATION");
|
require(block.timestamp <= deadline, 'INVALID_EXPIRATION');
|
||||||
uint256 currentValidNonce = _nonces[owner];
|
uint256 currentValidNonce = _nonces[owner];
|
||||||
bytes32 digest = keccak256(
|
bytes32 digest = keccak256(
|
||||||
abi.encodePacked(
|
abi.encodePacked(
|
||||||
"\x19\x01",
|
'\x19\x01',
|
||||||
DOMAIN_SEPARATOR,
|
DOMAIN_SEPARATOR,
|
||||||
keccak256(
|
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
|
||||||
abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
|
)
|
||||||
)
|
);
|
||||||
);
|
require(owner == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE');
|
||||||
require(owner == ecrecover(digest, v, r, s), "INVALID_SIGNATURE");
|
_nonces[owner] = currentValidNonce.add(1);
|
||||||
_nonces[owner] = currentValidNonce.add(1);
|
_approve(owner, spender, value);
|
||||||
_approve(owner, spender, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _transfer(
|
function _transfer(
|
||||||
|
@ -251,8 +276,8 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
address to,
|
address to,
|
||||||
uint256 amount,
|
uint256 amount,
|
||||||
bool validate
|
bool validate
|
||||||
) internal {
|
) internal {
|
||||||
if(validate){
|
if (validate) {
|
||||||
require(isTransferAllowed(from, amount), Errors.TRANSFER_NOT_ALLOWED);
|
require(isTransferAllowed(from, amount), Errors.TRANSFER_NOT_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,17 +288,16 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
||||||
super._transfer(from, to, scaledAmount);
|
super._transfer(from, to, scaledAmount);
|
||||||
|
|
||||||
emit BalanceTransfer(from, to, amount, index);
|
emit BalanceTransfer(from, to, amount, index);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _transfer(
|
function _transfer(
|
||||||
address from,
|
address from,
|
||||||
address to,
|
address to,
|
||||||
uint256 amount
|
uint256 amount
|
||||||
) internal override {
|
) internal override {
|
||||||
|
_transfer(from, to, amount, true);
|
||||||
_transfer(from, to, amount, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev aTokens should not receive ETH
|
* @dev aTokens should not receive ETH
|
||||||
**/
|
**/
|
||||||
|
|
|
@ -5,16 +5,20 @@ import {Context} from '../misc/Context.sol';
|
||||||
import {IERC20} from '../interfaces/IERC20.sol';
|
import {IERC20} from '../interfaces/IERC20.sol';
|
||||||
import {IERC20Detailed} from '../interfaces/IERC20Detailed.sol';
|
import {IERC20Detailed} from '../interfaces/IERC20Detailed.sol';
|
||||||
import {SafeMath} from '../libraries/math/SafeMath.sol';
|
import {SafeMath} from '../libraries/math/SafeMath.sol';
|
||||||
|
import {IAaveIncentivesController} from '../interfaces/IAaveIncentivesController.sol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title ERC20
|
* @title ERC20
|
||||||
* @notice Basic ERC20 implementation
|
* @notice Basic ERC20 implementation
|
||||||
* @author Aave, inspired by the Openzeppelin ERC20 implementation
|
* @author Aave, inspired by the Openzeppelin ERC20 implementation
|
||||||
**/
|
**/
|
||||||
contract ERC20 is Context, IERC20, IERC20Detailed {
|
contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
|
|
||||||
|
IAaveIncentivesController internal immutable _incentivesController;
|
||||||
|
|
||||||
mapping(address => uint256) internal _balances;
|
mapping(address => uint256) internal _balances;
|
||||||
|
|
||||||
mapping(address => mapping(address => uint256)) private _allowances;
|
mapping(address => mapping(address => uint256)) private _allowances;
|
||||||
uint256 internal _totalSupply;
|
uint256 internal _totalSupply;
|
||||||
string private _name;
|
string private _name;
|
||||||
|
@ -24,11 +28,13 @@ contract ERC20 is Context, IERC20, IERC20Detailed {
|
||||||
constructor(
|
constructor(
|
||||||
string memory name,
|
string memory name,
|
||||||
string memory symbol,
|
string memory symbol,
|
||||||
uint8 decimals
|
uint8 decimals,
|
||||||
|
address incentivesController
|
||||||
) public {
|
) public {
|
||||||
_name = name;
|
_name = name;
|
||||||
_symbol = symbol;
|
_symbol = symbol;
|
||||||
_decimals = decimals;
|
_decimals = decimals;
|
||||||
|
_incentivesController = IAaveIncentivesController(incentivesController);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,8 +175,18 @@ contract ERC20 is Context, IERC20, IERC20Detailed {
|
||||||
|
|
||||||
_beforeTokenTransfer(sender, recipient, amount);
|
_beforeTokenTransfer(sender, recipient, amount);
|
||||||
|
|
||||||
_balances[sender] = _balances[sender].sub(amount, 'ERC20: transfer amount exceeds balance');
|
uint256 oldSenderBalance = _balances[sender];
|
||||||
|
_balances[sender] = oldSenderBalance.sub(amount, 'ERC20: transfer amount exceeds balance');
|
||||||
|
uint256 oldRecipientBalance = _balances[recipient];
|
||||||
_balances[recipient] = _balances[recipient].add(amount);
|
_balances[recipient] = _balances[recipient].add(amount);
|
||||||
|
|
||||||
|
if (address(_incentivesController) != address(0)) {
|
||||||
|
uint256 totalSupply = _totalSupply;
|
||||||
|
_incentivesController.handleAction(sender, totalSupply, oldSenderBalance);
|
||||||
|
if (sender != recipient) {
|
||||||
|
_incentivesController.handleAction(recipient, totalSupply, oldRecipientBalance);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _mint(address account, uint256 amount) internal virtual {
|
function _mint(address account, uint256 amount) internal virtual {
|
||||||
|
@ -178,8 +194,15 @@ contract ERC20 is Context, IERC20, IERC20Detailed {
|
||||||
|
|
||||||
_beforeTokenTransfer(address(0), account, amount);
|
_beforeTokenTransfer(address(0), account, amount);
|
||||||
|
|
||||||
_totalSupply = _totalSupply.add(amount);
|
uint256 oldTotalSupply = _totalSupply;
|
||||||
_balances[account] = _balances[account].add(amount);
|
_totalSupply = oldTotalSupply.add(amount);
|
||||||
|
|
||||||
|
uint256 oldAccountBalance = _balances[account];
|
||||||
|
_balances[account] = oldAccountBalance.add(amount);
|
||||||
|
|
||||||
|
if (address(_incentivesController) != address(0)) {
|
||||||
|
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _burn(address account, uint256 amount) internal virtual {
|
function _burn(address account, uint256 amount) internal virtual {
|
||||||
|
@ -187,8 +210,15 @@ contract ERC20 is Context, IERC20, IERC20Detailed {
|
||||||
|
|
||||||
_beforeTokenTransfer(account, address(0), amount);
|
_beforeTokenTransfer(account, address(0), amount);
|
||||||
|
|
||||||
_balances[account] = _balances[account].sub(amount, 'ERC20: burn amount exceeds balance');
|
uint256 oldTotalSupply = _totalSupply;
|
||||||
_totalSupply = _totalSupply.sub(amount);
|
_totalSupply = oldTotalSupply.sub(amount);
|
||||||
|
|
||||||
|
uint256 oldAccountBalance = _balances[account];
|
||||||
|
_balances[account] = oldAccountBalance.sub(amount, 'ERC20: burn amount exceeds balance');
|
||||||
|
|
||||||
|
if (address(_incentivesController) != address(0)) {
|
||||||
|
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _approve(
|
function _approve(
|
|
@ -26,8 +26,9 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
||||||
address pool,
|
address pool,
|
||||||
address underlyingAsset,
|
address underlyingAsset,
|
||||||
string memory name,
|
string memory name,
|
||||||
string memory symbol
|
string memory symbol,
|
||||||
) public DebtTokenBase(pool, underlyingAsset, name, symbol) {}
|
address incentivesController
|
||||||
|
) public DebtTokenBase(pool, underlyingAsset, name, symbol, incentivesController) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev gets the revision of the stable debt token implementation
|
* @dev gets the revision of the stable debt token implementation
|
||||||
|
|
|
@ -22,8 +22,9 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
||||||
address pool,
|
address pool,
|
||||||
address underlyingAsset,
|
address underlyingAsset,
|
||||||
string memory name,
|
string memory name,
|
||||||
string memory symbol
|
string memory symbol,
|
||||||
) public DebtTokenBase(pool, underlyingAsset, name, symbol) {}
|
address incentivesController
|
||||||
|
) public DebtTokenBase(pool, underlyingAsset, name, symbol, incentivesController) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev gets the revision of the stable debt token implementation
|
* @dev gets the revision of the stable debt token implementation
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {ILendingPool} from '../../interfaces/ILendingPool.sol';
|
||||||
import {
|
import {
|
||||||
VersionedInitializable
|
VersionedInitializable
|
||||||
} from '../../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
|
} from '../../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
|
||||||
import {ERC20} from '../ERC20.sol';
|
import {IncentivizedERC20} from '../IncentivizedERC20.sol';
|
||||||
import {Errors} from '../../libraries/helpers/Errors.sol';
|
import {Errors} from '../../libraries/helpers/Errors.sol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,7 +17,7 @@ import {Errors} from '../../libraries/helpers/Errors.sol';
|
||||||
* @author Aave
|
* @author Aave
|
||||||
*/
|
*/
|
||||||
|
|
||||||
abstract contract DebtTokenBase is ERC20, VersionedInitializable {
|
abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable {
|
||||||
address internal immutable UNDERLYING_ASSET;
|
address internal immutable UNDERLYING_ASSET;
|
||||||
ILendingPool internal immutable POOL;
|
ILendingPool internal immutable POOL;
|
||||||
mapping(address => uint256) internal _usersData;
|
mapping(address => uint256) internal _usersData;
|
||||||
|
@ -38,8 +38,9 @@ abstract contract DebtTokenBase is ERC20, VersionedInitializable {
|
||||||
address pool,
|
address pool,
|
||||||
address underlyingAssetAddress,
|
address underlyingAssetAddress,
|
||||||
string memory name,
|
string memory name,
|
||||||
string memory symbol
|
string memory symbol,
|
||||||
) public ERC20(name, symbol, 18) {
|
address incentivesController
|
||||||
|
) public IncentivizedERC20(name, symbol, 18, incentivesController) {
|
||||||
POOL = ILendingPool(pool);
|
POOL = ILendingPool(pool);
|
||||||
UNDERLYING_ASSET = underlyingAssetAddress;
|
UNDERLYING_ASSET = underlyingAssetAddress;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,14 @@ interface IAToken is IERC20 {
|
||||||
**/
|
**/
|
||||||
function scaledBalanceOf(address user) external view returns (uint256);
|
function scaledBalanceOf(address user) external view returns (uint256);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev returns the principal balance of the user and principal total supply.
|
||||||
|
* @param user the address of the user
|
||||||
|
* @return the principal balance of the user
|
||||||
|
* @return the principal total supply
|
||||||
|
**/
|
||||||
|
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Used to validate transfers before actually executing them.
|
* @dev Used to validate transfers before actually executing them.
|
||||||
* @param user address of the user to check
|
* @param user address of the user to check
|
||||||
|
|
3
helpers/buidler-constants.ts
Normal file
3
helpers/buidler-constants.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export const TEST_SNAPSHOT_ID = '0x1';
|
||||||
|
export const BUIDLEREVM_CHAINID = 31337;
|
||||||
|
export const COVERAGE_CHAINID = 1337;
|
|
@ -1,22 +1,17 @@
|
||||||
import {
|
import {
|
||||||
iAssetBase,
|
|
||||||
iAavePoolAssets,
|
|
||||||
IMarketRates,
|
|
||||||
iAssetAggregatorBase,
|
|
||||||
AavePools,
|
AavePools,
|
||||||
|
eEthereumNetwork,
|
||||||
|
iAavePoolAssets,
|
||||||
|
iAssetAggregatorBase,
|
||||||
|
iAssetBase,
|
||||||
|
iBasicDistributionParams,
|
||||||
|
IMarketRates,
|
||||||
iMultiPoolsAssets,
|
iMultiPoolsAssets,
|
||||||
IReserveParams,
|
IReserveParams,
|
||||||
tEthereumAddress,
|
tEthereumAddress,
|
||||||
iBasicDistributionParams,
|
|
||||||
eEthereumNetwork,
|
|
||||||
} from './types';
|
} from './types';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import {getParamPerPool, getParamPerNetwork} from './contracts-helpers';
|
import {getParamPerNetwork, getParamPerPool} from './contracts-helpers';
|
||||||
|
|
||||||
export const TEST_SNAPSHOT_ID = '0x1';
|
|
||||||
|
|
||||||
export const BUIDLEREVM_CHAINID = 31337;
|
|
||||||
export const COVERAGE_CHAINID = 1337;
|
|
||||||
|
|
||||||
// ----------------
|
// ----------------
|
||||||
// MATH
|
// MATH
|
||||||
|
@ -536,17 +531,16 @@ export const getFeeDistributionParamsCommon = (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getATokenDomainSeparatorPerNetwork = (
|
export const getATokenDomainSeparatorPerNetwork = (network: eEthereumNetwork): tEthereumAddress =>
|
||||||
network: eEthereumNetwork
|
|
||||||
): tEthereumAddress =>
|
|
||||||
getParamPerNetwork<tEthereumAddress>(
|
getParamPerNetwork<tEthereumAddress>(
|
||||||
{
|
{
|
||||||
[eEthereumNetwork.coverage]: "0x95b73a72c6ecf4ccbbba5178800023260bad8e75cdccdb8e4827a2977a37c820",
|
[eEthereumNetwork.coverage]:
|
||||||
|
'0x95b73a72c6ecf4ccbbba5178800023260bad8e75cdccdb8e4827a2977a37c820',
|
||||||
[eEthereumNetwork.buidlerevm]:
|
[eEthereumNetwork.buidlerevm]:
|
||||||
"0x76cbbf8aa4b11a7c207dd79ccf8c394f59475301598c9a083f8258b4fafcfa86",
|
'0x76cbbf8aa4b11a7c207dd79ccf8c394f59475301598c9a083f8258b4fafcfa86',
|
||||||
[eEthereumNetwork.kovan]: "",
|
[eEthereumNetwork.kovan]: '',
|
||||||
[eEthereumNetwork.ropsten]: "",
|
[eEthereumNetwork.ropsten]: '',
|
||||||
[eEthereumNetwork.main]: "",
|
[eEthereumNetwork.main]: '',
|
||||||
},
|
},
|
||||||
network
|
network
|
||||||
);
|
);
|
||||||
|
|
|
@ -32,8 +32,8 @@ import {Ierc20Detailed} from '../types/Ierc20Detailed';
|
||||||
import {StableDebtToken} from '../types/StableDebtToken';
|
import {StableDebtToken} from '../types/StableDebtToken';
|
||||||
import {VariableDebtToken} from '../types/VariableDebtToken';
|
import {VariableDebtToken} from '../types/VariableDebtToken';
|
||||||
import {MockSwapAdapter} from '../types/MockSwapAdapter';
|
import {MockSwapAdapter} from '../types/MockSwapAdapter';
|
||||||
import { signTypedData_v4, TypedData } from "eth-sig-util";
|
import {signTypedData_v4, TypedData} from 'eth-sig-util';
|
||||||
import { fromRpcSig, ECDSASignature } from "ethereumjs-util";
|
import {fromRpcSig, ECDSASignature} from 'ethereumjs-util';
|
||||||
|
|
||||||
export const registerContractInJsonDb = async (contractId: string, contractInstance: Contract) => {
|
export const registerContractInJsonDb = async (contractId: string, contractInstance: Contract) => {
|
||||||
const currentNetwork = BRE.network.name;
|
const currentNetwork = BRE.network.name;
|
||||||
|
@ -251,49 +251,55 @@ export const deployDefaultReserveInterestRateStrategy = async ([
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
export const deployStableDebtToken = async ([name, symbol, underlyingAsset, poolAddress]: [
|
export const deployStableDebtToken = async ([
|
||||||
string,
|
name,
|
||||||
string,
|
symbol,
|
||||||
tEthereumAddress,
|
underlyingAsset,
|
||||||
tEthereumAddress
|
poolAddress,
|
||||||
]) => {
|
incentivesController,
|
||||||
|
]: [string, string, tEthereumAddress, tEthereumAddress, tEthereumAddress]) => {
|
||||||
const token = await deployContract<StableDebtToken>(eContractid.StableDebtToken, [
|
const token = await deployContract<StableDebtToken>(eContractid.StableDebtToken, [
|
||||||
poolAddress,
|
poolAddress,
|
||||||
underlyingAsset,
|
underlyingAsset,
|
||||||
name,
|
name,
|
||||||
symbol,
|
symbol,
|
||||||
|
incentivesController,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deployVariableDebtToken = async ([name, symbol, underlyingAsset, poolAddress]: [
|
export const deployVariableDebtToken = async ([
|
||||||
string,
|
name,
|
||||||
string,
|
symbol,
|
||||||
tEthereumAddress,
|
underlyingAsset,
|
||||||
tEthereumAddress
|
poolAddress,
|
||||||
]) => {
|
incentivesController,
|
||||||
|
]: [string, string, tEthereumAddress, tEthereumAddress, tEthereumAddress]) => {
|
||||||
const token = await deployContract<VariableDebtToken>(eContractid.VariableDebtToken, [
|
const token = await deployContract<VariableDebtToken>(eContractid.VariableDebtToken, [
|
||||||
poolAddress,
|
poolAddress,
|
||||||
underlyingAsset,
|
underlyingAsset,
|
||||||
name,
|
name,
|
||||||
symbol,
|
symbol,
|
||||||
|
incentivesController,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deployGenericAToken = async ([poolAddress, underlyingAssetAddress, name, symbol]: [
|
export const deployGenericAToken = async ([
|
||||||
tEthereumAddress,
|
poolAddress,
|
||||||
tEthereumAddress,
|
underlyingAssetAddress,
|
||||||
string,
|
name,
|
||||||
string
|
symbol,
|
||||||
]) => {
|
incentivesController,
|
||||||
|
]: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress]) => {
|
||||||
const token = await deployContract<AToken>(eContractid.AToken, [
|
const token = await deployContract<AToken>(eContractid.AToken, [
|
||||||
poolAddress,
|
poolAddress,
|
||||||
underlyingAssetAddress,
|
underlyingAssetAddress,
|
||||||
name,
|
name,
|
||||||
symbol,
|
symbol,
|
||||||
|
incentivesController,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
|
@ -491,20 +497,20 @@ export const buildPermitParams = (
|
||||||
) => ({
|
) => ({
|
||||||
types: {
|
types: {
|
||||||
EIP712Domain: [
|
EIP712Domain: [
|
||||||
{ name: "name", type: "string" },
|
{name: 'name', type: 'string'},
|
||||||
{ name: "version", type: "string" },
|
{name: 'version', type: 'string'},
|
||||||
{ name: "chainId", type: "uint256" },
|
{name: 'chainId', type: 'uint256'},
|
||||||
{ name: "verifyingContract", type: "address" },
|
{name: 'verifyingContract', type: 'address'},
|
||||||
],
|
],
|
||||||
Permit: [
|
Permit: [
|
||||||
{ name: "owner", type: "address" },
|
{name: 'owner', type: 'address'},
|
||||||
{ name: "spender", type: "address" },
|
{name: 'spender', type: 'address'},
|
||||||
{ name: "value", type: "uint256" },
|
{name: 'value', type: 'uint256'},
|
||||||
{ name: "nonce", type: "uint256" },
|
{name: 'nonce', type: 'uint256'},
|
||||||
{ name: "deadline", type: "uint256" },
|
{name: 'deadline', type: 'uint256'},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
primaryType: "Permit" as const,
|
primaryType: 'Permit' as const,
|
||||||
domain: {
|
domain: {
|
||||||
name: tokenName,
|
name: tokenName,
|
||||||
version: revision,
|
version: revision,
|
||||||
|
@ -520,16 +526,12 @@ export const buildPermitParams = (
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export const getSignatureFromTypedData = (
|
export const getSignatureFromTypedData = (
|
||||||
privateKey: string,
|
privateKey: string,
|
||||||
typedData: any // TODO: should be TypedData, from eth-sig-utils, but TS doesn't accept it
|
typedData: any // TODO: should be TypedData, from eth-sig-utils, but TS doesn't accept it
|
||||||
): ECDSASignature => {
|
): ECDSASignature => {
|
||||||
const signature = signTypedData_v4(
|
const signature = signTypedData_v4(Buffer.from(privateKey.substring(2, 66), 'hex'), {
|
||||||
Buffer.from(privateKey.substring(2, 66), "hex"),
|
data: typedData,
|
||||||
{
|
});
|
||||||
data: typedData,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return fromRpcSig(signature);
|
return fromRpcSig(signature);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ export enum eEthereumNetwork {
|
||||||
kovan = 'kovan',
|
kovan = 'kovan',
|
||||||
ropsten = 'ropsten',
|
ropsten = 'ropsten',
|
||||||
main = 'main',
|
main = 'main',
|
||||||
coverage = 'coverage'
|
coverage = 'coverage',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AavePools {
|
export enum AavePools {
|
||||||
|
@ -42,7 +42,7 @@ export enum eContractid {
|
||||||
AaveProtocolTestHelpers = 'AaveProtocolTestHelpers',
|
AaveProtocolTestHelpers = 'AaveProtocolTestHelpers',
|
||||||
IERC20Detailed = 'IERC20Detailed',
|
IERC20Detailed = 'IERC20Detailed',
|
||||||
StableDebtToken = 'StableDebtToken',
|
StableDebtToken = 'StableDebtToken',
|
||||||
VariableDebtToken = 'VariableDebtToken'
|
VariableDebtToken = 'VariableDebtToken',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ProtocolErrors {
|
export enum ProtocolErrors {
|
||||||
|
@ -67,6 +67,7 @@ export enum ProtocolErrors {
|
||||||
NO_VARIABLE_RATE_LOAN_IN_RESERVE = '18', // 'User does not have a variable rate loan in progress on this reserve'
|
NO_VARIABLE_RATE_LOAN_IN_RESERVE = '18', // 'User does not have a variable rate loan in progress on this reserve'
|
||||||
UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = '19', // 'The underlying balance needs to be greater than 0'
|
UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = '19', // 'The underlying balance needs to be greater than 0'
|
||||||
DEPOSIT_ALREADY_IN_USE = '20', // 'User deposit is already being used as collateral'
|
DEPOSIT_ALREADY_IN_USE = '20', // 'User deposit is already being used as collateral'
|
||||||
|
INVALID_EQUAL_ASSETS_TO_SWAP = '56', // User can't use same reserve as destination of liquidity swap
|
||||||
|
|
||||||
// require error messages - LendingPool
|
// require error messages - LendingPool
|
||||||
NOT_ENOUGH_STABLE_BORROW_BALANCE = '21', // 'User does not have any stable rate loan for this reserve'
|
NOT_ENOUGH_STABLE_BORROW_BALANCE = '21', // 'User does not have any stable rate loan for this reserve'
|
||||||
|
@ -100,6 +101,8 @@ export enum ProtocolErrors {
|
||||||
NO_ERRORS = '42', // 'No errors'
|
NO_ERRORS = '42', // 'No errors'
|
||||||
INVALID_FLASHLOAN_MODE = '43', //Invalid flashloan mode
|
INVALID_FLASHLOAN_MODE = '43', //Invalid flashloan mode
|
||||||
|
|
||||||
|
IS_PAUSED = '58', // Pool is paused
|
||||||
|
|
||||||
// old
|
// old
|
||||||
|
|
||||||
INVALID_FROM_BALANCE_AFTER_TRANSFER = 'Invalid from balance after transfer',
|
INVALID_FROM_BALANCE_AFTER_TRANSFER = 'Invalid from balance after transfer',
|
||||||
|
|
10836
package-lock.json
generated
10836
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -15,7 +15,10 @@
|
||||||
"test-scenarios": "buidler test test/__setup.spec.ts test/scenario.spec.ts",
|
"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-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-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-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",
|
"test-permit": "buidler test test/__setup.spec.ts test/atoken-permit.spec.ts",
|
||||||
"dev:coverage": "buidler coverage --network coverage",
|
"dev:coverage": "buidler coverage --network coverage",
|
||||||
"dev:deployment": "buidler dev-deployment",
|
"dev:deployment": "buidler dev-deployment",
|
||||||
|
|
|
@ -175,7 +175,8 @@ const initReserves = async (
|
||||||
lendingPoolAddressesProvider: LendingPoolAddressesProvider,
|
lendingPoolAddressesProvider: LendingPoolAddressesProvider,
|
||||||
lendingPool: LendingPool,
|
lendingPool: LendingPool,
|
||||||
lendingPoolConfigurator: LendingPoolConfigurator,
|
lendingPoolConfigurator: LendingPoolConfigurator,
|
||||||
aavePool: AavePools
|
aavePool: AavePools,
|
||||||
|
incentivesController: tEthereumAddress
|
||||||
) => {
|
) => {
|
||||||
if (aavePool !== AavePools.proto && aavePool !== AavePools.secondary) {
|
if (aavePool !== AavePools.proto && aavePool !== AavePools.secondary) {
|
||||||
console.log(`Invalid Aave pool ${aavePool}`);
|
console.log(`Invalid Aave pool ${aavePool}`);
|
||||||
|
@ -230,6 +231,7 @@ const initReserves = async (
|
||||||
`stableDebt${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
`stableDebt${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
||||||
tokenAddress,
|
tokenAddress,
|
||||||
lendingPool.address,
|
lendingPool.address,
|
||||||
|
incentivesController,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const variableDebtToken = await deployVariableDebtToken([
|
const variableDebtToken = await deployVariableDebtToken([
|
||||||
|
@ -237,6 +239,7 @@ const initReserves = async (
|
||||||
`variableDebt${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
`variableDebt${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
||||||
tokenAddress,
|
tokenAddress,
|
||||||
lendingPool.address,
|
lendingPool.address,
|
||||||
|
incentivesController,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const aToken = await deployGenericAToken([
|
const aToken = await deployGenericAToken([
|
||||||
|
@ -244,6 +247,7 @@ const initReserves = async (
|
||||||
tokenAddress,
|
tokenAddress,
|
||||||
`Aave interest bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
`Aave interest bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
||||||
`a${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
`a${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
||||||
|
incentivesController,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (process.env.POOL === AavePools.secondary) {
|
if (process.env.POOL === AavePools.secondary) {
|
||||||
|
@ -481,7 +485,8 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
|
||||||
addressesProvider,
|
addressesProvider,
|
||||||
lendingPoolProxy,
|
lendingPoolProxy,
|
||||||
lendingPoolConfiguratorProxy,
|
lendingPoolConfiguratorProxy,
|
||||||
AavePools.proto
|
AavePools.proto,
|
||||||
|
ZERO_ADDRESS
|
||||||
);
|
);
|
||||||
await enableReservesToBorrow(
|
await enableReservesToBorrow(
|
||||||
reservesParams,
|
reservesParams,
|
||||||
|
|
|
@ -2,7 +2,6 @@ import {
|
||||||
MAX_UINT_AMOUNT,
|
MAX_UINT_AMOUNT,
|
||||||
ZERO_ADDRESS,
|
ZERO_ADDRESS,
|
||||||
getATokenDomainSeparatorPerNetwork,
|
getATokenDomainSeparatorPerNetwork,
|
||||||
BUIDLEREVM_CHAINID,
|
|
||||||
} from '../helpers/constants';
|
} from '../helpers/constants';
|
||||||
import {buildPermitParams, getSignatureFromTypedData} from '../helpers/contracts-helpers';
|
import {buildPermitParams, getSignatureFromTypedData} from '../helpers/contracts-helpers';
|
||||||
import {expect} from 'chai';
|
import {expect} from 'chai';
|
||||||
|
@ -11,6 +10,7 @@ import {eEthereumNetwork} from '../helpers/types';
|
||||||
import {makeSuite, TestEnv} from './helpers/make-suite';
|
import {makeSuite, TestEnv} from './helpers/make-suite';
|
||||||
import {BRE} from '../helpers/misc-utils';
|
import {BRE} from '../helpers/misc-utils';
|
||||||
import {waitForTx} from './__setup.spec';
|
import {waitForTx} from './__setup.spec';
|
||||||
|
import {BUIDLEREVM_CHAINID} from '../helpers/buidler-constants';
|
||||||
|
|
||||||
const {parseEther} = ethers.utils;
|
const {parseEther} = ethers.utils;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
||||||
// ZERO_COLLATERAL,
|
// ZERO_COLLATERAL,
|
||||||
COLLATERAL_BALANCE_IS_0,
|
COLLATERAL_BALANCE_IS_0,
|
||||||
TRANSFER_NOT_ALLOWED,
|
TRANSFER_NOT_ALLOWED,
|
||||||
|
IS_PAUSED,
|
||||||
} = ProtocolErrors;
|
} = ProtocolErrors;
|
||||||
|
|
||||||
it('User 0 deposits 1000 DAI, transfers to user 1', async () => {
|
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 () => {
|
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 {users, pool, weth} = testEnv;
|
||||||
const userAddress = await pool.signer.getAddress();
|
const userAddress = await pool.signer.getAddress();
|
||||||
|
@ -92,5 +92,4 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
||||||
TRANSFER_NOT_ALLOWED
|
TRANSFER_NOT_ALLOWED
|
||||||
).to.be.revertedWith(TRANSFER_NOT_ALLOWED);
|
).to.be.revertedWith(TRANSFER_NOT_ALLOWED);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,12 +13,63 @@ const {expect} = require('chai');
|
||||||
|
|
||||||
makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => {
|
makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => {
|
||||||
let _mockSwapAdapter = {} as MockSwapAdapter;
|
let _mockSwapAdapter = {} as MockSwapAdapter;
|
||||||
const {HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD} = ProtocolErrors;
|
const {
|
||||||
|
HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,
|
||||||
|
NO_UNFREEZED_RESERVE,
|
||||||
|
NO_ACTIVE_RESERVE,
|
||||||
|
INVALID_EQUAL_ASSETS_TO_SWAP,
|
||||||
|
} = ProtocolErrors;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
_mockSwapAdapter = await getMockSwapAdapter();
|
_mockSwapAdapter = await getMockSwapAdapter();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should not allow to swap if from equal to', async () => {
|
||||||
|
const {pool, weth} = testEnv;
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
pool.swapLiquidity(
|
||||||
|
_mockSwapAdapter.address,
|
||||||
|
weth.address,
|
||||||
|
weth.address,
|
||||||
|
'1'.toString(),
|
||||||
|
'0x10'
|
||||||
|
)
|
||||||
|
).to.be.revertedWith(INVALID_EQUAL_ASSETS_TO_SWAP);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not allow to swap if from or to reserves are not active', async () => {
|
||||||
|
const {pool, weth, dai, configurator} = testEnv;
|
||||||
|
|
||||||
|
await configurator.deactivateReserve(weth.address);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
pool.swapLiquidity(
|
||||||
|
_mockSwapAdapter.address,
|
||||||
|
weth.address,
|
||||||
|
dai.address,
|
||||||
|
'1'.toString(),
|
||||||
|
'0x10'
|
||||||
|
)
|
||||||
|
).to.be.revertedWith(NO_ACTIVE_RESERVE);
|
||||||
|
await configurator.activateReserve(weth.address);
|
||||||
|
|
||||||
|
await configurator.deactivateReserve(dai.address);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
pool.swapLiquidity(
|
||||||
|
_mockSwapAdapter.address,
|
||||||
|
weth.address,
|
||||||
|
dai.address,
|
||||||
|
'1'.toString(),
|
||||||
|
'0x10'
|
||||||
|
)
|
||||||
|
).to.be.revertedWith(NO_ACTIVE_RESERVE);
|
||||||
|
|
||||||
|
//cleanup state
|
||||||
|
await configurator.activateReserve(dai.address);
|
||||||
|
});
|
||||||
|
|
||||||
it('Deposits WETH into the reserve', async () => {
|
it('Deposits WETH into the reserve', async () => {
|
||||||
const {pool, weth, users} = testEnv;
|
const {pool, weth, users} = testEnv;
|
||||||
const amountToDeposit = ethers.utils.parseEther('1');
|
const amountToDeposit = ethers.utils.parseEther('1');
|
||||||
|
@ -32,6 +83,7 @@ makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => {
|
||||||
.deposit(weth.address, amountToDeposit, await signer.getAddress(), '0');
|
.deposit(weth.address, amountToDeposit, await signer.getAddress(), '0');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('User tries to swap more then he can, revert expected', async () => {
|
it('User tries to swap more then he can, revert expected', async () => {
|
||||||
const {pool, weth, dai} = testEnv;
|
const {pool, weth, dai} = testEnv;
|
||||||
await expect(
|
await expect(
|
||||||
|
@ -45,19 +97,6 @@ makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => {
|
||||||
).to.be.revertedWith('55');
|
).to.be.revertedWith('55');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('User tries to swap asset on equal asset, revert expected', async () => {
|
|
||||||
const {pool, weth} = testEnv;
|
|
||||||
await expect(
|
|
||||||
pool.swapLiquidity(
|
|
||||||
_mockSwapAdapter.address,
|
|
||||||
weth.address,
|
|
||||||
weth.address,
|
|
||||||
ethers.utils.parseEther('0.1'),
|
|
||||||
'0x10'
|
|
||||||
)
|
|
||||||
).to.be.revertedWith('56');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('User tries to swap more then available on the reserve', async () => {
|
it('User tries to swap more then available on the reserve', async () => {
|
||||||
const {pool, weth, dai, users, aEth, deployer} = testEnv;
|
const {pool, weth, dai, users, aEth, deployer} = testEnv;
|
||||||
|
|
||||||
|
@ -134,6 +173,9 @@ makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => {
|
||||||
reserveBalanceDAIBefore.add(amountToReturn).toString(),
|
reserveBalanceDAIBefore.add(amountToReturn).toString(),
|
||||||
'was received incorrect amount if reserve funds'
|
'was received incorrect amount if reserve funds'
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
(await pool.getUserReserveData(dai.address, userAddress)).usageAsCollateralEnabled
|
||||||
|
).to.be.equal(true, 'usage as collateral was not enabled on destination reserve for the user');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('User tries to drop HF below one', async () => {
|
it('User tries to drop HF below one', async () => {
|
||||||
|
@ -151,7 +193,7 @@ makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should set usage as collateral to false if no leftovers after swap', async () => {
|
it('Should set usage as collateral to false if no leftovers after swap', async () => {
|
||||||
const {pool, weth, dai, aEth, users} = testEnv;
|
const {pool, weth, dai, users} = testEnv;
|
||||||
const userAddress = await pool.signer.getAddress();
|
const userAddress = await pool.signer.getAddress();
|
||||||
|
|
||||||
// add more liquidity to allow user 0 to swap everything he has
|
// add more liquidity to allow user 0 to swap everything he has
|
||||||
|
@ -195,4 +237,22 @@ makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => {
|
||||||
'usageAsCollateralEnabled are not set to false'
|
'usageAsCollateralEnabled are not set to false'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('Should not allow to swap if to reserve are freezed', async () => {
|
||||||
|
const {pool, weth, dai, configurator} = testEnv;
|
||||||
|
|
||||||
|
await configurator.freezeReserve(dai.address);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
pool.swapLiquidity(
|
||||||
|
_mockSwapAdapter.address,
|
||||||
|
weth.address,
|
||||||
|
dai.address,
|
||||||
|
'1'.toString(),
|
||||||
|
'0x10'
|
||||||
|
)
|
||||||
|
).to.be.revertedWith(NO_UNFREEZED_RESERVE);
|
||||||
|
|
||||||
|
//cleanup state
|
||||||
|
await configurator.unfreezeReserve(dai.address);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,7 @@ const {expect} = require('chai');
|
||||||
const {parseUnits, parseEther} = ethers.utils;
|
const {parseUnits, parseEther} = ethers.utils;
|
||||||
|
|
||||||
makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEnv) => {
|
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 () => {
|
it('User 1 provides some liquidity for others to borrow', async () => {
|
||||||
const {pool, weth, dai, usdc, deployer} = testEnv;
|
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(weth.address, amountToDepositWeth, user.address, '0');
|
||||||
await pool.connect(user.signer).deposit(dai.address, amountToDepositDAI, 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;
|
const amountToRepay = amountToBorrowVariable;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
TRANSFER_AMOUNT_EXCEEDS_BALANCE,
|
TRANSFER_AMOUNT_EXCEEDS_BALANCE,
|
||||||
INVALID_FLASHLOAN_MODE,
|
INVALID_FLASHLOAN_MODE,
|
||||||
SAFEERC20_LOWLEVEL_CALL,
|
SAFEERC20_LOWLEVEL_CALL,
|
||||||
|
IS_PAUSED,
|
||||||
} = ProtocolErrors;
|
} = ProtocolErrors;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
|
|
@ -54,7 +54,6 @@ const almostEqualOrEqual = function (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.assert(actual[key] != undefined, `Property ${key} is undefined in the actual data`);
|
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`);
|
expect(expected[key] != undefined, `Property ${key} is undefined in the expected data`);
|
||||||
|
|
||||||
|
@ -63,10 +62,9 @@ const almostEqualOrEqual = function (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actual[key] instanceof BigNumber) {
|
if (actual[key] instanceof BigNumber) {
|
||||||
|
|
||||||
const actualValue = (<BigNumber>actual[key]).decimalPlaces(0, BigNumber.ROUND_DOWN);
|
const actualValue = (<BigNumber>actual[key]).decimalPlaces(0, BigNumber.ROUND_DOWN);
|
||||||
const expectedValue = (<BigNumber>expected[key]).decimalPlaces(0, BigNumber.ROUND_DOWN);
|
const expectedValue = (<BigNumber>expected[key]).decimalPlaces(0, BigNumber.ROUND_DOWN);
|
||||||
|
|
||||||
this.assert(
|
this.assert(
|
||||||
actualValue.eq(expectedValue) ||
|
actualValue.eq(expectedValue) ||
|
||||||
actualValue.plus(1).eq(expectedValue) ||
|
actualValue.plus(1).eq(expectedValue) ||
|
||||||
|
|
|
@ -230,7 +230,7 @@ const executeAction = async (action: Action, users: SignerWithAddress[], testEnv
|
||||||
await rebalanceStableBorrowRate(reserve, user, target, expected, testEnv, revertMessage);
|
await rebalanceStableBorrowRate(reserve, user, target, expected, testEnv, revertMessage);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw `Invalid action requested: ${name}`;
|
throw `Invalid action requested: ${name}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -539,7 +539,7 @@ export const calcExpectedUserDataAfterBorrow = (
|
||||||
currentTimestamp
|
currentTimestamp
|
||||||
);
|
);
|
||||||
expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance;
|
expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance;
|
||||||
|
|
||||||
expectedUserData.walletBalance = userDataBeforeAction.walletBalance.plus(amountBorrowed);
|
expectedUserData.walletBalance = userDataBeforeAction.walletBalance.plus(amountBorrowed);
|
||||||
|
|
||||||
return expectedUserData;
|
return expectedUserData;
|
||||||
|
@ -623,7 +623,7 @@ export const calcExpectedUserDataAfterRepay = (
|
||||||
txTimestamp
|
txTimestamp
|
||||||
);
|
);
|
||||||
expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance;
|
expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance;
|
||||||
|
|
||||||
if (user === onBehalfOf) {
|
if (user === onBehalfOf) {
|
||||||
expectedUserData.walletBalance = userDataBeforeAction.walletBalance.minus(totalRepaid);
|
expectedUserData.walletBalance = userDataBeforeAction.walletBalance.minus(totalRepaid);
|
||||||
} else {
|
} else {
|
||||||
|
@ -926,9 +926,7 @@ export const calcExpectedATokenBalance = (
|
||||||
) => {
|
) => {
|
||||||
const index = calcExpectedReserveNormalizedIncome(reserveDataBeforeAction, currentTimestamp);
|
const index = calcExpectedReserveNormalizedIncome(reserveDataBeforeAction, currentTimestamp);
|
||||||
|
|
||||||
const {
|
const {scaledATokenBalance: scaledBalanceBeforeAction} = userDataBeforeAction;
|
||||||
scaledATokenBalance: scaledBalanceBeforeAction,
|
|
||||||
} = userDataBeforeAction;
|
|
||||||
|
|
||||||
return scaledBalanceBeforeAction.rayMul(index);
|
return scaledBalanceBeforeAction.rayMul(index);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) =>
|
||||||
INVALID_HF,
|
INVALID_HF,
|
||||||
SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER,
|
SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER,
|
||||||
COLLATERAL_CANNOT_BE_LIQUIDATED,
|
COLLATERAL_CANNOT_BE_LIQUIDATED,
|
||||||
|
IS_PAUSED,
|
||||||
} = ProtocolErrors;
|
} = ProtocolErrors;
|
||||||
|
|
||||||
it('LIQUIDATION - Deposits WETH, borrows DAI/Check liquidation fails because health factor is above 1', async () => {
|
it('LIQUIDATION - Deposits WETH, borrows DAI/Check liquidation fails because health factor is above 1', async () => {
|
||||||
|
|
378
test/pausable-functions.spec.ts
Normal file
378
test/pausable-functions.spec.ts
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -9,7 +9,7 @@ import {
|
||||||
import {getContractsData} from './helpers/actions';
|
import {getContractsData} from './helpers/actions';
|
||||||
import {waitForTx} from './__setup.spec';
|
import {waitForTx} from './__setup.spec';
|
||||||
import {timeLatest} from '../helpers/misc-utils';
|
import {timeLatest} from '../helpers/misc-utils';
|
||||||
import {tEthereumAddress} from '../helpers/types';
|
import {ProtocolErrors, tEthereumAddress} from '../helpers/types';
|
||||||
import {parse} from 'path';
|
import {parse} from 'path';
|
||||||
|
|
||||||
const {expect} = require('chai');
|
const {expect} = require('chai');
|
||||||
|
@ -39,6 +39,7 @@ export const expectRepayWithCollateralEvent = (
|
||||||
};
|
};
|
||||||
|
|
||||||
makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => {
|
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 () => {
|
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 {configurator, weth, pool, users, dai, mockSwapAdapter} = testEnv;
|
||||||
const user = users[1];
|
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).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);
|
await pool.connect(user.signer).borrow(usdc.address, amountToBorrowStable, 1, 0, user.address);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
import {MockAToken} from '../types/MockAToken';
|
import {MockAToken} from '../types/MockAToken';
|
||||||
import {MockStableDebtToken} from '../types/MockStableDebtToken';
|
import {MockStableDebtToken} from '../types/MockStableDebtToken';
|
||||||
import {MockVariableDebtToken} from '../types/MockVariableDebtToken';
|
import {MockVariableDebtToken} from '../types/MockVariableDebtToken';
|
||||||
|
import {ZERO_ADDRESS} from '../helpers/constants';
|
||||||
|
|
||||||
makeSuite('Upgradeability', (testEnv: TestEnv) => {
|
makeSuite('Upgradeability', (testEnv: TestEnv) => {
|
||||||
const {CALLER_NOT_LENDING_POOL_MANAGER} = ProtocolErrors;
|
const {CALLER_NOT_LENDING_POOL_MANAGER} = ProtocolErrors;
|
||||||
|
@ -24,16 +25,29 @@ makeSuite('Upgradeability', (testEnv: TestEnv) => {
|
||||||
dai.address,
|
dai.address,
|
||||||
'Aave Interest bearing DAI updated',
|
'Aave Interest bearing DAI updated',
|
||||||
'aDAI',
|
'aDAI',
|
||||||
|
ZERO_ADDRESS,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const stableDebtTokenInstance = await deployContract<MockStableDebtToken>(
|
const stableDebtTokenInstance = await deployContract<MockStableDebtToken>(
|
||||||
eContractid.MockStableDebtToken,
|
eContractid.MockStableDebtToken,
|
||||||
[pool.address, dai.address, 'Aave stable debt bearing DAI updated', 'stableDebtDAI']
|
[
|
||||||
|
pool.address,
|
||||||
|
dai.address,
|
||||||
|
'Aave stable debt bearing DAI updated',
|
||||||
|
'stableDebtDAI',
|
||||||
|
ZERO_ADDRESS,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const variableDebtTokenInstance = await deployContract<MockVariableDebtToken>(
|
const variableDebtTokenInstance = await deployContract<MockVariableDebtToken>(
|
||||||
eContractid.MockVariableDebtToken,
|
eContractid.MockVariableDebtToken,
|
||||||
[pool.address, dai.address, 'Aave variable debt bearing DAI updated', 'variableDebtDAI']
|
[
|
||||||
|
pool.address,
|
||||||
|
dai.address,
|
||||||
|
'Aave variable debt bearing DAI updated',
|
||||||
|
'variableDebtDAI',
|
||||||
|
ZERO_ADDRESS,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
newATokenAddress = aTokenInstance.address;
|
newATokenAddress = aTokenInstance.address;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user