3、宠物商店智能合约实战(truffle智能合约项目实战)
1-宠物商店环境搭建、运行
https://www.trufflesuite.com/boxes/pet-shop
这个还是不行
或者在github下载相对应的项目
直接使用课件源码
执行前修改jQuery及端口等
基本修改已经完成
连接ganache的私有链,再编译部署
先打开ganache
truffle develop
truffle(develop)> compile
truffle(develop)> deploy
Npm run dev
后续对应按钮,一旦领养成功就存到区块链上
所有的客户端都能
唯一要分析的就是App.js
具体的一些逻辑分析没有记录,可以看视频
jQuery的解决方案,需要模板才能
另一个react解决的方案
2-webjs与宠物逻辑实现
实现领养功能,及用户点击领养时,用户与狗狗就建立关系,关系要存到合约并不能被篡改
点击领养按钮可以
谁调用此函数就获得当前调用者的地址,而且地址在合约中是唯一的
领养者的地址可以知道,但宠物如何获取
总共16个宠物,并且获得唯一编号
能否创建一个数组用来存储领养者与宠物的关联信息
领养的合约代码如下
pragma solidity ^0.5.0;
contract Adoption {
// 创建一个固定数组,用来存储领养者与宠物的关联信息
//宠物只能被领养一次,即一个宠物对应一个用户地址
address[16] public adopters; // storage
// 完成宠物领养功能
function adopt(uint petId) public returns (uint){
// 判断当前petId的合法性
require(petId >=0 && petId <=15);
// 存储当前领养人的地址信息
adopters[petId] = msg.sender;
// 返回被领养的petID
return petId;
}
// 返回已领养者的信息 (只读) view 只读 pure 不读写
function getAdopters() public view returns (address[16] memory){
return adopters;
}
}
数组、结构体、映射都是引用类型
数据的存储位置,全局变量默认storyge是部署到合约中的
引用类型的话默认memory并且指定
可以尝试先在remix测试编译,编译成功后再在本地进行编译
类型相同之间赋值是指针间的
类型不同之间赋值是复制有副本的
initWeb3: async function() {
/*
* Replace me...
*/
//如果web3不是undefined,说明上下文有web3对象,直接获取web3.currentProvider链
if(typeof web3 !== 'undefined'){
console.log('if......');
App.web3Provider = web3.currentProvider;
}else{
//如果当前没有,则重新new个web3对象,链接到私有链
console.log('else......');
App.web3Provider = new Web3.providers.HttpProvider('http://127.0.0.1:7545')
web3 = new Web3(App.web3Provider); //创建一个web3对象
}
return App.initContract();
},
Truffle develop
Deploy
未打开ganache,直接部署到开发者模式的私有链
Npm run dev
使用chrome浏览器,无metamask,可以直接运行,看控制台执行到哪里
3-领养智能合约初始化
接着上节课完成合约的初始化
第一步是创建web3对象,完成
合约的初始化,变量已经在前面设置了
写法不是很熟悉,典型的nodejs写法
Nodejs不仅仅是js的运行环境还是升级版
有案例
如果将变量设置为json格式{,后续可以任意的向json变量中添加键和值}(视频有讲解)
web3Provider
保存的公有链或者私有链地址,同一时间只能有一个,默认空
Constracts
为json对象,后续可能有多个合约
此种方式可存储
第二步,初始化合约
上一个代币项目要通过jQuery获取编译好的json格式,然后通过TruffleContract
构建智能合约
获取合约是json文件,将对象data给第一个AdoptionArtifact
Js文件导入到了index.html
中,越在后面的js就可以使用上一个js声明的变量
initContract: function() {
// jquery $.getJSON用来获取json格式的文件
$.getJSON('Adoption.json', function(data) {
// Get the necessary contract artifact file and instantiate it with truffle-contract.
var AdoptionArtifact = data;
// 获取json文件中的合约名词
App.contracts.Adoption = TruffleContract(AdoptionArtifact);
// 配置合约关联的私有链
App.contracts.Adoption.setProvider(App.web3Provider);
// Use our contract to retieve and mark the adopted pets.
return App.markAdopted();
});
console.info('initContract......');
return App.bindEvents();
},
宠物领养有没有初始化的需求,有
如一个账户领养了一个宠物,另一个账户在另一个页面应该看到已有的狗已经被设置成领养状态了
哪些狗被领养了,领养的按钮就使用不了了
//初始化完毕显示当前哪些狗被领养
//标记宠物的领养状态
//实现了领养功能,大量使用了jQuery的功能
// 实现了给页面领养按钮的事件绑定
bindEvents: function() {
// 给页面所有的领养按钮注册了click事件
$(document).on('click', '.btn-adopt', App.handleAdopt);
},
当全部的无钱包模式开发完成的完整运行如下
前面进行cmd的develop开发者模式部署合约等消耗第一个账户钱
我们在chrome浏览器打开,直接点击领养,会成功,内部已经消耗了gas
消耗的是默认的第一个账户
在控制台可以看到,查询余额明显变少了,所以前面的代币转账也是消耗的账户的gas
只是一切在内部发生,没有metamask,无法明显显示,若安装metamask就会是否确认转钱的
4-宠物领养实现
上节完成智能合约json文件加载,并设置私有链信息
又调用了一个领养按钮事件绑定
Class样式,
每个宠物有个adopt
// 实现了给页面领养按钮的事件绑定
bindEvents: function() {
// 给页面所有的领养按钮注册了click事件
$(document).on('click', '.btn-adopt', App.handleAdopt);
},
点击那个按钮就获取那个按钮的对象
Data-id属性很好用
所以html4
Id属性
获取当前单机的按钮的宠物的id
在按钮事件中进行合约的实例化,以此调用合约函数
老版本的api和新版本的api差别很大
handleAdopt: function(event) {
// 获取当前单击按钮对应宠物的id
var petId = parseInt($(event.target).data('id'));
console.info('宠物的ID为:' + petId);
// 此变量用来存储实例化的合约
var adoptionInstance;
// 由于当前采用的是truffle 4.x + web3 0.x的版本,因此选择合适API查看
web3.eth.getAccounts(function(error, accounts) {
// 异步调用:
if (error) {
console.log(error);
}
// 拿到测试的第一个账户
var account = accounts[0];
console.info('account --->' + account);
web3.eth.defaultAccount = account;
// 通过合约名词实例化智能合约, 还可以通过ABI + address进行实例化
App.contracts.Adoption.deployed().then(function(instance) {
// 获取已经实例化的智能合约对象
adoptionInstance = instance;
return adoptionInstance.adopt(petId);
}).then(function(result) {
console.info('result --->' + result);
// 调用标记宠物状态函数
return App.markAdopted();
}).catch(function(err) {
console.log(err.message);
});
});
}
};
领养成功才会标记宠物
注意部署时迁移文件的,判断合约是否全部被部署
在代码中获取了第一个账户的地址,是内部部署的
选择哪个账户部署合约或者调用
在目前没有钱包的时候使用默认第一个账户的,当未指定账户地址就使用
web3.eth.defaultAccount
进行
当点击领养就会调用默认的地址
5-更新宠物领养状态
前面合约实例化和调用合约函数
给宠物设计标记避免重复领养
标记函数的 调用合约函数前对合约实例化
地址总共40个长度
// 标记宠物的领养状态
markAdopted: function(adopters, account) {
console.info('markAdopted......');
var adoptionInstance;
// 1: 根据宠物的状态来修改按钮
App.contracts.Adoption.deployed().then(function(instance) {
// 获取已经实例化的智能合约对象
adoptionInstance = instance;
// 返回 address[16] public adopters;
return adoptionInstance.getAdopters();
}).then(function(adopters) { //adopters = adoptionInstance.getAdopters();
console.log(adopters.length);
for(i=0;i<adopters.length;i++){
// 如果当前宠物被领养则地址不为 address(0x0)
if(adopters[i]!='0x0000000000000000000000000000000000000000'){
// 当前宠物已经被领养,通过jquery设置按钮状态为不可见
$('.panel-pet').eq(i).find('button').text('success').attr('disabled',true);
}
}
}).catch(function(err) {
console.log(err.message);
});
},
如果当前交易量很大,很多交易会迟迟得不到处理
交易执行的函数
当关掉develop时,无法调用合约
当关掉develop重新打开,但未部署时也无法调用合约
新的私有链无智能合约,这个cmd的develop开发者模式既不直观也不能保存之前的结果
我们可以使用ganache可以直观的看到信息
快速打开ganache
E:\乐轻至上\Truffle智能合约项目实战上课代码、资源下载\上课代码、资源下载\pet-shop (命令测试版- 缺省账户领养)\pet-shop>
Truffle develop
Deploy
Npm run dev
两个合约创建,两个构造函数的调用
点击领养按钮
接下来保存我们之前快速启动的私有链
然后关闭再次启动
直接点击workspace中的那个就进入了
可以直接进入之前保存的链上,数据也都在
再次刷新html信息也都在
我们可以保存此私有链,下次再启动就可以选择之前的私有链,一启动页面,之前的领养也有记录
下节课开始安装使用领养钱包