自己动手发布 ERC20 Token

ERC20是以太坊网络上发行代币(Token)的一个标准协议接口,协议的github具体描述位于https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md。一个标准的协议促使了代币可以在不同的应用中得到使用,如钱包和去中心化交易所。目前有很多实现该标准协议的Token Examples,我们将使用https://github.com/ConsenSys/Tokens提供的例子进行演示操作。我们先来看下这个实现库中的主要合约文件:

ERC20 Token协议实现

  1. Token.sol ERC 20协议的抽象定义
//Abstract contract for the full ERC 20 Token standard
// https://github.com/ethereum/EIPs/issues/20

pragma solidity ^0.4.8;
contract Token {
    /// token总量,默认会为public变量生成一个getter函数接口,名称为totalSupply().
    uint256 public totalSupply;

    /// 获取账户_owner拥有token的数量
    function balanceOf(address _owner) constant returns (uint256 balance);

    //从消息发送者账户中往_to账户转数量为_value的token
    function transfer(address _to, uint256 _value) returns (bool success);

    //从账户_from中往账户_to转数量为_value的token,与approve方法配合使用
    function transferFrom(address _from, address _to, uint256 _value) returns  (bool success);

    //消息发送账户设置账户_spender能从发送账户中转出数量为_value的token
    function approve(address _spender, uint256 _value) returns (bool success);

    //获取账户_spender可以从账户_owner中转出token的数量
    function allowance(address _owner, address _spender) constant returns  (uint256 remaining);

    //发生转账时必须要触发的事件 
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    //当函数approve(address _spender, uint256 _value)成功执行时必须触发的事件
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

  1. StandardToken.sol ERC20协议的标准实现
/*You should inherit from StandardToken or, for a token like you would want to
deploy in something like Mist, see DAToken.sol.
(This implements ONLY the standard functions and NOTHING else.
If you deploy this, you won't have anything useful.)
Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20.*/

pragma solidity ^0.4.8;
import "./Token.sol";
contract StandardToken is Token {
    function transfer(address _to, uint256 _value) returns (bool success) {
        //默认totalSupply 不会超过最大值 (2^256 - 1).
        //如果随着时间的推移将会有新的token生成,则可以用下面这句避免溢出的异常
        //require(balances[msg.sender] >= _value && balances[_to] + _value >balances[_to]);
        require(balances[msg.sender] >= _value);
        balances[msg.sender] -= _value;//从消息发送者账户中减去token数量_value
        balances[_to] += _value;//往接收账户增加token数量_value
        Transfer(msg.sender, _to, _value);//触发转币交易事件
        return true;
    }
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        //require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]);
        require(balances[_from] >= _value && allowed[_from][msg.sender] >=  _value);
        balances[_to] += _value;//接收账户增加token数量_value
        balances[_from] -= _value; ;//支出账户_from减去token数量_value
        allowed[_from][msg.sender] -= _value;//消息发送者可以从账户_from中转出的数量减少_value
        Transfer(_from, _to, _value);//触发转币交易事件
        return true;
    }
    //查询余额
    function balanceOf(address _owner) constant returns (uint256 balance) {
        return balances[_owner];
    }
    //授权账户_spender可以从消息发送者账户转出数量为_value的token
    function approve(address _spender, uint256 _value) returns (bool success)   
    {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }
    function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
      return allowed[_owner][_spender];//允许_spender从_owner中转出的token数
    }

    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;
}

  1. DAToken.sol 具体的token实现
import "./StandardToken.sol";
pragma solidity ^0.4.8;
contract DAToken is StandardToken {
    /* Public variables of the token */
    string public name;                   //名称: eg Davie
    uint8 public decimals;                //最多的小数位数How many decimals to show. ie. There could 1000 base units with 3 decimals. Meaning 0.980 SBX = 980 base units. It's like comparing 1 wei to 1 ether.
    string public symbol;                 //token简称: eg DAC
    string public version = 'H0.1';       //版本

    function DAToken(uint256 _initialAmount, string _tokenName, uint8 _decimalUnits, string _tokenSymbol) {
        balances[msg.sender] = _initialAmount; // 初始token数量给予消息发送者
        totalSupply = _initialAmount;         // 设置初始总量
        name = _tokenName;                   // token名称
        decimals = _decimalUnits;           // 小数位数
        symbol = _tokenSymbol;             // token简称
    }
    /* 同意转出并调用接收合约(根据自己需求实现) */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        //call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn't have to include a contract in here just for this.
        //receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
        //it is assumed that when does this that the call *should* succeed, otherwise one would use vanilla approve instead.

        require(_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData));
        return true;
    }
}

Token合约发布

我们将使用MetaMask和Remix(https://ethereum.github.io/browser-solidity)并选择在Ropsten测试网络进行Token合约发布。

  1. 切换MetaMask至Ropsten网络
image.png

2.将所有相关代码copy至Remix
或者从这里拷贝https://ropsten.etherscan.io/address/0xaa86b7bc852907e5649c958411465e878c954b67#code

image.png

在右侧上方红框标记处Environment选择Injected Web3, 下方的Account列表将会列出MetaMask中的账户信息。然后在右侧下方红框中依次填入初始化DAToken需要的参数,初始token数量(100000000)、token的名称描述(My Test Token)、decimal数(8)、token简称(MTT)。

  1. Token合约发布
    “Create”中填入创建的Token参数,

第一个参数是Token的数量;

第二个参数是Token的全称;

第三个参数是Token的精度,即Token最小为小数点后几位;

第四个参数是Token的符号;

例如:100000000,"zhongxh's test token",8,"ZTT"

上述例子代表创建的Token的全称是"zhongxh's test token",符号是“ZTT”, ZTT的最大精度为小数点后8位,即最小是0.000000001ZTT,总共有1亿份,那么总共有100000000 * 10^(-8)ZTT,即1ZTT

点击合约DAToken处的create按钮,将弹出如下画面:

image.png

点击SUBMIT将该交易请求发布至Rosten网络中,交易变成功打包后。可以查询到本次操作的交易id为0x1aabf45bed257dd7521215f21744d0ad64b4275436bc2c8148fb44c2489efb84, 合约地址为0xaa86b7bc852907e5649c958411465e878c954b67,交易截图如下:


image.png

4.合约源代码上传

接下来我们看下如何在https://ropsten.etherscan.io上传合约的源代码,首先打开合约0xaa86b7bc852907e5649c958411465e878c954b67的详情页,并切换至Contrant Code标签中,如下图。

image.png

在Contract code 标签页中点击“Verify And Publish”链接,然后填入下图红框各项内容。

image.png
  • Contract address为上面创建的合约地址;
  • Contract name为在Remix中选择创建的合约名称DAToken;
  • Compiler版本需选择在Remix进行合约创建时选择的编译器版本一致;
  • 是否优化Optimization也需要与Remix发布合约时保持一致;
  • 在“Enter the Solidity Contract Code below”中填入之前在Remix中的solidity合约代码;
  • 在“Constructor Arguments ABI-encoded”中填入构造函数参数(100000000,“My Test Token”,8,“MTT”)的ABI编码,这个会自动填好。

填好上述数据后,点击Verify and Publish,如果验证通过了就会出现如下页面:

image.png

最后我们切换到合约的详情页,点击Contract Source标签,就能看到上传的合约源代码了,如下图:

image.png

如果遇到错误"Unable to Verify Contract at this point time",请确认在提交合约源代码时,选择的编译器版本与是否优化选项,与你在Remix中的选择是否一致。

  1. 添加发布的Token到钱包

我们可以在MetaMask中添加上面生成的Token至MetaMask钱包中,如下图。


image.png

填入Token地址


image.png

点击Add后可以在Tokens标签页中看到上面发布的Token MTT. (因为我们在创建DAToken时,输入的初始量为1000000,而decimal值为8,这个初始量值的单位是token的最低单位,故总量为0.01MTT,大家可以根据自己的情况作出相应调整。)


image.png

接下来就可以在Ropsten测试网络上进行Token的转账以及相关的测试操作了,如果测试没问题就按照同样的流程把合约部署至以太坊主网络中发行真实的token了。

因为Metamask不支持toekn的发送,我们切换到MyEtherWallet钱包。

需要注意的是,MyEtherWallet也需要切换到Rostpen网络

image.png

接下来切换到“发送以太币/发送代币”

image.png

在这里我选择用私钥的方式解锁钱包,私钥可以从Metamask获得

点击Metamask右上角的“...”,然后点击"Export Private Key ",输入密码,即可获得私钥

image.png

将私钥拷到MyEtherWallet,就可以解锁你的钱包了。

点击右下角的“Load Token Balance”

image.png

右下角显示的正是刚刚创建的Token,也就是ZTT,余额为1,这表明我的ERC20 Token发布成功了!

image.png

给另一个账户转token

获取第二个账户地址
切换到account2


image.png

复制账户地址


image.png

填入转账地址和金额,token


image.png

注意这里选择我们刚才发布的LOVE token


image.png

点击生成交易,然后发送交易。

稍后回到Metamask查看


image.png

可以看到账户 account2收到了 100个LOVE

如果你觉得对你有帮助的话,请点击下方的“赞赏支持”,帮我买个煎饼吃吧,😝

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容