aave / protocol-v2

Aave Protocol V2
https://aave.com
Other
653 stars 741 forks source link

Error: execution reverted: SafeERC20: low-level call failed with #304

Open burgossrodrigo opened 2 years ago

burgossrodrigo commented 2 years ago

I don't know if here is the best place to ask but sure is the place with more experienced dev on the subject. I have this contract:


pragma solidity ^0.6.6;

import "@aave/protocol-v2/contracts/flashloan/base/FlashLoanReceiverBase.sol";
import "@aave/protocol-v2/contracts/interfaces/ILendingPoolAddressesProvider.sol";
import "@aave/protocol-v2/contracts/interfaces/ILendingPool.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import {SafeERC20} from "@aave/protocol-v2/contracts/dependencies/openzeppelin/contracts/SafeERC20.sol";

//import "@openzeppelin/contracts/interfaces/IERC20.sol";

contract FlashloanV2 is FlashLoanReceiverBase {

    using SafeERC20 for IERC20;

    constructor(
        ILendingPoolAddressesProvider _addressProvider,
        address _routerA, 
        address _routerB,
        address _token,
        address _WETH
    ) public FlashLoanReceiverBase(_addressProvider)
    {   
        owner = msg.sender;
        routerA = _routerA;
        routerB = _routerB;
        token = _token;
        WETH = _WETH;
    }

    address owner;
    address routerA;
    address routerB;
    address token;
    address WETH;

     modifier onlyOwner{
        require(msg.sender == owner, "Hey hey hey you can't use this function");
        _;
     }

    /**
     * @dev This function must be called only be the LENDING_POOL and takes care of repaying
     * active debt positions, migrating collateral and incurring new V2 debt token debt.
     *
     * @param assets The array of flash loaned assets used to repay debts.
     * @param amounts The array of flash loaned asset amounts used to repay debts.
     * @param premiums The array of premiums incurred as additional debts.
     * @param initiator The address that initiated the flash loan, unused.
     * @param params The byte array containing, in this case, the arrays of aTokens and aTokenAmounts.
     */
    function executeOperation(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata premiums,
        address initiator,
        bytes calldata params
    ) external override returns (bool) {
        //
        // This contract now has the funds requested.
        // Your logic goes here.
        //

        address[] memory path = new address[](2);
        path[0] = token;
        path[1] = WETH;

        address[] memory path2 = new address[](2);
        path2[0] = WETH;
        path2[1] = token;

        uint balance = address(this).balance;
        IERC20(WETH).approve(routerA, balance);  

        IUniswapV2Router02(routerA).swapExactTokensForTokensSupportingFeeOnTransferTokens(
            balance, 
            0, 
            path2, 
            address(this), 
            block.timestamp + 1200
        );

        uint tokenBalance = IERC20(token).balanceOf(address(this));
        IERC20(token).approve(routerB, tokenBalance);

        IUniswapV2Router02(routerB).swapExactTokensForTokensSupportingFeeOnTransferTokens(
            tokenBalance, 
            0, 
            path, 
            address(this), 
            block.timestamp + 1200
        );

        //payable(owner).transfer(address(this).balance - (amounts[0] + premiums[0]));

        // At the end of your logic above, this contract owes
        // the flashloaned amounts + premiums.
        // Therefore ensure your contract has enough to repay
        // these amounts.

        // Approve the LendingPool contract allowance to *pull* the owed amount
        for (uint256 i = 0; i < assets.length; i++) {
            uint256 amountOwing = amounts[i].add(premiums[i]);
            IERC20(assets[i]).approve(address(LENDING_POOL), amountOwing);
        }

        return true;
    }

    function _flashloan(address[] memory assets, uint256[] memory amounts)
        internal
    {
        address receiverAddress = address(this);

        address onBehalfOf = address(this);
        bytes memory params = "";
        uint16 referralCode = 0;

        uint256[] memory modes = new uint256[](assets.length);

        // 0 = no debt (flash), 1 = stable, 2 = variable
        for (uint256 i = 0; i < assets.length; i++) {
            modes[i] = 0;
        }

        LENDING_POOL.flashLoan(
            receiverAddress,
            assets,
            amounts,
            modes,
            onBehalfOf,
            params,
            referralCode
        );
    }

    /*
     *  Flash multiple assets
     */
    function flashloan(address[] memory assets, uint256[] memory amounts)
        public
        onlyOwner
    {
        _flashloan(assets, amounts);
    }

    /*
     *  Flash loan 100000000000000000 wei (0.1 ether) worth of `_asset`
     */
    function flashloan(address _asset) public onlyOwner {
        bytes memory data = "";
        uint256 amount = 50 ether;

        address[] memory assets = new address[](1);
        assets[0] = _asset;

        uint256[] memory amounts = new uint256[](1);
        amounts[0] = amount;

        _flashloan(assets, amounts);
    }

        event LogWithdraw(
        address indexed _from,
        address indexed _assetAddress,
        uint amount
    );

    /**
     * @dev Withdraw asset.
     * @param _assetAddress Asset to be withdrawn.
     */
    function withdraw(address _assetAddress) public onlyOwner {
        uint assetBalance;
        if (_assetAddress == WETH) {
            address self = address(this); // workaround for a possible solidity bug
            assetBalance = self.balance;
            payable(msg.sender).transfer(assetBalance);
        } else {
            assetBalance = IERC20(_assetAddress).balanceOf(address(this));
            IERC20(_assetAddress).safeTransfer(msg.sender, assetBalance);
        }
        emit LogWithdraw(msg.sender, _assetAddress, assetBalance);
    }

    function setter(address _routerA, address _routerB, address _token) external onlyOwner returns(bool){
        routerA = _routerA;
        routerB = _routerB;
        token = _token;
        return true;
    }

    function returnOwner() external view returns(address){
        return owner;
    }

    function returnToken() external view returns(address){
        return token;
    }

    function returnWETH() external view returns(address){
        return WETH;
    }

    fallback() external payable {}
}

When i call flashloan()using truffle CLI i receive this error:

SafeERC20: low-level call failed when calling

Could someone give me a hint over this?

defispartan commented 1 year ago

If you have a failed txHash I can help you find the exact error, but without it, I'm just making an educated guess since this is a general error.

If your contract does not return the borrowed amount plus the flashloan fee (0.09% in V2), then it will fail. So in your contract, you are borrowing 50ETH so your contract balance must be > 50.045 ETH by the end of the transaction.