以太坊Truffle宠物商店

以太坊Truffle宠物商店

环境版本

Windows (powershell)

Truffle v5.5.28 (core: 5.5.28)

Node v16.15.0

Ganache CLI v6.12.2 (ganache-core: 2.13.2)

小狐狸钱包

编译环境:vscode

创建项目

  1. 创建文件夹并用truffle unbox 创建项目
E:\VSCODE>mkdir pet-shop

E:\VSCODE>cd pet-shop

E:\VSCODE\pet-shop>truffle unbox pet-shop

Starting unbox...
=================

√ Preparing to download box
√ Downloading
npm WARN old lockfile
npm WARN old lockfile The package-lock.json file was created with an old version of npm,
npm WARN old lockfile so supplemental metadata must be fetched from the registry.
npm WARN old lockfile
npm WARN old lockfile This is a one-time fix-up, please be patient...
npm WARN old lockfile
npm WARN deprecated [email protected]: Critical bug fixed in v3.0.1, please upgrade to the latest version.
npm WARN deprecated [email protected]: Critical bug fixed in v2.0.1, please upgrade to the latest version.
npm WARN deprecated [email protected]: Critical bug fixed in v3.0.1, please upgrade to the latest version.
npm WARN deprecated [email protected]: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated [email protected]: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
npm WARN deprecated [email protected]: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated [email protected]: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated [email protected]: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated [email protected]: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410
√ Cleaning up temporary files
√ Setting up box

Unbox successful, sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test
  Run dev server: npm run dev

添加宠物领养合约文件

  1. cd contracts
  2. touch Adoption.sol
// SPDX-License-Identifier: MIT
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客户端都会重新初始化助记符)。记住一个私钥后面生成账户。

修改部署文件

  1. cd migrations
  2. touch 2_deploy_adoption.js
var Adoption = artifacts.require('Adoption');

module.exports = function(deployer) {
    
    
    deployer.deploy(Adoption);
};

修改配置文件

  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

PS E:\VSCODE\pet-shop> truffle console
truffle(development)>
  1. 打开第三个终端,依次输入:truffle compile ,truffle migrate
PS E:\VSCODE\pet-shop> truffle compile

Compiling your contracts...
===========================
> Compiling .\contracts\Adoption.sol
> Compiling .\contracts\Migrations.sol
> Artifacts written to E:\VSCODE\pet-shop\build\contracts
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang       
PS E:\VSCODE\pet-shop> truffle migrate

Compiling your contracts...
===========================
> Compiling .\contracts\Adoption.sol
> Compiling .\contracts\Migrations.sol
> Artifacts written to E:\VSCODE\pet-shop\build\contracts
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang


Starting migrations...
======================
> Network name:    'development'
> Network id:      1663338400658
> Block gas limit: 6721975 (0x6691b7)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > transaction hash:    0x014ed5f8526042a1ae66eb579bb9aa6fc9bd9c06afd500386c924b01f771cc42
   > Blocks: 0            Seconds: 0
   > contract address:    0x7dF4665DcBEB57F44901c9Bd7dB3Ce038A97213a
   > block number:        1
   > block timestamp:     1663339597
   > account:             0x8d18b08249F796D6745AB035f7DCfa74FabEce2D
   > balance:             99.99616114
   > gas used:            191943 (0x2edc7)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00383886 ETH

   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00383886 ETH


2_deploy_adoption.js
====================

   Deploying 'Adoption'
   --------------------
   > transaction hash:    0x5e83970fe6c3ddcc9b48319ba33493289e72384151b50722f4c83c5dc31167a4
   > Blocks: 0            Seconds: 0
   > contract address:    0x2936D35cbDDa25CFc01abeEb9E7dc69a7b4bD9A7
   > block number:        3
   > block timestamp:     1663339598
   > account:             0x8d18b08249F796D6745AB035f7DCfa74FabEce2D
   > balance:             99.99123784
   > gas used:            203827 (0x31c33)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00407654 ETH

   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00407654 ETH

Summary
=======
> Total deployments:   2
> Final cost:          0.0079154 ETH      

测试智能合约

  1. 在test目录下新建一个TestAdoption.sol,内容如下:
// SPDX-License-Identifier: MIT
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,输出内容如下:
PS E:\VSCODE\pet-shop> truffle test
Using network 'development'.


Compiling your contracts...
===========================
> Compiling .\contracts\Adoption.sol
> Compiling .\contracts\Migrations.sol
> Compiling .\test\TestAdoption.sol
> Compiling truffle\Assert.sol
> Compiling truffle\AssertAddress.sol
> Compiling truffle\AssertAddressArray.sol
> Compiling truffle\AssertBalance.sol
> Compiling truffle\AssertBool.sol
> Compiling truffle\AssertBytes32.sol
> Compiling truffle\AssertBytes32Array.sol
> Compiling truffle\AssertGeneral.sol
> Compiling truffle\AssertInt.sol
> Compiling truffle\AssertIntArray.sol
> Compiling truffle\AssertString.sol
> Compiling truffle\AssertUint.sol
> Compiling truffle\AssertUintArray.sol
> Compiling truffle\DeployedAddresses.sol
> Artifacts written to C:\Users\userli\AppData\Local\Temp\test--14320-FaYw5WUN61rM
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang


  TestAdoption
    ✔ testUserCanAdoptPet (428ms)
    ✔ testGetAdopterAddressByPetId (447ms)
    ✔ testGetAdopterAddressByPetIdInArray (379ms)


  3 passing (13s)

创建用户接口和智能合约交互

  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. 选择刚刚的私钥生成的账户,连接钱包

在这里插入图片描述

  1. 可以执行收养宠物等操作,MetaMask弹出弹窗确定转账操作

在这里插入图片描述

  1. 收养成功:

在这里插入图片描述

原文链接 https://www.cnblogs.com/GarrettWale/p/15440582.html

猜你喜欢

转载自blog.csdn.net/qq_52873515/article/details/126899275