请选择 进入手机版 | 继续访问电脑版
开启辅助访问
链路首页链路财经目前收录 币种 : 4908 交易所 : 310钱包 : 17 24H 交易量 : $43,403,137,051 总市值 : $245,388,183,835
2018
11/10
16:23
分享
评论
  • 在白皮书拆解篇之外,会渐渐补齐开发篇,本篇为以太坊平台发币合约的基础篇拆解。

    官宣:https://www.ethereum.org/token

    核心逻辑演进按照官网的示例,个人的工作就是从我自己的视角讲清楚这个逻辑。图文仅作为参考。

    首先我们需要知道,标准的发币合约是比较复杂的,我们这里先从最简单的开始入手。

    pragma solidity ^0.4.20;
    
    contract MyToken {    /* 一个类似字典的结构,链上存储--存储的是所有账户的余额,key是地址,value是余额 */
        mapping (address => uint256) public balanceOf;    /*初始化:初始发行总量全归创建者所有*/
        function MyToken(
            uint256 initialSupply
            ) public {
            balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens
        }    /* 发送代币的函数 */
        function transfer(address _to, uint256 _value) public returns (bool success) {        require(balanceOf[msg.sender] >= _value);           // Check if the sender has enough
            require(balanceOf[_to] + _value >= balanceOf[_to]); // Check for overflows
            balanceOf[msg.sender] -= _value;                    // Subtract from the sender
            balanceOf[_to] += _value;                           // Add the same to the recipient
            return true;
        }
    }

    代码拆解

     contract MyToken {     /* This creates an array with all balances */
         mapping (address => uint256) public balanceOf;
     }

    mapping数据结构是个字典,存储键值到值的映射,这里是从地址到余额的映射。

    如果就把上面这个合约部署到链上,啥用都没有。所以我们接着增加一些功能进来:

    contract MyToken {
        mapping (address => uint256) public balanceOf;    function MyToken() {
            balanceOf[msg.sender] = 21000000; // 比特币的总量~
        }
    }

    显式增加一个构造函数,加上一行代码,往msg.sender这个账户里新增2100万个ETH。

    这里的数字没有其他特别含义,可以任意指定,而更好的方式则是,把它作为变量,将来可以改动。

    contract MyToken {
        mapping (address => uint256) public balanceOf;    function MyToke(uint initialSupply) {
            balanceOf[msg.sender] = initialSupply;
        }
    }

    至此,我们创建的智能合约,就一个构造函数,创建者地址里多出来初始发行量的代币了,但是还没有转移代币的功能。时刻记住,智能合约编译后放在链上自动运行,像个智能体一样,功能是我们定义好的,暴露出来,交给事件自动触发执行。

    现在我们为它加上转移代币的功能:

    contract MyToken() {
        mapping(address => uint256) public balanceOf;    function MyToken(uint256 initialSupply) {
            balanceOf[msg.sender] = initialSupply;
        }    function transfer(address _to, uint256 _value) public {
            balanceOf[msg.sender] -= _value;
            balanceOf[_to] += _value;
        }
    }

    这里添加的是直接的转账逻辑,从发送者msg.sender账户里减去_value数量的代币,并将其加到_to账户地址里。

    这是有问题的,问题在哪里呢?发送者钱够不够转呢?接收者收到代币后会不会值溢出?

    transfer函数里,添加一行:

    require(balanceOf[msg.sender] >= _value && balanceOf[_to] + _value >= balanceOf[_to] )

    上面这个简单合约里还没有代币的基本信息,先设定好保存基本信息的容器:

    string public name;
    string public symbol;
    uint8 public decimals;

    这些信息在构造器函数中使用:

    function MyToken(uint256 initialSupply, string tokenSymbol, uint8 decimalUnits) {    require(balanceOf[msg.sender] >= _value && balanceOf[_to] + _value >= balanceOf[_to] )
        balanceOf[msg.sender] = initialSupply;
        name = tokenSymbol;
        decimals = decimalUnits;
    }

    现在是时候创建一些事件了。

    什么是事件?

    所谓事件呢,就是一些特殊的空函数,我们可以调用这些函数来帮助以太坊客户端,比如以太坊钱包来跟踪合约上发生的活动。事件需要以大写字母开头。

    事件的使用分成两个步骤

    • 声明事件:event关键字

    • 发射事件:emit关键字

    声明事件的方式

    event Transfer(address indexed from, address indexed to, uint256 value);

    注意到这里声明时,地址类型后面跟着一个修饰符indexed,现在我还不知道为啥要这个,但先记着。

    使用事件的方式

    事件定义完成之后,需要在合适的地方发射出去,让这个世界知道。这里的转账事件需要在transfer函数后面加上。

    function transfer(address _to, uint256 _value) public {    
       require(balanceOf[msg.sender] >= _value && balanceOf[_to] + _value >= balanceOf[_to] )    balanceOf[msg.sender] -= _value;    balanceOf[_to] += _value;    // 发射事件: 告知在监听的所有人,事件发生了    emit Transfer(msg.sender, _to, _value); }

    事件很像是C++里面的函数,先声明后调用。事件本质上是个函数,所以在emit时,也是按照调用函数的逻辑来运行。

    基础篇到此为止,具体如何部署,由于本人没有用基于Mist的客户端跑通,而基于Remix的之前写过,有些地方不太一样,大体还是可用的:https://bihu.com/article/16183

    下一篇讲进阶。

    更多精彩推荐,请关注我们

    ·END·
     

    币圈研习社

    有趣·有料·有见解

主题帖 12 关注 0 粉丝 0
情感指数

链路大数据分析置信度 6.84 %

TA的主题帖
主题相关
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表