【本文由赞我(zaneds.com)独家冠名】
本文针对ERC20的发币在window上的全步骤进行说明,下面的图大部分都是我边做边截图下来的,主要是步骤图。有不懂的可以在下面问,我会的会尽量解答。
先来做好创建以太坊私链的准备工作:
需要先准备一个创世区块,手动在桌面创建一个文件夹,名称为:privatechain。创建好privatechain文件夹后,手动双击进入privatechain文件夹。然后在privatechain文件夹下手动创建一个名称为data0的子文件夹,用来存放区块链初始数据。注意这个子文件夹名为data0是数字0不是字母o。接着手动创建创世区块配置文件genesis.json,可以先新建一个genesis.txt文件,打开文件把以下内容复制进去:
{
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "40",
"extraData" : "",
"gasLimit" : "0xffffffff",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"alloc": { }
}
刚复制后的文件保存后,需要更改扩展名,将genesis.txt改成genesis.json。这里要注意,有一些人,比如一开始创建的是一个.txt扩展名的文件,改成genesis.json,但其实发现只是把名称改成genesis.json,并没有把.txt这个扩展名改成了.json的扩展名,这样是不会识别的。所以大家把扩展名显示设置下即可,下面这个链接会教大家如何设置:https://jingyan.baidu.com/article/5d368d1e31ed903f60c057c6.html
以上步骤就是做好了创建以太坊私链的准备工作。
接下来要初始化一条以太坊的私链:
一定要进入到privatechain目录下执行,打开cmd,输入命令:cdC:\Users\Administrator\Desktop\privatechain
进入到privachain目录后,执行命令:geth --datadir data0 init genesis.json
(–datadir data0表示以太坊私链的初始化数据将会放到data0这个子文件夹里边,initgenesis.json表示,以genesis.json里的配置信息为准)
让我们进入到data0文件夹看看,我们初始化以后,原本空空的data0文件夹里边生成了什么?
以太坊私链的初始化完成以后,我们要来启动这条以太坊私链:
在cmd中回到刚刚创建的privatechain目录下,执行命令:
geth --identity "newEth" --rpc --rpcaddr "0.0.0.0" --rpccorsdomain "*" --datadir data0 --port 30303 --rpcapi "personal,db,eth,net,web3" --networkid 999 --rpcport 8080 console
(解析下这个命令中的字段含义:
--identity "newEth"表示我们启动以太坊私链的这个节点也就是我们的电脑,被我们命名为newEth
-rpc 表示启用HTTP-RPC服务器
--rpcaddr "0.0.0.0" 表明HTTP-RPC服务器接口地址是本地服务器
--datadir data0 表示以目录data0作为以太坊私有链的工作目录,以太坊私有链的数据都会保存在这个目录下
--port 30303 这个表示我们我们监听的端口号是30303
--networkid 999 网络标识符(整型, 1=Frontier表示以太坊主网, 2=Morden (弃用), 3=Ropsten 是一个测试网络, 4=Rinkeby 也是一个测试网络) (默认: 1)。当我们在部署智能合约的时候,如果你想把智能合约部署到以太坊主网,这里的值为1,如果要部署到主流的测试网络Ropsten,这个值就用3,4这个值代表了另外一个著名的测试网络Rinkeby。现在我们部署的是自己的以太坊私链,我们用999这个标示号来区分其他几条网络
--rpcport 8080 这个表示我们的rpc服务建立的端口
Console 表示启动一个交互式的环境,允许我们在这个环境里输入命令去执行以太坊私链上的指令)
这条命令的作用就是启动以太坊私链,并进入geth控制台。
接下来我们来看看这条私链上有没有账户,没有的话,新建好账户,查看账户余额:
上图eth.accounts指令,我们看到输出为空的[],表示这个刚刚启动的以太坊私链上还没有账户,新建两个账户:personal.newAccount(‘123456’)表示新建一个账户,账户密码是123456,第一行的绿色字符串,就是这个账户的地址。同样再新建第二个账户,密码还是123456,第二行绿色字符串是第二个账户的地址。
接下来我们把第一个账户命名为user1输入指令:user1=eth.accounts[0],把第二个账户命名为user2,输入指令:user2=eth.accounts[1]。
我们来分别查看两个账户的账户余额,eth.getBalance(user1),的到结果0,eth.getBalance(user2),也得到了结果0.说明两个账户里边都还没有余额。
下边我们来挖矿miner.start(),这里,挖矿的奖励默认是给第一个用户的,所以挖矿以后,你会发现第一个用户的账户余额有了。
执行miner.stop(),挖矿结束,来看一下结果:
这时可以看到账户1有钱了。
到这里,以太坊私链的搭建以及私链上用户的创建、以太坊代币的挖矿奖励已经准备完毕。
接下来去编写智能合约:
介绍一个以太坊智能合约的开发工具,叫做truffle。
今天要用的truffle这个工具,需要在nodejs的这个软件环境下去调用nodejs的一些功能。所以,首先来安装一下node.js。
首先从官网下载Node.js,下载地址:https://nodejs.org/en/#download
下载后测试Node.js 和npm,可以在终端下测试下Node.js 和npm 是否可以使用了。
注意这里新打开一个控制台查询,而不是在geth里查询。
查看node 的版本号 ,在终端里输入如下命令:node -v
说明我本地安装的是node8.12.0的版本。
*查看npm 的版本号 ,在终端里输入如下命令:npm -v
说明我本地的npm是6.4.1的版本。
安装完nodejs和npm以后,我们来继续安装truffle。
输入指令:npm install -g truffle
刚刚提到npm是一个nodejs的框架管理工具,通过npm,我们可以下载nodejs相关的非常多的软件包,truffle就是node.js的一个软件包。Npm指令的用法大家可以下来网上仔细研究,今天简单知道npm install就表示要去npm管理的软件库里下载软件,下载什么软件呢,后面的truffle就是我们要下载的软件名称。我们来执行一下程序看看结果:
若出现以上界面,需要设置npm为淘宝代理。因为使用 cnpm 安装后的目录都为软链,其真实地址是带上版本号的包,经常出现一些意想不到的错误;因此把 npm 的源设置为 taobao 源,直接使用 npm 安装。
这里我使用了方法2:
再次输入指令:npm install -g truffle
安装成功。我们可以执行下程序验证一下,输入命令:truffle
安装好工具以后,开始使用这个工具来开发我们的ERC20智能合约代码
在D盘首先创建一个自己的文件夹叫做myToken,新建控制台:输入cd/d D:\myToken。
以上建立了我们今天的智能合约的主工作目录,也就是我们的根目录。
为了方便大家快速容易的理解怎么发币,这里从truffle官方下载一个发币用的官方模版,大家只需要在模版里边添加自己的代码就可以,在刚刚创建的控制台里,执行以下命令:
truffle unboxtutorialtoken (这个命令的意思,就是去truffle官方下载tutorialtoken这个代码库)
上图表示我们已经下载完了这个代码库了。接下来,我们需要在这个工程里边下载发行代币需要的代码包。记得一定要在D:myToken中执行,执行命令:npm install zeppelin-solidity
下载zeppelin-solidity这个代码包,这个代码包里边,已经为我们定义好了基于ERC20的代币必须要有的一些基础代码。我们只需要在这些基础代码上加入我们自己代币个性化的东西。
下载成功!
接下来用我们的文本编辑器打开我们这个工程,我这里还是使用了python的一个编辑器Pycharm。Pycharm下载地址:http://www.jetbrains.com/pycharm/download/
下载好后,我们现在开始来写自己的代币合约。
Open 打开 D:myToken:
首先新建一个代币合约的代码文件,这个文件请放在contracts文件夹下。我们这次发一个海洋币SeaCoin,在工程目录下新建一个文件,名为SeaCoin.sol,并在文件里边贴入代码:
pragma solidity ^0.4.4;
import"zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
contract SeaCoin isStandardToken {
string public name = "SeaCoin";
string public symbol = "SEC"; //token的代号
uint8 public decimals = 4; //小数位
uint256 public INITIAL_SUPPLY = 2000000; //初始化代币总量,如这里200万
function BloggerCoin() {
totalSupply_ = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
}
接下来,我们还需要配置一下符合发布代币的智能合约。在 migrations 文件夹下添加文件2_deploy_contract.js,此处省略截图。
输入文件内容如下:
var SeaCoin =artifacts.require("SeaCoin")
module.exports =function(deployer){
deployer.deploy(SeaCoin);
};
定义了一个SeaCoin的变量,发布智能合约的时候,需要发布这个SeaCoin。
Truffle在进行发布的时候,会自动执行migrations下边的所有文件,所以刚刚我们新建的发布配置文件,也会被执行的。
最后,我们还需要修改工程根目录下的truffle.js文件,这个文件我刚刚讲过,作用就是为配置到那个链进行相关的属性设定。文件内容修改如下:
module.exports = {
networks: {
development: {
host: "localhost",
port: 8080,
network_id: "999"
}
}
}
到这里,我们所有的编码工作都结束了。接下来还有两个步骤。首先就是编译我们的代码,在终端控制台,工程的根目录输入以下命令:truffle.cmd compile – –compile-all
编译通过以后,我们就需要把智能合约部署到我们的链上去,如何部署呢,我们需要执行命令:truffle.cmdmigrate –reset
去geth控制台解锁两个账户:
然后再次执行命令:truffle.cmdmigrate –reset。在部署项目的过程中,程序会停止在...0x2b199cf69b982744acd55efd6ef3c50d17ef9215e83b28f49f198f2c029989ad这个地方,这个时候,需要在geth控制台挖矿,原因就是因为智能合约的部署其实也会在账本上形成新的记录,如果不挖矿的话,新的区块无法追加到账本上,所以这个时候需要挖矿。我们回到geth控制台,输入命令miner.start(),开始挖矿吧。
新的区块产生,智能合约部署的停顿这个时候消失,继续执行,等到上述智能合约部署的最后结果,saving artifacts…,证明智能合约已经部署到我们的以太坊私链上了。
之后回到geth的控制台,来进行一些智能合约的调用和验证的工作
1)在geth控制台生成abi
SeaCoinAbi=
=[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value">SeaCoinAbi
=
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"INITIAL_SUPPLY","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":false,"inputs":[],"name":"BloggerCoin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
这里等号右边的文字是我先前提到的,工程文件里的abi内容,大家拷贝以后,到https://www.bejson.com/ 可以压缩,压缩完以后,拷贝内容到geth控制台粘贴。
输入命令:SeaCoinAbi=加复制粘贴后如下:
点击 Enter:
2)生成合约实例:括号里的地址,是我们先前提到的工程里编译以后的json里的的address
SeaCoinContract=eth.contract(SeaCoinAbi).at('0xd5edbdfafc4dfb2ec5c545b31e564cac17c560a1')
就是指的这个地址。执行以后,让我们来看看结果:
让人兴奋的一幕出现了!!!
上面的截图中,出现了ERC20标准里边定义的所有功能,这些功能都在我们的智能合约里边实现了。这个时候,我们看到了代币智能合约的实例里边的所有方法,这些方法满足ERC20协议,具备ERC20协议里边规定的所有方法。我们一会调用这些方法实践一下,看看最终的效果。
让我们先来看看代币名称,代币初始值
调用SeaCoinContract.name(),显示了代币名称SeaCion
调用SeaCoinContract.totalSupply(),显示代币总量为0,因为这个时候代币还没有进行首发。
调用SeaCoinContract.INITIAL_SUPPLY(),显示代币初始量为200万
最后一个查询的是小数位数。
尝试发行代币,把初始代币的200万枚分配给合约创建者
进行代币的首发操作SeaCoinContract.BloggerCoin({from:user1}),意思是首发的200万币作为代币总量,并且把200万币都给合约创建者user1
发现首发失败,因为user1这个时候被锁定了,需要解锁,输入解锁命令:
personal.unlockAccount(user1,’123456’)
再次尝试首发代币
SeaCoinContract.BloggerCoin({from:user1}),首发成功。那我们去看看这个时候代币总量
SeaCoinContract.totalSupply()
结果显示为0,什么情况?首发失败吗?想起来了,这个时候这笔交易还没有出块,更没有追加到区块链账本上,挖矿去咯。
执行 miner.start()
一段时间后,执行miner.stop(),停止挖矿,来看看结果:
SeaCoinContract.totalSupply(),显示200万,再看看user1的海洋币数量:
SeaCoinContract.balanceOf(user1),显示200万。
有了,总量200万,user1作为合约创建者,首发的200万也给他了。一夜暴富啊。
接下来来转账试试,看看效果。
定义账本里的第二个用户为user2
user2=eth.accounts[1]
转账前,先看看他的余额
SeaCoinContract.balanceOf(user2),显示为0,证明这个时候他的海洋币数量是0.
好,开始从user1给转账给user2. SeaCoinContract.transfer(user2,500,{from:user1})
上图显示user1这个时候被锁定,解锁:personal.unlockAccount(user1,’123456’),接着输入密码。注意:如果输入后无法执行,注意空格的地方,手动输入记得使用英文输入法。注意空格和影号。
解锁后,再次执行转账:SeaCoinContract.transfer(user2,500,{from:user1})
从user1转账500海洋币给user2.
完成后,来看看user2的余额。SeaCoinContract.balanceOf(user2),显示为0
没到账,交易没有确认和出块,在此挖矿,挖矿结束后,再来看看
SeaCoinContract.balanceOf(user1)
SeaCoinContract.balanceOf(user2)
转账成功!