以太坊 (五)编写智能合约-建立简易加密代币

本篇文章,我们将写一个简易的加密代币的智能合约来给大家诠释加密代币的原理

启动 ganache-cli

打开终端,启动ganache-cli,相关环境在区块链学习日记(四)这篇文章里面已经有具体说明。

wangsanjundeMacBook-Pro:~ wangsanjun$ ganache-cli
Ganache CLI v6.0.3 (ganache-core: 2.0.2)

Available Accounts
==================
(0) 0x79221bc486bcc9380d280c4221856f7122b32d6f
(1) 0xc72f1267309aaa7aa79c1f6b971edca111e0c3e4
(2) 0x5139a3ca66f06102eabbb38989021bca9ade63db
(3) 0x20cb6137afeb2da01d2fb28ade7822a5ffe214e1
(4) 0x93382d64508ca98b9f2a7dbf13366be157be04fa
(5) 0x051a305c1d016391cea8d9d19c5560d0bb4148f4
(6) 0x9676763004ec23beab44feeb6d9d9f86a846b7ab
(7) 0xe0400ae3a7390d78397d12fc0b768f8209f5abf4
(8) 0xd17a5a1a9b26d35ef957bf5686db90b011f8d9a8
(9) 0x0b529a02f4f6c997dae911a64fce47d4a850b77c

Private Keys
==================
(0) 85e35b54c141ebe2df61cc56192aced3ba03f51e2ae8ca0ed299a25ab8ac7155
(1) 4215839182c1ffcb5f8854631fd1a2372be3b3910a0f193e392f90df85befb03
(2) 90081b0b6f3ffc6ce6245bed5f0f864982522d65a4b47a891f07b6be0deec03b
(3) 845efda127b31c0c0e4ef142bb62de73dc89bf3269d1ace9e3be3ad2476c29ff
(4) dfa540af69e16a81415e362295e9526acb4189eb883bbf30a843c2289a2f7cb0
(5) 18fac89e76063d582881ad98a6ad6f79e07782b64bbac507034ccb5a66cc5e7e
(6) 3e0ab00795f1f061f7ca681e64d51bd1ee59427bfe5477e751ee93f9596d95b6
(7) a09f85a55ee46a61030b87bea045cff8e43671287709608bd329f41e33660442
(8) 420ec6889ba6aa5ec1cfd1757b9209687350487cc14dc56e8792b2bd6727de4a
(9) 45e96bbd340ef850ee32b1f3a5808ed3aecad889f1929377fe6eabd95c0dcc77

HD Wallet
==================
Mnemonic:      neither mountain become final nephew drill ramp onion attract parade neck merge
Base HD Path:  m/44'/60'/0'/0/{account_index}

Listening on localhost:8545
...

接下来我们就可以一步步的创建我们的加密代币项目了。

代币合约的基本概念

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

创建代币合约项目

wangsanjundeMacBook-Pro:SmartContractDemo wangsanjun$ mkdir EncrptedToken
wangsanjundeMacBook-Pro:EncrptedToken wangsanjun$ truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test
wangsanjundeMacBook-Pro:EncrptedToken wangsanjun$ 

新建代币合约

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

《以太坊 (五)编写智能合约-建立简易加密代币》 EncryptedToken.sol.png

编写合约代码

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

pragma solidity ^0.4.17;

contract EncryptedToken {
  uint256 INITIAL_SUPPLY = 666666;
  mapping(address => uint256) balances;
  function EncryptedToken() {
    balances[msg.sender] = INITIAL_SUPPLY;
  }
  // 转账到一个指定的地址
  function transfer(address _to, uint256 _amount) {
    assert(balances[msg.sender] >= _amount);
    balances[msg.sender] -= _amount;
    balances[_to] += _amount;
  }
  // 查看指定地址的余额
  function balanceOf(address _owner) constant returns (uint256) {
    return balances[_owner];
  }
}

pragma solidity ^0.4.17中的0.4.17代表solidity的版本,^代表0.4.17 ~ 0.4.99之间的solidity都可以正常编译当前版本的合约。

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

uint256 INITIAL_SUPPLY = 666666声明了一个变量INITIAL_SUPPLY,初始化存储了一个666666的整数作为部署当前合约的钱包地址的代币数。

mapping(address => uint256) balances;balances是一个key类型为addressvalue类型为uint256的键值对 (mapping),相当于 Java 中的map、iOS 中的NSDictionary

function EncryptedToken()函数是EncryptedToken合约的构造函数 (contructor),当EncryptedToken合约调用时,会先执行它的构造函数。

在构造函数中,会以当前部署合约的钱包地址为key,以INITIAL_SUPPLYvalue初始化一个键值对。

function transfer(address _to, uint256 _amount) {
    assert(balances[msg.sender] >= _amount);
    balances[msg.sender] -= _amount;
    balances[_to] += _amount;
}

transfer函数是声明用来从转账到指定钱包地址的函数,_to代表转账的目的地地址,_amount代表转账金额。

assert(balances[msg.sender] >= _amount),这句代码中,我声明了一个断言,当balances[msg.sender] >= _amount,即当前钱包余额小于要转账的额度时,就会抛出异常。

balances[msg.sender] -= _amount;从当前钱包额度中减去_amount

balances[_to] += _amount;,将目标地址的额度增加_amount

 function balanceOf(address _owner) constant returns (uint256) {

    return balances[_owner];
 }

balanceOf(address _owner)函数是用来查询指定钱包地址的余额,_owner即是指定的钱包地址,returns (uint256)代表返回值的类型为uint256constant关键字的作用是,当我们调用balanceOf函数时,它会自动调用call()方法,表明是只读数据,而不需要往区块链写入数据,调用这个方法,不需要花费手续费。

编译与部署

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

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

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

《以太坊 (五)编写智能合约-建立简易加密代币》 2_deploy_contract.js.png

修改truffle.js文件,连接本地ganache-cli环境

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "*" // Match any network id
    }
  }
};

《以太坊 (五)编写智能合约-建立简易加密代币》 truffle.js.png

接下来执行compilemigrate命令:

wangsanjundeMacBook-Pro:EncrptedToken wangsanjun$ truffle compile
Compiling ./contracts/EncryptedToken.sol...
Compiling ./contracts/Migrations.sol...

Compilation warnings encountered:

/Users/wangsanjun/Desktop/SmartContractDemo/EncrptedToken/contracts/EncryptedToken.sol:6:3: Warning: No visibility specified. Defaulting to "public".
  function EncryptedToken() {
  ^
Spanning multiple lines.
,/Users/wangsanjun/Desktop/SmartContractDemo/EncrptedToken/contracts/EncryptedToken.sol:10:3: Warning: No visibility specified. Defaulting to "public".
  function transfer(address _to, uint256 _amount) {
  ^
Spanning multiple lines.
,/Users/wangsanjun/Desktop/SmartContractDemo/EncrptedToken/contracts/EncryptedToken.sol:16:3: Warning: No visibility specified. Defaulting to "public".
  function balanceOf(address _owner) constant returns (uint256) {
  ^
Spanning multiple lines.

Writing artifacts to ./build/contracts

wangsanjundeMacBook-Pro:EncrptedToken wangsanjun$ truffle migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xc4e64f8636e83fe67a9c0044667cf19237e631e801dd682f7ef01c8175eb7d6c
  Migrations: 0x252a66c521dd81312455411acdd8074c159ee300
Saving successful migration to network...
  ... 0x0c2c60f492f7a82ab7d72e523b75f024ae83f402be313d033078d46b49555a89
Saving artifacts...
Running migration: 2_deploy_contract.js
  Deploying EncryptedToken...
  ... 0x14675402f0781db21afccb69a11a3e2177d06d7eba4a95b67a1b146caf48262e
  EncryptedToken: 0x5c6d0f9528791e07350e00e80e66e655583d7b69
Saving successful migration to network...
  ... 0x447a94584192424ff4401892c5f478db7d39218895e856636e578ed536e838e1
Saving artifacts...
wangsanjundeMacBook-Pro:EncrptedToken wangsanjun$  

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

合约验证

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

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

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

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

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

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

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

truffle(development)> contract.transfer(web3.eth.accounts[1],666)
{ tx: '0x50c71bd9a522afb9ff054bf11755d7665d7d9770f1bfca3548973df7aace24ab',
  receipt: 
   { transactionHash: '0x50c71bd9a522afb9ff054bf11755d7665d7d9770f1bfca3548973df7aace24ab',
     transactionIndex: 0,
     blockHash: '0x2fc452564dad406210c26be62e44770c6fa6ec1f435ff488ffb393a5317b8de6',
     blockNumber: 28,
     gasUsed: 49120,
     cumulativeGasUsed: 49120,
     contractAddress: null,
     logs: [],
     status: 1 },
  logs: [] }
truffle(development)> contract.balanceOf(web3.eth.coinbase)
{ [String: '666000'] s: 1, e: 5, c: [ 666000 ] }
truffle(development)> contract.balanceOf(web3.eth.accounts[1])
{ [String: '666'] s: 1, e: 2, c: [ 666 ] }
truffle(development)> 

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

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

    原文作者:duanyu
    原文地址: https://www.jianshu.com/p/7280d9c86cec
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞