diff --git a/contracts/mocks/flashloan/MockFlashLoanReceiver.sol b/contracts/mocks/flashloan/MockFlashLoanReceiver.sol index 610e94cd..112084a7 100644 --- a/contracts/mocks/flashloan/MockFlashLoanReceiver.sol +++ b/contracts/mocks/flashloan/MockFlashLoanReceiver.sol @@ -18,12 +18,21 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase { event ExecutedWithFail(address _reserve, uint256 _amount, uint256 _fee); event ExecutedWithSuccess(address _reserve, uint256 _amount, uint256 _fee); - bool failExecution = false; + bool _failExecution; + uint256 _amountToApprove; constructor(ILendingPoolAddressesProvider provider) public FlashLoanReceiverBase(provider) {} - function setFailExecutionTransfer(bool _fail) public { - failExecution = _fail; + function setFailExecutionTransfer(bool fail) public { + _failExecution = fail; + } + + function setAmountToApprove(uint256 amountToApprove) public { + _amountToApprove = amountToApprove; + } + + function amountToApprove() public view returns (uint256) { + return _amountToApprove; } function executeOperation( @@ -36,12 +45,11 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase { MintableERC20 token = MintableERC20(reserve); //check the contract has the specified balance - require( - amount <= IERC20(reserve).balanceOf(address(this)), - 'Invalid balance for the contract' - ); + require(amount <= IERC20(reserve).balanceOf(address(this)), 'Invalid balance for the contract'); - if (failExecution) { + uint256 amountToReturn = (_amountToApprove != 0) ? _amountToApprove : amount.add(fee); + + if (_failExecution) { emit ExecutedWithFail(reserve, amount, fee); return; } @@ -51,7 +59,7 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase { token.mint(fee); - IERC20(reserve).approve(_addressesProvider.getLendingPool(), amount.add(fee)); + IERC20(reserve).approve(_addressesProvider.getLendingPool(), amountToReturn); emit ExecutedWithSuccess(reserve, amount, fee); } diff --git a/test/flashloan.spec.ts b/test/flashloan.spec.ts index 93915783..689796ec 100644 --- a/test/flashloan.spec.ts +++ b/test/flashloan.spec.ts @@ -282,4 +282,64 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { expect(callerDebt.toString()).to.be.equal('500450000', 'Invalid user debt'); }); + + it('Caller deposits 5 ETH as collateral, Takes a USDC flashloan, approves only partially funds. A loan for caller is created', async () => { + const {usdc, pool, weth, users} = testEnv; + + const caller = users[3]; + + await weth.connect(caller.signer).mint(await convertToCurrencyDecimals(weth.address, '5')); + + await weth.connect(caller.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); + + const amountToDeposit = await convertToCurrencyDecimals(weth.address, '5'); + + await pool.connect(caller.signer).deposit(weth.address, amountToDeposit, '0'); + + const flashloanAmount = await convertToCurrencyDecimals(usdc.address, '500'); + + await _mockFlashLoanReceiver.setFailExecutionTransfer(false); + + await _mockFlashLoanReceiver.setAmountToApprove(flashloanAmount.div(2)); + console.log((await _mockFlashLoanReceiver.amountToApprove()).toString()); + + await pool + .connect(caller.signer) + .flashLoan(_mockFlashLoanReceiver.address, usdc.address, flashloanAmount, 2, '0x10', '0'); + const {variableDebtTokenAddress} = await pool.getReserveTokensAddresses(usdc.address); + + const usdcDebtToken = await getContract( + eContractid.VariableDebtToken, + variableDebtTokenAddress + ); + + const callerDebt = await usdcDebtToken.balanceOf(caller.address); + + expect(callerDebt.toString()).to.be.equal('250450000', 'Invalid user debt'); + }); + + it('Caller deposits 1000 DAI as collateral, Takes WETH flashloan, does not return the funds and selects revert as result', async () => { + const {dai, pool, weth, users} = testEnv; + + const caller = users[3]; + + await dai.connect(caller.signer).mint(await convertToCurrencyDecimals(dai.address, '1000')); + + await dai.connect(caller.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); + + const amountToDeposit = await convertToCurrencyDecimals(dai.address, '1000'); + + await pool.connect(caller.signer).deposit(dai.address, amountToDeposit, '0'); + + const flashAmount = ethers.utils.parseEther('0.8'); + + await _mockFlashLoanReceiver.setFailExecutionTransfer(false); + await _mockFlashLoanReceiver.setAmountToApprove(flashAmount.div(2)); + + await expect( + pool + .connect(caller.signer) + .flashLoan(_mockFlashLoanReceiver.address, weth.address, flashAmount, 0, '0x10', '0') + ).to.be.revertedWith('ERC20: transfer amount exceeds allowance'); + }); });