web3.js
是一个与以太坊交互
的重要库,在上一篇介绍的文章中viem
也是与以太坊
交互的一个库,从功能上讲各有千秋,比起viem
,总体包体积web3.js
更大,性能也没有viem
更好,但很多dapp
都是直接使用web3.js
,所有这些并不影响众多dapp
使用它与以太坊
生态的交互
我们主要看下使用web3.js
如何查看区块
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
import { Web3 } from "web3";
let providers = await Web3.requestEIP6963Providers();
我们发现如果你浏览器安装了钱包会有以下钱包列表
我们通过web3.requestEIP6963Providers
这个接口可以检测出我们的浏览器安装了哪些钱包,并渲染出来了,因此我们通过指定钱包唤起钱包登录
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
创建钱包
...
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
创建的地址,会返回一个对象,这个对象里包含了钱包地址,以及privateKey
、sign
、signTransaction
、address
我们通过 web3 创建了地址,因此我们可以进行sign
操作
...
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
当我们进行 A 钱包与 B 钱包进行转账时,其实主要发生了以下几个步骤eth_getTransactionCount
、eth_chainId
、net_version
、eth_estimateGas
...
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
主要会产生以下几个阶段
sending
将交易发送到网络sent
交易已发送到网络transactionHash
已生成交易哈希receipt
交易已包含在区块中confirmation
交易区块已经被确认error
交易遇到错误
...
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 可以给maxFeePerGas
与maxPriorityFeePerGas
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 费成本更高。
web3
与以太坊交互的 api 非常之多,我们掌握根据具体需求,学会查看相关文档会比较重要,从官方文档上,其实给我们分类了,web3
主要分成
config
,主要修改默认配置,不同参数会影响不同函数的行为
import { Web3 } from 'web3';
const web3 = new Web3({
provider: "https://eth.llamarpc.com",
config: {
defaultTransactionType: '0x0',
defaultChain: "mainnet"
},
});
eth module
主要查询区块、gas、余额、以及发送交易、签名等
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
主要是一些验证以太坊官方的一些查询接口
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
中部分模块的一些大致功能扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有