Contract-Development
Transfer ERC20 Token - 在合約執行過程中遇到回复_______R和在和r噸和dReverted
嘗試從錢包發送一些 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
要成功完成此轉移,必須滿足以下各項:
contract.balanceOf(from)
必須 >= 100000contract.allowance(from, sender)
必須 >= 100000在 etherscan 上檢查上述條件:
contract.balanceOf(from) == 1600000 >= 100000
contract.allowance(from, sender) == 0 < 100000
第一個條件成立,但第二個條件不成立。
為了保持該條件,
from
必須contract.approve(sender, 100000)
事先呼叫。更新
ERC20代幣標準規定了功能
transfer
,transferFrom
並且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
,transferFrom
和approve
.如果您不能直接修改該介面,則只需聲明另一個介面:
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(...);