国际比特币大盘软件:以太坊开发学习-第一个生产级别ERC20合约
今天,我们来讲讲如何编写一个实际可用,并且没有安全漏洞的生产级别的ERC20代币合约,当然很多人通过百度可以搜索到一堆发币的合约代码,但是大部分都是有安全漏洞的,达不到生产级别。
废话不少,先上完整代码:
pragma solidity ^0.4.24;
library SafeMath {
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c)
{ if (_a==0) { return 0;
}
c=_a * _b;
assert(c / _a==_b); return c;
}
function div(uint256 _a, uint256 _b) internal pure returns (uint256) { return _a / _b;
}
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <=_a); return _a - _b;
}
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c=_a + _b;
assert(c >=_a); return c;
}
}
contract ERC20 {
uint256 public totalSupply; function balanceOf(address _who)
public view returns (uint256);
function allowance(address _owner, address _spender) public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
function approve(address _spender, uint256 _value) public returns (bool);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool);
event Transfer( address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Burn(address indexed from, uint256 value);
}contract StandardToken is ERC20 {
using SafeMath for uint256;
mapping(address=> uint256) balances;
mapping (address=> mapping (address=> uint256)) internal allowed;
function balanceOf(address _owner) public view returns (uint256)
{ return balances[_owner];
}
function allowance(address _owner, address _spender) public view returns
(uint256){ return allowed[_owner][_spender];
}
function transfer(address _to, uint256 _value) public returns
(bool) { require(_value <=balances[msg.sender]); require(_to !=address(0));
balances[msg.sender]=balances[msg.sender].sub(_value);
balances[_to]=balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value); return true;
} function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender]=_value;
emit Approval(msg.sender, _spender, _value); return true;
}
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool){ require(_value <=balances[_from]);
require(_value <=allowed[_from][msg.sender]); require(_to !=address(0));
balances[_from]=balances[_from].sub(_value);
balances[_to]=balances[_to].add(_value);
allowed[_from][msg.sender]=allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value); return true;
}
function increaseApproval(address _spender, uint256 _addedValue) public returns (bool) {
allowed[msg.sender][_spender]=(
allowed[msg.sender][_spender].add(_addedValue));
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true;
}
function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool) {
uint256 oldValue=allowed[msg.sender][_spender]; if (_subtractedValue >=oldValue) {
allowed[msg.sender][_spender]=0;
} else {
allowed[msg.sender][_spender]=oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true;
}
function burn(uint256 _value) public returns (bool success)
{ require(balances[msg.sender] >=_value);
balances[msg.sender]=balances[msg.sender].sub(_value);
totalSupply=totalSupply.sub(_value);
emit Burn(msg.sender, _value); return true;
}
function burnFrom(address _from, uint256 _value) public returns (bool success)
{ require(balances[_from] >=_value);
require(_value <=allowed[_from][msg.sender]);
balances[_from]=balances[_from].sub(_value);
allowed[_from][msg.sender]=allowed[_from][msg.sender].sub(_value);
totalSupply=totalSupply.sub(_value);
emit Burn(_from, _value); return true;
}
}
contract MyTokenERC20 is StandardToken { // Public variables of the token
string public name="My First ERC20 Token";
string public symbol="MFET";
uint8 constant public decimals=18;
uint256 constant public initialSupply=21000000; constructor() public {
totalSupply=initialSupply * 10 ** uint256(decimals);
balances[msg.sender]=totalSupply;
emit Transfer(address(0), msg.sender, totalSupply);
}
}
这些代码是什么意思呢?
一、ERC20(EIP-20)说明
ERC20是一个标准的token接口规范:A standard interface for tokens
我们来简单介绍下这个接口规范,规范里面定义了9个方法和2个事件
9个方法包括:
返回token的名字
function name() view returns (string name)
返回token的代码
function symbol() view returns (string symbol)
返回token的小数点位数
function decimals() view returns (uint8 decimals)
返回供应总量
unction totalSupply() view returns (uint256 totalSupply)
查询某个地址的余额
function balanceOf(address _owner) view returns (uint256 balance)
给某个地址转账,如果余额不足,该方法必须抛出异常而不是返回false
function transfer(address _to, uint256 _value) returns (bool success)
从from地址转账到to地址,该方法用于委托给其他合约代理你转账
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
允许多次从您的帐户委托到_spender地址,最高_value金额。如果再次调用此函数,则会覆盖当前允许值_value
function approve(address _spender, uint256 _value) returns (bool success)
返回_spender仍允许退出的金额_owner
function allowance(address _owner, address _spender) view returns (uint256 remaining)
2个事件包括:
转移令牌时必须触发,包括零值转移,注意:创建新token的合约应该触发Transfer事件,即从_from地址设置为0x0创建token的时候
event Transfer(address indexed _from, address indexed _to, uint256 _value)
委托转账必须触发
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
二、代码解释
代码包括几部分:
安全的数学计算库
contract类 ERC20,主要针对ERC20规范定义方法和事件
contract类StandardToken继承ERC20,定义具体的方法实现
contract 类MyTokenERC20集成StandardToken,定义名词,代号,总供应量和创建token
更多专栏文章:http://www.qukuaiwang.com.cn/zhuanlan
声明:本文由入驻区块网专栏作者撰写,观点仅代表作者本人,绝不代表区块网赞同其观点或证实其描述。