目前几乎所有用于艾希欧筹集资金的代币,都是基于同样的技术:以太坊ERC-20标准。
因此这些代币实际上就是实现了ERC20标准的智能合约。在下文中,我们将全面剖析ERC20
标准规范,并给出一个ERC20代币合约的完整实现代码。此外,在下文中我们将不加区分地使用
通证和代币来表示遵循ERC20规范的智能合约,虽然前者完全涵盖了后者的范围。
如果你希望马上开始学习以太坊智能合约和应用开发,可以访问汇智网提供的出色的在线互动教程:
ERC20是Fabian Vogelsteller在2015年末提出的以太坊改进建议,它是许多流行的合约都在遵循的标准。
ERC20使通证智能合约的行为非常类似于传统的加密货币,例如在不同账户之间发送和接收、
查看通证总供应量或者查看某个地址可用的通证余额,就像比特币或以太币一样。这类似于用以太坊钱包
发送和接收以太币、查看流通中的以太币总量、查看特定钱包的货币余额等。
ERC20定义了一些标准的接口函数:balanceOf 、 totalSupply 、transfer 、transferFrom 、approve和allowance 。
以及一些可选的字段,例如通证名称、符号以及小数保留位数等。你可以在github
查看ERC-20全文。
下面的代码声明一个简明的ERC20智能合约:
contract ERC20 {
function totalSupply() constant returns (uint theTotalSupply);
function balanceOf(address _owner) constant returns (uint balance);
function transfer(address _to, uint _value) returns (bool success);
function transferFrom(address _from, address _to, uint _value) returns (bool success);
function approve(address _spender, uint _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint remaining);
event Transfer(address indexed _from, address indexed _to, uint _value);
event Approval(address indexed _owner, address indexed _spender, uint _value);
}
合约中每个字段的描述及示例如下。
尽管与比特币一样,通证供给总量可以很容易地固定下来,但此函数允许合约实例计算
并返回存在于流通中的通证总量。
contract MyERCToken {
//在本示例中,通证供给量是固定的,但也可以将其设定为可修改的
uint256 _totalSupply = 1000000;
function totalSupply() constant returns (uint256 theTotalSupply) {
//函数声明中已经定义了返回变量theTotalSupply
theTotalSupply = _totalSupply;
return theTotalSupply;
}
}
该函数允许智能合约返回指定账户地址的通证余额。 该函数接受一个地址作为参数,
所以任何地址的通证余额都是公开的。
contract MyERCToken {
//创建映射表来记录账户余额
mapping(address => uint256) balances;
// Owner of this contract
//合约拥有者
address public owner;
function balanceOf(address _owner) constant returns (uint256 balance) {
//返回指定地址的通证余额
return balances[_owner];
}
}
此函数的调用方授权给定的地址可以从其地址中提款。
在这里,以及后面的代码片段中,你可能会看到一个变量msg 。 这是由外部应用程序(如钱包)提供
的隐含字段,以便更好地与合约进行交互。 以太坊虚拟机(EVM)允许我们使用该字段来存储和处理
由外部应用程序提供的数据。
在这个例子中, msg.sender是合约方法调用方的地址。
contract MyERCToken {
//创建映射表记录通证持有者、被授权者以及授权数量
mapping(address => mapping (address => uint256)) allowed;
function approve(address _spender, uint256 _amount) returns (bool success) {
allowed[msg.sender][_spender] = _amount;
//当授权时触发Approval事件
Approval(msg.sender, _spender, _amount);
return true;
}
}
该函数让调用方将指定数量的通证发送到另一个地址,就像加密货币交易一样。
contract MyERCToken {
mapping(address => uint256) balances;
//返回值为true时,表示转账成功
function transfer(address _to, uint256 _amount) returns (bool success) {
//如果发送方有足够的资金并且发送数量非0 ,则发送给指定地址
if (balances[msg.sender] >= _amount
&& _amount > 0
&& balances[_to] + _amount > balances[_to]) {
balances[msg.sender] -= _amount;
balances[_to] += _amount;
//触发Transfer事件
Transfer(msg.sender, _to, _amount);
return true;
} else {
return false;
}
}
}
该函数允许智能合约自动执行转账流程并代表所有者发送给定数量的通证。
看到这的时候你可能会有点困惑:为什么有了transfer(),还需要transferFrom()?。
回一下在日常生活中,通过转账来支付账单的情况。 通常你需要自己去办转账汇款来支付账单,这
就像使用transfer() :你需要自己执行,没有其他人的帮助。
在另一种情况下,你可以与银行签订自动代支付协议。 这就像使用transferFrom() :
银行的机器会自动以你的名义进行转账支持。 有了这个函数,合约就可以代表你自动
发送通证到另一个地址,而无需你的干预。
contract MyERCToken {
mapping(address => uint256) balances;
function transferFrom(address _from, address _to, uint256 _amount) returns (bool success) {
if (balances[_from] >= _amount
&& allowed[_from][msg.sender] >= _amount
&& _amount > 0
&& balances[_to] + _amount > balances[_to]) {
balances[_from] -= _amount;
balances[_to] += _amount;
Transfer(_from, _to, _amount);
return true;
} else {
return false;
}
}
}
name是一个可选字段,但许多流行的通证都定义了这个字段,以便像Mist和MyEtherWallet
这样的钱包能够识别它们:
contract MyERCToken {
string public constant name = "My Custom ERC20 Token";
}
symbol是另一个用于标识通证的可选字段,通常采用三到四个字母的缩写,就像BTC、ETH、AUG或SJCX一样,
contract MyERCToken {
string public constant symbol = "MET";
}
这是一个可选字段,用于确定通证数量的小数位数。 最常见的小数位数是18。
contract MyERCToken {
uint8 public constant decimals = 18;
}
这个ERC20通证的源代码可以在Github找到。
ERC20标准开辟了一套新的智能合约,可以像比特币或以太坊一样创建和分发,而且,
这些代币可以在交易所托管,像其他资产一样进行交易,因此投资者也可以轻松地购买和出售这些代币。