使用 Hardhat 入門以太坊智能合約


0x1 概述

我在入門以太坊智能合約開發時,首先我就面臨了一個選擇,Hardhat Vs Truffle Vs Remix,我應該選擇哪個開發工具。我就在谷歌上搜索很多對比,其中霍利維爾·瓦爾迪茲 的 《Hardhat Vs Truffle Vs Remix - Which Is The Best For Blockchain Development?
這篇文章很及時的幫助了我,並且OpenZeppelin、Aave、BitGo、1inch等都在使用該開發工具,而且我在深入了解官方文檔后發現文檔整體很清晰並且有條理,而我又有一定的前端開發經驗,所以在開發工具的選型上我選擇了 Hardhat 。如果你沒有前端經驗,希望在前期學習的時候更關注合約本身,那么我會推薦 Remix 作為前期學習的開發工具。
這是我基於 Hardhat 官方教程寫的第一篇以太坊合約和 dApp 開發指南,未來我也會持續分享所學。

0x2 搭建環境

首先 Hardhat 是基於 JavaScript 編寫的,所以我們首先需要安裝 Node.js 環境。

安裝 Node.js

如果你已經安裝了 Node.js 你可以跳過這個部分。如果沒有,接下來會介紹如何在 Ubuntu、MacOS和 Windows 上安裝它。

Linux

Ubuntu

將以下命令復制粘貼到終端:

sudo apt update
sudo apt install curl git
curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt install nodejs

MacOS

確保你已經安裝了 git ,如果沒有安裝可以參考 atlassian 寫的 《Install Git》。
在 MacOS 上安裝 Node.js 有多種方法。我選擇了使用 Node 版本管理器(nvm)。將以下命令復制粘貼到終端:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install --lts
nvm use stable
nvm alias default stable
npm install npm --global # 升級 npm 到最新版本

Windows

Windows 可以直接到 Node.js 官網,下載對應的安裝包即可完成安裝。

0x3 創建一個新的項目

我們將使用 npm CLI 來安裝 Hardhat。
打開終端並運行以下命令:

mkdir hardhat-tutorial
cd hardhat-tutorial
npm init --yes
npm install --save-dev hardhat

安裝 Hardhat 的過程中會安裝 Ethereum JavaScript 依賴項,所以請耐心等待。
在安裝 Hardhat 的同一目錄下運行:

npx hardhat

使用鍵盤選擇 Create an empty hardhat.config.js 並按下回車鍵。

$ npx hardhat
888    888                      888 888               888
888    888                      888 888               888
888    888                      888 888               888
8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
888    888 .d888888 888    888  888 888  888 .d888888 888
888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888

👷 Welcome to Hardhat v2.9.1 👷‍

? What do you want to do? …
  Create a basic sample project
  Create an advanced sample project
  Create an advanced sample project that uses TypeScript
❯ Create an empty hardhat.config.js
  Quit

當 Hardhat 運行時,它會從當前工作目錄開始搜索最近的 hardhat.config.js 文件。這個文件通常在你的項目根目錄,一個空的 hardhat.config.js 就足以讓 Hardhat 工作。未來我們對 Hardhat 的全部設置都會在這個文件中。

Hardhat 架構

Hardhat 基於任務和插件的理念設計。而 Hardhat 的大部分功能都來自插件,作為開發人員,你可以自由選擇要使用的插件。

任務

每次從 CLI 運行 Hardhat 時,你都在運行一項任務。例如 npx hardhat compile 命令就是運行 compile 任務。要查看項目當前可用的任務,只執行 npx hardhat。你也可以通過幫助命令了解其他任務 npx hardhat help [task]

當然我們也可以創建自定義的任務,參考創建任務

插件

在你最終使用什么工具方面,Hardhat 並不會限制你,但它確實帶有一些內置的默認設置。所有這些也都可以被重寫。
在本文中,我們將使用 Ethers.js 和 Waffle 插件。它們將允許你與以太坊交互並測試你的合約。稍后我們將解釋它們是如何使用的。要安裝它們,你只需在項目目錄中運行以下命令:

npm install --save-dev @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai

我們需要添加以下代碼

require("@nomiclabs/hardhat-waffle");

到如下位置,看起來會是這樣:

require("@nomiclabs/hardhat-waffle");

/**
 * @type import('hardhat/config').HardhatUserConfig
 */
module.exports = {
  solidity: "0.7.3",
};

我們只需要引用 hardhat-waffle

0x4 編寫與編譯合約

我們將創建一個簡單的智能合約來實現代幣轉移。代幣合約最常用於交換和存儲價值。我們不會在本文中展開詳細談考合約中的 Solidity 代碼,但是我們實現了一些你應該之大的邏輯:

  • 代幣的總供應量時固定的,無法被改變
  • 整個供應量分配到部署合約的地址
  • 任何人都可以收到代幣
  • 任何擁有至少一個代幣的人都可以轉移代幣
  • 代幣是不可分割的。你可以轉移1、2、3或者37個代幣,但不能轉移2.5個

你可能聽說過 ERC20,它是以太坊中的代幣標准。DAI、USDC、MKR和ZRX等代幣遵循 ERC20 標准,這使得它們都可以與任何可以處理 ERC20 代幣的軟件兼容。為簡單起見,我們要構建的代幣沒有遵循 ERC20。

編寫智能合約

首先創建一個名為新目錄 contracts,並在該目錄中創建一個名為 Token.sol
將下面的代碼粘貼到該文件中,花一點時間閱讀代碼。它很簡單,並且充滿了解釋 Solidity 基礎知識的備注。

要獲得語法高亮,你應該在文本編輯器中添加 Solidity 語言的支持。只需尋找 Solidity 或 Ethereum 插件。我們建議使用 Visual Studio Code 或 Sublime Text 3。

// Solidity 文件 第一行代碼都會是 pragma
// Solidity 編譯器將使用它來驗證對應的版本
pragma solidity ^0.7.0;


// 這是智能合約的主要組成部分
contract Token {
    // 一些字符串類型變量來標識代幣
    // `public` 修飾符使變量在合約外部可讀
    string public name = "My Hardhat Token";
    string public symbol = "MHT";

    // 存儲在無符號整型變量中的固定數量代幣
    uint256 public totalSupply = 1000000;

    // 地址類型變量用於存儲以太坊賬戶
    address public owner;

    // `mapping` 是一個鍵/值映射。我們在這里存儲每個帳戶余額
    mapping(address => uint256) balances;

    /**
     * 合約初始化
     *
     * `constructor` 只在合約創建時執行
     */
    constructor() {
        // totalSupply 被分配給交易發送方,即部署合約的帳戶
        balances[msg.sender] = totalSupply;
        owner = msg.sender;
    }

    /**
     * 傳遞代幣的函數
     *
     * `external` 修飾符使函數只能從合約外部調用
     */
    function transfer(address to, uint256 amount) external {
        // 檢查交易發送方是否有足夠的代幣
        // 如果 `require` 的第一個參數計算結果為 `false``,則整個交易會恢復
        require(balances[msg.sender] >= amount, "Not enough tokens");

        // 轉移金額
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }

    /**
     * 讀取給定帳戶的代幣余額
     *
     * `view` 修飾符表示它不修改合約的狀態,這允許我們在不執行交易的情況下調用它
     */
    function balanceOf(address account) external view returns (uint256) {
        return balances[account];
    }
}

*.sol 是 Solidity 的文件類型。我們建議將文件名與其包含的合約相匹配,這是一個常見的做法。

編譯合同

編譯合約,在你的終端中執行npx hardhat compile。該 compile 任務是內置任務之一。

$ npx hardhat compile
Compiling 1 file with 0.7.3
Compilation finished successfully

合約已經編譯成功,現在你就可以使用了。

0x5 測試合約

在構建智能合約時編寫自動化測試是至關重要的,因為我們的代碼將直接操作用戶的錢!為此,我們將使用 Hardhat 網絡,這是一個為開發而設計的本地以太坊網絡,它內置在 Hardhat 工具中,並且是默認網絡。你無需設置任何內容即可使用它。在我們的測試中,我們將使用 ethers.js 與我們在上節中構建的以太坊合約進行交互,並且使用 Mocha 作為我們的測試運行時。

編寫測試

在我們的項目根目錄中創建名為test的目錄,並在里面創建一個文件名為Token.js的文件。
我們從下面的代碼開始。我們將在接下來解釋其中的含義,但現在你只需將其粘貼到 Token.js 中:

const { expect } = require("chai");

describe("Token contract", function () {
  it("Deployment should assign the total supply of tokens to the owner", async function () {
    const [owner] = await ethers.getSigners();

    const Token = await ethers.getContractFactory("Token");

    const hardhatToken = await Token.deploy();

    const ownerBalance = await hardhatToken.balanceOf(owner.address);
    expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
  });
});

在你的終端上運行 npx hardhat test,你應該看到以下輸出:

npx hardhat test

  Token contract
    ✓ Deployment should assign the total supply of tokens to the owner (654ms)


  1 passing (663ms)

這意味着測試通過了。現在讓我們解釋每一行:

const [owner] = await ethers.getSigners();

Signer 代表 ethers.js 中以太坊的對象。 它用於向合約和其他賬戶發送交易。在這里,我們得到了所連接節點中的賬戶列表,在本例中時Hardhat 網絡,並且只保留第一個。

ethers變量在全局范圍內可用。你可以在頂部添加這么一行:

const { ethers } = require("hardhat");

要了解更多關於Singer的信息,你可以查看 Signers 文檔

const Token = await ethers.getContractFactory("Token");

在 ethers.js 中,ContractFactory 是一個用於部署新智能合約的抽象,所以這里的 Token是我們的代幣合約工廠的實例。

const hardhatToken = await Token.deploy();

在 ContractFactory 上調用deploy()將開始部署,並返回Contract解析后的 Promise。這是為你的每個智能合約功能提供方法的對象。

const ownerBalance = await hardhatToken.balanceOf(owner.address);

一旦部署了合約,我們就可以在hardhatToken上調用我們的合約方法,並通過調用balanceOf()來獲取相應所有者帳戶的余額。

請記住,獲得整個供應量的代幣所有者是進行部署的賬戶,當使用hardhat-ethers插件時,ContractFactoryContract實例默認連接到第一個簽名者。這意味着owner變量中的賬戶執行了部署,而balanceOf()應該返回整個供應量。

expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);

在這里,我們再次使用我們的Contract實例來調用 Solidity 代碼中的智能合約函數。totalSupply()返回代幣的供應量,我們檢查它是否等於ownerBalance,正如它應該做的那樣。

為了做到這一點,我們使用了 Chai,這是一個斷言庫。這些斷言函數被稱為 "匹配器",而我們在這里使用的函數實際上來自 Waffle。這就是為什么我們要使用hardhat-waffle插件,它使我們更容易從Ethereum 斷言值。請查看 Waffle 文檔中的這一節,了解整個以太坊特定匹配器的列表。

使用其他帳戶

如果你需要從默認賬戶(或ethers.js中的Signer)以外的賬戶發送交易來測試你的代碼,你可以使用ethers.js Contract中的connect()方法將其連接到一個不同的賬戶。像這樣:

const { expect } = require("chai");

describe("Transactions", function() {
  it("Should transfer tokens between accounts", async function() {
    const [owner, addr1, addr2] = await ethers.getSigners();

    const Token = await ethers.getContractFactory("Token");

    const hardhatToken = await Token.deploy();

    //  從所有者轉移50個代幣到addr1
    await hardhatToken.transfer(addr1.address, 50);
    expect(await hardhatToken.balanceOf(addr1.address)).to.equal(50);

    // 從addr1轉移50個代幣到addr2
    await hardhatToken.connect(addr1).transfer(addr2.address, 50);
    expect(await hardhatToken.balanceOf(addr2.address)).to.equal(50);
  });
});

完全覆蓋

現在我們已經介紹了測試合約所需的基礎知識,這里有一個完整的代幣測試套件,其中包含有關 Mocha 以及如何構建測試的大量附加信息。我們建議通讀。

// 我們在這里導入Chai以使用它的斷言函數
const { expect } = require("chai");

// `describe` 是一個Mocha函數,它允許您組織測試
// 實際上並不需要這樣做,但是組織測試會使調試變得更容易。所有的Mocha函數都可以在全局作用域中使用

// `describe` 參數為一個測試名稱和一個回調函數
// 回調必須定義該部分的測試。這個回調函數不能是一個異步函數
describe("Token contract", function () {
  // Mocha 有四個函數可以讓你能在整個測試生命周期中進行不同的操作,
  // 它們是: `before`, `beforeEach`, `after`, `afterEach`

  // 它們在設置測試環境和運行后清理環境方面非常有用

  // 一個常見的模式是聲明一些變量,並在 `before` 和 `beforeEach` 回調中分配它們

  let Token;
  let hardhatToken;
  let owner;
  let addr1;
  let addr2;
  let addrs;

  // `beforeEach` 將在每次測試之前運行,每次重新部署合約。它接收回調,可以是異步的
  beforeEach(async function () {
    // 在這里獲取 ContractFactory 和簽名者
    Token = await ethers.getContractFactory("Token");
    [owner, addr1, addr2, ...addrs] = await ethers.getSigners();

    // 要部署我們的合約,只需調用 Token.deploy() 並等待它被 deployed(),一旦它的交易被挖掘,就會發生部署
    hardhatToken = await Token.deploy();
  });

  // 你可以嵌套 describe 調用來創建小結
  describe("Deployment", function () {
    // `it` 是 MoCha 函數,這是用來定義測試的工具。它接收測試名和回調函數

    // 如果回調函數是一步的,Mocha 將 `await`
    it("Should set the right owner", async function () {
      // Expect 接收一個值,並將其包裝在Assertion對象中。這些對象有很多實用方法來斷言值

      // 這個測試期望存儲在合約中的所有者變量等於我們部署合約時候的所有者
      expect(await hardhatToken.owner()).to.equal(owner.address);
    });

    it("Should assign the total supply of tokens to the owner", async function () {
      const ownerBalance = await hardhatToken.balanceOf(owner.address);
      expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
    });
  });

  describe("Transactions", function () {
    it("Should transfer tokens between accounts", async function () {
      // 將50個代幣從所有者轉移到 addr1
      await hardhatToken.transfer(addr1.address, 50);
      const addr1Balance = await hardhatToken.balanceOf(addr1.address);
      expect(addr1Balance).to.equal(50);

      // 將50個代幣從 addr1 轉移到 addr2
      // 我們使用.connect(簽名者)從另一個帳戶發送交易
      await hardhatToken.connect(addr1).transfer(addr2.address, 50);
      const addr2Balance = await hardhatToken.balanceOf(addr2.address);
      expect(addr2Balance).to.equal(50);
    });

    it("Should fail if sender doesn’t have enough tokens", async function () {
      const initialOwnerBalance = await hardhatToken.balanceOf(owner.address);

      // 嘗試從 addr1 (0 代幣)發送1個代表給所有者(1000000 代幣)。
      // `require`將計算為 false 並恢復交易
      await expect(
        hardhatToken.connect(addr1).transfer(owner.address, 1)
      ).to.be.revertedWith("Not enough tokens");

      // 所有者余額不應該改變
      expect(await hardhatToken.balanceOf(owner.address)).to.equal(
        initialOwnerBalance
      );
    });

    it("Should update balances after transfers", async function () {
      const initialOwnerBalance = await hardhatToken.balanceOf(owner.address);

      // 將100個代幣從所有者轉移到 addr1
      await hardhatToken.transfer(addr1.address, 100);

      // 將另外50個代幣從所有者轉移到addr2
      await hardhatToken.transfer(addr2.address, 50);

      // 檢查余額
      const finalOwnerBalance = await hardhatToken.balanceOf(owner.address);
      expect(finalOwnerBalance).to.equal(initialOwnerBalance.sub(150));

      const addr1Balance = await hardhatToken.balanceOf(addr1.address);
      expect(addr1Balance).to.equal(100);

      const addr2Balance = await hardhatToken.balanceOf(addr2.address);
      expect(addr2Balance).to.equal(50);
    });
  });
});

這就是npx hardhat test完整測試套件的輸出,是這樣的:

$ npx hardhat test

  Token contract
    Deployment
      ✓ Should set the right owner
      ✓ Should assign the total supply of tokens to the owner
    Transactions
      ✓ Should transfer tokens between accounts (199ms)
      ✓ Should fail if sender doesn’t have enough tokens
      ✓ Should update balances after transfers (111ms)


  5 passing (1s)

請記住,當你運行npx hardhat test時,如果你的合約自上次運行測試以來發生更改,則將編譯它們。

0x6 使用 Hardhat 網絡進行調試

Hardhat 內置了Hardhat 網絡,這是一個專為開發而設計的本地以太坊網絡。它允許你部署合約、運行測試和調試代碼。這是 Hardhat 連接的默認網絡,因此你無需進行任何設置即可使其正常工作。只需運行你的測試。

Solidity console.log

在 Hardhat 網絡上運行合約和測試時,你可以在 Solidity 代碼中使用console.log()來打印日志消息與合約變量。要使用它,你必須在你的合約代碼中導入 hardhat/console.sol

pragma solidity ^0.8.0;

import "hardhat/console.sol";

contract Token {
  //...
}

像在 JavaScript 中使用console.log那樣在transfer()函數添加一些內容:

function transfer(address to, uint256 amount) external {
    console.log("Sender balance is %s tokens", balances[msg.sender]);
    console.log("Trying to send %s tokens to %s", amount, to);

    require(balances[msg.sender] >= amount, "Not enough tokens");

    balances[msg.sender] -= amount;
    balances[to] += amount;
}

運行測試時將顯示日志輸出:

$ npx hardhat test

  Token contract
    Deployment
      ✓ Should set the right owner
      ✓ Should assign the total supply of tokens to the owner
    Transactions
Sender balance is 1000 tokens
Trying to send 50 tokens to 0xead9c93b79ae7c1591b1fb5323bd777e86e150d4
Sender balance is 50 tokens
Trying to send 50 tokens to 0xe5904695748fe4a84b40b3fc79de2277660bd1d3
      ✓ Should transfer tokens between accounts (373ms)
      ✓ Should fail if sender doesn’t have enough tokens
Sender balance is 1000 tokens
Trying to send 100 tokens to 0xead9c93b79ae7c1591b1fb5323bd777e86e150d4
Sender balance is 900 tokens
Trying to send 100 tokens to 0xe5904695748fe4a84b40b3fc79de2277660bd1d3
      ✓ Should update balances after transfers (187ms)


  5 passing (2s)

查看文檔以了解有關此功能的更多信息。

0x7 部署到真實網絡

一旦你准備好與其他人分享你的 dApp,你可能想要做的就是部署到真實的網絡。這樣,其他人就可以訪問你的 dApp了。

涉及真錢交易的以太坊網絡,被稱為“mainnet”,然而還有其他不與真錢交易的網絡,但卻能很好的模擬現實世界的場景,也可以被其他人訪問的網絡稱為“testnets”。以太坊有多個測試網:Ropsten、Kovan、Rinkeby和Goerli。我們建議將合約部署到 Ropsten 測試網。

在軟件層面,部署到測試網與部署到主網是一樣的。唯一的區別是你連接到哪個網絡。讓我們看看使用ether.js部署合約的代碼是什么樣子的。

使用的主要概念是SignerContractFactoryContract,我們在測試部分中解釋過。與測試相比,沒有什么新事情需要做,因為當在測試合約時,實際上是在向你的開發網絡進行部署。這使得代碼非常相似。

讓我們在項目根目錄中創建一個新的目錄 scripts,並將以下內容粘貼到deploy.js文件中:

async function main() {
  const [deployer] = await ethers.getSigners();

  console.log("Deploying contracts with the account:", deployer.address);

  console.log("Account balance:", (await deployer.getBalance()).toString());

  const Token = await ethers.getContractFactory("Token");
  const token = await Token.deploy();

  console.log("Token address:", token.address);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);

要在運行任何任務時指定 Hardhat 連接到特定的以太坊網絡,可以使用--network參數。像這樣:

npx hardhat run scripts/deploy.js --network <network-name>

在這種情況下,不帶--network參數運行它會使代碼針在Hardhat 網絡的嵌入式實例運行,因此當 Hardhat 完成運行時,部署實際上會丟失,但測試我們的部署代碼是否有效仍然很有用:

$ npx hardhat run scripts/deploy.js
Deploying contracts with the account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Account balance: 10000000000000000000000
Token address: 0x5FbDB2315678afecb367f032d93F642f64180aa3

部署到遠程網絡

要部署到遠程網絡(例如主網或任何測試網),你需要在hardhat.config.js文件中添加一個network條目。我們將在此示例中使用 Ropsten,但你也可以以類似地方式添加任何網絡:

require("@nomiclabs/hardhat-waffle");

// 登錄https://www.alchemyapi.io,注冊,
// 在其儀表板中創建一個新的應用程序,並將“KEY”替換為其密鑰
const ALCHEMY_API_KEY = "KEY";

// 從 Metamask 導出你的私鑰,打開Metamask,並進入帳戶詳細信息>導出私鑰
// 千萬注意,永遠不要把真實的Ether轉到測試帳戶
const ROPSTEN_PRIVATE_KEY = "YOUR ROPSTEN PRIVATE KEY";

module.exports = {
  solidity: "0.7.3",
  networks: {
    ropsten: {
      url: `https://eth-ropsten.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
      accounts: [`${ROPSTEN_PRIVATE_KEY}`]
    }
  }
};

我們正在使用Alchemy,但指向任何以太坊節點或網關的url都可以工作。

要部署在Ropsten網絡上,你需要將Ropsten-ETH發送到將要進行部署的地址。你可以從測試網的水龍頭上得到一些ETH,這是一種免費分發測試ETH的服務。這是Ropsten的一個水龍頭,你必須在交易之前將Metamask的網絡更改為Ropsten。
最后,運行:

npx hardhat run scripts/deploy.js --network ropsten

如果一切順利,你應該會看到已部署的合約地址。

0x8 模版項目

如果你想快速開始使用你的dApp,亦或者想通過前端查看整個項目,你可以使用以下demo項目庫。
https://github.com/nomiclabs/hardhat-hackathon-boilerplate

包括些什么

  • 我們在本教程中使用的 Solidity 合約
  • 使用 ethers.js 和 Waffle 的測試套件
  • 使用 ethers.js 與合約交互的最小前端

Solidity 合約和測試

在 repo 的根目錄中,您會找到我們通過本教程與合約一起構建的Hardhat項目。Token刷新你對它實現的記憶:

  • 代幣的總供應量是固定的,無法更改
  • 整個供應分配到部署合約的地址
  • 任何人都可以收到代幣
  • 任何擁有至少一個代幣的人都可以轉移代幣
  • 代幣是不可分割的。你可以轉移 1、2、3 或 37 個代幣,但不能轉移 2.5 個

前端應用

你會發現一個簡單的應用程序,frontend它允許用戶做兩件事:

  • 檢查已連接錢包的余額
  • 將代幣發送到地址
    這是一個單獨的 npm 項目,它是使用create-react-app創建的,所以這意味着它使用了 webpackbabel

前端文件架構

  • `src/``包含所有代碼
    • src/components包含反應組件
      • Dapp.js是唯一具有業務邏輯的文件。如果你將其用作模版,你可以在此處用你自己的代碼替換
      • 其他所有組件都只呈現 HTML,沒有邏輯。
      • src/contracts有合約的 ABI 和地址,這些是由部署腳本自動生成的

如何使用它

首先克隆該庫,然后部署合約:

cd hardhat-hackathon-boilerplate
npm install
npx hardhat node

在這里,我們只安裝 npm 項目的依賴項,並通過運行npx hardhat node啟動一個Hardhat 網絡實例,你可以使用 MetaMask 連接到該實例。在同一目錄中的不同終端中,運行:

npx hardhat --network localhost run scripts/deploy.js

這會將合約部署到Hardhat網絡。完成后運行:

cd frontend
npm install
npm run start

啟動react web app。打開http://localhost:3000/ ,你應該會看到:

在 MetaMask 中將你的網絡設置為localhost:8545。 然后可能還需要配置 MetaMask 以與 Hardhat 配合使用。為此,請轉到Settings -> Networks -> Localhost 8545並將鏈 ID 更改為 31337。

現在單擊 Web 應用程序中的按鈕。然后你應該看到這個:

這里發生的情況是顯示當前錢包余額的前端代碼檢測到余額為0,因此你將無法嘗試轉賬功能。通過運行:

npx hardhat --network localhost faucet <your address>

這將運行我們包含在Hardhat中的自定義任務,該任務使用部署帳戶的余額向你的地址發送 100 MBT 和 1 ETH。這將允許你將代幣發送到另一個地址。
你可以查看/tasks/faucet.js中的任務代碼。

$ npx hardhat --network localhost faucet 0x0987a41e73e69f60c5071ce3c8f7e730f9a60f90
Transferred 1 ETH and 100 tokens to 0x0987a41e73e69f60c5071ce3c8f7e730f9a60f90

在你運行npx hardhat node的終端中,你也應該看到:

eth_sendTransaction
  Contract call:       Token#transfer
  Transaction:         0x460526d98b86f7886cd0f218d6618c96d27de7c745462ff8141973253e89b7d4
  From:                0xc783df8a850f42e7f7e57013759c285caa701eb6
  To:                  0x7c2c195cd6d34b8f845992d380aadb2730bb9c6f
  Value:               0 ETH
  Gas used:            37098 of 185490
  Block #8:            0x6b6cd29029b31f30158bfbd12faf2c4ac4263068fd12b6130f5655e70d1bc257

  console.log:
    Transferring from 0xc783df8a850f42e7f7e57013759c285caa701eb6 to 0x0987a41e73e69f60c5071ce3c8f7e730f9a60f90 100 tokens

在我們的合約中顯示transfer()函數的console.log輸出,這是運行水龍頭任務后web應用程序的樣子:

試着調試它並閱讀代碼。它充滿了注釋,解釋正在發生的事情,並清楚地表明哪些代碼是以太坊模版代碼,哪些實際上是dApp邏輯。這將使該項目易於為你的項目重用。

0x9 結束語

恭喜你完成了本教程!
以下是一些補充鏈接,讓你更深入了解:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM