mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Merge branch 'fix/78' into 'master'
Resolve "Extend flashloans to allow flashborrowing of multiple currencies" Closes #78 See merge request aave-tech/protocol-v2!87
This commit is contained in:
commit
85168f8ea7
|
@ -9,9 +9,9 @@ pragma solidity ^0.6.8;
|
||||||
**/
|
**/
|
||||||
interface IFlashLoanReceiver {
|
interface IFlashLoanReceiver {
|
||||||
function executeOperation(
|
function executeOperation(
|
||||||
address reserve,
|
address[] calldata assets,
|
||||||
uint256 amount,
|
uint256[] calldata amounts,
|
||||||
uint256 fee,
|
uint256[] calldata premiums,
|
||||||
bytes calldata params
|
bytes calldata params
|
||||||
) external returns (bool);
|
) external returns (bool);
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,16 +99,17 @@ interface ILendingPool {
|
||||||
/**
|
/**
|
||||||
* @dev emitted when a flashloan is executed
|
* @dev emitted when a flashloan is executed
|
||||||
* @param target the address of the flashLoanReceiver
|
* @param target the address of the flashLoanReceiver
|
||||||
* @param reserve the address of the reserve
|
* @param assets the address of the assets being flashborrowed
|
||||||
* @param amount the amount requested
|
* @param amounts the amount requested
|
||||||
* @param totalPremium the total fee on the amount
|
* @param premiums the total fee on the amount
|
||||||
* @param referralCode the referral code of the caller
|
* @param referralCode the referral code of the caller
|
||||||
**/
|
**/
|
||||||
event FlashLoan(
|
event FlashLoan(
|
||||||
address indexed target,
|
address indexed target,
|
||||||
address indexed reserve,
|
uint256 mode,
|
||||||
uint256 amount,
|
address[] assets,
|
||||||
uint256 totalPremium,
|
uint256[] amounts,
|
||||||
|
uint256[] premiums,
|
||||||
uint16 referralCode
|
uint16 referralCode
|
||||||
);
|
);
|
||||||
/**
|
/**
|
||||||
|
@ -264,16 +265,17 @@ interface ILendingPool {
|
||||||
* as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
|
* as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
|
||||||
* that must be kept into consideration. For further details please visit https://developers.aave.com
|
* that must be kept into consideration. For further details please visit https://developers.aave.com
|
||||||
* @param receiver The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
|
* @param receiver The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
|
||||||
* @param reserve the address of the principal reserve
|
* @param assets the address of the principal reserve
|
||||||
* @param amount the amount requested for this flashloan
|
* @param amounts the amount requested for this flashloan
|
||||||
|
* @param mode the flashloan mode
|
||||||
* @param params a bytes array to be sent to the flashloan executor
|
* @param params a bytes array to be sent to the flashloan executor
|
||||||
* @param referralCode the referral code of the caller
|
* @param referralCode the referral code of the caller
|
||||||
**/
|
**/
|
||||||
function flashLoan(
|
function flashLoan(
|
||||||
address receiver,
|
address receiver,
|
||||||
address reserve,
|
address[] calldata assets,
|
||||||
uint256 amount,
|
uint256[] calldata amounts,
|
||||||
uint256 debtType,
|
uint256 mode,
|
||||||
bytes calldata params,
|
bytes calldata params,
|
||||||
uint16 referralCode
|
uint16 referralCode
|
||||||
) external;
|
) external;
|
||||||
|
|
|
@ -484,11 +484,15 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FlashLoanLocalVars {
|
struct FlashLoanLocalVars {
|
||||||
uint256 premium;
|
|
||||||
uint256 amountPlusPremium;
|
|
||||||
IFlashLoanReceiver receiver;
|
IFlashLoanReceiver receiver;
|
||||||
address aTokenAddress;
|
|
||||||
address oracle;
|
address oracle;
|
||||||
|
ReserveLogic.InterestRateMode debtMode;
|
||||||
|
uint256 i;
|
||||||
|
address currentAsset;
|
||||||
|
address currentATokenAddress;
|
||||||
|
uint256 currentAmount;
|
||||||
|
uint256 currentPremium;
|
||||||
|
uint256 currentAmountPlusPremium;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -496,69 +500,91 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
||||||
* as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
|
* as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
|
||||||
* that must be kept into consideration. For further details please visit https://developers.aave.com
|
* that must be kept into consideration. For further details please visit https://developers.aave.com
|
||||||
* @param receiverAddress The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
|
* @param receiverAddress The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
|
||||||
* @param asset The address of the principal reserve
|
* @param assets The addresss of the assets being flashborrowed
|
||||||
* @param amount The amount requested for this flashloan
|
* @param amounts The amounts requested for this flashloan for each asset
|
||||||
* @param mode Type of the debt to open if the flash loan is not returned. 0 -> Don't open any debt, just revert, 1 -> stable, 2 -> variable
|
* @param mode Type of the debt to open if the flash loan is not returned. 0 -> Don't open any debt, just revert, 1 -> stable, 2 -> variable
|
||||||
* @param params Variadic packed params to pass to the receiver as extra information
|
* @param params Variadic packed params to pass to the receiver as extra information
|
||||||
* @param referralCode Referral code of the flash loan
|
* @param referralCode Referral code of the flash loan
|
||||||
**/
|
**/
|
||||||
function flashLoan(
|
function flashLoan(
|
||||||
address receiverAddress,
|
address receiverAddress,
|
||||||
address asset,
|
address[] calldata assets,
|
||||||
uint256 amount,
|
uint256[] calldata amounts,
|
||||||
uint256 mode,
|
uint256 mode,
|
||||||
bytes calldata params,
|
bytes calldata params,
|
||||||
uint16 referralCode
|
uint16 referralCode
|
||||||
) external override {
|
) external override {
|
||||||
_whenNotPaused();
|
_whenNotPaused();
|
||||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
|
||||||
FlashLoanLocalVars memory vars;
|
FlashLoanLocalVars memory vars;
|
||||||
|
|
||||||
vars.aTokenAddress = reserve.aTokenAddress;
|
ValidationLogic.validateFlashloan(assets, amounts, mode);
|
||||||
|
|
||||||
vars.premium = amount.mul(FLASHLOAN_PREMIUM_TOTAL).div(10000);
|
address[] memory aTokenAddresses = new address[](assets.length);
|
||||||
|
uint256[] memory premiums = new uint256[](assets.length);
|
||||||
ValidationLogic.validateFlashloan(mode, vars.premium);
|
|
||||||
|
|
||||||
ReserveLogic.InterestRateMode debtMode = ReserveLogic.InterestRateMode(mode);
|
|
||||||
|
|
||||||
vars.receiver = IFlashLoanReceiver(receiverAddress);
|
vars.receiver = IFlashLoanReceiver(receiverAddress);
|
||||||
|
vars.debtMode = ReserveLogic.InterestRateMode(mode);
|
||||||
|
|
||||||
|
for (vars.i = 0; vars.i < assets.length; vars.i++) {
|
||||||
|
aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress;
|
||||||
|
|
||||||
|
premiums[vars.i] = amounts[vars.i].mul(FLASHLOAN_PREMIUM_TOTAL).div(10000);
|
||||||
|
|
||||||
//transfer funds to the receiver
|
//transfer funds to the receiver
|
||||||
IAToken(vars.aTokenAddress).transferUnderlyingTo(receiverAddress, amount);
|
IAToken(aTokenAddresses[vars.i]).transferUnderlyingTo(receiverAddress, amounts[vars.i]);
|
||||||
|
}
|
||||||
|
|
||||||
//execute action of the receiver
|
//execute action of the receiver
|
||||||
require(
|
require(
|
||||||
vars.receiver.executeOperation(asset, amount, vars.premium, params),
|
vars.receiver.executeOperation(assets, amounts, premiums, params),
|
||||||
Errors.INVALID_FLASH_LOAN_EXECUTOR_RETURN
|
Errors.INVALID_FLASH_LOAN_EXECUTOR_RETURN
|
||||||
);
|
);
|
||||||
|
|
||||||
vars.amountPlusPremium = amount.add(vars.premium);
|
for (vars.i = 0; vars.i < assets.length; vars.i++) {
|
||||||
|
vars.currentAsset = assets[vars.i];
|
||||||
|
vars.currentAmount = amounts[vars.i];
|
||||||
|
vars.currentPremium = premiums[vars.i];
|
||||||
|
vars.currentATokenAddress = aTokenAddresses[vars.i];
|
||||||
|
|
||||||
if (debtMode == ReserveLogic.InterestRateMode.NONE) {
|
vars.currentAmountPlusPremium = vars.currentAmount.add(vars.currentPremium);
|
||||||
IERC20(asset).safeTransferFrom(receiverAddress, vars.aTokenAddress, vars.amountPlusPremium);
|
|
||||||
|
|
||||||
reserve.updateState();
|
if (vars.debtMode == ReserveLogic.InterestRateMode.NONE) {
|
||||||
reserve.cumulateToLiquidityIndex(IERC20(vars.aTokenAddress).totalSupply(), vars.premium);
|
_reserves[vars.currentAsset].updateState();
|
||||||
reserve.updateInterestRates(asset, vars.aTokenAddress, vars.premium, 0);
|
_reserves[vars.currentAsset].cumulateToLiquidityIndex(
|
||||||
|
IERC20(vars.currentATokenAddress).totalSupply(),
|
||||||
|
vars.currentPremium
|
||||||
|
);
|
||||||
|
_reserves[vars.currentAsset].updateInterestRates(
|
||||||
|
vars.currentAsset,
|
||||||
|
vars.currentATokenAddress,
|
||||||
|
vars.currentPremium,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
emit FlashLoan(receiverAddress, asset, amount, vars.premium, referralCode);
|
IERC20(vars.currentAsset).safeTransferFrom(
|
||||||
|
receiverAddress,
|
||||||
|
vars.currentATokenAddress,
|
||||||
|
vars.currentAmountPlusPremium
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
//if the user didn't choose to return the funds, the system checks if there
|
//if the user didn't choose to return the funds, the system checks if there
|
||||||
//is enough collateral and eventually open a position
|
//is enough collateral and eventually open a position
|
||||||
_executeBorrow(
|
_executeBorrow(
|
||||||
ExecuteBorrowParams(
|
ExecuteBorrowParams(
|
||||||
asset,
|
vars.currentAsset,
|
||||||
msg.sender,
|
msg.sender,
|
||||||
msg.sender,
|
msg.sender,
|
||||||
vars.amountPlusPremium,
|
vars.currentAmount,
|
||||||
mode,
|
mode,
|
||||||
vars.aTokenAddress,
|
vars.currentATokenAddress,
|
||||||
referralCode,
|
referralCode,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
emit FlashLoan(receiverAddress, mode, assets, amounts, premiums, referralCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -45,6 +45,7 @@ library Errors {
|
||||||
string public constant INVALID_EQUAL_ASSETS_TO_SWAP = '56';
|
string public constant INVALID_EQUAL_ASSETS_TO_SWAP = '56';
|
||||||
string public constant NO_MORE_RESERVES_ALLOWED = '59';
|
string public constant NO_MORE_RESERVES_ALLOWED = '59';
|
||||||
string public constant INVALID_FLASH_LOAN_EXECUTOR_RETURN = '60';
|
string public constant INVALID_FLASH_LOAN_EXECUTOR_RETURN = '60';
|
||||||
|
string public constant INCONSISTENT_FLASHLOAN_PARAMS = '69';
|
||||||
|
|
||||||
// require error messages - aToken - DebtTokens
|
// require error messages - aToken - DebtTokens
|
||||||
string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool'
|
string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool'
|
||||||
|
|
|
@ -327,11 +327,16 @@ library ValidationLogic {
|
||||||
/**
|
/**
|
||||||
* @dev validates a flashloan action
|
* @dev validates a flashloan action
|
||||||
* @param mode the flashloan mode (0 = classic flashloan, 1 = open a stable rate loan, 2 = open a variable rate loan)
|
* @param mode the flashloan mode (0 = classic flashloan, 1 = open a stable rate loan, 2 = open a variable rate loan)
|
||||||
* @param premium the premium paid on the flashloan
|
* @param assets the assets being flashborrowed
|
||||||
|
* @param amounts the amounts for each asset being borrowed
|
||||||
**/
|
**/
|
||||||
function validateFlashloan(uint256 mode, uint256 premium) internal pure {
|
function validateFlashloan(
|
||||||
require(premium > 0, Errors.REQUESTED_AMOUNT_TOO_SMALL);
|
address[] memory assets,
|
||||||
|
uint256[] memory amounts,
|
||||||
|
uint256 mode
|
||||||
|
) internal pure {
|
||||||
require(mode <= uint256(ReserveLogic.InterestRateMode.VARIABLE), Errors.INVALID_FLASHLOAN_MODE);
|
require(mode <= uint256(ReserveLogic.InterestRateMode.VARIABLE), Errors.INVALID_FLASHLOAN_MODE);
|
||||||
|
require(assets.length == amounts.length, Errors.INCONSISTENT_FLASHLOAN_PARAMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,8 +14,8 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase {
|
||||||
|
|
||||||
ILendingPoolAddressesProvider internal _provider;
|
ILendingPoolAddressesProvider internal _provider;
|
||||||
|
|
||||||
event ExecutedWithFail(address _reserve, uint256 _amount, uint256 _fee);
|
event ExecutedWithFail(address[] _assets, uint256[] _amounts, uint256[] _premiums);
|
||||||
event ExecutedWithSuccess(address _reserve, uint256 _amount, uint256 _fee);
|
event ExecutedWithSuccess(address[] _assets, uint256[] _amounts, uint256[] _premiums);
|
||||||
|
|
||||||
bool _failExecution;
|
bool _failExecution;
|
||||||
uint256 _amountToApprove;
|
uint256 _amountToApprove;
|
||||||
|
@ -44,33 +44,40 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeOperation(
|
function executeOperation(
|
||||||
address reserve,
|
address[] memory assets,
|
||||||
uint256 amount,
|
uint256[] memory amounts,
|
||||||
uint256 fee,
|
uint256[] memory premiums,
|
||||||
bytes memory params
|
bytes memory params
|
||||||
) public override returns (bool) {
|
) public override returns (bool) {
|
||||||
params;
|
params;
|
||||||
//mint to this contract the specific amount
|
|
||||||
MintableERC20 token = MintableERC20(reserve);
|
|
||||||
|
|
||||||
//check the contract has the specified balance
|
|
||||||
require(amount <= IERC20(reserve).balanceOf(address(this)), 'Invalid balance for the contract');
|
|
||||||
|
|
||||||
uint256 amountToReturn = (_amountToApprove != 0) ? _amountToApprove : amount.add(fee);
|
|
||||||
|
|
||||||
if (_failExecution) {
|
if (_failExecution) {
|
||||||
emit ExecutedWithFail(reserve, amount, fee);
|
emit ExecutedWithFail(assets, amounts, premiums);
|
||||||
return !_simulateEOA;
|
return !_simulateEOA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint256 i = 0; i < assets.length; i++) {
|
||||||
|
//mint to this contract the specific amount
|
||||||
|
MintableERC20 token = MintableERC20(assets[i]);
|
||||||
|
|
||||||
|
//check the contract has the specified balance
|
||||||
|
require(
|
||||||
|
amounts[i] <= IERC20(assets[i]).balanceOf(address(this)),
|
||||||
|
'Invalid balance for the contract'
|
||||||
|
);
|
||||||
|
|
||||||
|
uint256 amountToReturn = (_amountToApprove != 0)
|
||||||
|
? _amountToApprove
|
||||||
|
: amounts[i].add(premiums[i]);
|
||||||
//execution does not fail - mint tokens and return them to the _destination
|
//execution does not fail - mint tokens and return them to the _destination
|
||||||
//note: if the reserve is eth, the mock contract must receive at least _fee ETH before calling executeOperation
|
//note: if the reserve is eth, the mock contract must receive at least _fee ETH before calling executeOperation
|
||||||
|
|
||||||
token.mint(fee);
|
token.mint(premiums[i]);
|
||||||
|
|
||||||
IERC20(reserve).approve(_addressesProvider.getLendingPool(), amountToReturn);
|
IERC20(assets[i]).approve(_addressesProvider.getLendingPool(), amountToReturn);
|
||||||
|
}
|
||||||
|
|
||||||
emit ExecutedWithSuccess(reserve, amount, fee);
|
emit ExecutedWithSuccess(assets, amounts, premiums);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
await pool.flashLoan(
|
await pool.flashLoan(
|
||||||
_mockFlashLoanReceiver.address,
|
_mockFlashLoanReceiver.address,
|
||||||
weth.address,
|
[weth.address],
|
||||||
ethers.utils.parseEther('0.8'),
|
[ethers.utils.parseEther('0.8')],
|
||||||
0,
|
0,
|
||||||
'0x10',
|
'0x10',
|
||||||
'0'
|
'0'
|
||||||
|
@ -77,8 +77,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
const reserveDataBefore = await helpersContract.getReserveData(weth.address);
|
const reserveDataBefore = await helpersContract.getReserveData(weth.address);
|
||||||
const txResult = await pool.flashLoan(
|
const txResult = await pool.flashLoan(
|
||||||
_mockFlashLoanReceiver.address,
|
_mockFlashLoanReceiver.address,
|
||||||
weth.address,
|
[weth.address],
|
||||||
'1000720000000000000',
|
['1000720000000000000'],
|
||||||
0,
|
0,
|
||||||
'0x10',
|
'0x10',
|
||||||
'0'
|
'0'
|
||||||
|
@ -108,8 +108,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(
|
.flashLoan(
|
||||||
_mockFlashLoanReceiver.address,
|
_mockFlashLoanReceiver.address,
|
||||||
weth.address,
|
[weth.address],
|
||||||
ethers.utils.parseEther('0.8'),
|
[ethers.utils.parseEther('0.8')],
|
||||||
0,
|
0,
|
||||||
'0x10',
|
'0x10',
|
||||||
'0'
|
'0'
|
||||||
|
@ -128,8 +128,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(
|
.flashLoan(
|
||||||
_mockFlashLoanReceiver.address,
|
_mockFlashLoanReceiver.address,
|
||||||
weth.address,
|
[weth.address],
|
||||||
ethers.utils.parseEther('0.8'),
|
[ethers.utils.parseEther('0.8')],
|
||||||
0,
|
0,
|
||||||
'0x10',
|
'0x10',
|
||||||
'0'
|
'0'
|
||||||
|
@ -148,8 +148,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(
|
.flashLoan(
|
||||||
_mockFlashLoanReceiver.address,
|
_mockFlashLoanReceiver.address,
|
||||||
weth.address,
|
[weth.address],
|
||||||
ethers.utils.parseEther('0.8'),
|
[ethers.utils.parseEther('0.8')],
|
||||||
4,
|
4,
|
||||||
'0x10',
|
'0x10',
|
||||||
'0'
|
'0'
|
||||||
|
@ -176,8 +176,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(
|
.flashLoan(
|
||||||
_mockFlashLoanReceiver.address,
|
_mockFlashLoanReceiver.address,
|
||||||
weth.address,
|
[weth.address],
|
||||||
ethers.utils.parseEther('0.8'),
|
[ethers.utils.parseEther('0.8')],
|
||||||
2,
|
2,
|
||||||
'0x10',
|
'0x10',
|
||||||
'0'
|
'0'
|
||||||
|
@ -193,22 +193,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
const callerDebt = await wethDebtToken.balanceOf(caller.address);
|
const callerDebt = await wethDebtToken.balanceOf(caller.address);
|
||||||
|
|
||||||
expect(callerDebt.toString()).to.be.equal('800720000000000000', 'Invalid user debt');
|
expect(callerDebt.toString()).to.be.equal('800000000000000000', 'Invalid user debt');
|
||||||
});
|
|
||||||
|
|
||||||
it('tries to take a very small flashloan, which would result in 0 fees (revert expected)', async () => {
|
|
||||||
const {pool, weth} = testEnv;
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
pool.flashLoan(
|
|
||||||
_mockFlashLoanReceiver.address,
|
|
||||||
weth.address,
|
|
||||||
'1', //1 wei loan
|
|
||||||
2,
|
|
||||||
'0x10',
|
|
||||||
'0'
|
|
||||||
)
|
|
||||||
).to.be.revertedWith(REQUESTED_AMOUNT_TOO_SMALL);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tries to take a flashloan that is bigger than the available liquidity (revert expected)', async () => {
|
it('tries to take a flashloan that is bigger than the available liquidity (revert expected)', async () => {
|
||||||
|
@ -217,8 +202,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
await expect(
|
await expect(
|
||||||
pool.flashLoan(
|
pool.flashLoan(
|
||||||
_mockFlashLoanReceiver.address,
|
_mockFlashLoanReceiver.address,
|
||||||
weth.address,
|
[weth.address],
|
||||||
'1004415000000000000', //slightly higher than the available liquidity
|
['1004415000000000000'], //slightly higher than the available liquidity
|
||||||
2,
|
2,
|
||||||
'0x10',
|
'0x10',
|
||||||
'0'
|
'0'
|
||||||
|
@ -231,7 +216,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
const {pool, deployer, weth} = testEnv;
|
const {pool, deployer, weth} = testEnv;
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
pool.flashLoan(deployer.address, weth.address, '1000000000000000000', 2, '0x10', '0')
|
pool.flashLoan(deployer.address, [weth.address], ['1000000000000000000'], 2, '0x10', '0')
|
||||||
).to.be.reverted;
|
).to.be.reverted;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -257,8 +242,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
await pool.flashLoan(
|
await pool.flashLoan(
|
||||||
_mockFlashLoanReceiver.address,
|
_mockFlashLoanReceiver.address,
|
||||||
usdc.address,
|
[usdc.address],
|
||||||
flashloanAmount,
|
[flashloanAmount],
|
||||||
0,
|
0,
|
||||||
'0x10',
|
'0x10',
|
||||||
'0'
|
'0'
|
||||||
|
@ -297,7 +282,14 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
await expect(
|
await expect(
|
||||||
pool
|
pool
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(_mockFlashLoanReceiver.address, usdc.address, flashloanAmount, 2, '0x10', '0')
|
.flashLoan(
|
||||||
|
_mockFlashLoanReceiver.address,
|
||||||
|
[usdc.address],
|
||||||
|
[flashloanAmount],
|
||||||
|
2,
|
||||||
|
'0x10',
|
||||||
|
'0'
|
||||||
|
)
|
||||||
).to.be.revertedWith(COLLATERAL_BALANCE_IS_0);
|
).to.be.revertedWith(COLLATERAL_BALANCE_IS_0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -320,7 +312,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
await pool
|
await pool
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(_mockFlashLoanReceiver.address, usdc.address, flashloanAmount, 2, '0x10', '0');
|
.flashLoan(_mockFlashLoanReceiver.address, [usdc.address], [flashloanAmount], 2, '0x10', '0');
|
||||||
const {variableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(
|
const {variableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(
|
||||||
usdc.address
|
usdc.address
|
||||||
);
|
);
|
||||||
|
@ -332,7 +324,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
const callerDebt = await usdcDebtToken.balanceOf(caller.address);
|
const callerDebt = await usdcDebtToken.balanceOf(caller.address);
|
||||||
|
|
||||||
expect(callerDebt.toString()).to.be.equal('500450000', 'Invalid user debt');
|
expect(callerDebt.toString()).to.be.equal('500000000', 'Invalid user debt');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Caller deposits 1000 DAI as collateral, Takes a WETH flashloan with mode = 0, does not approve the transfer of the funds', async () => {
|
it('Caller deposits 1000 DAI as collateral, Takes a WETH flashloan with mode = 0, does not approve the transfer of the funds', async () => {
|
||||||
|
@ -355,7 +347,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
await expect(
|
await expect(
|
||||||
pool
|
pool
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(_mockFlashLoanReceiver.address, weth.address, flashAmount, 0, '0x10', '0')
|
.flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], 0, '0x10', '0')
|
||||||
).to.be.revertedWith(SAFEERC20_LOWLEVEL_CALL);
|
).to.be.revertedWith(SAFEERC20_LOWLEVEL_CALL);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -370,7 +362,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
await pool
|
await pool
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(_mockFlashLoanReceiver.address, weth.address, flashAmount, 1, '0x10', '0');
|
.flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], 1, '0x10', '0');
|
||||||
|
|
||||||
const {stableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(weth.address);
|
const {stableDebtTokenAddress} = await helpersContract.getReserveTokensAddresses(weth.address);
|
||||||
|
|
||||||
|
@ -381,6 +373,6 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
||||||
|
|
||||||
const callerDebt = await wethDebtToken.balanceOf(caller.address);
|
const callerDebt = await wethDebtToken.balanceOf(caller.address);
|
||||||
|
|
||||||
expect(callerDebt.toString()).to.be.equal('800720000000000000', 'Invalid user debt');
|
expect(callerDebt.toString()).to.be.equal('800000000000000000', 'Invalid user debt');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -186,7 +186,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => {
|
||||||
await expect(
|
await expect(
|
||||||
pool
|
pool
|
||||||
.connect(caller.signer)
|
.connect(caller.signer)
|
||||||
.flashLoan(_mockFlashLoanReceiver.address, weth.address, flashAmount, 1, '0x10', '0')
|
.flashLoan(_mockFlashLoanReceiver.address, [weth.address], [flashAmount], 1, '0x10', '0')
|
||||||
).revertedWith(IS_PAUSED);
|
).revertedWith(IS_PAUSED);
|
||||||
|
|
||||||
// Unpause pool
|
// Unpause pool
|
||||||
|
|
Loading…
Reference in New Issue
Block a user