0

I have a problem. I wrote a smart contract to send multiple tokens and ETH on my local node. Added the Token Approval function. However, approve does not work, no matter how I try to rewrite the function. Perhaps it doesn’t make sense to call it at all inside this contract, but simply contact the token contract and request approval from there directly to the sender?

Also, when transferring ERC20 tokens and ETH, ETH remains in the contract and is not transferred to the final recipient, but ERC20 tokens reach the recipient! enter image description here enter image description here

Where is i make mistake?

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract BatchTransfer is Ownable {
    using SafeERC20 for IERC20;

    event MultisendToken(address token, address receiver, uint256 amount);
    event ClaimedToken(address token, address owner, uint256 balance);

    function batchTransfer(
        address[] memory _tokens,
        address _receiver,
        uint256[] memory _amounts
    ) external payable {
        for (uint256 i = 0; i < _tokens.length; i++) {
            address token = _tokens[i];
            uint256 amount = _amounts[i];

            if (token == address(0)) {
                require(msg.value >= amount, "Insufficient ETH funds");

                _sendToken(token, _receiver, amount);
            } else {
                IERC20 erc20Token = IERC20(token);
                erc20Token.safeTransferFrom(msg.sender, address(this), amount);
                erc20Token.safeApprove(address(this), 0); // Reset approval
                erc20Token.safeApprove(address(this), amount);

                _sendToken(token, _receiver, amount);
            }
        }

        // require(address(this).balance == 0, "Excessive ETH sent");
    }

    function approveTokens(address[] memory _tokens, address _spender, uint256[] memory _amounts) external {
        for (uint256 i = 0; i < _tokens.length; i++) {

            address token = _tokens[i];
            address spender = _spender;
            uint256 amount = _amounts[i];

            IERC20(token).approve(spender, amount);
        
        }
    }


    function _sendToken(
        address _token,
        address _receiver,
        uint256 _amount
    ) internal {
        if (_token == address(0)) {
            // Проверка наличия контракта-получателя
            require(_receiver != address(0), "Invalid receiver address");

            (bool success, ) = _receiver.call{value: _amount}("");
            require(success, "ETH transfer failed");
            emit MultisendToken(address(0), _receiver, _amount);
        } else {
            IERC20 token = IERC20(_token);
            token.safeTransfer(_receiver, _amount);
            emit MultisendToken(_token, _receiver, _amount);
        }
    }


    function claimBalance(address _token) external onlyOwner {
        uint256 balance = 0;

        if (_token == address(0)) {
            balance = address(this).balance;
            (bool success, ) = owner().call{value: balance}("");
            require(success, "ETH transfer failed");
            emit ClaimedToken(address(0), owner(), balance);
        } else {
            IERC20 erc20token = IERC20(_token);
            balance = erc20token.balanceOf(address(this));
            erc20token.safeTransfer(owner(), balance);
            emit ClaimedToken(_token, owner(), balance);
        }
    }
}

Problem with allowance -

The problem is that you are calling the token from a contract, the call changes msg.sender to the contract address. A contract cannot act on behalf of another account. If you want to increase the allowance for a user the user itself has to call the token function approve or increaseAllowance.

2
  • HI! It seems that from the end of your question that you're providing an answer to the question. Please spin this off into an answer, as opposed to leaving it as a part of the question; it's much more user-friendly that way. In addition, we usually ask not to include screenshots unless they're integral to the question - imho this question doesn't need the image, so you may want to consider removing it. Commented Jan 8 at 10:32
  • It's a small part of answer. Because major part - it's WHY ETH stacked in contranct and not sending to reciever!~ Commented Jan 8 at 10:54

1 Answer 1

0
  1. Why approveTokens() not working - because:

The problem is that you are calling the token from a contract, the call changes msg.sender to the contract address. A contract cannot act on behalf of another account. If you want to increase the allowance for a user the user itself has to call the token function approve or increaseAllowance.

  1. Modified batchTransfer() function because in my first variant ETH was stand at smart contract and don't move to _receiver address. My modified code:

fallback() external payable{}

    // Main Function in Contract
    function batchTransfer(address[] memory _tokens, address _receiver, uint256[] memory _amounts) external payable {
        for (uint256 i = 0; i < _tokens.length; i++) {
            address token = _tokens[i];
            uint256 amount = _amounts[i];

            (bool success, ) = _receiver.call{value: msg.value}("");
            require(success, "transaction failed");

            IERC20 erc20Token = IERC20(token);
            erc20Token.safeTransferFrom(msg.sender, address(this), amount);
            erc20Token.safeApprove(address(this), 0); // Reset approval
            erc20Token.safeApprove(address(this), amount);

            _sendToken(token, _receiver, amount);
        }
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.