使用 Ethers.js 提高 gas 价格替换待处理交易的完整指南

·

Ethereum 交易拥堵 Ethers.js gasPrice nonce Web3 开发

一份开箱即用的代码范例,教你如何在不取消交易的前提下,只需几分钟即可把「卡住」的以太坊交易推进区块链。

交易为什么会卡?了解 gas 的底层逻辑

当一笔交易的生命周期开始后,矿工会把待处理交易池按 gasPrice 从高到低排序。如果你的出价低于当前网络档位,就会被不断往后挤。最简单的办法就是复制同一笔交易的所有参数,唯独把 gasPrice 提上去,同时保持 nonce 不变。
👀 不熟悉的概念先别急,阅读下文即可掌握。


适用场景


快速回顾:以太坊交易的六大核心参数

名称作用
from谁发起交易
to谁接收交易(如果是合约交互就是合约地址)
value转出的 ETH 数量
data与函数交互时打包的参数(纯转账则留空)
gasLimit此交易最多消耗多少 gas
gasPrice你愿意支付的 gas 单价(gwei)
nonce地址发出的累计交易计数,同一 nonce 只能被打包一次

准备开发环境

  1. 安装 Node ≥16:node -v
  2. 安装 ethers.js 5.7:

    npm install [email protected]
  3. 准备一个 私钥测试 ETH。主网上操作请转至钱包导出私钥并使用正式网络 endpoint,这里用 Sepolia 测试网演示。

秒创建钱包

// index.js
const ethers = require('ethers');
const PRIVATE_KEY = '0x...';
const wallet = new ethers.Wallet(PRIVATE_KEY);
console.log('地址:', wallet.address);

运行:

node index.js

三步完成「发交易 → 卡了 → 替换」

假设你已经把节点 URL 放入 .env 或硬编码到脚本里。

1. 构造原始交易

const provider = new ethers.providers.JsonRpcProvider('https://sepolia.infura.io/v3/YOUR_KEY');
const tx = {
  to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
  value: ethers.utils.parseEther('0.01'),
  nonce: 5,
  gasLimit: 21000
};
const gasPrice = ethers.utils.parseUnits('10', 'gwei');
tx.gasPrice = gasPrice;

const signedTx = await wallet.signTransaction(tx);
const txResponse = await provider.sendTransaction(signedTx);
console.log('第一次交易哈希:', txResponse.hash);

🎯 打印出的哈希赶紧去 sepolia.etherscan.io 查询——会看到状态是 pending

2. 调高 gasPrice 重新签名

tx.gasPrice = ethers.utils.parseUnits('25', 'gwei');   // 拉高 1.5–2 倍效果最佳
tx.nonce = 5;                                          // 关键!保持 nonce
const signedTx2 = await wallet.signTransaction(tx);
const txResponse2 = await provider.sendTransaction(signedTx2);
console.log('替换交易哈希:', txResponse2.hash);

⚠️ 新交易在链上只是同一个 nonce 的第二次广播,矿工一旦看到你的更高报价就会放弃旧交易

3. 验证结果

回到区块浏览器输入最新哈希,现在区块号已经出现,状态由 pending 变为 success。之前的那条低 gas 交易将在历史记录里显示 dropped/replaced


FAQ:开发者最关心的 5 个问题

Q1:我把 nonce 写错了怎么办?
A:你将发送一笔全新的交易,成功也只会多花钱,无法替换旧交易。

Q2:能用 EIP-1559 的 maxFeePerGas 吗?
A:支持。只需把对象改为 { maxFeePerGas, maxPriorityFeePerGas },步骤保持一致。

Q3:有没有一键取消交易的极简方法?
A:把 value 设为 0,同时把 to 写回本地址,调高 gas,即可“空转”掉该 nonce,用自转交易实现取消。

Q4:测试网 faucet 经常缺水,去哪领 ETH?
A:推荐使用 Sepolia PoW faucetGoerli Authenticated Faucet,无需社交媒体验证即可提取 0.1–0.2 ETH。

Q5:脚本在主网跑太慢,怎样快速同步网络状态?
A:使用专业 RPC 提供方(如 Infura、Alchemy),或自建 geth 打开 --http --http.api eth,txpool,监听 pendingTransactions 就能实时推送交易。


进阶:自动化监控脚本

不想让交易卡在半路?可以启动一个持续轮询的小服务,当检测到 txReceipt == null && 当前区块高度 > 40 个区块未上链 时,自动把 gasPrice 乘以 1.4 倍 重新签名。关键代码:

async function bumpGas(txHash, provider, wallet, multiplier = 1.4) {
  const tx = await provider.getTransaction(txHash);
  if (!tx || tx.blockNumber) return;         // 已打包无需替换
  const oldGas = tx.gasPrice;
  const newGas = oldGas.mul(Math.floor(multiplier * 100)).div(100);
  const replacement = {
    ...tx,
    gasPrice: newGas,
    nonce: tx.nonce
  };
  delete replacement.hash;                   // 清除旧 hash
  const signed = await wallet.signTransaction(replacement);
  return await provider.sendTransaction(signed);
}

multiplier 设为 1.05–1.5 之间就能在不溢出的情况下最大化上链成功率。


总结

  1. nonce 是“替换”开关,千万别动它
  2. gasPrice 一口气拉到位,让矿工一眼看到你
  3. 主网实战前先在测试网模拟流程,保证私钥与助记词的安全
  4. 👉 想实时追踪全网 gas 行情?点击获取详细数据面板

通过以上步骤,你可以在任意时间点把“拖延”的交易硬生生地拽进区块,再也不会因为低 gas 而捶胸顿足。祝挖矿顺利!