此文档为个人整理学习使用,部分内容来源于网络,也期待能给你带来益处!如果转载,请保留原始链接!
https://steemit.com/@chaimyu
访问ClassicEtherWallet钱包,上方大红提示一个安全警告,如下:
意思是ERC20代币不要使用transfer传输到一个合约地址,否则会导致代币丢失。
ERC20代币现在很多,我们肯定会经常用到,决定好好看一下这个安全警示到底是什么?
ERC20代币传输有两种方式:
ERC20只提供了函数原型,没有标准实现,我们来看一下这几个函数的实现,如下:
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
transfer只是调用内部函数,内部_transfer最主要的工作就是操作代币地址表,减少发消息者的代币数量,增加接收者的代币数量,如下:
// Subtract from the sender
balanceOf[_from] -= _value;
// Add the same to the recipient
balanceOf[_to] += _value;
代币合约参看 https://steemit.com/ethereum/@chaimyu/5eu2fa
从这大概能明白了,这些地址都只是智能合约中的变量,并不能区分是外部钱包地址还是合约地址,接收方没法得到任何事件通知,做任何处理!
那为什么以太币不会有这种问题呢?以太币发送到合约时,正常情况下合约是不会接收以太币并会自动回滚操作的,合约如果要接收以太币需要增加以下函数,并针对收到的以太币数量和发币地址做处理:
function () payable public { ... }
从这也明白了,Ether和ERC20代币传输之间最大的区别,一个是在以太坊链网上进行,一个是在智能合约内部进行(只是改改合约变量),所以不要用transfer直接传输代币给合约地址!
针对现有的ERC20代币,建议的用的approve + transferFrom方式呢,来看看:
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]); // Check allowance
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public
returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
用这种方式,就是用户首先通过approve授权合约地址可以操作自己的代币,可以指定允许操作的数量,然后由代币接收方合约来调用transferFrom函数,这样能保证代币接收方合约知道在干什么!
新的代币标准不受这个bug影响:
ERC223 https://github.com/ethereum/EIPs/issues/223
ERC777 https://github.com/ethereum/EIPs/issues/777
ERC20标准 https://github.com/ethereum/EIPs/issues/20
问题英文描述 https://gist.github.com/Dexaran/ddb3e89fe64bf2e06ed15fbd5679bd20
丢失示例 https://docs.google.com/document/d/1Feh5sP6oQL1-1NHi-X1dbgT3ch2WdhbXRevDN681Jv4/edit
感谢您阅读 @chaimyu 的帖子,期待您能留言交流!