本文详细介绍了如何将最新版本的web3.js 4.x集成到HTML中,从连接MetaMask、显示账户信息、发送交易到与智能合约交互,逐步指导读者完成Dapp开发的基础操作。
最新版本的 web3.js,4.x,已刚刚推出。在本指南中,我们将深入探讨如何将 web3.js 集成到 HTML 中,以转移、铸造 NFT 以及查询区块链。web3.js v 1.10.0 文档中的一些特性将被弃用,因此我们已经汇编了此 web3.js 教程中最新的方法。我们将避免使用像 React js 这样的框架。在不使用任何框架的情况下,我们必须深入理解 Dapp 开发中的基本概念。这种动手实践的方法将帮助你为区块链开发技能打下坚实的基础。只需按照逐步说明,复制粘贴代码,并阅读提供的代码片段。以下是本教程的内容:
我们在整个教程中提供示例和视觉效果,以说明讨论的概念。
本指南向你介绍了迁移到 Web3.js 4.x 一些重要的代码更改。
// Web3.js 1.x 导入
const Web3 = require('web3');
// Web3.js 4.x 导入
const { Web3 } = require('web3');
在 Web3.js 4.x 中,我们已切换到解构语法以导入 Web3 对象。
在 Web3.js 4.x 中,web3.givenProvider 和 web3.currentProvider 的默认值为 undefined。此前,当没有提供者实例化 web3 时,它们的值为 null。
// 在 Web3.js 4.x 中默认值为 undefined,之前为 null
console.log(web3.givenProvider);
console.log(web3.currentProvider);
如果你使用 MetaMask,建议将 window.ethereum 直接传递给 Web3 构造函数,而不是使用 Web3.givenProvider。
// 使用 MetaMask 提供者实例化 Web3
const web3 = new Web3(window.ethereum);
在函数中不再支持回调,除事件监听器外。以下是 Web3.js 4.x 中无效使用回调的示例,从前版本 1 是有效的:
// 在 Web3.js 4.x 中无效
web3.eth.getBalance("0x407d73d8a49eeb85d32cf465507dd71d507100c1", function(err, result) {
if (err) {
console.log(err);
} else {
console.log(result);
}
});
在 Web3.js 4.x 中,你必须使用 new 关键字来实例化 web3.eth.Contract() 对象。
// Web3.js 1.x
const contract = web3.eth.Contract(jsonInterface, address);
// Web3.js 4.x
const contract = new web3.eth.Contract(jsonInterface, address);
在 Web3.js 4.x 中,getBalance 返回的结果是一个 BigInt,而非字符串。有关完整的迁移指南,请访问 web3.js 文档 : <https://web3js.org/#/>
创建一个文件夹,目录如下:
├── directory/
│ ├── index.html
│ ├── main.js
│ ├── styles.css
在哪里下载 web3.js:
在以下地方查找此项目:
现在我们将创建一个按钮,以建立与 MetaMask 的连接。前端代码将放在 index.html 中,web3.js JavaScript 代码放在 main.js 中。
以下代码包含:
<!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" />
<title>Web3.js 示例</title>
<link rel="stylesheet" href="./styles.css" />
<script
src="https://cdnjs.cloudflare.com/ajax/libs/web3/4.0.1-alpha.5/web3.min.js"
integrity="sha512-NfffVWpEqu1nq+658gzlJQilRBOvjs+PhEKSjT9gkQXRy9OfxI2TOXr33zS7MgGyTpBa5qtC6mKJkQGd9dN/rw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
</head>
<body>
<main>
<p id="status1" class="status" style="color: red">未连接</p>
<p id="status2" style="color: white"></p>
<div class="maincontainer">
<!-- 连接钱包 -->
<div class="container">
<div class="buttonswrapper">
<div class="buttonswrapperGrid">
<button id="metamask" class="button28">MetaMask</button>
</div>
</div>
</div>
<!-- 账户信息按钮 -->
<!-- 发送交易 -->
<!-- 铸造 -->
</div>
</main>
<script src="./main.js"></script>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/4.0.1-alpha.5/web3.min.js"
integrity="sha512-NfffVWpEqu1nq+658gzlJQilRBOvjs+PhEKSjT9gkQXRy9OfxI2TOXr33zS7MgGyTpBa5qtC6mKJkQGd9dN/rw=="
crossorigin="anonymous" referrerpolicy="no-referrer">
该脚本标签用于加载 web3.js CDN 库。
这相当于 const { Web3 } = require(‘web3’);
<script src="./main.js"></script>
这将我们的 “main.js” 函数加载到 HTML 中。最佳实践是将其放在 body 的底部,以避免在渲染前访问 DOM 元素。
从 Github 复制粘贴 css 代码:Github 文件链接:<https://github.com/AymericRT/web3.js/blob/master/styles.css>
在 main.js 文件中,我们将加入必要的 JavaScript 功能来激活 MetaMask 按钮。下面将有三个主要功能:
请将上述说明与以下代码对照。
const web3 = new Web3(window.ethereum);
// 检查 MetaMask 是否可用的函数
async function checkMetaMaskAvailability() {
if (window.ethereum) {
try {
// 请求访问 MetaMask 帐户
await window.ethereum.request({ method: "eth_requestAccounts" });
return true;
} catch (err) {
console.error("连接 MetaMask 失败:", err);
return false;
}
} else {
console.error("未找到 MetaMask");
return false;
}
}
// MetaMask 按钮的事件监听器
document.getElementById("metamask").addEventListener("click", async () => {
const metaMaskAvailable = await checkMetaMaskAvailability();
if (metaMaskAvailable) {
await ConnectWallet();
} else {
// 未找到 MetaMask
console.error("未找到 MetaMask");
// 更新状态
document.getElementById("status1").innerText = "未找到 MetaMask";
document.getElementById("status1").style.color = "red";
}
});
// 连接到 MetaMask 的函数
async function ConnectWallet() {
try {
// 请求访问 MetaMask 帐户
await window.ethereum.request({ method: "eth_requestAccounts" });
// 更新状态
document.getElementById("status1").innerText = "已连接到 MetaMask";
document.getElementById("status1").style.color = "green";
} catch (err) {
// 处理错误
console.error("连接 MetaMask 失败:", err);
// 更新状态
document.getElementById("status1").innerText = "连接 MetaMask 失败";
document.getElementById("status1").style.color = "red";
}
}
const web3 = new Web3(window.ethereum);
web3 是 Web3.js 库的新实例。
通过将 window.ethereum 赋值给 Web3 构造函数,web3 变量使用提供的以太坊提供程序与以太坊网络进行交互。
await window.ethereum.request({ method: "eth_requestAccounts" });
此代码请求应用程序使用 eth_requestAccounts 方法访问用户的以太坊帐户。
在终端中,导航到你的目录并运行此 Python 命令,它将自动在 8000 端口部署你的服务器。
python -m SimpleHTTPServer 8000
你的网站在 localhost:8000 上应该如下所示:
现在我们的 MetaMask 已连接,我们能够查询区块链以获取重要的账户详细信息,如连接的账户地址、余额和当前网络费用。我们将创建一个按钮用于该功能,命名为 “Account_Information”。
在该注释下插入 “account_Information” 按钮。
<!-- 账户信息按钮 -->
<div class="secondcontainer">
<button id="accountbutton" class="button49">
账户信息
</button>
</div>
我们将编写一个函数来从 MetaMask 中获取数据。数据显示如下:
所需的两个主要函数:
// 账户信息的事件监听器
document.getElementById("accountbutton").addEventListener("click", async () => {
const metaMaskAvailable = await checkMetaMaskAvailability();
if (metaMaskAvailable) {
await AccountInformation();
}
});
// 调用账户信息的函数
async function AccountInformation() {
const account = await web3.eth.getAccounts();
const from = account[0];
const balanceInWei = await web3.eth.getBalance(from);
const balanceInEth = web3.utils.fromWei(balanceInWei, "ether");
const gasPrice = await web3.eth.getGasPrice();
const gasPriceInEth = web3.utils.fromWei(gasPrice, "ether");
// 显示账户信息
document.getElementById("status2").innerText ="账户地址: " + from + "
余额: " + balanceInEth + " ETH" +"
汽油价格: " + gasPriceInEth;
document.getElementById("status2").style.color = "white";
}
const account = await web3.eth.getAccounts() //返回账户列表
const from = account[0]; //获取列表中的第一个账户
getAccounts() 方法返回节点控制的账户列表。实际上,它返回连接的 MetaMask 账户。
列表中的第一个元素将代表主要连接账户。
web3.eth.getBalance(from)
getBalance() 方法获取传递到参数的账户地址的余额,单位为 Wei。请注意,1 Ether 等于 10^18 Wei。
web3.eth.getGasPrice()
getGasPrice() 方法检索以太坊网络上交易的当前汽油价格,单位为 Wei。
web3.utils.fromWei(balanceInWei, "ether")
该方法将你的余额从 Wei 单位转换为 Ether。如果你想将其转换为 GWEI,只需将“ether”更改为“gwei”。
发送交易需要以下参数:
我们的发送者地址将是默认连接的账户。对于接收者地址和指定金额,我们将生成一个带有两个输入字段和一个 “发送” 按钮的表单,该按钮将启动转账。
在 <!— 发送交易 —> 注释下插入表单。
<!-- 发送交易 -->
<form>
<div class="inputcontainer">
<input
id="addressinput"
class="myinput"
placeholder="地址 0x0..."
/>
<input
id="amountinput"
class="myinput"
placeholder="金额 ether..."
/>
</div>
<div class="buttoncontainer">
<button type="button" id="sendButton" class="button64">发送</button>
</div>
</form>
为了激活发送交易功能,我们需要创建两个主要函数。
// 发送交易的事件监听器
document.getElementById("sendButton").addEventListener("click", async () => {
const metaMaskAvailable = await checkMetaMaskAvailability();
if (metaMaskAvailable) {
await SendFunction();
}
});
// 调用发送功能的函数
async function SendFunction() {
// 获取输入值
const to = document.getElementById("addressinput").value;
const amount = document.getElementById("amountinput").value;
// 检查是否提供了接收地址和金额
if (!to || !amount) {
console.error("接收地址和金额是必填的");
return;
}
// 将金额转换为 wei (1 ether = 10^18 wei)
const amountWei = web3.utils.toWei(amount, "ether");
// 从 MetaMask 获取选定的账户
const accounts = await web3.eth.getAccounts();
const from = accounts[0];
// 创建交易对象
const transaction = {
from: from,
to: to,
value: amountWei,
};
// 发送交易
try {
const result = await web3.eth.sendTransaction(transaction);
console.log("交易结果:", result);
// 更新状态
document.getElementById("status2").innerText ="交易成功发送";
document.getElementById("status2").style.color = "green";
} catch (err) {
// 处理错误
console.error("发送交易失败:", err); // 更新状态
document.getElementById("status2").innerText = "发送交易失败";
document.getElementById("status2").style.color = "red";
}
}
await web3.eth.sendTransaction(transaction)
sendTransaction 只接受一个参数,transaction。如果交易不成功,将抛出错误。
transaction 是一个包含待发送交易详细信息的对象。格式如下:
{
from: "发送者地址",
to: "接收者地址",
value: "发送金额(单位:WEI)",
};
你的网站应如下所示:
在最后一部分,你将学习如何使用 web3.eth.Contract 对象与智能合约互动。这包括读取数据、写入数据和处理事件。
这里有一个你将要处理的合约:
// Rareskills 合约
pragma solidity ^0.8.0;
contract RareSkills {
mapping(address => uint256) public balances;
uint256 public totalSupply;
event Mint(address indexed to, uint256 amount);
function mint(uint256 amount) public {
balances[msg.sender] += amount;
totalSupply += amount;
emit Mint(msg.sender, amount);
}
}
此合约已部署在 Mumbai Polygon 网络上。你可以通过以下链接进行查看:<https://mumbai.polygonscan.com/>
首先在该注释下插入 “mint” 按钮。
<!-- 铸造 NFT -->
<div class="mintcontainer">
<button id="mintactual" class="button49">铸造</button>
<p id="demo3"></p>
</div>
在 web3.js 中,我们首先需要实例化合约才能与之互动。实例化合约有两个核心元素:
我们的 JavaScript 将有两个主要函数:
我们将深入探讨代码片段中的每个细节。
// 铸造按钮的事件监听器
document.getElementById("mintactual").addEventListener("click", async () => {
const metaMaskAvailable = await checkMetaMaskAvailability();
if (metaMaskAvailable) {
await mintNFT();
}
});
// 合约详细信息
const contractAddress = "0x88d099496C1A493A36E678062f259FE9919B9150"; // 硬编码的合约地址
const contractABI = [
// 硬编码的 ABI
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "to",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "Mint",
type: "event",
},
{
inputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
name: "balances",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "totalSupply",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
];
// 铸造的函数
async function mintNFT() {
// 获取连接的账户
const accounts = await web3.eth.getAccounts();
const from = accounts[0];
// 实例化合约
const contract = new web3.eth.Contract(contractABI, contractAddress);
try {
// 调用合约方法
const result = await contract.methods.mint(1).send({ from: from , value: 0});
const _totalSupply = await contract.methods.totalSupply().call();
document.getElementById("status2").innerText = "总供应量: " + _totalSupply;
document.getElementById("status2").style.color = "green";
document.getElementById("status3").innerText = "铸造成功";
document.getElementById("status3").style.color = "green";
// 事件监听器
contract
.getPastEvents("Mint", {
fromBlock: "latest", // 从最新区块开始
})
.then((results) => console.log(results));
} catch (err) {
console.error("铸造失败:", err);
document.getElementById("status3").innerText = "铸造失败";
document.getElementById("status3").style.color = "red";
}
}
const contract = new web3.eth.Contract(contractABI, contractAddress);
我们使用 web3.eth.Contract 构造函数实例化一个 RareSkills 合约的新实例,传入 contractABI 和 contractAddress 作为参数。这个实例允许我们使用 contractAddress 直接与位于此地址上的智能合约互动,使用在 contractABI 中定义的接口。与智能合约互动要求我们根据修改状态或查看状态的方法调用 .send() 或 .call() 函数。
web3.js .send()
contract.methods.mint(1).send({ from: from , value: 0});
send() 方法用于执行改变合约状态的函数。由于我们的 mint 函数会增加合约的总供应量,因此它是一个状态改变的函数。传递给 send() 方法的对象 { from: from, value: 0 } 指定了交易的详细信息。
contract.methods.totalSupply().call()
call() 合约方法用于执行不改变合约状态的函数。由于 totalSupply() 方法是一个“查看”函数,因此使用 call() 方法。
contract
.getPastEvents("Mint", {fromBlock: "latest",}).then((results) => console.log(results));
getPastEvents 是在 contract 对象上调用的事件处理方法,用于获取最后发出的事件。
第一个参数是事件名称,在我们的例子中是“Mint ”事件。
第二个参数是选项对象。在本例中,将 fromBlock 设置为“latest”,以从当前区块获取事件。更多内容在此。
results 数组记录到控制台,应该如下所示:
最终网站效果:
恭喜你完成本 web3.js 教程!
最初发布于 2023 年 5 月 26 日
- 原文链接: rareskills.io/post/web3-...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!