1. 程式人生 > 其它 >以太坊Truffle寵物商店開發

以太坊Truffle寵物商店開發

以太坊Truffle寵物商店開發

建立專案

  1. 建立專案目錄並進入
    mkdir pet-shop
  2. 使用truffle unbox 建立專案
    truffle unbox pet-shop

新增寵物領養合約檔案

  1. cd contracts
  2. 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

  1. 輸入命令:ganache-cli
  2. 記住12個單詞的助記符,後續需要使用(每次新開啟一個ganache客戶端都會重新初始化助記符)。output parent when east clown cake duck garbage jump spin medal cute

修改配置檔案

  1. 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
    }
  }
};

編譯部署智慧合約

  1. truffle console
  2. truffle compile
  3. truffle migrate

測試智慧合約

  1. 在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.");
  }
}
  1. truffle test

建立使用者介面和智慧合約互動

  1. 編輯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

  1. 在瀏覽器中安裝MetaMask外掛:chrome外掛
  2. 使用前面複製的ganache的助記符,配置錢包並設定自定義的密碼
  3. 預設連線好localhost:8545 rpc

啟動服務

  1. 開啟lite-server
    npm run dev
  2. 瀏覽器訪問:http://localhost:3000/
  3. 可以執行收養寵物等操作,MetaMask彈出彈窗確定轉賬操作
  4. 收養成功:
Either Excellent or Rusty