BlockChain區塊鏈
  • 本書簡介
  • 區塊鏈運作原理
  • Bitcoin介紹
    • 簡介
    • Bitcoin其他知識
  • Bitcoin原理與實作
  • BitcoinJS
    • BTC 地址格式種類
    • 從 Mnemonic 轉為地址
  • Serverless 架構實作
  • Docker常用指令
  • ethereum初探
    • ethereum歷史
    • EVM
  • ethereum PoS 節點架設
  • ethereum(Docker)
  • ethereum(Geth)
    • Parity
  • ethereum(智能合約)
    • 合約測試 Unit Test
    • DAO
    • 可升級合約
    • 使用合約進行 multiswap
    • 合約安全
    • 開發工具
    • Hardhat 教學
      • Hardhat 寫測試
    • ERC-721 範例
      • 白名單機制
    • OpenZeppelin 合約 library
    • Truffle
    • 合約部屬
    • solidity 教學
  • ethereum(Dapp)
    • 相關 SDK
    • Multicall
    • Ethers.js 使用
    • Remix IDE
    • web3.js 使用
    • 在網頁上使用 web3 並操作區塊鏈
      • solidity筆記
  • Hyperledger Fabric
  • blockchainDB
  • 挖礦程式使用教學
    • 門羅幣/Monero (XMR)
  • Bitfinex API 使用
  • FTX API
  • CCXT 通用交易所 API
  • Solana 教學
  • Ethereum BigQuery
  • The Graph
    • yaml 定義
    • mapping 語法
    • Schema 定義
    • Query 範例
    • Unit test
  • DeFi 筆記
    • MEV 相關
    • Dex 聚合
    • Yearn
    • Curve
    • Uniswap
      • Swap 互動
    • AAVE、Compound
      • Compound 原理
      • AAVE 合約開發
Powered by GitBook
On this page
  • 安裝與初始化
  • 專案結構
  • 在本地測試與部屬
  • 寫測試檔案
  • Artifacts
  • 使用 Mainnet fork 測試
  • 測試檔案內設置區塊時間
  • 部署合約
  • Etherscan 驗證合約
  • 測試單一檔案
  • 相關連結
  • 常見問題

Was this helpful?

  1. ethereum(智能合約)

Hardhat 教學

Previous開發工具NextHardhat 寫測試

Last updated 4 months ago

Was this helpful?

類似 Truffle 為一個智能合約開發 SDK。

安裝與初始化

mkdir hardhat-test && cd hardhat-test
npx hardhat init

專案結構

必須照著官方規定取名資料夾,分別為放合約以及部署script,與測試檔案,以及網路等 config。

在本地測試與部屬

  1. 啟動本地節點

[可選] 如果沒有啟動節點與指定節點,預設都會使用 in-memory instance of Hardhat Network

npx hardhat node

2.部署合約

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

3.使用 console 測試功能

npx hardhat console --network localhost

之後輸入

const Greeter = await ethers.getContractFactory("Greeter");
const greeter = await Greeter.attach(<剛才部署本地的合約地址>);
await greeter.greet()

寫測試檔案

test/test.js

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

describe("Greeter12", function () {
  it("Should return the new greeting once it's changed", async function () {
    
    const Greeter = await ethers.getContractFactory("Greeter");
    // const greeter = await Greeter.deploy("Hello, world!");
    // await greeter.deployed();

    //expect(await greeter.greet()).to.equal("Hello, world!");
    const greeter = await Greeter.attach("0x5FbDB2315678afecb367f032d93F642f64180aa3");

    const setGreetingTx = await greeter.setGreeting("Hola, mundo!");

    // wait until the transaction is mined
    await setGreetingTx.wait();
    const a = await greeter.greet()
    //console.log(a)

    expect(await greeter.greet()).to.equal("Hola, mundo!");
  });
});

之後輸入

npx hardhat test --network localhost

Artifacts

部署合約或 compile 後會產生此資料夾,裡面包含一些 json 檔案,為合約的 ABI

使用 Mainnet fork 測試

使用 mainnet 特定 block data 來測試合約

設置 hardhat.config.js 即可

require("@nomicfoundation/hardhat-toolbox");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.28",
  networks: {
      hardhat: {
          forking: {
              url: "https://eth-mainnet.g.alchemy.com/v2/<API KEY>",
          },
      },
  },
};

之後可獲取當前主網地址餘額

貼上以下檔案到 /test 後,輸入 `npx hardhat test`

const { expect } = require("chai");
const { ethers } = require("hardhat"); // Import ethers from Hardhat

describe("Query Account Balance on Forked Mainnet", function () {
    it("should fetch the balance of the specified account", async function () {
        // Replace this with the address you want to query
        const targetAddress = "...";

        // Use ethers to get the balance
        const balance = await ethers.provider.getBalance(targetAddress);

        // Log the balance for debugging
        console.log(`Balance of ${targetAddress}: ${balance} ETH`);

        // Verify that the balance is returned as a BigNumber
        expect(balance).to.be.a("BigInt");
    });
});

或是以下獲取主網特定地址的 USDC 餘額

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

describe("USDC Balance Check", function () {
  it("Should return the USDC balance of the address", async function () {
    const usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; // USDC Contract Address
    const addressToCheck = "..."; // Address whose balance you want to check

    // USDC Contract ABI (Simplified; use the full ABI from Etherscan)
    const usdcAbi = ["function balanceOf(address owner) view returns (uint256)"];
    
    // Connect to the USDC contract
    const usdcContract = new ethers.Contract(usdcAddress, usdcAbi, ethers.provider);

    // Fetch the balance
    const balance = await usdcContract.balanceOf(addressToCheck);

    // Log the balance (optional)
    console.log("USDC Balance:", balance.toString());


    // 也可手動改變地址 ETH 餘額
    const mainnetAccount = addressToCheck; // Replace with a mainnet account address
    await hre.network.provider.request({
      method: "hardhat_impersonateAccount",
      params: [mainnetAccount],
    });
    await hre.network.provider.send("hardhat_setBalance", [
      mainnetAccount,
      "0x8AC7230489E80000000", // 40960 ETH
    ]);

    const ethBalance = await ethers.provider.getBalance(addressToCheck);

    // Log the balance (optional)
    console.log("ETH Balance:", ethers.formatEther(ethBalance), "ETH");

    // Assert (for example, checking if the balance is greater than a certain amount)
    expect(balance).to.be.gt(ethers.parseUnits("100", 6)); // Check if balance is greater than 100 USDC
  });
});

測試檔案內設置區塊時間

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

// Fast forward time by 7 days for testing
await ethers.provider.send("evm_increaseTime", [7 * 24 * 60 * 60]);
await ethers.provider.send("evm_mine");

部署合約

要先去 hardhat.config.ts 檔案設置網路設置

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
require('dotenv').config()

const config: HardhatUserConfig = {
  solidity: "0.8.24",
  networks: {
    someTestnet: {
      url: "<rpc url>",
      accounts: [`${process.env.PRIVATE_KEY}`],
      gasPrice: 160000000000, // 160 GWei (部署的 Gas Price)
    }
  }
};

export default config;

部署腳本 scripts/deploy.ts

import { ethers } from "hardhat";

async function main() {
  const EthStaker = await ethers.deployContract("EthStaker");

  await EthStaker.waitForDeployment();

  console.log(
    `EthStaker deployed to ${EthStaker.target}`
  );
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

之後輸入

npx hardhat run scripts/deploy.ts --network someTestnet

Etherscan 驗證合約

設置hardhat config

不同網路有不同的 api key

etherscan: {
  //apiKey: process.env.ETHERSCAN_API_KEY,
  apiKey: process.env.POLYGONSCAN_API_KEY,
},

之後輸入以下

npx hardhat verify --network <網路名稱> <要驗證的合約地址> <建構子參數>

測試單一檔案

會監聽檔案改變,自動跑測試,並且可在 config 寫要執行哪個檔案

相關連結

常見問題

1.Error: call revert exception

通常是直接使用 hardhat vm 部署與測試合約所產生,可改用 hardhat localhost node 試試

2.Error HH12: Trying to use a non-local installation of Hardhat

3.TypeError: unsupported addressable value (argument="target", value=null, code=INVALID_ARGUMENT, version=6.11.1)

v6 之後要用 .target 取代 .address

SimplifiedNFT1155 = await ethers.getContractFactory("SimplifiedNFT1155");
simplifiedNFT1155 = await SimplifiedNFT1155.deploy("baseURI/");

NFTStaker = await ethers.getContractFactory("NFTStaker");
nftStaker = await NFTStaker.deploy(simplifiedNFT1155.target);

可使用:

範例專案:

https://hardhat.org/guides/project-setup.html#sample-hardhat-project
https://hardhat.org/hardhat-network/docs/guides/forking-other-networks
https://github.com/wighawag/hardhat-deploy#hardhat-deploy-in-a-nutshell
https://hardhat.org/plugins/hardhat-watcher.html
https://github.com/symfoni/hardhat-react-boilerplate
Ethereum development environment for professionalsHardhatHQ
Ethereum development environment for professionalsHardhatHQ
Error HH12: Trying to use a non-local installation of Hardhat, which is not supported. Please install Hardhat locally using npm or Yarn, and try againStack Overflow
Ethereum development environment for professionalsHardhatHQ
Logo
Logo
Logo
Logo