区块链:建立加密代币

启动testrpc

打开终端,启动testrpc

testrpc
EthereumJS TestRPC v6.0.3 (ganache-core: 2.0.2)
...

代币合约的基本概念

代币合约扮演的角色相当于银行的角色。使用者在代币合约中,用自己的以太币帐户地址当作银行帐户,可以透过代币合约执行转账(transfer,将代币由一个帐户转到另一个帐户),查询余额(balanceOf,查询指定帐户中拥有的代币)等原本由银行负责的工作。因为合约部署在公开区块链上,所有的交易都是公开透明,可供检验的。

创建代币合约项目

 cd /Users/mac/Desktop/GitHub/Solidity/learn/SmartContractDemo/EncryptedToken 
macdeiMac:EncryptedToken mac$ pwd /Users/mac/Desktop/GitHub/Solidity/learn/SmartContractDemo/EncryptedToken
/Users/mac/Desktop/GitHub/Solidity/learn/SmartContractDemo/EncryptedToken
macdeiMac:EncryptedToken mac$ truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test
macdeiMac:EncryptedToken mac$ 

新建代币合约

终端执行truffle create contract EncryptedToken命令创建EncryptedToken.sol合约。

macdeiMac:EncryptedToken mac$ truffle create contract EncryptedToken
macdeiMac:EncryptedToken mac$ 

区块链:建立加密代币_第1张图片

编写合约代码

将下面的合约代码拷贝,替换EncryptedToken.sol文件的代码。

pragma solidity ^0.4.22;//代表solidity的版本

//contract相当于其他语言中的class,EncryptedToken相当于类的名字。
//contract EncryptedToken可以理解为class EncryptedToken extends Contract。
contract EncryptedToken {

  //声明了一个变量INITIAL_SUPPLY,初始化存储了一个666666的整数作为部署当前合约的钱包地址的代币数。
  uint256 INITIAL_SUPPLY = 666666;
  //balances是一个key类型为address,value类型为uint256的键值对(mapping),相当于Java中的map、iOS中的NSDictionary。
  mapping(address => uint256) balances;

  //EncryptedToken合约的构造函数(contructor),当EncryptedToken合约调用时,会先执行它的构造函数
  constructor() public{
    //以当前部署合约的钱包地址为key,以INITIAL_SUPPLY为value初始化一个键值对。
     balances[msg.sender] = INITIAL_SUPPLY;
  }

  // 转账到一个指定的地址
  /*
    param:address _to  转账的目的地地址
    param:uint256 _amount 转账金额
  */
  function transfer(address _to, uint256 _amount) public{
    //声明断言,当条件满足,即当前钱包余额小于要转账的额度时,就会抛出异常。
    assert(balances[msg.sender] < _amount);
    //从当前钱包额度中减去_amount
    balances[msg.sender] -= _amount;
    //将目标地址的额度增加_amount
    balances[_to] += _amount;
  }
  // 查看指定地址的余额
  /*
   param:address _owner 指定的钱包地址
   constant 关键字的作用 调用balanceOf函数时,它会自动调用call()方法
   表明只是读书数据,而不需要往区块链写入数据,调用这个方法,不需要花费手续费
  */
  function balanceOf(address _owner) public constant returns (uint256) {
    return balances[_owner];
  }
}

编译与部署

migrations/目录下创建一个名字叫做3_deploy_contract.js的文件。文件中的内容为:

var EncryptedToken = artifacts.require('./EncryptedToken.sol');

module.exports = function(deployer) {
  deployer.deploy(EncryptedToken);
}

区块链:建立加密代币_第2张图片

修改truffle.js文件如下

module.exports = {
  networks:{
    development:{
      host:"localhost",
      port:8545,
      network_id:"*"//匹配任何netword id
    }
  }
};

接下来执行compile和migrate命令:

macdeiMac:EncryptedToken mac$ truffle compile
Compiling ./contracts/EncryptedToken.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

macdeiMac:EncryptedToken mac$ truffle migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xb294a83d6af78566da598d005e35a0c1aff1c9b9aab6bad47c2a7c64c8f78548
  Migrations: 0xe32cf4c736d7eaed2e014f7922cc90e65291461a
Saving successful migration to network...
  ... 0xa4b7ffff3ae198a23b56aa79447811abc8073a877ce83a36c25638b10369cab9
Saving artifacts...
Running migration: 3_deploy_contract.js
  Deploying EncryptedToken...
  ... 0x472380c714b1331d6b62202f489009e8aeb34a82f5f60fdfa04fed191c1b42cd
  EncryptedToken: 0x87ef1502b36ec52e661091178b991211417815eb
Saving successful migration to network...
  ... 0x14cb8d7b4234d004b6d6e33a6524a4428e1d8f7202deb86556e2f37e6b21381d
Saving artifacts...
macdeiMac:EncryptedToken mac$ 

如上所示,我们已经将EncryptedToken代币合约部署到了testrpc上。

合约验证

合约部署完成后,我们通过truffle console开启console控制台,在这个控制台中对已经部署的合约进行验证。

macdeiMac:EncryptedToken mac$ truffle console
truffle(development)> web3.eth.coinbase
'0x62c806c5751e952352ed23c21ea63b92f4d37e49'
truffle(development)> web3.eth.accounts[0]
'0x62c806c5751e952352ed23c21ea63b92f4d37e49'
truffle(development)> web3.eth.accounts[1]
'0x2148c956ae0d20110abfc741f47cab1812cd7100'
truffle(development)> web3.eth.accounts[2]
'0x3bd3500477294891fae9ec0d07b96864f648668c'
truffle(development)> web3.eth.accounts[3]
'0x40dcf037cc9bd7008eb268a93002b8ee760467cb'
truffle(development)> web3.eth.accounts[9]
'0x5dce4583cdda41ea1720ea54defc0febf779aa18'
truffle(development)> 

区块链:建立加密代币_第3张图片

testrpc启动时,系统会给我们分配10个钱包地址,如上图所示我们可以通过web3.eth.coinbase或者web3.eth.accounts[0]获取首个钱包地址,当然也可以根据索引获取其他的钱包地址。

接下来声明一个合约变量存储EncryptedToken合约实例。

let contract;
undefined
truffle(development)> EncryptedToken.deployed().then(instance => contract = instance)
....

验证web3.eth.coinbaseweb3.eth.accounts[1]中的余额。

truffle(development)> contract.balanceOf(web3.eth.coinbase)
BigNumber { s: 1, e: 5, c: [ 666666 ] }
truffle(development)> contract.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 0, c: [ 0 ] }
truffle(development)> 

经验证,第0个钱包地址中的代币余额为666666,第1个钱包地址中的代币余额为0

下一步,我们将从第0个账号中向第1个账号转账666个代币。

truffle(development)> contract.transfer(web3.eth.accounts[1], 666)
Error: VM Exception while processing transaction: invalid opcode
    at XMLHttpRequest._onHttpResponseEnd (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:509:1)
    at XMLHttpRequest._setReadyState (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:354:1)
    at XMLHttpRequestEventTarget.dispatchEvent (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:64:1)
    at XMLHttpRequest.request.onreadystatechange (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/httpprovider.js:128:1)
    at /usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-provider/wrapper.js:134:1
    at /usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/requestmanager.js:86:1
    at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/errors.js:38:1)
truffle(development)> 

如上所示,转账过程中出现了异常,转账失败,仔细检查一下,不难发现是因为在我们合约代码EncryptedToken.sol中有这么一句代码assert(balances[msg.sender] < _amount);,也就是说只有当balances[msg.sender] 小于_amount时,才不会出现异常,所以我们应该将<符号换成>符号,即当balances[msg.sender]余额不足时抛出异常。

区块链:建立加密代币_第4张图片

代码修改后,需要重新编译,部署。

truffle(development)> .exit
macdeiMac:EncryptedToken mac$ pwd /Users/mac/Desktop/GitHub/Solidity/learn/SmartContractDemo/EncryptedToken 
/Users/mac/Desktop/GitHub/Solidity/learn/SmartContractDemo/EncryptedToken
macdeiMac:EncryptedToken mac$ ls
build           migrations      truffle-config.js
contracts       test            truffle.js
macdeiMac:EncryptedToken mac$ rm -rf build/
macdeiMac:EncryptedToken mac$ ls
contracts       test            truffle.js
migrations      truffle-config.js
macdeiMac:EncryptedToken mac$ truffle compile
Compiling ./contracts/EncryptedToken.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

macdeiMac:EncryptedToken mac$ truffle compile
macdeiMac:EncryptedToken mac$ truffle migrate --reset
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0x06dc2459d1475eb3695046aecf69853a5d48118b083e7b35029e28608fc9a31e
  Migrations: 0x21784acbb71ea4ff918dcddfa6480ccd8dbd37f3
Saving successful migration to network...
  ... 0x1ee0008c47caa05a4e3c46fe74a1cf861db6cef360f89c42520dad0a7353447c
Saving artifacts...
Running migration: 3_deploy_contract.js
  Deploying EncryptedToken...
  ... 0x0b4755c4c54c3aaa35458d0f2032146e112a884f6c1564258e8a6cc4a7b858d6
  EncryptedToken: 0x428519366dbbf4f40f724a4270e60351e7550191
Saving successful migration to network...
  ... 0x161d89d9fe24bbd1bffc64585115519b5ed76c69a66929e63908b5fa086ef03e
Saving artifacts...
macdeiMac:EncryptedToken mac$ 

备注:编译时,一定要先将build文件夹删除,其次在部署合约时,一定要添加--reset,否则修改后的合约没法部署成功。

打开控制台,按照如下操作进行验证。

macdeiMac:EncryptedToken mac$ truffle console
truffle(development)> let contract
undefined
truffle(development)>  EncryptedToken.deployed().then(instance => contract = instance)
...
truffle(development)>  contract.balanceOf(web3.eth.coinbase)
BigNumber { s: 1, e: 5, c: [ 666666 ] }
truffle(development)> contract.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 0, c: [ 0 ] }
truffle(development)> contract.transfer(web3.eth.accounts[1], 666)
{ tx: '0x3e864aa0b4509a6650dbd44115776e22e2ab3fb08620734ceef91a97d1cd2a43',
  receipt: 
   { transactionHash: '0x3e864aa0b4509a6650dbd44115776e22e2ab3fb08620734ceef91a97d1cd2a43',
     transactionIndex: 0,
     blockHash: '0x35feeaf4772df9abca434e2f9c5a60dcbb6d5bf9923f7d8dde6f109d768218ba',
     blockNumber: 10,
     gasUsed: 49083,
     cumulativeGasUsed: 49083,
     contractAddress: null,
     logs: [],
     status: 1 },
  logs: [] }
truffle(development)> contract.balanceOf(web3.eth.coinbase)
BigNumber { s: 1, e: 5, c: [ 666000 ] }
truffle(development)> contract.balanceOf(web3.eth.accounts[1])
BigNumber { s: 1, e: 2, c: [ 666 ] }
truffle(development)> 

如上所示,代币转账成功。

简单介绍了代币系统的逻辑,并没有对安全进行相关操作,比如:余额不够的处理、地址合不合法的处理等等。

你可能感兴趣的:(区块链)