以太坊发token教程

2017年出现了非常多的数字货币。但是这种货币是如何产生的,作为一个程序员。怀着对发币的好奇,自己动手把发币的流程给走了一遍。再此记录下。这里发币特指ERC20 token。

在发Token前,你先的确定一下几点:

  1. Token的名称
  2. Token的标识
  3. Token的小数位
  4. Token发型量

我的选择是:

  1. 名称:MyFreeCoin
  2. 标识:MFC
  3. 小数位: 18
  4. 发行量: 10000

小数位是18位,表示MFC这个Token最小可以到 .0000000000000000001。

编写 MFC的智能合约:

Token的合约代码我们参考Token-Factory的代码。

pragma solidity ^0.4.4;

contract Token {

    /// @return 返回token的发行量
    function totalSupply() constant returns (uint256 supply) {}

    /// @param _owner 查询以太坊地址token余额
    /// @return The balance 返回余额
    function balanceOf(address _owner) constant returns (uint256 balance) {}

    /// @notice msg.sender(交易发送者)发送 _value(一定数量)的 token 到 _to(接受者)  
    /// @param _to 接收者的地址
    /// @param _value 发送token的数量
    /// @return 是否成功
    function transfer(address _to, uint256 _value) returns (bool success) {}

    /// @notice 发送者 发送 _value(一定数量)的 token 到 _to(接受者)  
    /// @param _from 发送者的地址
    /// @param _to 接收者的地址
    /// @param _value 发送的数量
    /// @return 是否成功
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}

    /// @notice 发行方 批准 一个地址发送一定数量的token
    /// @param _spender 需要发送token的地址
    /// @param _value 发送token的数量
    /// @return 是否成功
    function approve(address _spender, uint256 _value) returns (bool success) {}

    /// @param _owner 拥有token的地址
    /// @param _spender 可以发送token的地址
    /// @return 还允许发送的token的数量
    function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}

    /// 发送Token事件
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    /// 批准事件
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
/*
This implements ONLY the standard functions and NOTHING else.
For a token like you would want to deploy in something like Mist, see HumanStandardToken.sol.

If you deploy this, you won't have anything useful.

Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20

实现ERC20标准
.*/

pragma solidity ^0.4.4;

import "./Token.sol";

contract StandardToken is Token {

    function transfer(address _to, uint256 _value) returns (bool success) {
        //默认token发行量不能超过(2^256 - 1)
        //如果你不设置发行量,并且随着时间的发型更多的token,需要确保没有超过最大值,使用下面的 if 语句
        //if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
        if (balances[msg.sender] >= _value && _value > 0) {
            balances[msg.sender] -= _value;
            balances[_to] += _value;
            Transfer(msg.sender, _to, _value);
            return true;
        } else { return false; }
    }

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        //向上面的方法一样,如果你想确保发行量不超过最大值
        //if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
        if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
            balances[_to] += _value;
            balances[_from] -= _value;
            allowed[_from][msg.sender] -= _value;
            Transfer(_from, _to, _value);
            return true;
        } else { return false; }
    }

    function balanceOf(address _owner) constant returns (uint256 balance) {
        return balances[_owner];
    }

    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];
    }

    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;
    uint256 public totalSupply;
}
/*
This Token Contract implements the standard token functionality (https://github.com/ethereum/EIPs/issues/20) as well as the following OPTIONAL extras intended for use by humans.

In other words. This is intended for deployment in something like a Token Factory or Mist wallet, and then used by humans.
Imagine coins, currencies, shares, voting weight, etc.
Machine-based, rapid creation of many tokens would not necessarily need these extra features or will be minted in other manners.

1) Initial Finite Supply (upon creation one specifies how much is minted).
2) In the absence of a token registry: Optional Decimal, Symbol & Name.
3) Optional approveAndCall() functionality to notify a contract if an approval() has occurred.

.*/
pragma solidity ^0.4.4;

import "./StandardToken.sol";

contract MyFreeCoin is StandardToken {

    function () {
        //if ether is sent to this address, send it back.
        throw;
    }

    /* Public variables of the token */

    /*
    NOTE:
    The following variables are OPTIONAL vanities. One does not have to include them.
    They allow one to customise the token contract & in no way influences the core functionality.
    Some wallets/interfaces might not even bother to look at this information.
    */
    string public name;                   //token名称: MyFreeCoin 
    uint8 public decimals;                //小数位
    string public symbol;                 //标识
    string public version = 'H0.1';       //版本号

    function MyFreeCoin(
        uint256 _initialAmount,
        string _tokenName,
        uint8 _decimalUnits,
        string _tokenSymbol
        ) {
        balances[msg.sender] = _initialAmount;               // 合约发布者的余额是发行数量
        totalSupply = _initialAmount;                        // 发行量
        name = _tokenName;                                   // token名称
        decimals = _decimalUnits;                            // token小数位
        symbol = _tokenSymbol;                               // token标识
    }

    /* 批准然后调用接收合约 */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);

        //调用你想要通知合约的 receiveApprovalcall 方法 ,这个方法是可以不需要包含在这个合约里的。
        //receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
        //假设这么做是可以成功,不然应该调用vanilla approve。
        if(!_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData)) { throw; }
        return true;
    }
}

如果想要发行自己的token,只需要把 MyFreeCoin出现的地方替换为你的token名称。

需要注意的一点是,你发行的数量需要相对token小数点来设置。例如如果token的小数点是0,而你要发行1000个token,那么发行数量的值1000。但是如果token的小数点是18位,你要发行1000个token,那么发行数量的值是1000000000000000000000(1000后面加上18个0)。

balances[msg.sender] = _initialAmount;
这行代码,我们把合约的发布者的余额设置为发行量的数量。

在测试网络上发行我们的token:

  1. 安装MetaMask钱包。
  2. 安装MetaMask之后,登陆Metamask, 左上角选择Ropsten。如下图:


    1.jpg

这个账号将会是我们的智能合约的所有者,也就是说token发行数量都是存入到这个账号。

  1. 打开Solidity Remix Compiler ,remix 是一个在线编译器可以帮我们把智能合约直接发布到以太坊上。

  2. 把上面三个文件代码复制到remix编辑器中。可以先删除remix中默认ballot.sol 文件,在新建 Token.sol , StandardToken.sol, MyFreeCoin.sol 三个文件, 相应的把代码复制到文件中,如下图:


    2.jpg
  3. 点击 start to compile 编译代码文件。

  4. 给我们的测试账号申请点 eth来测试,如下图点击 buy按钮,再点击ropsten test faucet

    3.jpg

    4.jpg

  5. 会打开 faucet metamask 网站,点击
    request 1 eth from faucet。成功后会生成 交易记录。

    5.jpg

    6.jpg

  6. 可以查看到我们的测试账户上已经有了eth可以用了。


    7.jpg
  7. 选中remix中的run 菜单,下拉框中选择MyFreeCoin, 在create按钮的左边输入框中输入 "10000000000000000000000","MyFreeCoin",18,"MFC", 如下图

    8.jpg

  8. 点击create 按钮,需要注意的是发行量需要包含在 "" 中。 metamask会弹出确认框。如下图:


    9.jpg
  9. 确定后,会进入挂起状态,等待旷工打包。

  10. 等一段时间后,交易完成,会显示MyFreeCoin 合约。


    10.jpg
  11. 点击MyFreeCoin 的复制按钮,复制合约地址在 ropsten etherscan中查询,可以查询到我们的合约情况,如下图:

    11.jpg

  12. 验证我们发布的token。在metamask的token中点击 add token 按钮。如下图:


    12.jpg
  13. 在add token 的地址填入我们刚才复制的合约地址,如下图:


    13.jpg
  14. 可以在token中看到我们新创建的token。如下图:


    14.jpg
  15. 认证我们的合约代码。 在刚才ropsten ethscan 的合约地址页面中,点击Contract code, 如下图:


    15.jpg
  16. 点击Verify and Publish, 会进入如下页面:


    16.jpg
  1. Contract name: 的输入框输入token 名称MyFreeCoin, Compiler 选择在remix的sttings 中Solidity version 显示的版本号。Optimization 选择 No。 然后在Enter the Solidity Contract Code below 下面的输入框中填入代码,我们的代码有三个文件,需要把它们合并成一个文件,合并的格式是这样:
pragma solidity ^0.4.4;
contract Token {
}
contract StandardToken is Token {
}
contract MyFreeCoin is StandardToken {
}

去掉原来代码文件中的 import语句。最后提交。成功后,会显示下面的页面表示验证成功:


17.jpg

最后让我们在不同地址之间流通这个token。我们第一个账户已经有1000的MFC了。

先让我们在创建一个新的账户,如下图:


18.jpg

可以看到我们新创建的账户 MFC的值是0.


19.jpg

在切回我们的第一个账户,在transfer 中填入第二账户的地址和转入的数量("0xe4da4CBC744708A6656BeD252f49DF5exxxxxxC97","1000000000000000000")。如下图:


20.jpg

点击transfer 会弹出弹框让你确定,点击sumbit,等待区块打包。切换到第二个账户,查看MFC余额。可以看到已经到转过来的1MFC了。


21.jpg

最终我们的发token的流程已经结束了。但是这还只是第一步,后面我们还需要程序化的执行token的充币,提币操作。也是一个应用若想引入token进来必须要有的功能。后面我会继续研究下去,实现用程序来操作token的转让。

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

推荐阅读更多精彩内容