以太坊开发之搭建宠物商店
查看更多文章: https://alili.tech
truffle的宠物商店是一个了解以太坊开发的一个很不错的例子.
跟着官方提供的demo与教程,可以完整的感受一下整个流程的开发.
Ganache
为了环境需要,并且快速的在本地搭建一个私有链环境.
truffle推出了一个可视化私有链客户端:
Ganache下载地址
下载之后运行,你会看到这样一个界面:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ueP8hSnx-1600174507424)(https://static.alili.tech/images/Jietu20180421-213717.jpg)]
初始化你的项目
首先我们新建一个目录,并且初始化一下项目
$ mkdir pet-shop
$ cd pet-shop
$ truffle unbox pet-shop
项目目录结构
这里只列出了重要的目录与文件
├── bs-config.json
├── contracts //合约目录
│ └── Migrations.sol //合约文件
├── migrations // 部署脚本
│ └── 1_initial_migration.js
├── package-lock.json
├── package.json
├── src // 前端代码目录
├── test // 测试代码目录
└── truffle.js // truffle配置文件
编写智能合约
在contracts/目录中,创建一个Adoption.sol文件
文件内容:
pragma solidity ^0.4.17;
contract Adoption {
address[16] public adopters; // 声明一个地址变量,用于保存领养者地址
// 领养宠物
function adopt(uint petId) public returns (uint) {
require(petId >= 0 && petId <= 15); // 确保宠物id正确,为0到15之间,
// 如果不符合条件就会回滚
//msg.sender 为调用这个函数的人的地址
adopters[petId] = msg.sender; // 保存调用这地址
return petId;
}
// 返回领养者
function getAdopters() public view returns (address[16]) {
return adopters;
}
}
编译你的智能合约
$ truffle compile
//输出
Compiling ./contracts/Adoption.sol...
Writing artifacts to ./build/contracts
这样你就会发现你的项目多了一个build文件夹,
里面存放这里刚刚写好的智能合约编译完成的json文件
部署你的智能合约
你的智能合约写好了,你可以暂且理解为你的后台代码写好了.要部署起来便于前端调用.
在你的migrations/
目录新建一个部署脚本:2_deploy_contracts.js
var Adoption = artifacts.require("Adoption");
module.exports = function(deployer) {
deployer.deploy(Adoption);
};
打开刚刚下载的Ganache, Ganache会启动一个私有链.
我们的智能合约就是要部署在这个私有链上.
确认项目录根目录的truffle.js
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545, //确保端口地址,是否与私有链地址一致,如果不一致请保持一致
network_id: "*" // Match any network id
}
}
};
执行以下命令,部署合约:
truffle migrate
# 输出
Using network \'develop\'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0x3076b7dac65afc44ec51508bf6f2b6894f833f0f9560ecad2d6d41ed98a4679f
Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying Adoption...
... 0x2c6ab4471c225b5473f2079ee42ca1356007e51d5bb57eb80bfeb406acc35cd4
Adoption: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...
重新打开Ganache,你会发现区块链的状态发生了变化,多了4个区块.
OK,部署完毕
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EryPlo7E-1600174507428)(https://learnblockchain.cn/images/ganache-migrated.png)]
前端与智能合约的交互
好,智能合约我们已经部署好了.接下来我们就要开始我们的javascript部分了
打开 src/js/app.js
初始化web3
web3是一个前端与以太坊通信的库,所有调用智能合约的操作,我们基于web3来实现.
我们在app.js里找到initWeb3方法,为其添加以下代码:
initWeb3: function() {
// 判断是否有全局web3对象,一般装了MetaMask这种钱包就会有全局的web3对象
if (typeof web3 !== \'undefined\') {
// 如果有,就直接使用
App.web3Provider = web3.currentProvider;
} else {
// 如果没有全局的web3对象,就直接在本地初始化一个
App.web3Provider = new Web3.providers.HttpProvider(\'http://localhost:7545\');
}
web3 = new Web3(App.web3Provider);
return App.initContract();
}
实例化智能合约
找到initContract方法部分,添加以下代码:
initContract: function() {
//加载我们的之前写好的智能合约
$.getJSON(\'Adoption.json\', function(data) {
// 用Adoption.json数据创建一个可交互的TruffleContract合约实例。
var AdoptionArtifact = data;
//TruffleContract 为该项目的全局方法,使用的是 truffle-contract这个库
//如果在其他项目,你可以直接npm i truffle-contract --save 来安装这个库
//用于实例化合约
App.contracts.Adoption = TruffleContract(AdoptionArtifact);
// Set the provider for our contract
App.contracts.Adoption.setProvider(App.web3Provider);
// Use our contract to retrieve and mark the adopted pets
return App.markAdopted();
});
return App.bindEvents();
}
领养部分
handleAdopt方法部分,添加以下代码:
handleAdopt: function(event) {
event.preventDefault();
//dom里获取到宠物的id
var petId = parseInt($(event.target).data(\'id\'));
var adoptionInstance;
// 获取用户账号
web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
//获取用户,如果装了钱包只会返回长度只有1的数组,如果没有装钱包,会返回所有用户的地址
var account = accounts[0];
//调用智能合约
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
// 发送交易领养宠物
return adoptionInstance.adopt(petId, {from: account});
}).then(function(result) {
return App.markAdopted();
}).catch(function(err) {
console.log(err.message);
});
});
}
找到 markAdopted方法,添加以下代码:
markAdopted: function(adopters, account) {
var adoptionInstance;
//调用合约的方法
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
// 调用合约的getAdopters(), 用call读取信息不用消耗gas
return adoptionInstance.getAdopters.call();
}).then(function(adopters) {
for (i = 0; i < adopters.length; i++) {
if (adopters[i] !== \'0x0000000000000000000000000000000000000000\') {
$(\'.panel-pet\').eq(i).find(\'button\').text(\'Success\').attr(\'disabled\', true);
}
}
}).catch(function(err) {
console.log(err.message);
});
}
启动服务
好了,所有代码我们都已经填充完毕,启动我们的项目,开始领养你喜欢的宠物吧
$ npm run dev