掌握 web3.js:从零到实战部署 ETH 合约

·

web3-eth 是 web3.js 的核心子包,专为 与以太坊交互、管理账户、发送交易与部署智能合约 而生。本教程使用 TypeScript 和 web3.js 4.x,带你一步步完成本地 Ganache 环境搭建、转账、估算_gas_、签名交易、配置 web3-eth 以及发送传统、EIP-2930、EIP-1559 类交易的完整流程。

文章将围绕 web3-eth、以太坊开发、智能合约、本地测试链、交易签名、EIP-1559、gas 估算、web3.js 这些关键词循序渐进,助你真正用好 web3-eth。


1. 环境准备:安装 Node、Ganache 与 npm

  1. Ganache:一口气为你生成 10 个内置百枚以太的本地账户,调试神器。
    安装:进入官网下载 GUI 或直接 npm i ganache-cli -g
  2. Node.js & npm:托管 web3.js 代码与依赖。👉 升级 Node 的完整攻略都在这了!
  3. (可选)yarn 替换 npm:npm i -g yarn

2. 初始化 TypeScript 项目

mkdir smart-contract-tutorial && cd smart-contract-tutorial
npm init -y
npm i typescript @types/node ts-node --save-dev
npx tsc --init

此时 package.json 已就绪,后续所有代码统一放在 src/


3. 连接 Ganache,获取区块号

// src/index.ts
import { Web3 } from 'web3';

const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:7545'));

(async () => {
  const bn = await web3.eth.getBlockNumber();
  console.log('当前区块:', bn);
})();

遇到 ECONNREFUSED 127.0.0.1:7545 多半是 Ganache 没跑,或者端口被占用。


4. 以太坊转账实战

在 Ganache 里,默认账户已解锁,不需要私钥 即可用 sendTransaction

4.1 主脚本:发送 1 ETH

// src/transaction.ts
import { Web3 } from 'web3';
const web3 = new Web3('http://localhost:7545');

(async () => {
  const [acc0, acc1] = await web3.eth.getAccounts();

  console.log('转账前余额:');
  console.log(await web3.eth.getBalance(acc0)); // 100 ETH
  console.log(await web3.eth.getBalance(acc1)); // 100 ETH

  const tx = {
    from: acc0,
    to: acc1,
    value: web3.utils.toWei('1', 'ether')
  };

  const receipt = await web3.eth.sendTransaction(tx);
  console.log('交易哈希:', receipt.transactionHash);

  console.log('转账后余额:');
  console.log(await web3.eth.getBalance(acc0)); // ≈ 99 ETH
  console.log(await web3.eth.getBalance(acc1)); // ≈ 101 ETH
})();

运行:

npx ts-node src/transaction.ts

4.2 估算 gas

部署智能合约之前先打预算,避免主网烧钱。

// src/estimate.ts
import { Web3, ETH_DATA_FORMAT } from 'web3';
const web3 = new Web3('http://localhost:7545');

(async () => {
  const abi = [...] // 省略
  const bytecode = '0x6080...';
  const accounts = await web3.eth.getAccounts();

  const contract = new web3.eth.Contract(abi);
  const deploy = contract.deploy({ data: bytecode, arguments: [1] });

  console.log('默认 BigInt 格式:', await deploy.estimateGas({ from: accounts[0] }));
  console.log('十六进制格式:', await deploy.estimateGas({ from: accounts[0] }, ETH_DATA_FORMAT));
})();

4.3 高级:手动签名交易

在主网或 实时测试网 转账时,必须用私钥离线签名。

// src/sendSigned.ts
import { Web3 } from 'web3';
const web3 = new Web3('http://localhost:7545');
const PRIVATE_KEY = '0x...'; // 从 Ganache accounts 标签页复制

(async () => {
  const [from] = await web3.eth.getAccounts();
  const to = '0x...';

  const tx = {
    to,
    value: web3.utils.toWei('1', 'ether'),
    gas: 21000,
    gasPrice: web3.utils.toWei('10', 'gwei'),
    nonce: await web3.eth.getTransactionCount(from)
  };

  const signed = await web3.eth.accounts.signTransaction(tx, PRIVATE_KEY);
  const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction!);
  console.log('签名交易回执:', receipt);
})();

5. 精简构建:直接引入 web3-eth

打包体积焦虑?只需拉取 web3-eth 获得以太坊核心功能即可。

// src/web3-eth-demo.ts
import { Web3Eth } from 'web3-eth';
const eth = new Web3Eth('http://localhost:7545');

(async () => {
  const [address] = await eth.getAccounts();
  const balance = await eth.getBalance(address);
  console.log('余额 via web3-eth:', balance);
})();

动态配置交易类型

eth.setConfig({ defaultTransactionType: '0x2' }); // 默认 EIP-1559

6. 三种交易类型一次讲透

6.1 传统交易(Legacy tx)

const tx = {
  type: 0,
  gasPrice: await web3.eth.getGasPrice(),
  ...其他
};

优点:兼容所有老节点;缺点:gasPrice 手动估算,容易多花钱。


6.2 EIP-2930 访问列表交易

const tx = {
  type: 1,
  accessList: [{
    address: '0xGreeter',
    storageKeys: ['0x...']
  }],
  ...其他
};

适合复杂合约交互、降低部分 SLOAD/SSTORE 开销。👉 实战访问列表生成器在此!


6.3 EIP-1559 动态费率交易

const tx = {
  type: 2,
  maxFeePerGas: 100n * 10n ** 9n, // 100 gwei
  maxPriorityFeePerGas: 2n * 10n ** 9n, // 2 gwei
  ...其他
};

基础费用将随网络负载自动调整,手续费更可预测,已成为钱包默认策略。


FAQ:常见疑问解答

疑问解答
必须用 Gwei?以太坊内部使用 wei(1 ETH = 1e18 wei)。web3.utils 提供 toWei/fromWei 换算。
Ganache 私钥安全吗?本地调试 OK;上线前请替换成 keystore + 加密密码 或硬件钱包。
estimateGas 不够怎么办?复杂合约交互先加 20-30% 余量,主网失败将损失 gas。
Ganache 端口占用?lsof -i :7545 查 PID,再 kill -9 PID 释放端口。
我能一次监听很多事件?contract.events.allEvents();生产环境配合 ethers.js + event filter 轻量读取。
二次转账卡住?检查 nonce 是否正确;也可使用 web3.eth.getTransactionCount(addr, 'pending')

实战小贴士 & 最佳实践

  1. 先本地,后测试网,再主网 三步走,避免高 gas 弹性起步。
  2. Solidity 0.8+ 内建溢出检查,推荐 pragma solidity ^0.8.19;
  3. Lucide/Lint 工具:开启 [solhint](https://protofire.github.io/solhint/) 规范合约写法。
  4. 私钥管理:生产切勿明文写在代码,使用 .env + dotenv
  5. 实时看板:把 etherscanoklink 中的区块、gas 监控集成进监控群里。

恭喜!你已完整掌握 web3-eth 的核心 API 与最佳实战,从开发、调试到上线不再踩坑。下一步可深入 web3-net、web3-utils、web3-contract 探索更多高级玩法。祝你在以太坊世界里挖坑愉快,扎根技术,一路高飞!