以太坊Truffle寵物商店開發
阿新 • • 發佈:2021-10-22
以太坊Truffle寵物商店開發
建立專案
- 建立專案目錄並進入
mkdir pet-shop - 使用truffle unbox 建立專案
truffle unbox pet-shop
新增寵物領養合約檔案
- cd contracts
- touch Adoption.sol
pragma solidity ^0.5.0; contract Adoption { address[16] public adopters; // 儲存領養者的地址 // 領養寵物 function adopt(uint petId) public returns (uint) { require(petId >= 0 && petId <= 15); // 確保id在陣列長度內 adopters[petId] = msg.sender; // 儲存呼叫這地址 return petId; } // 返回領養者 function getAdopters() public view returns (address[16] memory) { return adopters; } }
開啟ganache-cli
- 輸入命令:ganache-cli
- 記住12個單詞的助記符,後續需要使用(每次新開啟一個ganache客戶端都會重新初始化助記符)。output parent when east clown cake duck garbage jump spin medal cute
修改配置檔案
- vim truffle-config.js
module.exports = { // See <http://truffleframework.com/docs/advanced/configuration> // for more about customizing your Truffle configuration! networks: { development: { host: "127.0.0.1", port: 8545, // ganache監視的埠 network_id: "*" // Match any network id }, develop: { port: 8545 } } };
編譯部署智慧合約
- truffle console
- truffle compile
- truffle migrate
測試智慧合約
- 在test目錄下新建一個TestAdoption.sol
pragma solidity ^0.5.0; import "truffle/Assert.sol"; // 引入的斷言 import "truffle/DeployedAddresses.sol"; // 用來獲取被測試合約的地址 import "../contracts/Adoption.sol"; // 被測試合約 contract TestAdoption { Adoption adoption = Adoption(DeployedAddresses.Adoption()); // 領養測試用例 function testUserCanAdoptPet() public { uint returnedId = adoption.adopt(8); uint expected = 8; Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded."); } // 寵物所有者測試用例 function testGetAdopterAddressByPetId() public { // 期望領養者的地址就是本合約地址,因為交易是由測試合約發起交易, address expected = address(this); address adopter = adoption.adopters(8); Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded."); } // 測試所有領養者 function testGetAdopterAddressByPetIdInArray() public { // 領養者的地址就是本合約地址 address expected = address(this); address[16] memory adopters = adoption.getAdopters(); Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded."); } }
- truffle test
建立使用者介面和智慧合約互動
- 編輯src/js/目錄下的app.js
App = {
web3Provider: null,
contracts: {},
init: async function() {
// Load pets.
$.getJSON('../pets.json', function(data) {
var petsRow = $('#petsRow');
var petTemplate = $('#petTemplate');
for (i = 0; i < data.length; i ++) {
petTemplate.find('.panel-title').text(data[i].name);
petTemplate.find('img').attr('src', data[i].picture);
petTemplate.find('.pet-breed').text(data[i].breed);
petTemplate.find('.pet-age').text(data[i].age);
petTemplate.find('.pet-location').text(data[i].location);
petTemplate.find('.btn-adopt').attr('data-id', data[i].id);
petsRow.append(petTemplate.html());
}
});
return await App.initWeb3();
},
initWeb3: async function() {
// Modern dapp browsers...
if (window.ethereum) {
App.web3Provider = window.ethereum;
try {
// Request account access
await window.ethereum.enable();
} catch (error) {
// User denied account access...
console.error("User denied account access")
}
}
// Legacy dapp browsers...
else if (window.web3) {
App.web3Provider = window.web3.currentProvider;
}
// If no injected web3 instance is detected, fall back to Ganache
else {
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
}
web3 = new Web3(App.web3Provider);
return App.initContract();
},
initContract: function() {
// 載入Adoption.json,儲存了Adoption的ABI(介面說明)資訊及部署後的網路(地址)資訊,它在編譯合約的時候生成ABI,在部署的時候追加網路資訊
$.getJSON('Adoption.json', function(data) {
// 用Adoption.json資料建立一個可互動的TruffleContract合約例項。
var AdoptionArtifact = data;
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();
},
bindEvents: function() {
$(document).on('click', '.btn-adopt', App.handleAdopt);
},
markAdopted: function() {
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);
});
},
handleAdopt: function(event) {
event.preventDefault();
var petId = parseInt($(event.target).data('id'));
var adoptionInstance;
// 獲取使用者賬號
web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
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);
});
});
}
};
$(function() {
$(window).load(function() {
App.init();
});
});
安裝MetaMask
- 在瀏覽器中安裝MetaMask外掛:chrome外掛
- 使用前面複製的ganache的助記符,配置錢包並設定自定義的密碼
- 預設連線好localhost:8545 rpc
啟動服務
- 開啟lite-server
npm run dev - 瀏覽器訪問:http://localhost:3000/
- 可以執行收養寵物等操作,MetaMask彈出彈窗確定轉賬操作
- 收養成功: