超详细 DApp搭建全流程 | 发行代币 | 宠物领养

超详细 DApp搭建全流程 | 发行代币 | 宠物领养

全文字1.5w+,图n+,预计n分钟,建议先码住啦~

先验知识

官网的中文手册 truffle / solidity / web3js 及 官网box的代码 是最好的学习方式关于 solidity:它是一门编程语言,可实现分布式数据库/账本,但是不能直接与前端交互,故需要web3做桥梁 关于 truffle: 它对solidity实现了封装,可以实现环境开发、部署、测试等;它是一个web框架,使用JavaScript编写关于web3:它提供了智能合约实例化,和合约调用的工程(RPC 远程过程调用);它有js版、python版等各种语言编写版本,多用webjs一定要建立起truffle、solidity、web3js的宏观概念,对项目组成部分有大致了解

环境配置

truffle

① 安装 nodejs(js运行时环境)并配置PATH环境变量,nodejs默认安装npm(npm是js的包管理工具,类似python中pip)

② 安装 cnpm(国内镜像,比npm命令快;也默认装到nodejs下):

npm install cnpm -g –registry=https://registry.npmmirror.com

③ 全局 (-g)安装 `truffle` 框架(truffle默认安装webjs):

npm install -g truffle

④ 执行truffle命令时,要 以管理员身份打开控制台(不易报错)

truffle命令:

truffle init 创建空工程 truffle compile 编译sol文件生成abi文件(调用contract的使用手册) truffle develop 搭建本地以太坊测试网络(提供10个账户和密钥) truffle deploy / truffle migrate 部署 (–reset从头迁移部署)

一般命令的执行顺序为:

truffle develop -> compile -> deploy / migrate [–reset]

ps:如果不compile,部署时会自动编译

关于部署:

① 部署前需要改下truffle-config

truffle-config中一般改这俩部分即可:

代码里有个坑,开发者环境是develop,而不是development,要改成develop,

否则最直观的一个显示就是develop端口和项目端口不同

② 必须有网络才能部署,即在develop开发者环境下,而develop提供的网络可以直接命令行显示,也可以连上Ganache可视化,这需要在项目config文件中改端口为Ganache的端口7545即可

③ 迁移脚本(migrations/1_initial_migration.js等js文件)暂存部署任务,帮助将合约部署到以太坊网络

④ truffle要求初始化的迁移脚本 migrations/1_initial_migration.js不可删除,且按文件名打头数字顺序部署,如先部署1_xxx.js,再部署2_xxx.js,再部署3_xxx.js

web3js

安装truffle时会自动安装web3

web3js常用命令 | 详细见 中文手册

web3.eth.getAccounts() 返回账户列表 web3.eth.getBalance() 返回帐号曰 web3.eth.defaultAccount() 设置默认账户 web3.eth.sendTransaction ({from: },{to: },{value: }) 向网络提交交易 web3.utils.toWei (1,ether) 位和以太币相互转换(1 ether = 2……18 wei) web3.utils.fromWei (200000000000000000,ether)

ps:注意是函数还是属性,是否需要带括号

官网的中英文手册是最好的学习资料,建议查阅

Ganache

模拟区块链除了使用develop命令,还可以使用 Ganache (更直观地看账号与交易)

根据操作系统下载安装包,如我下windows的如下,建议下载exe版本,下载appex版本操作起来很麻烦

ps: 想连Ganache时,先打开Ganache,再进入develop开发者模式,否则Ganache会报错7545端口已被占用,要求修改端口

Atom

官方推荐的编辑器是Atom,下载插件(File -> settings -> install)language-ethereum和autocomplete-solidity,作用分别是高亮和补全

Atom中内置控制台、debug等好像需要下载插件,我没下载成功,就直接使用cmd控制台了,不知道其内置的能不能用

案例1 | 代币token发行

tutorialtoken

下载官方写好的代币框架

truffle unbox tutorialtoken

进入开发者模式

truffle develop

会出现这个问题,是因为官方有个bug,需要把config.js改成truffle-config.js

顺便把package.json (配置文件)中 “main”: “truffle-config.js”也改掉

可以不compile而直接migrate

compile migrate

提供一个本地的服务器端口(默认3000)(浏览器页面)

该语句需要在develop开发者模式外

npm run dev

port可以在bs-config.js中更改:

可以在控制台 以管理员身份 查看所使用端口占用情况:

netstat -ab

jQuery

index.html中引入的jQuery是google站点的,自己本地下一个

<script src=”https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js”></script>

jquery1和2有较大区别,遂下1就OK

下载到 src\js 目录下(所有js文件都抛到这)

则语句可修改为

<script src=”js/jquery.min.js”></script>

项目架构

项目架构(部分):

├─build

│ └─contracts

├─contracts

├─migrations

├─node_modules:依赖包

├─src

│ ├─css :组件美化(不必动)

│ ├─fonts :字体、图标(不必动)

│ ├─index.html:用户展示页面(编辑)

│ └─js

│ ├─app.js:后续编写业务逻辑的js文件(编辑)

│ ├─truffle-contract.js:truffle框架(不用动)

│ └─web3.min.js:web3(不用动)

├─test

├─truffle-config.js

├─package.json:重要配置文件

├─bs-config.json:重要配置文件(server有关)

分析app.js文件,发现其缺少部分待补充的定义如下:

① 缺少一个TutorialToken.sol文件

② 缺少一个transfer()函数

③ 缺少一个balanceOf()函数

openzeppelin

使用cnpm命令为项目局部安装

cnpm install openzeppelin-solidity@2.5.1

ps:这里安装必须制定版本,否则现在默认安装版本是3,3版本框架使用的solidity版本是0.8.0,常用一般0.5.0写,会不兼容,编译报错

在Contract目录下创建TutorialToken.sol文件,文件内容如下:

pragma solidity >=0.4.22 <0.9.0; import “openzeppelin-solidity/contracts/token/ERC20/ERC20.sol”; //发行代币的协议 contract TutorialToken is ERC20{ //ERC20中有transfer函数和getBalanceof函数的定义,继承ERC20后不需重写 string public name = “TutorialToken”; string public symbol = “TT”;//代币符号 uint8 public decimals = 2;//代币精度 //发行代币的总量 uint public INITIAL_SUPPLY = 12000; //构造函数 constructor() public{ _mint(msg.sender,INITIAL_SUPPLY); } }

在migration下创建2_xxx.js文件,内容如下:

var Migrations = artifacts.require(“TutorialToken”); module.exports = function(deployer) { deployer.deploy(TutorialToken); };

truffle-config中端口号改掉(以便接下来连接Ganache):

develop: { host: “127.0.0.1”, // Localhost (default: none) port: 7545, // Standard Ethereum port (default: none) network_id: “*”, // Any network (default: none) },

执行命令:

truffle develop migrate –reset npm run dev

浏览器显示如下:

发现Balance余额没显示,检查控制台,发现其报错”web3 is not defined”、

这是个官方的bug,错误在app.js中,如果从else语句进入,没有对web3的定义,则底下就没发调用,加上红框中这一句:

OK,balance正常显示了

ps:还有一种balance不显示的原因是开了metamask插件,关上就好了

界面显示有问题,说到底就是合约交互的问题,有意识地往这方面思考就ok了

在Ganache中找个账户转账后:

对于页面交互的显示,要擅用控制台检查功能,

可以在js文件中添加一些console.log()等语句辅助检查

案例2 | 宠物领养

truffle unbox pet-shop

ps:如果unbox命令失败,可使用git下载

参照token案例,改下jquery、端口等

truffle develop compile deploy npm run dev

但是框架只能显示页面,不能实现领养功能,也不能与网页交互,因为box没写业务逻辑,需要自行填充

contracts下建立Adoptation.sol:

pragma solidity >=0.4.22 <0.8.0; contract Adoption{ address[16] public adopters; function adopt(uint petId) public returns (uint){ require(petId<=15 && petId>=0); adopters[petId] = msg.sender;//记录领养者地址 return petId; } /*此处该数组若未声明为memory变量会报错 因为memory表示值变量,即只是复制副本;而默认为storage是引用变量,所有的引用都实际只想一处 如果这里是storage变量,则外部可以修改该变量,这显然不符合区块链的安全性原则 view只读 pure不读写 */ function getAdopters() public view returns (address[16] memory){ return adopters; } }

有返回值的函数一定要定义为view / pure 格式,这里涉及到区块链中关于读和写的操作,补充一下:

因为以太坊修改数据的手续费很高,所以数据分为严格的读和写。读取数据为调用(call),写入数据为交易(transaction),二者区别很大。

交易会改变网络状态,消耗Gas费用,需要较长的响应时间处理。所以在执行合约的函数时,无法及时获得该函数的返回值,仅仅可以获得一个交易ID。

call不改变网络状态,免费,立刻执行,有返回值。

这里如果不加pure在app.js中调用该函数时会出现错误

migration下写迁移文件2_adoption.js:

var Adoption = artifacts.require(“Adoption”); module.exports = function(deployer){ deployer.deploy(Adoption); };

补全app.js中初始web3部分内容:

initWeb3: async function() { if(typeof web3 ==! undefined){//如果有MetaMask(连接公有链/私有链/主网),则已有web3 console.log(if); App.web3Provider = new web3.currentProvider; }else{ console.log(else); App.web3Provider = new Web3.providers.HttpProvider(http://127.0.0.1:7545); web3 = new Web3(App.web3Provider); } return App.initContract(); },

补全app.js中初始化合约的内容:

initContract: function() { /*合约初始化逻辑: 获取json文件 -> 解析json数据 -> 初始化web3 -> 初始化合约界面 */ $.getJSON(Adoption.json, function(data) { var AdoptionArtifact = data; App.contracts.Adoption = TruffleContract(AdoptionArtifact);//解析json数据 App.contracts.Adoption.setProvider(App.web3Provider); //初始化,其他人浏览页面时应显示有哪些已经被领养了,不能再被领养了 return App.markAdopted(); }); return App.bindEvents(); },

补全app.js中宠物领养状态显示功能(相当于代币项目中浏览页面balance功能):

markAdopted: function(adopters, account) { console.log(“markAdopted”); var adoptionInstance; App.contracts.Adoption.deployed().then(function(Instance){ adoptionInstance = Instance; return adoptionInstance.getAdopters(); }).then(function(adopters){ console.log(adopters.length); for(i=0;i<adopters.length;i++){ //如果当前宠物领养地址不为 空(0x0) if(adopters[i] != 0x0000000000000000000000000000000000000000) //0x (40个0) { //当前宠物已被领养,通过jQuery设置按钮状态为不可见 $(.panel-pet).eq(i).find(button).text(adopted).attr(disabled,true); //eq(i) 获取第i个div } } }).catch(function(err){ console.log(err.message); }); },

补全app.js中宠物领养功能:

handleAdopt: function(event) { // 获取当前单击按钮对应宠物的id var petId = parseInt($(event.target).data(id)); console.info(宠物的ID为: + petId); // 此变量用来存储实例化的合约 var adoptionInstance; web3.eth.getAccounts(function(error, accounts) { // 异步调用: if (error) { console.log(error); } // 拿到测试的第一个账户 var account = accounts[0]; console.info(account —> + account); web3.eth.defaultAccount = account; // 由于当前采用的是truffle 4.x + web3 0.x的版本,因此选择合适API查看 App.contracts.Adoption.deployed().then(function(instance) { // 获取已经实例化的智能合约对象 adoptionInstance = instance; return adoptionInstance.adopt(petId); }).then(function(result) { console.info(result %o, result); // 调用标记宠物状态函数 return App.markAdopted(); }).catch(function(err) { console.log(err.message); }); }); } };

老一套

truffle develop migrate npm run dev

公网部署

不同测试网络大致相同,无非是共识机制和挖矿算法的不同

测试网络为测试使用,其测试币没有太大价值,挖矿也更容易

首先get一些测试币:

如果从水管获取测试币失败,即显示下面红色的字,可以从 这个网址 获取

记得先

当将自己的dapp连到测试网络时,面多众多有自己规则的测试网络,如果都遵循它们的规则来写会很麻烦,所以有了一个中间平台——infura的诞生,它可以使得dapp快速接入以太坊平台。

infura就像我们和银行之间要经过支付宝一样,每个银行的页面、按钮位置啥都不同,但是我们只要熟悉支付宝,就可以通过支付宝与各个银行进行交易。infura在公网和私有链之间充当的就是支付宝的作用。

infura免费,且还可以方便地接入IPFS。

IPFS:分布式存储系统,适合存储多媒体等

进入 官网 后无脑注册一下,创建一个项目:

获得ID:

测试下infura能用不:

truffle develop web3.setProvider(https://ropsten.infura.io/v3/yourID) web3.currentProvider web3.eth.getBalance(acountAdress)

修改下配置文件truffle-config.js:

const HDWalletProvider = require(@truffle/hdwallet-provider); //取消注释 const memonic = “你的记词助”; //取消注释 ropsten: { provider: () => new HDWalletProvider(memonic, https://ropsten.infura.io/v3/你的infrualID), network_id: 3, // Ropstens id gas: 5500000, // Ropsten has a lower block limit than mainnet confirmations: 2, // # of confs to wait between deployments. (default: 0) timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) },

node-gyp:

node中需要调用其它语言编写的一些程序,甚至windows的动态链接库dll

如果下载的是编译后的程序,则移植性不好,如在linux下编译的程序在windows下就用不了了,

所以下载原码,再用node中自带的node-gyp编译一下,生成c++模块,嵌入程序中

一般新版nodejs里都自带了,如果没有自己下一下:

install -g node-gyp

在项目路径下安装:

cnpm install @truffle/hdwallet-provider truffle develop deploy –reset –network ropsten

如果部署一直timeout,这里面有非常多解决方法

对我有效的是:将 https://ropsten.infura.io/v3/ 改成 wss://http://ropsten.infura.io/ws/v3/

npm run dev

收官!!

你真棒,看到这里啦~

区块链系列文章,见同名CSDN (111辄),懒得搬运啦嘿嘿

区块链DApp从零开始学 (一) | DApp抓包

区块链DApp从零开始学 (二) | 超详细 DApp创建 | 发行代币token |宠物领养

区块链报错1 | npm run dev 无法解析json格式 | npm ERR JSON.parse Failed to parse json

区块链报错2 | 区块链npm run dev失败lite-server

区块链报错3 | truffle unbox 报错 | downloading失败 | unbox failed

区块链报错4 | 区块链玄学 | truffle unbox下载downloading步骤失败

区块链报错5 | Contract has not been deployed to detect network (network/artifact mismatch)

区块链报错6 | Failed to load resource: the server responded with a status of 404 (Not Found)

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Proudly powered by WordPress | Theme: HoneyWaves by SpiceThemes