如何编写智能合约(Smart Contract)?(II)建立加密代币

接着上一篇如何编写智能合约(Smart Contract)?,本篇文章,我们将写一个简单的加密代币的智能合约来给大家诠释加密代币的原理,当然这篇文章只是告诉你加密代币的原理,存在很多漏洞,不能直接使用。

启动testrpc

打开终端,启动testrpc,相关环境在如何编写智能合约(Smart Contract)?这篇文章里面已经有具体说明。

liyuechun:~ yuechunli$ testrpc
EthereumJS TestRPC v4.1.3 (ganache-core: 1.1.3)
...

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

代币合约的基本概念

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

创建代币合约项目

liyuechun:EncryptedToken yuechunli$ pwd
/Users/liyuechun/Desktop/SmartContractDemo/EncryptedToken
liyuechun:EncryptedToken yuechunli$ truffle init
Downloading project...
Project initialized.

  Documentation: http://truffleframework.com/docs

Commands:

  Compile: truffle compile
  Migrate: truffle migrate
  Test:    truffle test

liyuechun:EncryptedToken yuechunli$

新建代币合约

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

编写合约代码

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

pragma solidity ^0.4.4;

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.4中的0.4.4代表solidity的版本,^代表0.4.4 ~ 0.4.9之间的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/目录下创建一个名字叫做3_deploy_contract.js的文件。文件中的内容为:

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

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

接下来执行compilemigrate命令:

liyuechun:EncryptedToken yuechunli$ truffle compile
Compiling ./contracts/ConvertLib.sol...
Compiling ./contracts/EncryptedToken.sol...
Compiling ./contracts/MetaCoin.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

liyuechun:EncryptedToken yuechunli$ truffle migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0x8b31575b8ac09efae7bdf933823fcf91885b4e1c93b4d9b37421d22ab73cef25
  Migrations: 0x9b34fffa8e0d2e6d09f59ee289db13e0662b68fe
Saving successful migration to network...
  ... 0x45ba02af03a7e94f66bebbb72eebf547ffe128a49f01437aca6b45c2f489b0a1
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying ConvertLib...
  ... 0xae9c5fd334d8925b027d8de3ca9aeb13e2bd1d2d3b95b49ef3c7b472446d73ae
  ConvertLib: 0x3f7fff3afe38a0a152806a0f4f416e52a338829f
  Linking ConvertLib to MetaCoin
  Deploying MetaCoin...
  ... 0x8da8a4c881eb9bb62a1477db13044ce84707aac0df54f7ab1baf8b7f0904d251
  MetaCoin: 0x7b9cc3ebba27a1ef8dda0b1825ae47369d647739
Saving successful migration to network...
  ... 0x319cebe2651f0dfbb4adb0a187745a6d47bde22243e4cb32346790ea9abbc5c8
Saving artifacts...
Running migration: 3_deploy_contract.js
  Deploying EncryptedToken...
  ... 0x5e6203aaf1280bac1f991cb3d2858342d9287c0970da8068eeae657b54022cab
  EncryptedToken: 0x16685fb5d7e88293fc1c79a0428f3ab9d2165384
Saving successful migration to network...
  ... 0x713227a22cafea3ff1fa3bd35ff38cb367d9c8dbdc698124053f72020d37bf28
Saving artifacts...
liyuechun:EncryptedToken yuechunli$

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

合约验证

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

liyuechun:EncryptedToken yuechunli$ truffle console
truffle(development)> web3.eth.coinbase
'0x38ae16e70a31ba8679cdcac1cac6ffda7226f2d1'
truffle(development)> web3.eth.accounts[0]
'0x38ae16e70a31ba8679cdcac1cac6ffda7226f2d1'
truffle(development)> web3.eth.accounts[1]
'0xedbbf7b06f3f35fd32ab8157e6cd4ced257451e8'
truffle(development)> web3.eth.accounts[2]
'0xfdb73d8ed20f7e9981264be7639346e57db28698'
truffle(development)> web3.eth.accounts[3]
'0x77f0688b69c236f0fb9264a9daf8ca06952f278f'
truffle(development)> web3.eth.accounts[4]
'0x4f1ed5c8c87fad9c37ab509203026d041e00417b'
truffle(development)> web3.eth.accounts[5]
'0xdead10c6c02ef4121e0d2f63d979daa3b9a692be'
truffle(development)> web3.eth.accounts[6]
'0xf265663d195078f445a08966a660fbffff421d20'
truffle(development)> web3.eth.accounts[7]
'0x1d822a897b9ca697ee03766b3d13a5a0c7235b78'
truffle(development)> web3.eth.accounts[8]
'0xafcc21dc7a09c8e23532aba4c8cc64b1b7831892'
truffle(development)> web3.eth.accounts[9]
'0x4693ab1bc520ac1314e77077645b7ee15f7510ce'
truffle(development)>

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

接下来声明一个合约变量存储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)
Error: VM Exception while processing transaction: invalid opcode
    at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:37295:16)
    at /usr/local/lib/node_modules/truffle/build/cli.bundled.js:224765:36
    at /usr/local/lib/node_modules/truffle/build/cli.bundled.js:208348:9
    at XMLHttpRequest.request.onreadystatechange (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:209773:13)
    at XMLHttpRequestEventTarget.dispatchEvent (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:67130:18)
    at XMLHttpRequest._setReadyState (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:67420:12)
    at XMLHttpRequest._onHttpResponseEnd (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:67575:12)
    at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:67535:24)
    at emitNone (events.js:110:20)
    at IncomingMessage.emit (events.js:207:7)
truffle(development)>

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

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

liyuechun:EncryptedToken yuechunli$ pwd
/Users/liyuechun/Desktop/SmartContractDemo/EncryptedToken
liyuechun:EncryptedToken yuechunli$ ls
build       contracts   migrations  test        truffle.js
liyuechun:EncryptedToken yuechunli$ rm -rf build/
liyuechun:EncryptedToken yuechunli$ ls
contracts   migrations  test        truffle.js
liyuechun:EncryptedToken yuechunli$ truffle compile
Compiling ./contracts/ConvertLib.sol...
Compiling ./contracts/EncryptedToken.sol...
Compiling ./contracts/MetaCoin.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

liyuechun:EncryptedToken yuechunli$ truffle migrate --reset
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0x04c008d8e7008afa1ace7c0dc294eb2e5b02a94960e559811d12187c53b07e56
  Migrations: 0x192929621fd7cf4dd2ac72b42c5f52b40ccfa999
Saving successful migration to network...
  ... 0xd4c65a206e68caab63957343e59282f7a34d92b0f1e1ac99cf77c127d014f958
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying ConvertLib...
  ... 0x4d9e476d05e1b7aea3764c0fd44799ce984d04006435d2959a87b97f62ee2c5a
  ConvertLib: 0xdf7dc01c43772881f21f857f2d689ea591a66a20
  Linking ConvertLib to MetaCoin
  Deploying MetaCoin...
  ... 0xe4ef8fc746d9772a964d8137af4c14eab4c03a7071e1b1b1f27ec963a28558b0
  MetaCoin: 0x685a10d1a8d5196e20a8ae31e0fe80f122e4dd47
Saving successful migration to network...
  ... 0xdd3a300b3f22997540ae019f31f0de4b6b8117cf1dcbc61ed5c2b25bb8011e7c
Saving artifacts...
Running migration: 3_deploy_contract.js
  Deploying EncryptedToken...
  ... 0x08ff437889f6bca7650550491937ed078d09bbbec5a2986146824ba7b7bd0e27
  EncryptedToken: 0xe4de630b2c2818dc18a1ac16935a945634c33a03
Saving successful migration to network...
  ... 0x6eadbc688aca46b34d11696ceca3564ded694dec772412ecf3da4cb6310f7d23
Saving artifacts...
liyuechun:EncryptedToken yuechunli$

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

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

liyuechun:EncryptedToken yuechunli$ truffle console
truffle(development)> let contract
undefined
truffle(development)> EncryptedToken.deployed().then(instance => contract = instance)
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)> contract.transfer(web3.eth.accounts[1], 666)
{ tx: '0x93a38d9c86520cdd5c033511bb67f4aa5230811acf8eb6a703d907d31a4d044d',
  receipt:
   { transactionHash: '0x93a38d9c86520cdd5c033511bb67f4aa5230811acf8eb6a703d907d31a4d044d',
     transactionIndex: 0,
     blockHash: '0xe02e7c9859d43e398bf0ece48e3a15510bb76beefa9bd48ce46a39022ccf5a43',
     blockNumber: 31,
     gasUsed: 48952,
     cumulativeGasUsed: 48952,
     contractAddress: null,
     logs: [] },
  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)>

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

总结

在这篇文章中,只是简单介绍了代币系统的逻辑,并没有对安全进行相关操作,比如:余额不够的处理、地址合不合法的处理等等。当然,通过这篇文章的学习,你再回头看我们初始项目中的MetaCoin代码时,你就应该能看懂了。

打赏地址

比特币:1FcbBw62FHBJKTiLGNoguSwkBdVnJQ9NUn
以太坊:0xF055775eBD516e7419ae486C1d50C682d4170645

技术交流

  • 区块链技术交流QQ群:348924182
  • 「区块链部落」官方公众号

参考资料

时间: 2024-08-31 01:22:05

如何编写智能合约(Smart Contract)?(II)建立加密代币的相关文章

如何编写智能合约(Smart Contract)?(III)建立标准代币部落币「BLC」

在上一篇中,我们我们如何编写智能合约?(II) 建立简易的加密代币,但是它存在很多安全问题,在本章中,我们将一步步带领大家创建一个能够放到以太币钱包的加密代币. 创建项目 有别于之前使用truffle init指令来初始化项目,在Truffle推出Boxes功能之后,我们可以直接套用称作react-box的样板,此样板已经整合create-react-app,可以直接用它来开发react web,省下项目设置的时间. liyuechun:BloggerCoin yuechunli$ pwd /U

手把手教你搭建智能合约测试环境、开发、编译、部署以及如何通过JS调用合约方法

如何编写智能合约(Smart Contract)?(I) 完整视频教程 https://v.qq.com/x/page/h0552ba9k8h.html 学习目标 了解智能合约 简单环境搭建 能够利用solidity编写Hello World合约 合约部署 和合约互动 使用solidity语言撰写智能合约 Ethereum上的智能合约需要使用solidity语言来撰写.虽然还有其他能用来撰写智能合约的语言如Serpent(类Python).lll(类Fortran),但目前看到所有公开的智能合约

【区块链】Truffle 部署 编译 测试 智能合约 的 完整实践操作

Truffle 部署 编译 测试 智能合约 的 完整实践操作 目标 搭建开发环境 创建一个Truffle项目 编写智能合约 编译转移智能合约 测试智能合约 创建用户界面连接智能合约 在浏览器中访问Dapp 搭建开发环境 Node.js v6+ LTS and npm (comes with Node) Git 这里配置脚本略过.... xiaoyu@LIXIAOYUdeMacBook-Pro.com node -v v8.5.0 xiaoyu@LIXIAOYUdeMacBook-Pro.com

智能合约不够安全?微软建专项小组从编程语言入手根治

据外媒报道,微软对外公开其已经成立了一个专门负责提高智能合约安全性的工作小组"Kinakuta",旨在让行业内共享智能合约信息和协议更加简单. 所谓智能合约,是指基于区块链自动执行命令的代码的合约形式.但由于The DAO等安全事件暴露了该技术还处于早期阶段的现状,不少对区块链抱有希望的人们更多的意识到,如果使用不当时是相当危险的. 不过,微软商业发展和战略主管Marley Gray表示,开放共享的信息和革新的工具或将帮助开发者在未来避免类似错误.Gray称,他已经和纽约初创公司Con

『区块链智能合约』从零构建Ethereum智能合约到实战开发

『区块链智能合约』从零构建Ethereum智能合约到实战开发 为什么说现在学习区块链才是最好的时机? 区块链技术不只是能开发数字货币,不只是能进行ICO.当我分享一些区块链文章的时候,偶尔总会有人艾特我说,春哥,现在国家都不让炒币了,还弄个毛的区块链啊.我一般会很平静的告诉他,数字货币只是区块链落地产品类型之一,严格来讲,交易所关闭,国家不让ICO是好事,大家会发现,现在国家禁止ICO后,币圈瞬间清净多了,我觉得是好事,因为现在暴露了很多打着ICO牌子裸泳的人,只有揭开皇帝的新装,区块链技术才能

区块链里所说的“智能合约”是什么?

谈到区块链,必然离不开"智能合约"这个词.我们在本系列的第一篇文章中提到"智能合约"(smart contract)是由多产的跨领域法律学者 Nick Szabo 在1995年提出来的,他的定义为:"一个智能合约是一套以数字形式定义的承诺,包括合约参与方可以在上面执行这些承诺的协议."那么,我们该如何理解这段话呢? 回顾一下比特币区块链系统中的转账: Alice 转账给 Bob 100比特币,在比特币区块链系统中是这样记录的:   本质上,这就是

【区块链】DOCKER部署量子链私有网络环境以及部署智能合约实践

DOCKER部署量子链私有网络环境以及部署智能合约实践 安装环境 安装Docker https://store.docker.com/editions/community/docker-ce-desktop-mac 这里安装的是CE的稳定版 xiaoyu@LIXIAOYUdeMacBook-Pro.com docker version Client: Version: 17.09.0-ce API version: 1.32 Go version: go1.8.3 Git commit: afd

【智能合约】客户端和web端对智能合约的事件Event进行调用的代码示例

客户端和web端对智能合约的事件Event进行调用的代码示例 web truffle 按官网的例子 http://truffleframework.com/boxes/pet-shop truffle作为一个运行测试框架,用的也是web3对智能合约进行调用. 文件所在的位置src/js/app.js initWeb3: function() { // web3入口 if (typeof web3 !== 'undefined') { App.web3Provider = web3.current

两学一做,基于区块链的智能合约技术

书接上文,上回书说到如何快速上手大数据处理框架SMACK,由于其强大的处理性能和复杂的技术架构,洋洋洒洒复制粘贴了近三千字依然难表其貌,更多详情移步原文地址.本节云框架将用"两学一做"思想,帮助大家清晰明了理解「基于区块链的智能合约技术」. 学习区块链的核心思想: 学习区块链应用场景-智能合约: 快速上手实践. 区块链核心思想 先给大家讲一个发生在象牙山这块小区故事,带大家认识认识我们屯里的人.... 特点1 去中心化: 传统谢大脚在记账的时候,刘能经常来捣乱说"谢谢谢大脚,