【以太坊开发】发币指南--基础篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011240016/article/details/83930276

官宣: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账户地址里。

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

扫描二维码关注公众号,回复: 4096484 查看本文章

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.

猜你喜欢

转载自blog.csdn.net/u011240016/article/details/83930276
今日推荐