创建项目
有别于之前使用truffle init
指令来初始化项目,在Truffle
推出Boxes
功能之后,我们可以直接套用称作react-box
的样板,此样板已经整合create-react-app
,可以直接用它来开发react web
,省下项目设置的时间。
yuyangdeMacBook-Pro:~ yuyang$ cd /Users/yuyang/BloggerCoin
yuyangdeMacBook-Pro:BloggerCoin yuyang$ truffle unbox react-box
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
Test dapp: npm test
Run dev server: npm run start
Build for production: npm run build
目录结构
/contracts
:存放智能合约原始码的地方,可以看到里面已经有放两个sol
文件。我们开发的BloggerCoin.sol
也会放在这里。/migrations
:这是Truffle
用来部署智能合约的功能,待会我们会修改2_deploy_contracts.js
来部署BloggerCoin.sol
。/test
:测试智能合约的代码放这目录,支持js
与sol
测试。/public
、/src
:存放react web
的地方,后面用到会再说明。truffle.js
:Truffle
的设置文件。
开发前的准备
打开终端,启动
testrpc
,继续通过testrpc
模拟以太坊区块链测试环境(Ganache
已经取代了testrpc
,可以使用Ganache
或者truffle develop
模拟测试环境。查看之前的文章获取帮助)。创建的代币如果想要能够通过以太币钱包来进行转账和收帐,必须兼容于以太坊的
ERC20
标准,ERC20
定义了支持钱包所必需的合约界面。在本篇文章中,我们将安装
OpenZeppelin
来简化加密钱包开发的过程。OpenZeppelin
是一套能够给我们方便提供编写加密合约的函数库,同时里面也提供了兼容ERC20
的智能合约。
安装zeppelin-solidity
yuyangdeMacBook-Pro:BloggerCoin yuyang$ npm install zeppelin-solidity
npm WARN The package dotenv is included as both a dev and production dependency.
+ zeppelin-solidity@1.8.0
added 3 packages in 16.261s
Atom打开项目查看zeppelin-solidity安装结果
通过Atom打开项目,在node_modules
中的最后一个文件夹就是zeppelin-solidity
的内容。
创建标准的代币合约
在contracts/
目录下建立一个BloggerCoin.sol
文件。也可以使用以下命令来创建文件:
yuyangdeMacBook-Pro:BloggerCoin yuyang$ truffle create contract BloggerCoin
BloggerCoin.sol
代码如下:
pragma solidity ^0.4.4;
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
contract BloggerCoin is StandardToken {
string public name = "BloggerCoin";
string public symbol = "BLC";
uint8 public decimals = 2;
uint256 public INITIAL_SUPPLY = 666666;
function BloggerCoin() public {
totalSupply_ = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
}
这里在ATOM中会报错,找不到StandardToken.sol文件。但是不影响truffle的编译。
代码解释:
pragma solidity ^0.4.4;
第一行代表solidity
的版本,不同的版本编译的字节码不一样,^
代表向上兼容,不过版本不能超过0.5.0
。
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
这句代码是通过import
来导入我们需要使用到的StandardToken
合约。
contract BloggerCoin is StandardToken {
...
}
建立BloggerCoin
合约时,让BloggerCoin
合约直接继承自StandardToken
。is
既是继承。因此BloggerCoin
继承了StandardToken
所有的状态数据和方法。
当我们继承了StandardToken
合约,也就支持了以下ERC20
标准中规定的函数。
函数 | 方法 |
---|---|
totalSupply() | 代币发行的总量 |
balanceOf(A) | 查询A帐户下的代币数目 |
transfer(A,x) | 发送x个代币到A帐户 |
transferFrom(A,x) | 从A帐户提取x个代币 |
approve(A,x) | 同意A帐户从我的帐户中提取代币 |
allowance(A,B) | 查询B帐户可以从A帐户提取多少代币 |
和之前一样,后面验证时会用到balanceOf
和transfer
两个函数。因为StandardToken
合约中已经帮我们实现了这些函数,因此我们不需要自己从头再写一次。
string public name = "BloggerCoin";
string public symbol = "BLC";
uint8 public decimals = 2;
uint256 public INITIAL_SUPPLY = 666666;
这边设定参数的目的是指定这个代币的一些特性。以人民币为例,人民币的名称(name)是RMB
,美元的代号为¥
,拿1
元去找零最小可以拿到零钱是一分,也就是0.01
元。因为1
元最小可分割到小数点后2
位(0.01)
,因此最小交易单位(decimals)
为2
。
这里将这个加密代币取名(name)为BloggerCoin
(部落币),代币的代号(symbol)为BLC
,最小分割单位是2
(最小可以找0.01
个部落币)。
以下为人民币,比特币,以太币,部落币的对照表供参考:
name | symbol | decimals |
---|---|---|
RMB | ¥ | 4 |
Bitcoin | BTC | 8 |
Ethereum | ETH | 18 |
BloggerCoin | BLC | 2 |
最后也定义了初始代币数目INITIAL_SUPPLY
。这里选择了一个吉祥数字666666
。另外,当我们把全局变量设为public
(公开),编译时就会自动新增一个读取公开变量的ABI
接口,我们在truffle console
中也可以读取这些变量。
function BloggerCoin() {
totalSupply_ = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
和合约同名的BloggerCoin
方法,就是BloggerCoin
合约的构造函函数(constructor)。在构造函数里指定了totalSupply_
数目,并将所有的初始代币INITIAL_SUPPLY
都指定给msg.sender
帐号,也就是用来部署这个合约的帐号。totalSupply_
和balances
定义于BasicToken.sol
中。
pragma solidity ^0.4.18;
import "./ERC20Basic.sol";
import "../../math/SafeMath.sol";
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
uint256 totalSupply_;
/**
* @dev total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
进一步追去看BasicToken.sol
合约的内容,可以发现BasicToken.sol
合约中导入了SafeMath.sol
合约。SafeMath
对各种数值运算加入了必要的验证,让合约中的数字计算更安全。
如此一来,我们已写好一个可通过以太币钱包交易的新加密代币合约。这个合约一经部署,就可以一直存在于以太坊区块链上,世界上从此也就多了一种新的加密代币。只要你能找到人想拥有这种代币,这种代币就有交易的价值。
编译、部署、验证
在migrations/
目录下建立一个3_deploy_bloggercoin.js
文件,内容如下:
var BloggerCoin = artifacts.require("./BloggerCoin.sol");
module.exports = function(deployer) {
deployer.deploy(BloggerCoin);
};
开启truffle develop,模拟测试网络:
yuyangdeMacBook-Pro:BloggerCoin yuyang$ truffle develop
Truffle Develop started at http://127.0.0.1:9545/
Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de
Private Keys:
(0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
(1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f
(2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1
(3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c
(4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418
(5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63
(6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8
(7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7
(8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4
(9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5
Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat
⚠️ Important ⚠️ : This mnemonic was created for you by Truffle. It is not secure.
Ensure you do not use it on production blockchains, or else you risk losing funds.
truffle(develop)>
truffle compile 编译:
truffle(develop)> compile
Compiling ./contracts/BloggerCoin.sol...
Compiling ./contracts/Migrations.sol...
Compiling ./contracts/SimpleStorage.sol...
Compiling zeppelin-solidity/contracts/math/SafeMath.sol...
Compiling zeppelin-solidity/contracts/token/ERC20/BasicToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20/ERC20.sol...
Compiling zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol...
Compiling zeppelin-solidity/contracts/token/ERC20/StandardToken.sol...
Writing artifacts to ./build/contracts
truffle migrate 部署:
truffle(develop)> migrate
Using network 'develop'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0xa2bc55eadab727fd49776fce33779e32eb7ccb89e7138d1a5b272d9e352209f8
Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying SimpleStorage...
... 0xdefa84918abe976e6404c9cf5ecfa86fbf5e194e1801447b37bd697b25692df6
SimpleStorage: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...
Running migration: 3_deploy_bloggercoin.js
Deploying BloggerCoin...
... 0x60dda8ead64aabcba003ae1d212d3f4430dbaf90bb57387b7b0356cd68dc0c64
BloggerCoin: 0x8f0483125fcb9aaaefa9209d8e9d7b9c8b9fb90f
Saving successful migration to network...
... 0x55b13865c62964c3b211dd22c1106101855e698e00dbf6d21aad05d6707cf626
Saving artifacts...
验证:
truffle(develop)> let contract
undefined
truffle(develop)> BloggerCoin.deployed().then(instance => contract = instance)
... ...
truffle(develop)> contract.balanceOf(web3.eth.coinbase)
BigNumber { s: 1, e: 5, c: [ 666666 ] }
truffle(develop)> contract.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 0, c: [ 0 ] }
truffle(develop)> contract.transfer(web3.eth.accounts[1], 600000)
{ tx: '0x650a1535dc5adaa946358c627321686d799894babbfee5001f301c91ec1225dc',
receipt:
{ transactionHash: '0x650a1535dc5adaa946358c627321686d799894babbfee5001f301c91ec1225dc',
transactionIndex: 0,
blockHash: '0x75285b3a555f5f677d0f1915cd0b7af1343d6d5d1025fb60ce98a75860b1d61b',
blockNumber: 7,
gasUsed: 51669,
cumulativeGasUsed: 51669,
contractAddress: null,
logs: [ [Object] ],
status: '0x01',
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000008000000000008000000000000000080000000000000000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000400000000000000000000000010000000002000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000' },
logs:
[ { logIndex: 0,
transactionIndex: 0,
transactionHash: '0x650a1535dc5adaa946358c627321686d799894babbfee5001f301c91ec1225dc',
blockHash: '0x75285b3a555f5f677d0f1915cd0b7af1343d6d5d1025fb60ce98a75860b1d61b',
blockNumber: 7,
address: '0x8f0483125fcb9aaaefa9209d8e9d7b9c8b9fb90f',
type: 'mined',
event: 'Transfer',
args: [Object] } ] }
truffle(develop)> contract.balanceOf(web3.eth.coinbase)
BigNumber { s: 1, e: 4, c: [ 66666 ] }
truffle(develop)> contract.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 5, c: [ 600000 ] }