前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >web3.js之以太坊交互

web3.js之以太坊交互

作者头像
Maic
发布于 2025-02-12 06:22:54
发布于 2025-02-12 06:22:54
13900
代码可运行
举报
文章被收录于专栏:Web技术学苑Web技术学苑
运行总次数:0
代码可运行

web3.js是一个与以太坊交互的重要库,在上一篇介绍的文章中viem也是与以太坊交互的一个库,从功能上讲各有千秋,比起viem,总体包体积web3.js更大,性能也没有viem更好,但很多dapp都是直接使用web3.js,所有这些并不影响众多dapp使用它与以太坊生态的交互

查看区块

我们主要看下使用web3.js如何查看区块

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import { Web3 } from "web3";
// https://mainnet.infura.io/v3/5920517516ba405d8b898b80f8bc4243
// https://eth.llamarpc.com
const web3 = new Web3("https://eth.llamarpc.com");

const app = document.getElementById("app");
let html = "";
console.log("web3 start");
const getBlockNumber = async () => {
  const blockNum = await web3.eth.getBlockNumber();
  console.log(`blockNum:`, blockNum);
  html += `blockNum:${blockNum}<br/>`;
};
const getChinId = async () => {
  const chainId = await web3.eth.getChainId();
  console.log(`chainId:`, chainId);
  html += `chainId:${chainId}<br/>`;
};

const getBlance = async () => {
  const res = await web3.eth.getBalance(
    "0x5A39756bAE97685917a292B33ddFb2B54DF1e806"
  );
  html += `blance:${res}<br/>`;
  console.log(`blance:`, res);
};

// https://mainnet.infura.io/v3/5920517516ba405d8b898b80f8bc4243

Promise.all([getBlockNumber(), getChinId(), getBlance()]).then(() => {
  app.innerHTML = html;
});

console.log("222");

我们会发现查询这三个数据都是向https://eth.llamarpc.com/发送三次不一样的请求,从而拿到了对应的数据

provider

所有的钱包交互的provider

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import { Web3 } from "web3";
let providers = await Web3.requestEIP6963Providers();

我们发现如果你浏览器安装了钱包会有以下钱包列表

唤起钱包登录

我们通过web3.requestEIP6963Providers这个接口可以检测出我们的浏览器安装了哪些钱包,并渲染出来了,因此我们通过指定钱包唤起钱包登录

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import { Web3 } from "web3";
let providers = await Web3.requestEIP6963Providers();
const app = document.getElementById("app");
const walletList = app.querySelector(".wallet-list");
const wallets = [];
for (const [key, value] of providers) {
  console.log(value, "value");
  wallets.push(value);
  console.log(value.info.name);
  // if (value.info.name === "MetaMask") {
  //   const web3 = new Web3(value.provider);
  //   console.log(web3);
  //   // now you can use web3 object with injected provider
  // }
}
console.log(wallets, "wallets");
wallets.forEach((wallet) => {
  const walletItem = document.createElement("div");
  const icon = document.createElement("img");
  const label = document.createElement("span");
  icon.src = wallet.info.icon;
  icon.style.width = "30px";
  icon.style.height = "30px";
  label.textContent = wallet.info.name;
  walletItem.style.display = "flex";
  walletItem.style.alignItems = "center";
  walletItem.setAttribute("wallet-name", wallet.info.name);
  walletItem.appendChild(icon);
  walletItem.appendChild(label);
  walletList.appendChild(walletItem);

  walletItem.addEventListener("click", async () => {
    if (wallet.info.name === "MetaMask") {
      // 链接钱包
      const accounts = await window.ethereum.request({
        method: "eth_requestAccounts",
      });
      console.log(accounts);
    }
    // 链接钱包
    if (wallet.info.name === "OKX Wallet") {
      await window.okxwallet.request({
        method: "eth_requestAccounts",
      });
    }

    // now you can use web3 object with injected provider
  });
});

对于不同钱包唤起钱包登录主要是window.ethereum.request或者window.okxwallet.request这两个接口,本质上主要方法是eth_requestAccounts

创建钱包

我们可以借助web3.js创建钱包

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
    ...
    const app = document.getElementById("app");
    const createBtn = app.querySelector(".create-wallet");
    let account = null;
    createBtn.addEventListener("click", () => {
        account = web3.eth.accounts.create();
        console.log(account);
        createBtn.parentNode.querySelector(".address").innerText = account.address;
        createBtn.parentNode.querySelector(".privateKey").innerText =
          account.privateKey;
   });

我们会发现使用web3.eth.accounts创建的地址,会返回一个对象,这个对象里包含了钱包地址,以及privateKeysignsignTransactionaddress

sign

我们通过 web3 创建了地址,因此我们可以进行sign操作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
  ...
  signBtn.addEventListener("click", async () => {
    if (!account) {
      alert("请先创建钱包");
      return;
    }
    console.log(account);
    const message = "Hello, World!";
    const signature = await account.sign(message);
    console.log(signature);
    signBtn.parentNode.querySelector(".signature").innerText =
      signature.messageHash;
  });

返回的messageHash就是以下的0xc8ee0d506e864589b799a645ddb88b08f5d39e8049f9f702b3b61fa15e55fc73

signTransaction

当我们进行 A 钱包与 B 钱包进行转账时,其实主要发生了以下几个步骤eth_getTransactionCounteth_chainIdnet_versioneth_estimateGas

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
  ...
  const signTrans = app.querySelector(".signTransaction");
  signTrans.addEventListener("click", async () => {
    if (!account) {
      alert("请先创建钱包");
      return;
    }
    const tx = {
      from: account.address,
      to: "0x5A39756bAE97685917a292B33ddFb2B54DF1e806",
      value: web3.utils.toWei("1", "ether"), // 1 ether
    };
    const signedTx = await account.signTransaction(tx);
    console.log(signedTx);
  });

sendTransaction

主要是发送交易,在sendTransaction主要会产生以下几个阶段

  • sending将交易发送到网络
  • sent交易已发送到网络
  • transactionHash已生成交易哈希
  • receipt交易已包含在区块中
  • confirmation交易区块已经被确认
  • error交易遇到错误
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
  ...
   const transSigin = app.querySelector(".transSigin");
  transSigin.addEventListener("click", async () => {
    try {
      const web3 = new Web3("http://127.0.0.1:8545/");
      // create a new Web3.js account object with the private key of a Hardhat test account
      const privateKey =
        "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
      // the account is created with a wallet, which makes it easier to use
      const sender = web3.eth.accounts.wallet.add(privateKey)[0];

      // generate a new random Web3.js account object to receive the transaction
      const receiver = web3.eth.accounts.create();
      // log initial balances

      const senderBlance = await web3.eth.getBalance(sender.address);
      const receiverBlance = await web3.eth.getBalance(receiver.address);
      console.log("before");
      console.log(senderBlance, receiverBlance);
      // sign and send the transaction
      const receipt = await web3.eth.sendTransaction({
        from: sender.address,
        to: receiver.address,
        // amount in wei
        value: web3.utils.toWei("1", "ether"),
      })
      .on("sending", (sending) => {
          console.log("sending", sending);
        })
       .on("sent", (sent) => {
          console.log("sent", sent);
        })
       .on("transactionHash", (transactionHash) => {
          console.log("transactionHash", transactionHash);
        })
       .on("receipt", (receipt) => {
          console.log("receipt", receipt);
       })
       .on("confirmation", (confirmation) => {
          console.log("confirmation", confirmation);
       })
       .on("error", (error) => {
          console.log("error", error);
       });;
      const senderBlance2 = await web3.eth.getBalance(sender.address);
      const receiverBlance2 = await web3.eth.getBalance(receiver.address);
      debugger;
      console.log("after");
      console.log(senderBlance2, receiverBlance2);
      console.log(receipt);
    } catch (error) {
      console.log(error);
    }
  });

sendTransaction 可以给maxFeePerGasmaxPriorityFeePerGas

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import { Web3 } from "web3";

const web3 = new Web3("http://127.0.0.1:8545/");

async function txEIP1559() {
  const wallet = web3.eth.wallet.add(
    "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
  );

  const sender = wallet[0].address;
  const recipient = "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC";
  const value = 1;
  const nonce = await web3.eth.getTransactionCount(sender);
  const gasLimit = 21000;
  const maxFeePerGas = Number((await web3.eth.calculateFeeData()).maxFeePerGas);
  const maxPriorityFeePerGas = Number(
    (await web3.eth.calculateFeeData()).maxPriorityFeePerGas
  );

  debugger;

  console.log("before");
  const senderBinance0 = await web3.eth.getBalance(sender);
  const recipientBinance1 = await web3.eth.getBalance(recipient);
  console.log(senderBinance0);
  console.log(recipientBinance1);
  const tx = {
    from: sender,
    to: recipient,
    value,
    nonce,
    gasLimit,
    maxFeePerGas,
    maxPriorityFeePerGas,
    type: 2,
  };

  const txReceipt = await web3.eth.sendTransaction(tx);

  const senderBinance = await web3.eth.getBalance(sender);
  const recipientBinance = await web3.eth.getBalance(recipient);
  console.log("after");
  console.log(senderBinance);
  console.log(recipientBinance);
  debugger;
  console.log("Tx hash", txReceipt.transactionHash);
}

txEIP1559();

关于maxFeePerGas,参考官方解释,其实gas可以理解成给网络节点的小费,主要是在执行交易时的费用,gas成本主要与需要计算或者更新状态的交易有关,一个账户到另外一个账户的简单交易比复杂计算或者智能合约交易所产生的 gas 费用要小,在网络活动频繁期间所消耗的 gas 费成本更高。

API

web3与以太坊交互的 api 非常之多,我们掌握根据具体需求,学会查看相关文档会比较重要,从官方文档上,其实给我们分类了,web3主要分成

  • config,主要修改默认配置,不同参数会影响不同函数的行为
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import { Web3 } from 'web3';

const web3 = new Web3({
provider: "https://eth.llamarpc.com",
config: {
    defaultTransactionType: '0x0',
    defaultChain: "mainnet"
},
});
  • eth module主要查询区块、gas、余额、以及发送交易、签名等
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
import { Web3 } from 'web3';
const web3 = new Web3('https://eth.llamarpc.com');
const walletAddress = '0x0000000000000000000000000000000000000000';
(async () => {
      const blockNumber = await web3.eth.getBlockNumber();

  const balance = await web3.eth.getBalance(walletAddress);

  const gasPrice = await web3.eth.getGasPrice();

  const transactionReceipt = await web3.eth.getTransactionReceipt(
    '0x8ff2cba51cb1d6457a399fc3c70f4201ffc74095f0469c1237e1394288a80718'
  );
  const transaction = await web3.eth.getTransaction(
    '0x8ff2cba51cb1d6457a399fc3c70f4201ffc74095f0469c1237e1394288a80718'
  );
})()
  • ens module主要是一些验证以太坊官方的一些查询接口
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 
  const web3 = new Web3('https://eth.llamarpc.com');
  const key = await web3.eth.ens.getPubkey('ethereum.eth');
  const ttl = await web3.eth.ens.getTTL('ethereum.eth');
  const recordExists = await web3.eth.ens.recordExists('ethereum.eth');
  console.log(key);
  console.log(ttl);
  console.log(recordExists);
  • utils module主要是一些eth面额的换算,以及16进制hash的转换

好了关于API[1]这块我们需要的是学会如何看懂并掌握api,以及了解具体每一个 api 在实际业务的场景就行

总结

  • 学习web3.js在以太坊中的交互,我们发现在viem中所做的事情,我们可以使用web3.js去做,我们发现钱包签名发送交易都可以使用web3.js中的接口可以去实现,并且还可以使用web3.js手动创建钱包账号
  • Hardhat可以模拟一个本地开发环境的rpc环境,因此很容易实现并测试web3.js中的很多交易,签名,发送转账等功能
  • 了解并学会查询官方文档,知道web3.js中部分模块的一些大致功能
  • code example[2]
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Web技术学苑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档