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!
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
.