mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Merge branch 'master' into 100/flash-loan-bath-modes
This commit is contained in:
commit
1954f609c2
|
@ -99,17 +99,18 @@ interface ILendingPool {
|
|||
/**
|
||||
* @dev emitted when a flashloan is executed
|
||||
* @param target the address of the flashLoanReceiver
|
||||
* @param assets the address of the assets being flashborrowed
|
||||
* @param amounts the amount requested
|
||||
* @param premiums the total fee on the amount
|
||||
* @param asset the address of the assets being flashborrowed
|
||||
* @param amount the amount requested
|
||||
* @param premium the total fee on the amount
|
||||
* @param referralCode the referral code of the caller
|
||||
**/
|
||||
event FlashLoan(
|
||||
address indexed target,
|
||||
uint256[] modes,
|
||||
address[] assets,
|
||||
uint256[] amounts,
|
||||
uint256[] premiums,
|
||||
// uint256[] modes,
|
||||
// address indexed onBehalfOf,
|
||||
address asset,
|
||||
uint256 amount,
|
||||
uint256 premium,
|
||||
uint16 referralCode
|
||||
);
|
||||
|
||||
|
@ -286,7 +287,7 @@ interface ILendingPool {
|
|||
* @param receiver The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
|
||||
* @param assets the address of the principal reserve
|
||||
* @param amounts the amount requested for this flashloan
|
||||
* @param modes the flashloan mode
|
||||
* @param modes the flashloan borrow modes
|
||||
* @param params a bytes array to be sent to the flashloan executor
|
||||
* @param referralCode the referral code of the caller
|
||||
**/
|
||||
|
@ -295,6 +296,7 @@ interface ILendingPool {
|
|||
address[] calldata assets,
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata modes,
|
||||
address onBehalfOf,
|
||||
bytes calldata params,
|
||||
uint16 referralCode
|
||||
) external;
|
||||
|
@ -349,11 +351,14 @@ interface ILendingPool {
|
|||
|
||||
function getReserveData(address asset) external view returns (ReserveLogic.ReserveData memory);
|
||||
|
||||
function balanceDecreaseAllowed(
|
||||
address reserve,
|
||||
address user,
|
||||
uint256 amount
|
||||
) external view returns (bool);
|
||||
function finalizeTransfer(
|
||||
address asset,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
uint256 balanceFromAfter,
|
||||
uint256 balanceToBefore
|
||||
) external;
|
||||
|
||||
function getReservesList() external view returns (address[] memory);
|
||||
|
||||
|
|
|
@ -493,6 +493,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
uint256 currentAmount;
|
||||
uint256 currentPremium;
|
||||
uint256 currentAmountPlusPremium;
|
||||
address debtToken;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -503,6 +504,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
* @param assets The addresss of the assets being flashborrowed
|
||||
* @param amounts The amounts requested for this flashloan for each asset
|
||||
* @param modes Types of the debt to open if the flash loan is not returned. 0 -> Don't open any debt, just revert, 1 -> stable, 2 -> variable
|
||||
* @param onBehalfOf If mode is not 0, then the address to take the debt onBehalfOf. The onBehalfOf address must already have approved `msg.sender` to incur the debt on their behalf.
|
||||
* @param params Variadic packed params to pass to the receiver as extra information
|
||||
* @param referralCode Referral code of the flash loan
|
||||
**/
|
||||
|
@ -511,6 +513,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
address[] calldata assets,
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata modes,
|
||||
address onBehalfOf,
|
||||
bytes calldata params,
|
||||
uint16 referralCode
|
||||
) external override {
|
||||
|
@ -567,13 +570,21 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
vars.currentAmountPlusPremium
|
||||
);
|
||||
} else {
|
||||
if (msg.sender != onBehalfOf) {
|
||||
vars.debtToken = _reserves[vars.currentAsset].getDebtTokenAddress(modes[vars.i]);
|
||||
|
||||
_borrowAllowance[vars.debtToken][onBehalfOf][msg.sender] = _borrowAllowance[vars
|
||||
.debtToken][onBehalfOf][msg.sender]
|
||||
.sub(vars.currentAmount, Errors.BORROW_ALLOWANCE_ARE_NOT_ENOUGH);
|
||||
}
|
||||
|
||||
//if the user didn't choose to return the funds, the system checks if there
|
||||
//is enough collateral and eventually open a position
|
||||
_executeBorrow(
|
||||
ExecuteBorrowParams(
|
||||
vars.currentAsset,
|
||||
msg.sender,
|
||||
msg.sender,
|
||||
onBehalfOf,
|
||||
vars.currentAmount,
|
||||
modes[vars.i],
|
||||
vars.currentATokenAddress,
|
||||
|
@ -582,7 +593,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
)
|
||||
);
|
||||
}
|
||||
emit FlashLoan(receiverAddress, modes, assets, amounts, premiums, referralCode);
|
||||
emit FlashLoan(
|
||||
receiverAddress,
|
||||
vars.currentAsset,
|
||||
vars.currentAmount,
|
||||
vars.currentPremium,
|
||||
referralCode
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -723,29 +740,48 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev validate if a balance decrease for an asset is allowed
|
||||
* @dev validates and finalizes an aToken transfer
|
||||
* @param asset the address of the reserve
|
||||
* @param user the user related to the balance decrease
|
||||
* @param from the user from which the aTokens are transferred
|
||||
* @param to the user receiving the aTokens
|
||||
* @param amount the amount being transferred/redeemed
|
||||
* @return true if the balance decrease can be allowed, false otherwise
|
||||
* @param balanceFromBefore the balance of the from user before the transfer
|
||||
* @param balanceToBefore the balance of the to user before the transfer
|
||||
*/
|
||||
function balanceDecreaseAllowed(
|
||||
function finalizeTransfer(
|
||||
address asset,
|
||||
address user,
|
||||
uint256 amount
|
||||
) external override view returns (bool) {
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
uint256 balanceFromBefore,
|
||||
uint256 balanceToBefore
|
||||
) external override {
|
||||
_whenNotPaused();
|
||||
return
|
||||
GenericLogic.balanceDecreaseAllowed(
|
||||
asset,
|
||||
user,
|
||||
amount,
|
||||
_reserves,
|
||||
_usersConfig[user],
|
||||
_reservesList,
|
||||
_reservesCount,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
require(msg.sender == _reserves[asset].aTokenAddress, Errors.CALLER_MUST_BE_AN_ATOKEN);
|
||||
|
||||
ValidationLogic.validateTransfer(
|
||||
from,
|
||||
_reserves,
|
||||
_usersConfig[from],
|
||||
_reservesList,
|
||||
_reservesCount,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
uint256 reserveId = _reserves[asset].id;
|
||||
|
||||
if (from != to) {
|
||||
if (balanceFromBefore.sub(amount) == 0) {
|
||||
UserConfiguration.Map storage fromConfig = _usersConfig[from];
|
||||
fromConfig.setUsingAsCollateral(reserveId, false);
|
||||
}
|
||||
|
||||
if (balanceToBefore == 0 && amount != 0) {
|
||||
UserConfiguration.Map storage toConfig = _usersConfig[to];
|
||||
toConfig.setUsingAsCollateral(reserveId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,6 +46,7 @@ library Errors {
|
|||
string public constant NO_MORE_RESERVES_ALLOWED = '59';
|
||||
string public constant INVALID_FLASH_LOAN_EXECUTOR_RETURN = '60';
|
||||
string public constant INCONSISTENT_FLASHLOAN_PARAMS = '69';
|
||||
string public constant CALLER_MUST_BE_AN_ATOKEN = '76';
|
||||
|
||||
// require error messages - aToken - DebtTokens
|
||||
string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool'
|
||||
|
@ -97,7 +98,6 @@ library Errors {
|
|||
string public constant INVALID_DECIMALS = '73';
|
||||
string public constant INVALID_RESERVE_FACTOR = '74';
|
||||
|
||||
|
||||
enum CollateralManagerErrors {
|
||||
NO_ERROR,
|
||||
NO_COLLATERAL_AVAILABLE,
|
||||
|
|
|
@ -46,6 +46,11 @@ library ValidationLogic {
|
|||
* @param reserveAddress the address of the reserve
|
||||
* @param amount the amount to be withdrawn
|
||||
* @param userBalance the balance of the user
|
||||
* @param reservesData the reserves state
|
||||
* @param userConfig the user configuration
|
||||
* @param reserves the addresses of the reserves
|
||||
* @param reservesCount the number of reserves
|
||||
* @param oracle the price oracle
|
||||
*/
|
||||
function validateWithdraw(
|
||||
address reserveAddress,
|
||||
|
@ -331,10 +336,10 @@ library ValidationLogic {
|
|||
* @param amounts the amounts for each asset being borrowed
|
||||
**/
|
||||
function validateFlashloan(
|
||||
address[] memory assets,
|
||||
uint256[] memory amounts,
|
||||
uint256[] memory modes
|
||||
) internal pure {
|
||||
address[] calldata assets,
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata modes
|
||||
) external pure {
|
||||
require(
|
||||
assets.length == amounts.length && assets.length == modes.length,
|
||||
Errors.INCONSISTENT_FLASHLOAN_PARAMS
|
||||
|
@ -398,4 +403,35 @@ library ValidationLogic {
|
|||
|
||||
return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev validates an aToken transfer.
|
||||
* @param from the user from which the aTokens are being transferred
|
||||
* @param reservesData the state of all the reserves
|
||||
* @param userConfig the state of the user for the specific reserve
|
||||
* @param reserves the addresses of all the active reserves
|
||||
* @param oracle the price oracle
|
||||
*/
|
||||
function validateTransfer(
|
||||
address from,
|
||||
mapping(address => ReserveLogic.ReserveData) storage reservesData,
|
||||
UserConfiguration.Map storage userConfig,
|
||||
mapping(uint256 => address) storage reserves,
|
||||
uint256 reservesCount,
|
||||
address oracle
|
||||
) internal view {
|
||||
(, , , , uint256 healthFactor) = GenericLogic.calculateUserAccountData(
|
||||
from,
|
||||
reservesData,
|
||||
userConfig,
|
||||
reserves,
|
||||
reservesCount,
|
||||
oracle
|
||||
);
|
||||
|
||||
require(
|
||||
healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
|
||||
Errors.TRANSFER_NOT_ALLOWED
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,16 +241,6 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
return super.totalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Used to validate transfers before actually executing them.
|
||||
* @param user address of the user to check
|
||||
* @param amount the amount to check
|
||||
* @return true if the user can transfer amount, false otherwise
|
||||
**/
|
||||
function isTransferAllowed(address user, uint256 amount) public override view returns (bool) {
|
||||
return POOL.balanceDecreaseAllowed(UNDERLYING_ASSET_ADDRESS, user, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev transfers the underlying asset to the target. Used by the lendingpool to transfer
|
||||
* assets in borrow(), redeem() and flashLoan()
|
||||
|
@ -317,14 +307,24 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
uint256 amount,
|
||||
bool validate
|
||||
) internal {
|
||||
if (validate) {
|
||||
require(isTransferAllowed(from, amount), Errors.TRANSFER_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
uint256 index = POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
|
||||
|
||||
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
|
||||
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
|
||||
|
||||
super._transfer(from, to, amount.rayDiv(index));
|
||||
|
||||
if (validate) {
|
||||
POOL.finalizeTransfer(
|
||||
UNDERLYING_ASSET_ADDRESS,
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
fromBalanceBefore,
|
||||
toBalanceBefore
|
||||
);
|
||||
}
|
||||
|
||||
emit BalanceTransfer(from, to, amount, index);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,8 +54,6 @@ interface IAToken is IERC20, IScaledBalanceToken {
|
|||
uint256 value
|
||||
) external;
|
||||
|
||||
function isTransferAllowed(address user, uint256 amount) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @dev transfer the amount of the underlying asset to the user
|
||||
* @param user address of the user
|
||||
|
|
|
@ -91,6 +91,7 @@ export enum ProtocolErrors {
|
|||
REQUESTED_AMOUNT_TOO_SMALL = '25', // 'The requested amount is too small for a FlashLoan.'
|
||||
INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26', // 'The actual balance of the protocol is inconsistent'
|
||||
CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27', // 'The actual balance of the protocol is inconsistent'
|
||||
BORROW_ALLOWANCE_ARE_NOT_ENOUGH = '54', // User borrows on behalf, but allowance are too small
|
||||
INVALID_FLASH_LOAN_EXECUTOR_RETURN = '60', // The flash loan received returned 0 (EOA)
|
||||
|
||||
// require error messages - aToken
|
||||
|
|
|
@ -50,8 +50,8 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
);
|
||||
});
|
||||
|
||||
it('User 0 deposits 1 WETH and user 1 tries to borrow, but the aTokens received as a transfer are not available as collateral (revert expected)', async () => {
|
||||
const {users, pool, weth} = testEnv;
|
||||
it('User 0 deposits 1 WETH and user 1 tries to borrow the WETH with the received DAI as collateral', async () => {
|
||||
const {users, pool, weth, helpersContract} = testEnv;
|
||||
const userAddress = await pool.signer.getAddress();
|
||||
|
||||
await weth.connect(users[0].signer).mint(await convertToCurrencyDecimals(weth.address, '1'));
|
||||
|
@ -61,26 +61,6 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
await pool
|
||||
.connect(users[0].signer)
|
||||
.deposit(weth.address, ethers.utils.parseEther('1.0'), userAddress, '0');
|
||||
await expect(
|
||||
pool
|
||||
.connect(users[1].signer)
|
||||
.borrow(
|
||||
weth.address,
|
||||
ethers.utils.parseEther('0.1'),
|
||||
RateMode.Stable,
|
||||
AAVE_REFERRAL,
|
||||
users[1].address
|
||||
),
|
||||
COLLATERAL_BALANCE_IS_0
|
||||
).to.be.revertedWith(COLLATERAL_BALANCE_IS_0);
|
||||
});
|
||||
|
||||
it('User 1 sets the DAI as collateral and borrows, tries to transfer everything back to user 0 (revert expected)', async () => {
|
||||
const {users, pool, aDai, dai, weth} = testEnv;
|
||||
await pool.connect(users[1].signer).setUserUseReserveAsCollateral(dai.address, true);
|
||||
|
||||
const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '1000');
|
||||
|
||||
await pool
|
||||
.connect(users[1].signer)
|
||||
.borrow(
|
||||
|
@ -91,9 +71,34 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
users[1].address
|
||||
);
|
||||
|
||||
const userReserveData = await helpersContract.getUserReserveData(
|
||||
weth.address,
|
||||
users[1].address
|
||||
);
|
||||
|
||||
expect(userReserveData.currentStableDebt.toString()).to.be.eq(ethers.utils.parseEther('0.1'));
|
||||
});
|
||||
|
||||
it('User 1 tries to transfer all the DAI used as collateral back to user 0 (revert expected)', async () => {
|
||||
const {users, pool, aDai, dai, weth} = testEnv;
|
||||
|
||||
const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '1000');
|
||||
|
||||
await expect(
|
||||
aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer),
|
||||
TRANSFER_NOT_ALLOWED
|
||||
).to.be.revertedWith(TRANSFER_NOT_ALLOWED);
|
||||
});
|
||||
|
||||
it('User 1 tries to transfer a small amount of DAI used as collateral back to user 0', async () => {
|
||||
const {users, pool, aDai, dai, weth} = testEnv;
|
||||
|
||||
const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '100');
|
||||
|
||||
await aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer);
|
||||
|
||||
const user0Balance = await aDai.balanceOf(users[0].address);
|
||||
|
||||
expect(user0Balance.toString()).to.be.eq(aDAItoTransfer.toString());
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
SAFEERC20_LOWLEVEL_CALL,
|
||||
IS_PAUSED,
|
||||
INVALID_FLASH_LOAN_EXECUTOR_RETURN,
|
||||
BORROW_ALLOWANCE_ARE_NOT_ENOUGH,
|
||||
} = ProtocolErrors;
|
||||
|
||||
before(async () => {
|
||||
|
@ -48,6 +49,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
[0],
|
||||
_mockFlashLoanReceiver.address,
|
||||
'0x10',
|
||||
'0'
|
||||
);
|
||||
|
@ -77,6 +79,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
[weth.address],
|
||||
['1000720000000000000'],
|
||||
[0],
|
||||
_mockFlashLoanReceiver.address,
|
||||
'0x10',
|
||||
'0'
|
||||
);
|
||||
|
@ -108,6 +111,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
[0],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
)
|
||||
|
@ -128,6 +132,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
[0],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
)
|
||||
|
@ -148,6 +153,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
[4],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
)
|
||||
|
@ -176,6 +182,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
[weth.address],
|
||||
[ethers.utils.parseEther('0.8')],
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
);
|
||||
|
@ -194,14 +201,16 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
});
|
||||
|
||||
it('tries to take a flashloan that is bigger than the available liquidity (revert expected)', async () => {
|
||||
const {pool, weth} = testEnv;
|
||||
const {pool, weth, users} = testEnv;
|
||||
const caller = users[1];
|
||||
|
||||
await expect(
|
||||
pool.flashLoan(
|
||||
pool.connect(caller.signer).flashLoan(
|
||||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
['1004415000000000000'], //slightly higher than the available liquidity
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
),
|
||||
|
@ -210,10 +219,19 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
});
|
||||
|
||||
it('tries to take a flashloan using a non contract address as receiver (revert expected)', async () => {
|
||||
const {pool, deployer, weth} = testEnv;
|
||||
const {pool, deployer, weth, users} = testEnv;
|
||||
const caller = users[1];
|
||||
|
||||
await expect(
|
||||
pool.flashLoan(deployer.address, [weth.address], ['1000000000000000000'], [2], '0x10', '0')
|
||||
pool.flashLoan(
|
||||
deployer.address,
|
||||
[weth.address],
|
||||
['1000000000000000000'],
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
)
|
||||
).to.be.reverted;
|
||||
});
|
||||
|
||||
|
@ -242,6 +260,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
[usdc.address],
|
||||
[flashloanAmount],
|
||||
[0],
|
||||
_mockFlashLoanReceiver.address,
|
||||
'0x10',
|
||||
'0'
|
||||
);
|
||||
|
@ -284,6 +303,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
[usdc.address],
|
||||
[flashloanAmount],
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
)
|
||||
|
@ -309,7 +329,15 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
|
||||
await pool
|
||||
.connect(caller.signer)
|
||||
.flashLoan(_mockFlashLoanReceiver.address, [usdc.address], [flashloanAmount], [2], '0x10', '0');
|
||||
.flashLoan(
|
||||
_mockFlashLoanReceiver.address,
|
||||
[usdc.address],
|
||||
[flashloanAmount],
|
||||
[2],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
);
|
||||
const {variableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(
|
||||
usdc.address
|
||||
);
|
||||
|
@ -344,7 +372,15 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
await expect(
|
||||
pool
|
||||
.connect(caller.signer)
|
||||
.flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], [0], '0x10', '0')
|
||||
.flashLoan(
|
||||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
[0],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
)
|
||||
).to.be.revertedWith(SAFEERC20_LOWLEVEL_CALL);
|
||||
});
|
||||
|
||||
|
@ -359,7 +395,15 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
|
||||
await pool
|
||||
.connect(caller.signer)
|
||||
.flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], [1], '0x10', '0');
|
||||
.flashLoan(
|
||||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
[1],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
);
|
||||
|
||||
const {stableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(weth.address);
|
||||
|
||||
|
@ -372,4 +416,82 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
|
||||
expect(callerDebt.toString()).to.be.equal('800000000000000000', 'Invalid user debt');
|
||||
});
|
||||
|
||||
it('Caller takes a WETH flashloan with mode = 1 onBehalfOf user without allowance', async () => {
|
||||
const {dai, pool, weth, users, helpersContract} = testEnv;
|
||||
|
||||
const caller = users[5];
|
||||
const onBehalfOf = users[4];
|
||||
|
||||
// Deposit 1000 dai for onBehalfOf user
|
||||
await dai.connect(onBehalfOf.signer).mint(await convertToCurrencyDecimals(dai.address, '1000'));
|
||||
|
||||
await dai.connect(onBehalfOf.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
|
||||
|
||||
const amountToDeposit = await convertToCurrencyDecimals(dai.address, '1000');
|
||||
|
||||
await pool
|
||||
.connect(onBehalfOf.signer)
|
||||
.deposit(dai.address, amountToDeposit, onBehalfOf.address, '0');
|
||||
|
||||
const flashAmount = ethers.utils.parseEther('0.8');
|
||||
|
||||
await _mockFlashLoanReceiver.setFailExecutionTransfer(true);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(caller.signer)
|
||||
.flashLoan(
|
||||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
[1],
|
||||
onBehalfOf.address,
|
||||
'0x10',
|
||||
'0'
|
||||
)
|
||||
).to.be.revertedWith(BORROW_ALLOWANCE_ARE_NOT_ENOUGH);
|
||||
});
|
||||
|
||||
it('Caller takes a WETH flashloan with mode = 1 onBehalfOf user with allowance. A loan for onBehalfOf is creatd.', async () => {
|
||||
const {dai, pool, weth, users, helpersContract} = testEnv;
|
||||
|
||||
const caller = users[5];
|
||||
const onBehalfOf = users[4];
|
||||
|
||||
const flashAmount = ethers.utils.parseEther('0.8');
|
||||
|
||||
// Deposited for onBehalfOf user already, delegate borrow allowance
|
||||
await pool
|
||||
.connect(onBehalfOf.signer)
|
||||
.delegateBorrowAllowance(weth.address, caller.address, 1, flashAmount);
|
||||
|
||||
await _mockFlashLoanReceiver.setFailExecutionTransfer(true);
|
||||
|
||||
await pool
|
||||
.connect(caller.signer)
|
||||
.flashLoan(
|
||||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
[1],
|
||||
onBehalfOf.address,
|
||||
'0x10',
|
||||
'0'
|
||||
);
|
||||
|
||||
const {stableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(weth.address);
|
||||
|
||||
const wethDebtToken = await getContract<StableDebtToken>(
|
||||
eContractid.VariableDebtToken,
|
||||
stableDebtTokenAddress
|
||||
);
|
||||
|
||||
const onBehalfOfDebt = await wethDebtToken.balanceOf(onBehalfOf.address);
|
||||
|
||||
expect(onBehalfOfDebt.toString()).to.be.equal(
|
||||
'800000000000000000',
|
||||
'Invalid onBehalfOf user debt'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -187,7 +187,15 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => {
|
|||
await expect(
|
||||
pool
|
||||
.connect(caller.signer)
|
||||
.flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], [1], '0x10', '0')
|
||||
.flashLoan(
|
||||
_mockFlashLoanReceiver.address,
|
||||
[weth.address],
|
||||
[flashAmount],
|
||||
[1],
|
||||
caller.address,
|
||||
'0x10',
|
||||
'0'
|
||||
)
|
||||
).revertedWith(IS_PAUSED);
|
||||
|
||||
// Unpause pool
|
||||
|
|
Loading…
Reference in New Issue
Block a user