在本文中,咱们将讨论经过RSK
网络部署和交互Smart-Contracts
智能合约。咱们的合约将是一个基于OpenZeppelin库的ERC20代币,咱们将把它直接部署到Mainnet中。php
咱们须要作的第一件事就是知道如何使用Truffle
。java
当咱们这样作node
$ truffle init
在一个空文件夹中,除了建立配置文件外,咱们还为项目和迁移合约建立了文件夹,以记录对同一合约的更改。python
合约的.sol
代码文件位于android
~/Truffle/contracts
迁移脚本在git
~/Truffle/migrations
已编译的合约在程序员
~/Truffle/build
测试合约在github
~/Truffle/test
咱们如今只处理前两个文件夹。web
在Truffle文件夹中,咱们从OpenZeppelin导入库mongodb
$ npm install -E openzeppelin-solidity
这些库不只会安装咱们代币token的主要类库,还会安装全部权相关,安全数学运算和许多其余设施的库。值得一提的是,这些库已通过审核以实现高标准的安全性,所以依赖于它们的合约在正确使用时不易受到黑客攻击。
咱们的库将安装在
~/Truffle/node_modules/openzeppelin-solidity/contracts
以后,咱们能够将库ABCD.sol
导入到咱们的合约中,以下所示:
import 'zeppelin-solidity/contracts/token/ERC20/ABCD.sol';
要建立咱们的ERC20代币,咱们将从该存储库导入2个库:StandardToken.sol
,它具备代币的主要功能,而且已经更多地导入了一堆库,例如SafeMath.sol
;Ownable.sol
,这些容许咱们设置全部者对合约中的功能控制。
要继承库属性和函数,咱们只需使用“is”关键字以这种方式将合约定义为StandardToken
和Ownable
:
contract CoinFabrikToken is StandardToken, Ownable { }
以后,咱们拥有这些库和导入库中的全部功能。
接下来,咱们将代币的名称定义为CoinFabrik
,这是它的符号,18个小数位,用于代币的精度(以太坊类网络中的标准,使咱们有可能使用web3的以太转换功能)并将代币的初始供应量设置为1000,像这样:
string public name = 'CoinFabrik'; string public symbol = 'CF'; uint8 public decimals = 18; uint public INITIAL_SUPPLY = 1000;
咱们还将建立另外一个字符串,一个与代币功能无关的非公共变量,以显示Ownable
库属性的用法,该属性仅容许建立者与某些指定的函数进行交互。咱们稍后会看到。
已经定义了咱们的参数,如今是时候经过构造函数将它们分配给Token变量了。到目前为止,构造函数被定义为一个与智能合约同名的函数,可是从如今开始,将会有一个名为constructor()
的函数,它将替换旧方法。若是你像之前同样调用构造函数,Solidity编译器将发出警告。
INITIAL_SUPPLY
乘以小数精度的次方将分配给BasicToken
合约的totalSupply_
:
totalSupply_ = INITIAL_SUPPLY * (10**uint(decimals));
并将它们存入创做者的账户:
balancesb [msg.sender] = totalSupply_;
有了这个,咱们就可使用一个简单而标准的代币,但正如咱们所说,咱们将使用Ownable
合约添加一些功能。首先,咱们将定义一些函数:一个修改咱们的非公共变量的状态,但只有你拥有权限,而另外一个函数返回字符串的消息。定义以下:
function setON(string _n) public onlyOwner returns (bool) { Owner = _n; return true; } function getON() public view returns (string) { return Owner; }
二者都是公开的,因此任何人均可以尝试调用他们,但对于第一个,只有全部者的地址不会致使恢复。若是你是全部者而且调用了函数,则字符串将保存在咱们的变量Owner
(带有大写字母)中,而且它还将返回一个咱们能够在交易中检查的true值。
因为Owner
变量不是公共的而且没有Getter,咱们须要一个函数来返回变量的值而不改变区块链的状态。这是第二个功能。
咱们还将建立一个回调函数,若是有人错误地调用咱们的合约,则会发出事件:
function () public payable { if (msg.value > 0) { emit Yes('Thanks for donating SBTC! :)'); } else { emit No('Error 404: Function not found :P'); } }
最后,咱们在合约中添加了一个可销毁的功能,其中全部者是惟一能够执行它的人。
咱们的简单代币已经完成。全部代码应该是同样的:
pragma solidity ^0.4.17; import 'zeppelin-solidity/contracts/token/ERC20/StandardToken.sol'; import "zeppelin-solidity/contracts/ownership/Ownable.sol"; contract CoinFabrikToken is StandardToken, Ownable { string public name = 'CoinFabrik'; string public symbol = 'CF'; uint8 public decimals = 18; uint public INITIAL_SUPPLY = 1000; string Owner; event Yes(string); event No(string); constructor() public { totalSupply_ = INITIAL_SUPPLY * (10**uint(decimals)); balances[msg.sender] = totalSupply_; } function setON(string _n) public onlyOwner returns (bool) { Owner = _n; return true; } function getON() public view returns (string) { return Owner; } function () public payable { if (msg.value > 0) { emit Yes('Thanks for donating SBTC! :)'); } else { emit No('Error 404: Function not found :P'); } } function destroy() public onlyOwner { selfdestruct(owner); } }
对于每一个合约,咱们须要告诉Truffle哪一个合约是咱们想要部署的合约以及咱们能够在哪里找到合约。这是经过/Truffle/migrations
文件夹中的迁移文件完成的。
迁移脚本02_deploy_token.js
应以下所示
var CoinFabrikToken = artifacts.require("./CoinFabrikToken.sol"); module.exports = function(deployer) { deployer.deploy(CoinFabrikToken); };
咱们已配置Truffle,咱们的节点已同步,咱们的合约已经编写而且咱们的迁移已配置,完成部署就是个时间问题。
若是咱们以前中止了咱们的节点,咱们将恢复在线状态,而后咱们将与Truffle链接:
$ sudo service rsk start $ cd ~/Truffle/ && truffle console --network rsk
以后编译合约:
truffle(rsk)> compile --all
不该该对咱们的合约有任何错误或警告。而后咱们转移合约:
truffle(rsk)> migrate --reset
为了节约时间,咱们能够在一行中执行两个命令
truffle(rsk)> migrate --all --reset
将首先部署迁移合约。Truffle为咱们提供了每一个操做的交易哈希,所以咱们能够稍后检查详细信息或日志。这是我收到的完整输出
truffle(rsk)> migrate --all --reset Compiling ./contracts/CoinFabrikToken.sol... Compiling ./contracts/Migrations.sol... Compiling zeppelin-solidity/contracts/math/SafeMath.sol... Compiling zeppelin-solidity/contracts/ownership/Ownable.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 Using network 'rsk'. Running migration: 1_initial_migration.js Deploying Migrations... ... 0xf00d4ecf2b5752022384f7609fe991aa72dda00a0167a974e8c69864844ae270 Migrations: 0x1dc2550023bc8858a7e5521292356a3d42cdcbe9 Saving successful migration to network... ... 0x3e759e8ff8a7b8e47a441481fa5573ccf502b83f3d591ad3047e622af0f9169e Saving artifacts... Running migration: 2_deploy_token.js Deploying CoinFabrikToken... ... 0x300c8bb1e434e2aa4b13dcc76087d42fcbe0cb953989ca53a336c59298716433 CoinFabrikToken: 0xc341678c01bcffa4f7362b2fceb23fbfd33373ea Saving successful migration to network... ... 0x71771f7ee5d4e251e386979122bdda8728fa519d95a054572751bb10d40eb8c5 Saving artifacts...
若是咱们检查交易,咱们能够计算全部部署过程的gas成本。在我这里的状况,它是2340788gas(277462+42008+1994310+27008)。
所以将其更改成真实的SBTC,咱们获得2340788*183000000/10^18=0,000428364 SBTC。在撰写本文时,这大约是4美圆左右。
咱们的合约如今部署在0xc341678c01bcffa4f7362b2fceb23fbfd33373ea。
恭喜!
经过Truffle迁移给出的地址,以及合约的ABI,咱们建立了一个实例,所以简化语法更容易处理函数。为此,在咱们部署以后,咱们写了
truffle(rsk)> var cfToken = web3.eth.contract(CoinFabrikToken.abi).at(CoinFabrikToken.address)
若是合约已经部署,而且知道它的地址和ABI,咱们就能够作到
truffle(rsk)> var cfToken = web3.eth.contract(‘Contract_ABI’).at(‘Contract_ADDRESS’)
其中Contract_ABI
是简化为一行ABI,Contract_ADDRESS
不须要解释。
我以前建立了2个账户,如今为方便起见,咱们将它们重命名:
truffle(rsk)> var acc0 = web3.eth.accounts[0] truffle(rsk)> var acc1 = web3.eth.accounts[1]
acc0
是部署合约的人。Acc0
被添加到truffle.js
和node.conf
配置文件中。
咱们将首先使用咱们讨论过的库来测试合约的全部权功能。
若是咱们从任何账户调用getON
函数,只要它是公开的而且没有任何全部权问题,咱们就会获得:
truffle(rsk)> cfToken.getON() ''
如今,setON函数具备全部权属性。任何来自其余账户的交易都将被驳回。例如,咱们看到,试图用个人名字从acc1
签定合约不会改变它的价值。
truffle(rsk)> cfToken.setON('Andres Bachfischer', {from: acc1}) 0x5f115190b60238240bedf36d1c5bb69a443a0f8ee971b0fc40fe5ca9c727d47c
使用交易的哈希,咱们看到返回的值为false,而且函数未正确执行。再次调用getON函数,咱们看到变量没有改变它的值。
如今签署相同的交易可是从全部者的账户acc0,咱们获得状态'0x01'而且该功能正确执行。
truffle(rsk)> cfToken.setON('Andres Bachfischer', {from: acc0}) 0x0c894fa7e5369573fb14addeaed4cd9d5b6cd1425cb4eeeae16cb4e1fa8e0364
再次调用函数getON
,咱们看到全部权库按照咱们但愿的那样工做。
truffle(rsk)> cfToken.getON()
Ownable.sol
还具备容许咱们将合约全部者更改成其余地址的功能。咱们不会用它。然而,它的用法以下:
truffle(rsk)> cfToken.transferOwnership(acc1, {from: acc0})
有了这个,acc1将成为合约的新全部者。
让咱们转到代币。
咱们要作的第一件事是检查在建立合约时是否正确分配了代币的余额。
咱们检查每一个账户的余额以下:
web3.fromWei(cfToken.balanceOf(acc0).toString(10)) // = ‘1000’ web3.fromWei(cfToken.balanceOf(acc1).toString(10)) // = ‘0’
所以,咱们能够看到全部代币都已正确分配到咱们的初始账户。
咱们要作的第一笔交易是将一些代币转移到第二个账户acc1
,进行三次。
为第一笔交易这样作:
truffle(rsk)> cfToken.transfer(acc1, web3.toWei(88.8), {from: acc0}) 0xd45437b777f1430e7cec57bd80b261ce8f87bf8a3f9a113fecd20563403c4d9c
truffle(rsk)> web3.fromWei(cfToken.balanceOf(acc0).toString(10)) // = '733.6' truffle(rsk)> web3.fromWei(cfToken.balanceOf(acc1).toString(10)) // = '266.4'
咱们看到从咱们的部署账户中获取的代币与在acc1中收到的代币数量相同。
使用StandardToken
合约,咱们还得到了表明某个账户(在本例中为acc1)支出代币的权限。若是咱们想在得到批准以前执行此操做,则交易将失败(状态为“0x00”)
truffle(rsk)> cfToken.transferFrom(acc1, acc0, web3.toWei(5), {from: acc0}) 0x5cee7cf60849283a0088d71483a606ba2101b500e13f972abada4f75781596bf
检查后,acc0
不容许从acc1
发送:
truffle(rsk)> web3.fromWei(cfToken.allowance(acc1, acc0, {from: acc0}).toString(10)) // = '0'
咱们受权acc0
从acc1
的交易中以acc1
的名义花费10个代币:
truffle(rsk)> cfToken.approve(acc0, web3.toWei(10), {from: acc1}) 0x6e1a202f4ca7f43dfb28034952d54a572993b986a55857790aa51854afbc1fb4
在输出日志中,咱们看到函数已成功完成,而且日志显示容许acc0
用于支出的金额。检查allowance:
truffle(rsk)> web3.fromWei(cfToken.allowance(acc1, acc0, {from: acc0}).toString(10)) // = '10'
如今,若是咱们再次执行支出交易:
truffle(rsk)> cfToken.transferFrom(acc1, acc0, web3.toWei(5), {from: acc0}) 0x41f750eabb6e0d3ab576aac0333b0d337ca61808aae1eeafa9d8e2a0b81b979b
咱们获得状态为“0x01”的成功交易。
再检查一下余额:
truffle(rsk)> web3.fromWei(cfToken.balanceOf(acc0).toString(10)) // = '738.6' truffle(rsk)> web3.fromWei(cfToken.balanceOf(acc1).toString(10)) // = '261.4'
最后,若是咱们签署一个调用不可用函数的事务,咱们将调用咱们的回退函数。 签署一个像这样的交易:
truffle(rsk)> web3.eth.sendTransaction({from: acc0, to: cfToken.address}) 0x4106a287fc60669bf9682a73ec4c457b094c086ec7408a5dea95d200688c4ee9
将返回一个日志,其数据表示字符串Error 404:Function not found:P
(十六进制:'0x00 ... 00204572726f72203430343a2046756e6374696f6e206e6f7420666f756e64203a50'
)。
咱们的最后一个功能,即咱们不会由于显而易见的缘由而执行,就是销毁功能。咱们须要合约不被销毁才能显示交易。要调用,全部者应该这样作:
truffle(rsk)> cfToken.destroy({from: acc0})
在演练的第二部分中,我展现了在RSK网络中开发简单智能合约的示例。 咱们已经看过:
正如咱们所看到的,RSK网络用于Solidity Smart Contracts部署和交互的用法几乎与以太坊节点中的相同。固然,这仍然是一个测试网络,预计会出现问题和错误,主要是在节点中,但RSK Labs团队在他们出现时尽量快地解决它们。随着时间的推移,将实现稳健性。
======================================================================
分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:
- java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
- python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
- php以太坊,主要是介绍使用php进行智能合约开发交互,进行帐号建立、交易、转帐、代币开发以及过滤器和交易等内容。
- 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
- 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
- C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括帐户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
- EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、帐户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
- java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如建立地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
- php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如建立地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
- tendermint区块链开发详解,本课程适合但愿使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。
汇智网原创翻译,转载请标明出处。这里是原文使用OpenZeppelin在RSK上进行ERC20代币开发