ERC20 Token Transfer – Encountered Reverted During Contract Execution

contract-developmenterc-20revert-opcodetokenstransferfrom

When trying to sent some ERC20 Token from wallet getting following error:

 Warning! Error encountered during contract execution [Reverted] 

This error returned when i call transferFrom()( I made approve() before it ) and transfer(). Furthermore, I have of lot gas/token amount of my addresses/wallets.

Smart
Contract code :

pragma solidity ^0.5.7;

contract ERC20 {
   //core ERC20 functions
  function allowance(address _owner, address _spender) public view returns (uint remaining);
  function approve(address _spender, uint _value)  public returns (bool success);
  function balanceOf(address _owner) public view returns (uint balance);
  function totalSupply() public view returns (uint);
  function transfer(address _to, uint _value) public returns (bool success);
  function transferFrom(address _from, address _to, uint _value) public returns (bool success);
// logging events
  event Approval(address indexed _owner, address indexed _spender, uint _value);
  event Transfer(address indexed _from, address indexed _to, uint  _value);
}

contract Transfer  {
    ERC20 public token;
    uint public balance = 0;
    address public owner;
    constructor (address _tokenAddress) public {
        owner = msg.sender;
        token = ERC20(_tokenAddress);
    }

    function() payable external {
        balance += msg.value;
    }

    function transferETH(address payable _to, uint256 _value) public onlyOwner returns (bool){
        _to.transfer(_value);
        return true;
    }

    function transferEth2Many(address payable[] memory _receivers, uint[] memory _values) public onlyOwner returns (bool) {
        require(_receivers.length == _values.length && _receivers.length >= 1);
        for (uint j = 0; j < _receivers.length; j++) {
            _receivers[j].transfer(_values[j]);
        }
        return true;
    }

    function totalSupply() public view returns (uint) {
        return token.totalSupply();
    }

    function balanceOf(address who) public view returns (uint) {
        return token.balanceOf(who);
    }

    function allowance(address _owner, address _spender) public view returns (uint){
        return token.allowance(_owner, _spender);
    }

    function approve(address _spender, uint _value) public returns (bool success){
        return token.approve(_spender, _value);
    }

    function transfer(address _to, uint _value) public returns (bool success) {
        return token.transfer(_to, _value);
    }

    function transferFrom(address _from, address _to, uint _value) public returns (bool success) {
        return token.transferFrom(_from, _to, _value);
    }

    function TransferOne2Many(address[] memory _receivers, uint[] memory _values) public onlyOwner returns (bool) {
        require(_receivers.length == _values.length && _receivers.length >= 1);
        for (uint j = 0; j < _receivers.length; j++) {
            token.transfer(_receivers[j], _values[j]);
        }
        return true;
    }

    function TransferFromOne2Many(address _from, address[] memory _receivers, uint[] memory _values) public onlyOwner returns (bool) {
        require(_receivers.length == _values.length && _receivers.length >= 1);
        for (uint j = 0; j < _receivers.length; j++) {
            token.transferFrom(_from, _receivers[j], _values[j]);
        }
        return true;
    }

    function TransferFromMany2one(address[] memory _froms, address _receiver, uint[] memory _values) public onlyOwner returns (bool) {
        require(_froms.length == _values.length && _froms.length >= 1);
        for (uint j = 0; j < _froms.length; j++) {
            token.transferFrom(_froms[j], _receiver, _values[j]);
        }
        return true;
    }

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
}

Best Answer

Following the etherscan-link that you have posted in a comment to your own question:

From: 0x87ee3337108a31ab539e244f3d22f4070f03d12a
To: Contract 0x812a27078f0644b5bb88d5c0b9d616eb3550bcec

Function: transferFrom(address _from, address _to, uint256 _value)

[0]:  00000000000000000000000018c7abf493c747f39ce006abeb9bd6d2592e833e
[1]:  000000000000000000000000b7a5329bcb48308e3fba671dfe7e0f6477b1f759
[2]:  00000000000000000000000000000000000000000000000000000000000186a0

This is what we have here:

  • Sender 0x87ee3337108a31ab539e244f3d22f4070f03d12a
  • Has called a function in contract 0x812a27078f0644b5bb88d5c0b9d616eb3550bcec
  • In an attempt to transfer 0x186a0 (100000) tokens
  • From 0x18c7abf493c747f39ce006abeb9bd6d2592e833e
  • To 0xb7a5329bcb48308e3fba671dfe7e0f6477b1f759

For this transfer to complete successfully, each one of the following must hold:

  1. contract.balanceOf(from) must be >= 100000
  2. contract.allowance(from, sender) must be >= 100000

Checking the above conditions on etherscan:

  1. contract.balanceOf(from) == 1600000 >= 100000
  2. contract.allowance(from, sender) == 0 < 100000

The 1st condition holds, but the 2nd condition does not hold.

In order for that condition to hold, from must call contract.approve(sender, 100000) beforehand.


UPDATE

The ERC20 Token Standard dictates that functions transfer, transferFrom and approve should return true for success and false for failure.

However, various ERC20 tokens deployed on the network have not implemented this requirement.

Your contract appears to be using one such token.

Calling a function which doesn't return anything using an interface of it which returns bool causes the transaction to revert.

Calling a function which returns bool using an interface of it which doesn't return anything doesn't cause the transaction to revert.

See a coding example for both cases in an answer that I have posted to my own question.

The first (unfortunate) case among these two is exactly what happens in your contract:

contract ERC20 {
    ...
    function approve(address _spender, uint _value) public returns (bool success);
    function transfer(address _to, uint _value) public returns (bool success);
    function transferFrom(address _from, address _to, uint _value) public returns (bool success);
    ...
}

contract Transfer {
    ERC20 public token;
    uint public balance = 0;
    address public owner;
    constructor (address _tokenAddress) public {
        owner = msg.sender;
        token = ERC20(_tokenAddress);
    }

    ...

    function approve(address _spender, uint _value) public returns (bool success) {
        return token.approve(_spender, _value);
    }

    function transfer(address _to, uint _value) public returns (bool success) {
        return token.transfer(_to, _value);
    }

    function transferFrom(address _from, address _to, uint _value) public returns (bool success) {
        return token.transferFrom(_from, _to, _value);
    }

    ...
}

A quick solution would be to modify your ERC20 interface and get rid of the returns (bool) in the declaration of functions transfer, transferFrom and approve.

If you cannot modify that interface directly, then just declare another interface:

contract NonStandardERC20 {
    function approve(address _spender, uint _value) public;
    function transfer(address _to, uint _value) public;
    function transferFrom(address _from, address _to, uint _value) public;
}

And cast each relevant function-call in your code as follows:

  • NonStandardERC20(token).approve(...);
  • NonStandardERC20(token).transfer(...);
  • NonStandardERC20(token).transferFrom(...);
Related Topic