Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
burgossrodrigo opened this issue Aug 5, 2022 · 2 comments
Open

Comments

@burgossrodrigo
Copy link

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
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@defispartan @burgossrodrigo and others