跳至主要內容
本頁面使用機器翻譯自英語,可能包含錯誤或不清楚的語言。如需最準確的信息,請參閱英文原文。由於更新頻繁,部分內容可能與英文原文有出入。請加入我們在 Crowdin 上的努力,幫助我們改進本頁面的翻譯。 (Crowdin translation page, Contributing guide)

使用 Hardhat 部署第一個智能合約

導言

本節將指導你使用 Hardhat 向Kaia-Kairos網絡部署靈魂令牌。

Hardhat 是一個智能合約開發環境,它將為您提供幫助:

  • 開發和編譯智能合約。
  • 調試、測試和部署智能合約和 dApp。

靈魂綁定令牌(SBT)是不可轉讓的 NFT。 也就是說,一旦獲得,就不得出售或轉讓給其他用戶。 要了解有關 SBT、其工作原理和使用案例的更多信息,可以查看 Vitalik Buterin 發表的這篇 參考文章

完成本指南後,您將能夠

  • 在 Kaia 上建立一個 "Hardhat "項目。
  • 創建一個簡單的靈魂綁定令牌。
  • 使用 Hardhat 編譯智能合約。
  • 使用 Hardhat 測試、部署智能合約並與之交互。
  • 探索 Hardhat 分叉功能。

先決條件

學習本教程的前提條件如下:

設置開發環境

要使用 hardhat,我們需要建立開發環境並安裝 hardhat。 讓我們按以下步驟來做:

第 1步創建項目目錄


mkdir soulbound-tokens
cd soulbound-tokens

步驟 2:初始化 npm 項目

在終端中粘貼此命令以創建 package.json 文件


npm init -y

第 3 步:安裝 hardhat 和其他依賴項:

  • 在終端中粘貼下面的代碼安裝 hardhat

npm install --save-dev hardhat

  • 粘貼下面的代碼以安裝其他依賴項

npm install dotenv @kaiachain/contracts

注意:這將安裝本項目所需的其他依賴項,包括 hardhatklaytn/contractdotenv 等。

第 4 步:初始化硬頭盔項目:

運行以下命令啟動硬頭盔項目


npx hardhat

在本指南中,您將選擇一個排版腳本項目,如下所示:

注意:初始化項目時,系統會提示安裝 hardhat-toolbox 插件。 該插件捆綁了所有常用軟件包和 Hardhat 插件,建議在開始使用 Hardhat 進行開發時使用。

初始化硬帽項目後,當前目錄應包括

contracts/ - 此文件夾包含智能合約代碼。

ignition/modules/ - 該文件夾包含在區塊鏈網絡上部署合約的代碼。

test/ - 該文件夾包含測試智能合約的所有單元測試。

hardhat.config.js - 該文件包含對 Hardhat 工作和部署靈魂綁定令牌非常重要的配置。

第 5 步創建 .env 文件

現在,在項目文件夾中創建 .env 文件。 該文件可幫助我們將 .env 文件中的環境變量加載到 process.env 文件中。

  • 在終端中粘貼此命令以創建 .env 文件

touch .env

  • 創建文件後,讓我們將 .env 文件配置為如下所示:

KAIROS_TESTNET_URL= "您的 Kairos RPC 鏈接"
PRIVATE_KEY= "從 MetaMask 錢包複製的您的私人密鑰"

注:你也可以選擇使用 hardhat 提供的配置變量 功能來配置不應包含在代碼庫中的變量。

第 6 步:設置Hardhat配置

用以下配置修改 hardhat.config.js


require("@nomicfoundation/hardhat-toolbox");
require('dotenv').config()
module.exports = {
solidity: "0.8.17",
networks: {
kairos: {
url: process.env.KAIROS_TESTNET_URL || "",
gasPrice: 250000000000,
accounts:
process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
}
}
};

現在,我們的開發環境已經準備就緒,讓我們開始編寫我們的靈魂綁定令牌智能合約吧。

創建 SBT 智能合約

在本節中,您將使用 Kaia Contracts:這是一個建立在社區驗證代碼堅實基礎上的安全智能合約開發庫。 它是開放式齊柏林合同的分叉。

注意:您已在 "設置開發環境 "一節的第 3** 步安裝了該庫。

步驟 1:在資源管理器窗格中選擇合同文件夾,單擊 "新建文件 "按鈕並創建名為 "SBT.sol "的新文件

第 2步打開文件並粘貼以下代碼:


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@kaiachain/contracts/KIP/token/KIP17/KIP17.sol";
import "@kaiachain/contracts/utils/Counters.sol";
import "@kaiachain/contracts/access/Ownable.sol";
contract SoulBoundToken is KIP17, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() KIP17("SoulBoundToken", "SBT") {}
function safeMint(address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
}
function _beforeTokenTransfer(address from, address to, uint256) pure override internal {
require(from == address(0) || to == address(0), "This a Soulbound token. It cannot be transferred.");
}
function _burn(uint256 tokenId) internal override(KIP17) {
super._burn(tokenId);
}
}

代碼演練

這就是你的智能合約。 第 1 行顯示 Hardhat 使用的是 0.8.7 或更高版本的 Solidity。 除此之外,它還導入了 KIP17.sol 和其他輔助合同。 從第6-12**行開始,創建了一個繼承KIP17的智能合約。 此外,構造函數中還傳遞了標記名稱和符號。

如上代碼所示,令牌名稱和符號已分別設置為 SoulBoundTokenSBT。 您可以隨意更改令牌名稱和符號。

該合約的一個主要特點是禁止代幣轉讓,這使得發行的代幣成為靈魂債券。

測試 SBT 智能合約

在本節中,我們將測試一些合同功能。

步驟 1:在資源管理器窗格中,選擇測試文件夾並單擊 "新建文件 "按鈕,創建一個名為 "sbtTest.js "的新文件。

步驟 2:在 sbtTest.js 文件中複製以下代碼。


// This is an example test file. Hardhat will run every *.js file in `test/`,
// so feel free to add new ones.
// Hardhat tests are normally written with Mocha and Chai.
// We import Chai to use its asserting functions here.
const { expect } = require("chai");
// We use `loadFixture` to share common setups (or fixtures) between tests.
// Using this simplifies your tests and makes them run faster, by taking
// advantage of Hardhat Network's snapshot functionality.
const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers");
// `describe` is a Mocha function that allows you to organize your tests.
// Having your tests organized makes debugging them easier. All Mocha
// functions are available in the global scope.
//
// `describe` receives the name of a section of your test suite, and a
// callback. The callback must define the tests of that section. This callback
// can't be an async function.
describe("Token contract", function () {
// We define a fixture to reuse the same setup in every test. We use
// loadFixture to run this setup once, snapshot that state, and reset Hardhat
// Network to that snapshot in every test.
async function deployTokenFixture() {
// Get the ContractFactory and Signers here.
const [owner, addr1, addr2] = await ethers.getSigners();
// To deploy our contract, we just have to call ethers.deployContract() and call the
// waitForDeployment() method, which happens onces its transaction has been
// mined.
const sbtContract = await ethers.deployContract("SoulBoundToken");
await sbtContract.waitForDeployment();
// Fixtures can return anything you consider useful for your tests
return { sbtContract, owner, addr1, addr2 };
}
// You can nest describe calls to create subsections.
describe("Deployment", function () {
// `it` is another Mocha function. This is the one you use to define each
// of your tests. It receives the test name, and a callback function.
//
// If the callback function is async, Mocha will `await` it.
it("Should mint SBT to owner", async function () {
const { sbtContract, owner } = await loadFixture(deployTokenFixture);
const safemint = await sbtContract.safeMint(owner.address);
expect(await sbtContract.ownerOf(0)).to.equal(owner.address);
});
});
describe("Transactions", function () {
it("Should prohibit token transfer using transferFrom", async function () {
const { sbtContract, owner, addr1 } = await loadFixture(
deployTokenFixture
);
const safemintTx = await sbtContract.safeMint(owner.address);
// prohibit token transfer of token id (0) from owner to addr1
await expect(
sbtContract.transferFrom(owner.address, addr1.address, 0)
).to.be.reverted;
});
it("Should prohibit token transfer using safeTransferFrom", async function () {
const { sbtContract, owner, addr1 } = await loadFixture(
deployTokenFixture
);
const safemintTx = await sbtContract.safeMint(owner.address);
// prohibit token transfer of token id (0) from owner to addr1
await expect(sbtContract['safeTransferFrom(address,address,uint256)'](
owner.address,
addr1.address,
0
)).to.be.reverted;
});
});
})

在你剛剛複製的代碼中,第 7 行和第 12 行顯示你從 hardhat-network-helpers 的 ChailoadFixture 中導入了 expect。

上述測試可檢查以下內容:

  • 特定代幣 ID 的所有者是否與該代幣的鑄造者相同?
  • 是否禁止在賬戶之間轉移代幣?

第 3 步:要運行測試,請運行以下命令:


npx 硬帽測試 test/sbtTest.js

如需更深入的測試指南,請查看 Hardhat 測試

部署智能合約

腳本是 JavaScript/Typescript 文件,可幫助您將合約部署到區塊鏈網絡。 在本節中,您將為智能合約創建一個腳本。

步驟 1:在資源管理器窗格中,選擇 "scripts "文件夾,然後單擊 "新建文件 "按鈕,創建一個名為 "sbtDeploy.js "的新文件。

第 2步將以下代碼複製並粘貼到文件中。

注意:在 deployerAddr 變量中輸入您的 MetaMask 錢包地址。


const { ethers } = require("hardhat");
async function main() {
const deployerAddr = "Your Metamask wallet address";
const deployer = await ethers.getSigner(deployerAddr);
console.log(`Deploying contracts with the account: ${deployer.address}`);
console.log(`Account balance: ${(await deployer.provider.getBalance(deployerAddr)).toString()}`);
const sbtContract = await ethers.deployContract("SoulBoundToken");
await sbtContract.waitForDeployment();
console.log(`Congratulations! You have just successfully deployed your soul bound tokens.`);
console.log(`SBT contract address is ${sbtContract.target}. You can verify on https://kairos.kaiascope.com/account/${sbtContract.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;
});

**第 3 步在終端運行以下命令,讓 Hardhat 在 Kaia 測試網絡 (Kairos) 上部署 SBT 令牌


npx hardhat run ignition/modules/sbtDeploy.js --network kairos

第 4 步:打開 Kaiascope,檢查 SBT 令牌是否已成功部署。

第 5 步:在搜索欄中複製並粘貼部署的合同地址,然後按 Enter 鍵。 您應該能看到最近部署的合同。

硬帽叉

Hardhat 為開發人員提供了在本地開發網絡中模擬主網(任何給定區塊)的功能。 這一功能的主要好處之一是,它能讓開發人員與已部署的合同進行交互,還能為複雜的案例編寫測試。

要使該功能有效運行,您需要連接到存檔節點。 您可在 此處 閱讀有關此功能的更多信息。

分叉主網

現在,我們已經建立了 Hardhat 項目,讓我們使用 Hardhat fork Kaia 主網。 打開終端,運行以下命令


npx hardhat node --fork<YOUR ARCHIVE NODE URL>
npx hardhat node --fork https://archive-en.node.kaia.io

您也可以配置 hardhat.config.js - Hardhat Network 始終這樣做:


networks: {
hardhat: {
forking: {
url: "<YOUR ARCHIVE NODE URL>",
}
}
}

輸出

成功運行該命令後,您的終端看起來就像上圖一樣。 您將擁有 20 個開發賬戶,這些賬戶預存了 10,000 個測試代幣。

分叉鏈的 RPC 服務器正在http://127.0.0.1:8545/監聽。 您可以通過查詢最新的區塊編號來驗證分叉網絡。 讓我們嘗試使用 cURL 訪問 RPC,以獲取區塊編號。 打開一個新的終端窗口,使用以下命令:


curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545

輸出

輸出結果為十六進制,如上圖所示。 要從十六進制中獲取塊編號,請使用此 工具 將十六進制轉換為十進制。 您應該從分叉網絡時獲得最新的區塊編號。 您可以通過 kaiascope確認區塊編號。

在街區分叉

使用硬頭盔,您可以在特定區塊分叉主網。 在這種情況下,讓我們在區塊編號 "105701850 "處分叉鏈。


npx hardhat node --fork<YOUR ARCHIVE NODE URL> --fork-block-number 105701850
npx hardhat node --fork https://archive-en.node.kaia.io --fork-block-number 105701850

要在指定區塊確認分叉鏈,請打開一個新的終端窗口並使用以下命令:


curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545

輸出返回十六進制,使用此 工具 轉換後應等於 105701850

有關 Hardhat 的更深入指南,請參閱 Hardhat 文檔。 此外,您還可以在 GitHub 上找到本指南的完整代碼實現。

讓這個頁面變得更好