Solidity教程:使用 Ethers.js 创建以太坊 dApp
在本教程中,我们将学习如何使用 Ethers.js 库构建一个带有与 Solidity 智能合约交互的前端的基本以太坊 dApp。
本教程是Solidity 教程系列的延续。如果您不熟悉编写 Solidity 智能合约,请在继续阅读本文之前查看如何构建您的第一个智能合约。
介绍
智能合约是仅在满足特定条件时才在区块链上部署和执行的功能。我们可以通过多种方式与我们在区块链上部署的智能合约进行交互。
一种方法是使用 Ethers.js 库将我们的 dApp 前端连接到作为后端的智能合约。
在本文中,我们将编写和部署一个接受宠物姓名、主人姓名和年龄的智能合约。我们还将使用前端项目中的 getter 函数从智能合约中检索宠物的详细信息。
演示
这是我们将在本教程结束时构建的宠物 dApp 的演示视频:
先决条件
在继续本教程之前,您应该具备:
• 对 HTML 和 CSS 有基本的了解,• 了解 JavaScript 中的函数和 DOM,• 您可以在此处[1]找到对 Solidity 的基本了解。本教程中使用的其他技术包括:Ethers.js 库、Remix IDE 和 Metamask。
构建 dApp
我们的项目分为两部分:后端,我们将在 Goerli 测试网上编写和部署我们的 Solidity 智能合约;前端,我们将在这里使用 HTML 和 CSS 构建我们的 dApp 界面,并使用带有 Ethers.js 的 JavaScript 与我们部署的智能合约进行交互。
构建后端
在这一部分中,我们将使用 Remix IDE 和 Metamask 在 Goerli 测试网上编写和部署我们的 Solidity 智能合约。
第 1 步 – Solidity IDE(Remix)
Remix IDE 是一个基于 Web 的 Solidity 编译器。它允许我们直接从浏览器编写、测试和部署我们的 Solidity 智能合约,无需任何配置或设置。
我们将使用 Remix IDE 来编写和部署我们的宠物智能合约。
单击此处[2]在浏览器上启动 Remix IDE:
第 2 步 – 编写智能合约
找到Remix 的“文件资源管理器”下的contracts文件夹并创建一个名为Pet_Contract.sol的新文件:
在Pet_Contract.sol文件中复制并粘贴下面的 Solidity 智能合约:
// SPDX-License-Identifier: MIT pragma solidity ^ 0.8.13; // 1. Creating a new pet contract contract Pet_Contract{ // 2. Declaring our smart contract state variables string public petName; string public petOwner; string public petAge; // 3. Creating a set pet function function setPet( string memory newPetName, string memory newPetOwner, string memory newPetAge ) public { petName = newPetName; petOwner = newPetOwner; petAge = newPetAge; } // 4. Creating a fetch pet function function getPet() public view returns ( string memory, string memory, string memory ){ return (petAge, petName, petOwner); } }上面的智能合约是我们在这里[3]编写的第一个智能合约的修改。我们正在创建一个setPet函数,该函数接受三个参数:petName、petOwner和petAge,并在调用setPet函数时将它们存储在内存中。
getPet函数将返回我们智能合约内存中的petAge、petName和petOwner状态的当前值。
可以在此处[4]找到智能合约的完整细分说明。
第 3 步 – 编译智能合约
请按照以下步骤在 Remix IDE 上编译您的 Solidity 智能合约:
• 确保将源文件保存为ctrl + s.• 然后,导航到“Solidity Compiler”部分:第 4 步 – 获取 Goerli Testnet Token
现在,我们要在 Goerli 测试网络上部署我们的宠物智能合约,我们需要一些假 ETH 来支付 gas 费。
请按照以下步骤为您的 Metamask 钱包获取免费的 Goerli Testnet 代币:
• 如果您还没有安装Metamask 。[5]• 接下来,导航到faucets.chain.link[6]。• 连接您的 Metamask 钱包:你可以在这里[7]查看其他地方以获得免费的 ETH 用于 dApp 开发。
第 5 步 – 部署智能合约
现在我们已经成功编译了我们的智能合约(参见步骤 3),并且我们的 Metamask 钱包中有一些 Goerli Testnet 代币,我们将在 Goerli 测试网络上部署我们的智能合约。
• 导航到“部署和运行事务”部分:第 6 步 – 测试智能合约
在这一步中,我们将在 Remix IDE 上测试我们的智能合约并与之交互。
• 点击setPet函数中的下拉箭头,展开输入框:我们的 Solidity 智能合约按预期运行。您可以继续使用不同的宠物名称、所有者姓名和年龄来测试智能合约。
构建前端
在这一部分中,我们将构建 dApp 的前端,它使用 Ethers.js 与我们的智能合约进行交互。
什么是 Ethers.js
Ethers.js[8]是web3.js[9]库的替代品。它是一个 JavaScript 库,允许开发人员与以太坊区块链进行交互。
第 1 步 – 安装 Ethers.js
在我们的项目中使用 Ethers.js 的最快方法是通过Ethers.js CDN[10]。
• index.html使用以下内容创建一个新文件:<!DOCTYPE html> <html lang=“en”> <head> <meta charset=“UTF-8” /> <meta http-equiv=“X-UA-Compatible” content=“IE=edge” /> <meta name=“viewport” content=“width=device-width, initial-scale=1.0” /> <!– Importing css styles –> <link rel=“stylesheet” href=“./index.css” /> <title>Pet dApp</title> </head> <body> <!– Importing Ethers.js script –> <script src=“https://cdn.ethers.io/lib/ethers-5.2.umd.min.js” type=“application/javascript” ></script> <!– Importing javascript file –> <script src=“./index.js”></script> </body> </html>在上面的代码中,我们导入了 Ethers.js CDN 脚本、我们的 CSS 以及我们稍后将创建的 JavaScript 文件。
您的 JavaScript 文件应在 Ethers.js CDN 脚本之后导入。
第 2 步 – 构建宠物表格
在这一步中,我们将创建一个表单,该表单将接受宠物的姓名、主人的姓名和年龄,以及一个“提交”按钮,以将详细信息发送到我们部署的智能合约。
在index.html文件的 body 标记中添加以下代码行:
<section class=“pet-form-section”> <section class=“section-header”> <h1>Pet Form</h1> </section> <!– Form –> <form> <label for=“pet-name”>Pet Name</label> <input type=“text” id=“pet-name” /> <label for=“pet-owner”>Pet Owner</label> <input type=“text” id=“pet-owner” /> <label for=“pet-age”>Pet Age</label> <input type=“number” id=“pet-age” /> <input type=“button” value=“Submit” id=“set-new-pet” /> </form> </section>接下来,创建一个新index.css文件,并添加以下代码:
/* Reset browser styles */ * { margin: 0; box-sizing: border-box; } body { font-family: Arial; line-height: 1.5; color: #333333; display: flex; justify-content: center; flex-direction: column; min-height: 100vh; max-width: 500px; margin: 0 auto; padding: 0 20px; } /* Header */ .section-header{ font-size: 1.5rem; font-weight: bold; margin-bottom: 1rem; background-color: #333333; color: #ffffff; padding: 0.5rem 1rem; border-radius: 0.25rem; text-align: center; } /* Pet Form Section */ form { padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); } label { font-size: 14px; display: block; margin-bottom: 5px; } input { width: 100%; border: 1px solid #cccccc; border-radius: 5px; padding: 10px; margin-bottom: 10px; } input[type=button]{ border: 1px solid #333333; background-color: #333333; color: #fff; cursor: pointer; }我们的宠物表单在浏览器中应该是这样的:
第 3 步 – 构建宠物详细信息部分
在这一步中,我们将创建宠物详细信息部分,该部分将显示存储在我们的智能合约内存中的当前宠物信息。
在宠物表格部分之后,在您的index.html文件中添加以下代码:
<!– Pet details section –> <section class=“pet-detail-section”> <section class=“section-header”> <h1>Pet Details</h1> </section> <section class=“pet-details”> <h3 class=“pet-detail-heading”> Pet Name: <span class=“pet-data pet-detail-name”></span> </h3> <h3 class=“pet-detail-heading”> Pet Owner: <span class=“pet-data pet-detail-owner”></span> </h3> <h3 class=“pet-detail-heading”> Pet Age: <span class=“pet-data pet-detail-age”></span> </h3> </section> <section class=“section-footer”> <button class=“show-pet-form-btn”>Set New Pet</button> <button class=“refresh-pet-details-btn”>Refresh</button> </section> </section>接下来,使用以下代码更新您的index.css文件:
/* Pet details section */ .pet-detail-section{ display: none; /* hidden by default */ } .pet-details { margin-bottom: 10px; padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); } .pet-detail-heading { font-size: 16px; margin-bottom: 10px; font-weight: 500; letter-spacing: 0.5px; } .section-footer{ display: flex; gap: 12px; } .show-pet-form-btn, .refresh-pet-details-btn{ width: 50%; padding: 10px; border: none; border-radius: 5px; color: #fff; cursor: pointer; } .show-pet-form-btn{ background-color: #4CAF50; } .refresh-pet-details-btn{ background-color: #00a8ff; }在上面的代码中,宠物详细信息部分将默认为hidden;只有在我们的智能合约上设置了宠物详细信息时,它才会可见。我们将在下一步中实现逻辑。
我们的宠物详细信息部分将如下所示:
第 4 步 – 创建签名者逻辑
在这一步中,我们将提示用户将他们的 Metamask 钱包地址与我们的 dApp 连接,然后他们才能与我们的智能合约进行交互。然后,用户将被识别为签名者,使用他们的钱包地址。
• 使用以下内容创建一个index.js新文件:// 1. Declare global variable to store the web3 instance let PetContract; // 2. Set contract address and ABI const Pet_Contract_Address = “”; const Pet_Contract_ABI = []; /* 3. Prompt user to sign in to MetaMask */ const provider = new ethers.providers.Web3Provider(window.ethereum, “goerli”); provider.send(“eth_requestAccounts”, []).then(() => { provider.listAccounts().then((accounts) => { const signer = provider.getSigner(accounts[0]); /* 3.1 Create instance of pet smart contract */ PetContract = new ethers.Contract( Pet_Contract_Address, Pet_Contract_ABI, signer ); }); });在上面的代码中:
1. 我们将PetContract变量设为全局变量,因为我们将在其他函数中重用它。
2. 在Pet_Contract_Address和Pet_Contract_ABI中提供你的智能合约地址和ABI。
• 您可以从 Remix “Solidity Compiler”部分获取您的智能合约 ABI 代码:3. 我们提示用户在他们的 MetaMask 钱包上连接到 Goerli 网络,我们的智能合约在该钱包中部署(参见后端 – 步骤 5)。
当用户访问我们的宠物表单页面时,他们将看到以下屏幕:
连接钱包地址后,我们现在可以通过PetContract变量访问智能合约中的setPet和getPet函数。
第 5 步 – 创建SetNewPet函数
在这一步中,我们将创建一个setNewPet函数,使用我们智能合约中的PetContract.setPet()函数将宠物的详细信息从宠物表单发送到我们的智能合约(请参阅后端 – 步骤 2)。
使用以下代码更新您的index.js文件:
// 4. Creating variables for reusable dom elements const petFormSection = document.querySelector(“.pet-form-section”); const showPetFormBtn = document.querySelector(“.show-pet-form-btn”); const petSection = document.querySelector(“.pet-detail-section”); const setPetButton = document.querySelector(“#set-new-pet”); const refreshBtn = document.querySelector(“.refresh-pet-details-btn”); /* 5. Function to set pet details */ const setNewPet = () => { // update button value setPetButton.value = “Setting Pet…”; /* 5.1 Get inputs from pet form */ const petNameInput = document.querySelector(“#pet-name”); const petOwnerInput = document.querySelector(“#pet-owner”); const petAgeInput = document.querySelector(“#pet-age”); // 5.2 Getting values from the inputs petName = petNameInput.value; petOwner = petOwnerInput.value; petAge = petAgeInput.value; /* 5.3 Set pet details in smart contract */ PetContract.setPet(petName, petOwner, petAge) .then(() => { // update button value setPetButton.value = “Pet Set…”; /* 5.4 Reset form */ petNameInput.value = “”; petOwnerInput.value = “”; petAgeInput.value = “”; // update button value setPetButton.value = “Set Pet”; /* 5.5 Get pet details from smart contract */ getCurrentPet(); }) .catch((err) => { // If error occurs, display error message setPetButton.value = “Set Pet”; alert(“Error setting pet details” + err.message); }); }; /* Function to set pet details on click of button */ setPetButton.addEventListener(“click”, setNewPet);第6步 – 创建getCurrentPet函数
在这一步,我们将创建getCurrentPet函数,使用智能合约中的PetContract.getPet()函数,获取智能合约内存中最后一个宠物的详细信息(见后台–第2步)。
用下面的代码更新你的index.js文件。
/* 6. Function to get pet details */ const getCurrentPet = async () => { setPetButton.value = “Getting Pet…”; /* 6.1 Get pet details from smart contract */ const pet = await PetContract.getPet(); /* 6.2 Display the pet details section 6.2.1 Hide the pet form in DOM */ petSection.style.display = “block”; petFormSection.style.display = “none”; /* 6.3 Pet is an array of 3 strings [petName, petOwner, petAge] */ const petName = pet[0]; const petOwner = pet[1]; const petAge = pet[2]; /* 6.4 Display pet details in DOM */ document.querySelector(“.pet-detail-name”).innerText = petName; document.querySelector(“.pet-detail-owner”).innerText = petOwner; document.querySelector(“.pet-detail-age”).innerText = petAge; };最后,我们将添加一个函数,让用户返回到宠物表格,并添加另一个函数来刷新宠物的详细信息。
在你的index.js文件中添加以下几行代码。
/* 7. Function to show the pet form on click of button */ showPetFormBtn.addEventListener(“click”, () => { petSection.style.display = “none”; petFormSection.style.display = “block”; setPetButton.value = “Submit”; }); /* 8. Function to refresh pet details */ refreshBtn.addEventListener(“click”, (e) => { e.target.innerText = “Refreshing…”; getCurrentPet().then(() => { e.target.innerText = “Refreshed”; setTimeout(() => { e.target.innerText = “Refresh”; }, 2000); }); });测试我们的dApp
现在我们的dApp的代码已经准备好了,我们可以继续测试我们的实现,如下所示。
这个项目的完整源代码可以在这个资源库中找到。
总结
在本教程中,我们学习了如何使用 Ether.js 从前端应用程序中与 Solidity 智能合约进行交互。
引用链接
[1] 您可以在此处: https://web3.hashnode.com/solidity-tutorial-how-to-build-your-first-smart-contract[2] 此处: https://remix.ethereum.org/[3] 这里: https://web3.hashnode.com/solidity-tutorial-how-to-build-your-first-smart-contract[4] 此处: https://web3.hashnode.com/solidity-tutorial-how-to-build-your-first-smart-contract[5] Metamask 。: https://metamask.io/[6] faucets.chain.link: https://faucets.chain.link/[7] 你可以在这里: https://web3.hashnode.com/link-to-5-places-to-get-testnet-tokens[8] Ethers.js: https://docs.ethers.io/v5/getting-started/[9] web3.js: https://web3js.readthedocs.io/en/v1.7.3/getting-started.html[10] Ethers.js CDN: https://docs.ethers.io/v5/getting-started/#importing
发表回复