以太坊实践整理(五)DApp开发全过程记录(上)
说明:本篇所涉及的DAPP众筹需求及合约实现来自登链社区通过前面的内容,我们大致了解了如何使用Ganache + Truffle开发智能合约,一个完整的应用还包括用户界面。我们把构建在智能合约之上的应用成为DAPP,即去中心化应用。
DAPP开发 常规互联网应用是前端请求中心化服务器,服务器同步响应数据。DAPP则是前端请求去中心化网络中的任意节点,节点收到交易请求后,广播到整个网络,在网络中达成共识从而完成交易。
【以太坊实践整理(五)DApp开发全过程记录(上)】在DAPP应用中,发送给节点的请求称为“交易”,需要关联钱包进行签名之后才能发送给节点;另外,交易因为需要等待网络共识,所以大多数是异步的,一般通过事件回调获取结果。
前端与智能合约的通信
开发DAPP应用,最重要的两部分就是前端应用及智能合约。智能合约运行在以太坊虚拟机(EVM)上,前端调用智能合约是通过向节点发起请求完成的。前端部分同互联网前端应用一样,可以使用任何自己擅长的前端框架如Vue或React来开发,然后通过web3.js函数库去调用智能合约。以太坊提供了与节点交互的JSON-RPC接口,Web3函数库是JSON-RPC的封装,主流语言都有Web3的实现,JavaScript是web3.js,java是web3j。
众筹项目需求分析 假设我准备协作一本书,但是不确定多少人愿意购买。于是,我发起一个众筹,如果在一个月内,能筹集到10个ETH,就进行写作,并且众筹参与用户每人赠送一本,如果未能筹到足够的资金,用户可以取回投入的资金。同时为了让用户积极参与,设置了一个阶梯价格,初始时,参与众筹的价格非常低(0.02ETH),每筹集满1个ETH时,价格上涨0.002ETH。
从需求可以归纳出合约三个对外的动作(函数):
- 用户汇款进合约,通过实现合约的退回函数来实现;
- 用户赎回汇款,这个函数需要在众筹未达标之后,由用户本人调用生效;
- 发起者提取资金,这个函数需要在众筹达标之后,由发起者调用。
- 记录用户众筹的金额,可以使用一个mapping类型来保存;
- 记录当前众筹的价格,价格可以使用一个mapping类型来保存;
- 记录合约众筹的截止时间,用uint类型来保存截止时间,可以在构造函数中使用当前时间加上30天作为截止时间;
- 记录众筹的受益者,用address类型记录,在构造函数中记录合约创作者;
- 记录当前众筹状态(是否已经关闭),如果众筹达标(创作者提取资金时应及时关闭状态)之后,就需要阻止用户参与。
Vue CLI没安装的先安装:
npm install -g @vue/cli
创建crowdfunding前端工程:
vue create crowdfunding
实现众筹合约 编写智能合约
truffle初始化
cd crowdfunding
truffle init
在contracts下创建Crowdfunding.sol:
pragma solidity >=0.6.0 <0.7.0;
contract Crowdfunding {
// 创作者
address public author;
// 参与金额
mapping(address => uint) public joined;
// 众筹目标
uint constant Target = 10 ether;
// 众筹截止时间
uint public endTime;
// 记录当前众筹价格
uint public price = 0.02 ether;
// 作者提取资金之后,关闭众筹
bool public closed = false;
// 部署合约时调用,初始化作者及众筹结束时间
constructor() public {
author = msg.sender;
endTime = now + 30 days;
}
// 更新价格,这是一个内部函数
function updatePrice() internal {
uint rise = address(this).balance / 1 ether * 0.002 ether;
price = 0.02 ether + rise;
}
// 用户向合约转账时,触发的回调函数
receive() external payable {
require(now < endTime && !closed , "众筹已结束");
require(joined[msg.sender] == 0, "你已经参与过众筹");
require(msg.value >= price, "出价太低了");
joined[msg.sender] = msg.value;
updatePrice();
}
// 作者提取资金
function withdrawFund() external {
require(msg.sender == author, "你不是作者");
require(address(this).balance >= Target, "未达到众筹目标");
closed = true;
msg.sender.transfer(address(this).balance);
}
// 读者赎回资金
function withdraw() external {
require(now > endTime, "还未到众筹结束时间");
require(!closed, "众筹达标, 众筹资金已提取");
require(Target > address(this).balance, "众筹达标,你没法提取资金");
msg.sender.transfer(joined[msg.sender]);
}
}
编译智能合约
truffle compile
部署智能合约
在migrations下创建部署脚本,2_crowfunding.js:
const crowd = artifacts.require("Crowdfunding");
module.exports = function (deployer) {
deployer.deploy(crowd);
};
在truffle-config.js配置要部署的网络,同时确保Ganache已运行,执行智能合约部署:
truffle migrate
众筹前端实现 Vue创建的脚手架工程,默认会有个HelloWorld.vue组件,我们写一个自己的CrowdFund.vue组件,把App.vue中的HelloWorld.vue替换掉。
App.vue修改为:
然后在CrowdFund.vue中完成众筹界面及相应逻辑,界面需要显示以下几个部分:
- 当前众筹到的金额;
- 众筹的截止时间;
- 当前众筹的价格,参与众筹按钮;
- 如果是已经参与,显示其参与的价格以及赎回按钮;
- 如果是创作者,显示一个提取资金的按钮。
新书众筹
以最低的价格获取我的新书 已众筹资金:{{ total }} ETH
众筹已完成
众筹截止时间:{{ endDate }}参与价格
{{ joinPrice }} ETH 当前众筹价格
{{ price }} ETH
继续编写JavaScript逻辑部分,与合约交互需要用到truffle-contract及web3,先安装:
npm install --save truffle-contract web3
CrowdFund.vue修改如下:
到之类,众筹案例就全部完成了。
DAPP运行 在项目目录运行应用:
npm run serve
浏览器地址访问http://localhost:8080即可体验该DAPP:
文章图片
注意要确保MetaMask连接的网络和合约部署的网络一致,这样子DAPP才能通过web3获取到合约数据DAPP发布
npm run build
dist目录下,构建出用户发布的完整前端代码。拷贝到公网服务器对外服务即可。
推荐阅读
- 不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
- 六项精进20180530
- 以太坊中的计量单位及相互转换
- 数据库|SQL行转列方式优化查询性能实践
- 【Day31课后实践】
- 区块链开发平台(以太坊)
- 2021—3—8日教练实践总结&呼吸练习&觉察日记
- 湖州大学生实践团开展系列活动践行生态文明理念
- 来到“社会磨坊”的第二天
- 好的思维需要实践