Web3.js 示例最新版本 4.x转账、铸造与查询区块链

本文详细介绍了如何将最新版本的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 部分:连接到 MetaMask
  • 第 2 部分:显示账户信息
  • 第 2 部分:发送交易
  • 第 3 部分:与智能合约互动

我们在整个教程中提供示例和视觉效果,以说明讨论的概念。

Web3.js 4.x 迁移亮点

本指南向你介绍了迁移到 Web3.js 4.x 一些重要的代码更改。

重大变化

1. 模块导入

// Web3.js 1.x 导入
const Web3 = require('web3');

// Web3.js 4.x 导入
const { Web3 } = require('web3');

在 Web3.js 4.x 中,我们已切换到解构语法以导入 Web3 对象。

2. 默认提供者

在 Web3.js 4.x 中,web3.givenProviderweb3.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);

3. 函数中的回调

在函数中不再支持回调,除事件监听器外。以下是 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);
        }
});

小变化

1. 实例化合约

在 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);

2. getBalance

在 Web3.js 4.x 中,getBalance 返回的结果是一个 BigInt,而非字符串。有关完整的迁移指南,请访问 web3.js 文档 : <https://web3js.org/#/>

入门:Web3.js

创建一个文件夹,目录如下:

├── directory/
│   ├── index.html
│   ├── main.js
│   ├── styles.css

在哪里下载 web3.js:

  • CDN 链接:web3.js

在以下地方查找此项目:

第 1 部分:连接到 MetaMask

现在我们将创建一个按钮,以建立与 MetaMask 的连接。前端代码将放在 index.html 中,web3.js JavaScript 代码放在 main.js 中。

Index.html

以下代码包含:

  • HTML 骨架
  • Meta Mask 按钮
  • web3.js CDN 包脚本标签
  • main.js 脚本标签
&lt;!DOCTYPE html>
&lt;html lang="en">
      &lt;head>
            &lt;meta charset="UTF-8" />
            &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" />
            &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" />
            &lt;title>Web3.js 示例&lt;/title>
            &lt;link rel="stylesheet" href="./styles.css" />
            &lt;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"
            >&lt;/script>
      &lt;/head>
      &lt;body>
            &lt;main>
                  &lt;p id="status1" class="status" style="color: red">未连接&lt;/p>
                  &lt;p id="status2" style="color: white">&lt;/p>
                  &lt;div class="maincontainer">

                        &lt;!-- 连接钱包 -->
                        &lt;div class="container">
                              &lt;div class="buttonswrapper">
                                    &lt;div class="buttonswrapperGrid">
                                          &lt;button id="metamask" class="button28">MetaMask&lt;/button>
                                    &lt;/div>
                              &lt;/div>
                        &lt;/div>

                        &lt;!-- 账户信息按钮 -->

                        &lt;!-- 发送交易 -->

                        &lt;!-- 铸造 -->

                  &lt;/div>
            &lt;/main>
            &lt;script src="./main.js">&lt;/script>
      &lt;/body>
&lt;/html>

HTML 代码片段解释

&lt;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’);

&lt;script src="./main.js">&lt;/script>

这将我们的 “main.js” 函数加载到 HTML 中。最佳实践是将其放在 body 的底部,以避免在渲染前访问 DOM 元素。

Styles.css

从 Github 复制粘贴 css 代码:Github 文件链接:<https://github.com/AymericRT/web3.js/blob/master/styles.css>

Main.js 文件

在 main.js 文件中,我们将加入必要的 JavaScript 功能来激活 MetaMask 按钮。下面将有三个主要功能:

  • “metamask” 按钮的事件监听器
    • 在点击事件中,它检查 MetaMask 有没有可用并且已连接。
    • 如果可用,它调用 ConnectWallet 函数。
    • 否则,它将错误消息记录到控制台,并更新网页状态以指示缺少 MetaMask。
  • checkMetaMaskAvailability()
    • 该函数用于确定 MetaMask 浏览器扩展是否存在并已连接。
    • 它检查 window.ethereum 的存在,并尝试通过 ConnectMetaMask() 请求访问 MetaMask 帐户。
    • 如果帐户访问被授予,该函数返回 true ,表示连接成功。否则,它记录一条错误消息并返回 false
  • ConnectMetaMask();
    • 该函数负责连接 MetaMask。
    • 它尝试使用 eth_requestAccounts 请求访问 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";
    }
}

重要代码片段:连接到 MetaMask

web3.js window.ethereum

const web3 = new Web3(window.ethereum);

web3 是 Web3.js 库的新实例。

通过将 window.ethereum 赋值给 Web3 构造函数,web3 变量使用提供的以太坊提供程序与以太坊网络进行交互。

web3.js 请求帐户

await window.ethereum.request({ method: "eth_requestAccounts" });

此代码请求应用程序使用 eth_requestAccounts 方法访问用户的以太坊帐户。

运行你的服务器

在终端中,导航到你的目录并运行此 Python 命令,它将自动在 8000 端口部署你的服务器。

python -m SimpleHTTPServer 8000

你的网站在 localhost:8000 上应该如下所示:

Web3.js 按钮连接到提供者,metamask

第 2 部分:显示账户信息

现在我们的 MetaMask 已连接,我们能够查询区块链以获取重要的账户详细信息,如连接的账户地址、余额和当前网络费用。我们将创建一个按钮用于该功能,命名为 “Account_Information”。

Index.html

在该注释下插入 “account_Information” 按钮。

&lt;!-- 账户信息按钮 -->
&lt;div class="secondcontainer">
    &lt;button id="accountbutton" class="button49">
        账户信息
    &lt;/button>
&lt;/div>

Main.js

我们将编写一个函数来从 MetaMask 中获取数据。数据显示如下:

  • 账户地址
  • 账户余额
  • 当前网络费用

所需的两个主要函数:

  • 账户信息按钮的事件监听器
    • 在点击事件中,它检查 MetaMask 是否可用且已连接。
    • 如果可用,它调用 AccountInfo() 函数。
    • 否则,它记录错误并更新网页状态。
  • AccountInformarion();
    • 此函数负责从以太坊钱包获取数据。
    • 它通过 web3.eth.getAccounts() 方法检索账户地址。
    • 账户余额通过 web3.eth.getBalance(from) 方法获取。
    • 此外,它通过调用 web3.eth.getGasPrice() 方法检索当前汽油价格。
// 账户信息的事件监听器 
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";
}

重要代码片段:显示账户信息

web3.js 获取账户

const account = await web3.eth.getAccounts() //返回账户列表
const from = account[0]; //获取列表中的第一个账户

getAccounts() 方法返回节点控制的账户列表。实际上,它返回连接的 MetaMask 账户。

列表中的第一个元素将代表主要连接账户。

web3.js 获取余额

web3.eth.getBalance(from)   

getBalance() 方法获取传递到参数的账户地址的余额,单位为 Wei。请注意,1 Ether 等于 10^18 Wei。

web3.js 获取汽油价格

web3.eth.getGasPrice() 

getGasPrice() 方法检索以太坊网络上交易的当前汽油价格,单位为 Wei。

web3.utils.fromWei(balanceInWei, "ether")

该方法将你的余额从 Wei 单位转换为 Ether。如果你想将其转换为 GWEI,只需将“ether”更改为“gwei”。

Web3.js 按钮检索账户地址、账户余额、当前汽油费用

第 3 部分:发送以太交易

发送交易需要以下参数:

  • 发送者地址
  • 接收者地址
  • 指定金额

我们的发送者地址将是默认连接的账户。对于接收者地址和指定金额,我们将生成一个带有两个输入字段和一个 “发送” 按钮的表单,该按钮将启动转账。

Index.html

<!— 发送交易 —> 注释下插入表单。

&lt;!-- 发送交易 -->
&lt;form>
      &lt;div class="inputcontainer">
            &lt;input
                  id="addressinput"
                  class="myinput"
                  placeholder="地址 0x0..."
            />
            &lt;input
                  id="amountinput"
                  class="myinput"
                  placeholder="金额 ether..."
            />
      &lt;/div>
      &lt;div class="buttoncontainer">
            &lt;button type="button" id="sendButton" class="button64">发送&lt;/button>
      &lt;/div>
&lt;/form>

Main.js

为了激活发送交易功能,我们需要创建两个主要函数。

  • 发送交易按钮的事件监听器
    • 在点击事件中,它检查 MetaMask 是否可用且已连接。
    • 如果可用,它调用 SendFunction() 函数。
    • 否则,它记录错误并更新网页状态。
  • SendFunction()
    • 此函数负责发送交易。
    • 它通过 DOM 操作检索接收者地址和指定金额。
    • 此外,创建一个包含交易细节的 JavaScript 对象:from、to、amount;在 transaction 中。
    • 通过 web3.eth.sendTransaction(transaction) 在以太坊网络上发送带有提供的 transaction 交易细节的交易。
// 发送交易的事件监听器
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";
    }
}

重要代码片段:发送交易

web3.js 发送交易

await web3.eth.sendTransaction(transaction)

sendTransaction 只接受一个参数,transaction。如果交易不成功,将抛出错误。

transaction 是一个包含待发送交易详细信息的对象。格式如下:

{
    from: "发送者地址",
    to: "接收者地址",
    value: "发送金额(单位:WEI)",
};

你的网站应如下所示:

Web3.js 表单域发送以太交易

第 4 部分:与智能合约互动

在最后一部分,你将学习如何使用 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/>

Index.html

首先在该注释下插入 “mint” 按钮。

&lt;!-- 铸造 NFT -->
&lt;div class="mintcontainer">
    &lt;button id="mintactual" class="button49">铸造&lt;/button>
    &lt;p id="demo3">&lt;/p>
&lt;/div>

Main.js

在 web3.js 中,我们首先需要实例化合约才能与之互动。实例化合约有两个核心元素:

  • 合约地址: 0x88d099496C1A493A36E678062f259FE9919B9150
  • 合约 ABI: 在这里找到

我们的 JavaScript 将有两个主要函数:

  • 铸造按钮的事件监听器
    • 在点击事件中,它检查 MetaMask 是否可用且已连接。
    • 如果可用,它调用 mintNFT() 函数。
    • 否则,它记录错误并更新网页状态。
  • mintNFT()
    • 该函数负责与 RareSkills 合约 互动。
    • 使用 web3.eth.Contract 对象实例化合约,传递 contractABIcontractAddress 作为参数。
    • 通过读取 totalSupply 函数检索合约的总供应量。
    • 通过执行 mint(uint256 amount) 函数铸造合约数据。
    • 监听“Mint 事件”的发生并进行处理。

我们将深入探讨代码片段中的每个细节。

// 铸造按钮的事件监听器
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";
    }
}

重要代码片段

web3.js 合约

const contract = new web3.eth.Contract(contractABI, contractAddress); 

我们使用 web3.eth.Contract 构造函数实例化一个 RareSkills 合约的新实例,传入 contractABIcontractAddress 作为参数。这个实例允许我们使用 contractAddress 直接与位于此地址上的智能合约互动,使用在 contractABI 中定义的接口。与智能合约互动要求我们根据修改状态或查看状态的方法调用 .send().call() 函数。

web3.js .send()

contract.methods.mint(1).send({ from: from , value: 0}); 

send() 方法用于执行改变合约状态的函数。由于我们的 mint 函数会增加合约的总供应量,因此它是一个状态改变的函数。传递给 send() 方法的对象 { from: from, value: 0 } 指定了交易的详细信息。

  • from: 表示交易发送者的地址。
  • value: 表示与交易一起发送的以太金额。在此情况下,没有发送任何以太。

web3.js .call()

contract.methods.totalSupply().call()

call() 合约方法用于执行不改变合约状态的函数。由于 totalSupply() 方法是一个“查看”函数,因此使用 call() 方法。

web3.js 事件监听器()

contract
      .getPastEvents("Mint", {fromBlock: "latest",}).then((results) => console.log(results));

getPastEvents 是在 contract 对象上调用的事件处理方法,用于获取最后发出的事件。

  1. 第一个参数是事件名称,在我们的例子中是“Mint ”事件。

  2. 第二个参数是选项对象。在本例中,将 fromBlock 设置为“latest”,以从当前区块获取事件。更多内容在此。

results 数组记录到控制台,应该如下所示:

Web3.js 事件处理输出结果示例

最终网站效果:

Web3.js 铸造按钮,与智能合约互动

恭喜你完成本 web3.js 教程!

最初发布于 2023 年 5 月 26 日

  • 原文链接: rareskills.io/post/web3-...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/