简单发行基于ETH的ERC20代币
目前除了BTC,ETH,EOS三大公链外,其余的虚拟币均是基于公链上发行的代币。其实发行代币很简单,只需要不到100行代码就能发行属于自己的虚拟货币了。
智能合约
所谓的智能合约,其实就是运行在ETH主网上的代码。Code is Low。在区块链中,代码即是法律,称其为合约,代表这是大家都遵守的一个东西。
ERC20
这次发行的是基于ETH的ERC20标准的代币。何为ERC20?简单点讲,ERC20可以理解为编程语言的一个接口,我们必须实现这些接口。比如这个接口定义了变量totalSupply,这个变量代表着发行总量。还有诸如transfer,freeze等等,只有按照这些规范写出来的智能合约,才能被认可为代币。
合约代码
合约使用的V神自己写的语言Solidity
,如果不想再配置麻烦的环境的话,可以使用在线的IDE,Remix。
先贴出代码
pragma solidity ^0.4.25;
/**
* Math operations with safety checks
*/
library Safe {
function safeMul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeDiv(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b > 0);
uint256 c = a / b;
assert(a == b * c + a % b);
return c;
}
function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c>=a && c>=b);
return c;
}
}
contract MyCoin{
uint public totalSupply = 500004322.443245*10**18; //Total amount of distribution
uint8 constant public decimals = 18;
string constant public name = "MyCoin";
string constant public symbol = "MC";
address public owner;
mapping (address => uint256) public balanceOf;
mapping (address => uint256) public freezeOf;
mapping (address => mapping (address => uint256)) public allowance;
event Transfer(address indexed from, address indexed to, uint256 value);
event Burn(address indexed from, uint256 value);
event Freeze(address indexed from, uint256 value);
event Unfreeze(address indexed from, uint256 value);
/* Initializes contract with initial supply tokens to the creator of the contract */
constructor() public{
balanceOf[msg.sender] = totalSupply;
owner = msg.sender;
}
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
function transfer(address _to, uint256 _value) public {
require(_to != 0x0);
require(_value > 0);
require(balanceOf[msg.sender] >= _value);
require(balanceOf[_to] + _value >= balanceOf[_to]);
balanceOf[msg.sender] = Safe.safeSub(balanceOf[msg.sender], _value);
balanceOf[_to] = Safe.safeAdd(balanceOf[_to], _value);
emit Transfer(msg.sender, _to, _value);
}
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of wei to be approved for transfer
/// @return Is it successfully approved
function approve(address _spender, uint256 _value) public
returns (bool success) {
require(_value > 0);
allowance[msg.sender][_spender] = _value;
return true;
}
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != 0x0);
require(_value > 0);
require(balanceOf[_from] > _value);
require(balanceOf[_to] + _value >= balanceOf[_to]);
require(_value <= allowance[_from][msg.sender]);
balanceOf[_from] = Safe.safeSub(balanceOf[_from], _value);
balanceOf[_to] = Safe.safeAdd(balanceOf[_to], _value);
allowance[_from][msg.sender] = Safe.safeSub(allowance[_from][msg.sender], _value);
emit Transfer(_from, _to, _value);
return true;
}
/// @param _value The amount of token to be burned
/// @return Is it successfully burned
function burn(uint256 _value) public returns (bool) {
require(balanceOf[msg.sender] >= _value);
require(_value > 0);
balanceOf[msg.sender] = Safe.safeSub(balanceOf[msg.sender], _value);
totalSupply = Safe.safeSub(totalSupply,_value);
emit Burn(msg.sender, _value);
return true;
}
/// @param _value The amount of token to be freeze
/// @return Is it successfully froze
function freeze(uint256 _value) public returns (bool) {
require(balanceOf[msg.sender] >= _value);
require(_value > 0);
balanceOf[msg.sender] = Safe.safeSub(balanceOf[msg.sender], _value);
freezeOf[msg.sender] = Safe.safeAdd(freezeOf[msg.sender], _value);
emit Freeze(msg.sender, _value);
return true;
}
/// @param _value The amount of token to be unfreeze
/// @return Is it successfully unfroze
function unfreeze(uint256 _value) public returns (bool) {
require(freezeOf[msg.sender] >= _value);
require(_value > 0);
freezeOf[msg.sender] = Safe.safeSub(freezeOf[msg.sender], _value);
balanceOf[msg.sender] = Safe.safeAdd(balanceOf[msg.sender], _value);
emit Unfreeze(msg.sender, _value);
return true;
}
function() payable public {
revert();
}
}
第一行pragma solidity
声明了编译的版本,不可去掉。
safe
类用于安全的处理加减乘除运算。
contract MyCoin
代表着我们的合约,名字为MyCoin。在合约开始就通过赋值的方式实现了ERC20标准中的totalSupply,decimals,name和symbol,同时还定义了owner。
除此之外声明了4个事件,Transfer,Burn,Freeze,Unfreeze。这是因为在调用完对应的方法之后,必须emit
对应的事件。
constructor() public
则是构造函数。在智能合约中,构造函数只能被执行一次,那就是部署合约的那一次。所以在构造函数中,我们将owner赋值为msg.sender,即为部署合约的地址。同时将该地址的余额改为发行总额。
其他方法为实现ERC20标准的一些方法,各个代币合约都大同小异,看看就行。
调试
在Remix右边Compile中,选好对应的编译器版本后,Start to compile
。如果红色或黄色的报错框,那么代码就是通过编译了。
在Run中可以调试自己的合约代码。Environment为调试环境,共有三种环境
- JavaScript VM:JS虚拟机,通过JS模拟的钱包环境。
- Injected Web3:使用MetaMask之类的Chrome插件钱包作为调试环境。
- Web3 Provider:使用eth钱包作为测试环境,如geth。
这里我们先使用JavaScript VM,accounts中默认添加了一些测试账户,选择一个账户后,再选择我们的合约MyCoin
,点击Deploy部署,此时这个合约就被部署在选中的虚拟钱包地址上了。在Deployed Contracts中能看到被部署的合约,点开后就会出现我们代码中实现的方法。
在要测试的方法后面填入参数,多个参数用,
隔开,再点击方法明就能执行,并且在中间的Debug区域会输出方法执行的情况。
部署合约
代码调试完毕后就可以部署了,部署很简单。
在Compile中,点击details,可以看到ABI,BYTECODE等信息。找到WEB3DEPLOY,把里面的代码复制下来,在钱包中的JS命令行环境中粘贴并执行就OK了。一键部署,非常简单,我使用的geth进行部署。
在etherscan中可以看到部署的情况。部署完成后还需要一次确认。
未确认的合约点开Code会提示你
Are you the Contract Creator? Verify And Publish Your Contract Source Code Today!
点击** Verify And Publish**开始确认。
填写必要的选项,Contract Name合约名,Compiler编译器版本,在大框中输入合约的代码,必须是和部署时的代码一模一样。
下一步后会提示你验证签名,这里我们使用钱包的web3.eth.sign()
。根据提示会生成一段字符串让你的钱包验证,必须是使用部署合约的钱包验证。
var account = web3.eth.accounts[0];
var sha3Msg = web3.sha3("需要被验证的一串字符串");
var signedData = web3.eth.sign(account, sha3Msg);
将得到的signedData
填入验证框中,通过验证就确认成功了。此时再查看合约的Code,Code旁会有绿色的小勾,并且你的代码也被公开出来了。
如果你想让你的代币拥有图标,网站邮箱链接等等,在Links中点击Update,这里同样会给你一串字符串Signed message,还是用web3.eth.sign()
验证签名。通过验证后在Fill in form里按照规范填写需要的内容即可。
Or you can contact me by Email