// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;

import '@openzeppelin/contracts/math/SafeMath.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

import '../../flashloan/base/FlashLoanReceiverBase.sol';
import '../tokens/MintableERC20.sol';
import '../../libraries/UniversalERC20.sol';

contract MockFlashLoanReceiver is FlashLoanReceiverBase {
  using SafeMath for uint256;
  using UniversalERC20 for IERC20;

  event ExecutedWithFail(address _reserve, uint256 _amount, uint256 _fee);
  event ExecutedWithSuccess(address _reserve, uint256 _amount, uint256 _fee);

  bool failExecution = false;

  constructor(ILendingPoolAddressesProvider _provider) public FlashLoanReceiverBase(_provider) {}

  function setFailExecutionTransfer(bool _fail) public {
    failExecution = _fail;
  }

  function executeOperation(
    address _reserve,
    address _destination,
    uint256 _amount,
    uint256 _fee,
    bytes memory _params
  ) public override {
    //mint to this contract the specific amount
    MintableERC20 token = MintableERC20(_reserve);

    //check the contract has the specified balance
    require(
      _amount <= getBalanceInternal(address(this), _reserve),
      'Invalid balance for the contract'
    );

    if (failExecution) {
      emit ExecutedWithFail(_reserve, _amount, _fee);
      return;
    }

    //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

    if (!IERC20(_reserve).isETH()) {
      token.mint(_fee);
    }

    //returning amount + fee to the destination
    transferFundsBackInternal(_reserve, _destination, _amount.add(_fee));

    emit ExecutedWithSuccess(_reserve, _amount, _fee);
  }
}