Contract-Development

Transfer ERC20 Token - 在合約執行過程中遇到回复_______R和在和r噸和dReverted

  • April 6, 2020

嘗試從錢包發送一些 ERC20 令牌時出現以下錯誤:

Warning! Error encountered during contract execution [Reverted] 

當我呼叫transferFrom()(我approve()在它之前)和transfer()。此外,我的地址/錢包中有很多氣體/代幣。

智能合約程式碼:

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);
       _;
   }
}

按照您在對自己問題的評論中發布的etherscan-link :

From: 0x87ee3337108a31ab539e244f3d22f4070f03d12a
To: Contract 0x812a27078f0644b5bb88d5c0b9d616eb3550bcec

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

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

這就是我們這裡的:

  • 發件人0x87ee3337108a31ab539e244f3d22f4070f03d12a
  • 在合約中呼叫了一個函式0x812a27078f0644b5bb88d5c0b9d616eb3550bcec
  • 試圖轉移0x186a0(100000)個代幣
  • 0x18c7abf493c747f39ce006abeb9bd6d2592e833e
  • 0xb7a5329bcb48308e3fba671dfe7e0f6477b1f759

要成功完成此轉移,必須滿足以下各項:

  1. contract.balanceOf(from)必須 >= 100000
  2. contract.allowance(from, sender)必須 >= 100000

在 etherscan 上檢查上述條件:

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

第一個條件成立,但第二個條件不成立。

為了保持該條件,from必須contract.approve(sender, 100000)事先呼叫。


更新

ERC20代幣標準規定了功能transfertransferFrom並且approve應該返回true成功和false失敗。

然而,部署在網路上的各種 ERC20 代幣並沒有實現這一要求。

您的合約似乎正在使用一種這樣的令牌

使用返回的介面呼叫不返回任何內容的函式bool會導致事務恢復。

呼叫bool使用不返回任何內容的介面返回的函式不會導致事務恢復。

在我發佈到我自己的問題的答案中查看這兩種情況的編碼範例。

這兩個中的第一個(不幸的)案例正是您的契約中發生的情況:

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);
   }

   ...
}

一個快速的解決方案是修改你的ERC20界面並去掉returns (bool)函式聲明中的transfer,transferFromapprove.

如果您不能直接修改該介面,則只需聲明另一個介面:

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;
}

並在您的程式碼中轉換每個相關的函式呼叫,如下所示:

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

引用自:https://ethereum.stackexchange.com/questions/82158