跳至主要內容

如何使用 Ethers.js 以更高的 gas 價格重新發送交易

更新於
2025年11月26日

閱讀時間 8 分鐘

重要通知

本指南中提及的 Kovan 測試網,目前已不再進行積極維護。雖然與該鏈相關的具體步驟可能不再適用,但整體流程對於其他鏈而言仍可能有效。我們建議您在實作時探索當前的替代方案。如果您希望查看本指南的更新版本,請告訴我們

概覽

有時,由於網路擁塞,或是有太多待處理交易開出的 gas 價格高於您交易中開出的價格,導致您在以太坊上提交交易時 gas 不足。如果您有高優先級的交易但 gas 不足,最終可能得等待數小時甚至數天,交易才能完成。在這種情況下,您需要重新發送一筆 gas 更高且 nonce 相同的交易,以便讓交易盡快被礦工採礦。

在本指南中,我們將詳細說明在以太坊上發送交易,以及使用 Ethers.js 在其中一個以太坊測試網路上重新發送相同交易時所涉及的所有術語與相關資訊。

以太坊中的交易是什麼?

每當我們想在以太坊網路上新增、更新或修改任何內容時,就會進行一筆交易。基本上,交易就是現實世界與以太坊區塊鏈網路互動的方式。對於我們在以太坊網路上進行的每筆交易,都需要支付一筆稱為「gas」的手續費。gas 的單位可以是 wei(ETH 的最小單位)或 gwei。

以太坊中的交易類型

以太坊網路上有三種常見的交易類型:

  1. 一筆普通交易,即 ETH/以太幣從一個帳戶轉移至另一個帳戶的交易。
  2. 建立合約的交易,是指將智慧合約部署至以太坊區塊鏈網路的交易類型。
  3. 一項呼叫合約的交易;此交易會攜帶某些資料發送,並用於查詢或與先前已部署的智慧合約進行互動。

典型以太坊交易的參數

  • from:寄件者地址,一個 20 位元組的地址,代表發起該交易的帳戶。
  • 收件人地址:一個 20 位元組的地址,代表收件人的帳戶或合約帳戶。
  • value:這是交易中從一個帳戶發送至另一個帳戶的 ETH 數量。
  • data:此欄位包含合約部署交易的位元組碼。若為執行合約函式,則包含函式簽名及編碼後的參數。在資金轉帳交易中,此欄位並非必要,亦可留空。
  • gasLimit:這是交易可使用的 gas 最大值(單位為 wei)。
  • gasPrice:這是發送者願意為該筆交易支付的金額(單位為 wei)。
  • chainId:這是您的以太坊節點的網路識別碼(主網:1、Rinkeby:4、Kovan:42 等)
  • nonce:這是特定地址發送的交易數量。每當該地址發送一筆交易時,nonce 便會增加 1。

以太坊中的交易流程

  • 建立一個交易物件,並為其提供所有必要的參數。
  • 使用發送者的私鑰對該交易進行簽名。
  • 使用以太坊節點將交易發送至以太坊區塊鏈網路。

簽署交易

對交易進行簽署,意指使用發送者的私鑰,對交易物件產生一個簽名。若您想進一步了解以太坊中的簽署與驗證機制,以下是幾篇極佳的參考文章:《以太坊簽名與驗證》(作者:Yos)以及《以太坊:簽署與驗證》(作者:Angello Pozo)。

現在,既然我們對以太坊中的交易有了更深入的了解,就讓我們親自發送一筆交易吧。

先決條件

  • 您的系統上已安裝 Node.js
  • 文字編輯器
  • 終端機(又稱命令列)

安裝必要的工具。

我們將使用 NodeJS 來管理我們的函式庫套件,並處理 JavaScript 檔案。若要確認您的系統是否已安裝 NodeJS,請開啟終端機並執行以下指令:

$ node -v

若尚未安裝,您可以從官方網站下載 NodeJS 的 LTS 版本。

要發送一筆交易,我們將使用一段簡短的 JavaScript 程式碼,並採用 ethers.js 函式庫(請確保版本為 5.7)。您可以透過命令列/終端機使用 npm 安裝它:

$ npm install --save ethers@5.7

此步驟中最常見的問題是 `node-gyp` 發生內部錯誤。您可以參閱此處的 node-gyp 安裝說明

另一個常見的問題是快取過期。只需在終端機中輸入以下指令,即可清除您的 npm 快取:

$ npm cache clean

您可以參閱我們的ethers.js 指南,進一步了解 ethers.js 函式庫。

建立錢包並取得一些測試用 ETH

現在,讓我們為自己建立一個錢包。要做到這一點,首先請建立一個名為 index.js 的檔案,或建立一個您自選名稱的 JavaScript 檔案。您可以將以下內容複製並貼上至您的程式碼編輯器中:

var ethers = require('ethers');  
var privateKey = "0x0111111111111111111122222222222222222223333333333333333333344445";
var 錢包 = new ethers.錢包(私鑰);
控制台.log("地址:" + 錢包.地址);

讓我們來看看這裡會發生什麼事:導入我們先前安裝的 ethers.js 函式庫(第 1 行),  建立專屬於我們錢包的私鑰,您需要自行建立一個,數字可以是任意數值,但請確保位數與上方的數字相同(第 2 行),使用該私鑰透過 ethers 建立錢包實例(第 3 行),並在控制台以「Address」字樣輸出我們的錢包地址(第 4 行)。

現在,請使用以下指令執行該檔案:

$ node index.js

如果一切順利,終端視窗中顯示的輸出應如下所示:

地址:0x3f5D3070Fc7924479B5e367a83EC2b284E9c4e04

由於每筆交易都需要支付 gas 費,而且我們需要一些 gas 來發送這筆交易,因此讓我們先在錢包中存入一些測試用 ETH。為此,我們將使用 Kovan 節點,請前往這個Kovan 水龍頭領取一些測試用 ETH,將執行上述程式碼後獲得的錢包地址貼上,然後點擊「send me KETH!」。 

註:這將是測試用的 ETH,不具備市場價值。

設定您的 Quicknode 以太坊端點

就今天的目的而言,我們幾乎可以使用任何以太坊客戶端,例如 Geth 或 OpenEthereum(前身為 Parity)。若要自行啟動一個以太坊節點,我們首先需要選擇一個客戶端並進行設定;同步以太坊節點並進行維護是一項艱鉅的任務;同步一個以太坊全節點可能需要數天時間。

由於僅僅是發送一筆交易而言,這步驟稍顯繁瑣,因此我們將使用 Quicknode 提供的免費端點來簡化流程。建立好您的免費以太坊端點後,請複製您的 HTTP Provider 端點: 

本指南將使用 Kovan 測試網節點。

Quicknode Kovan 端點的螢幕截圖

稍後你會需要這個,所以請複製並儲存下來。

發送與重新發送交易

現在,我們已經有一個錢包,裡面還有些測試用的 ETH。接下來,讓我們發送一筆交易,將部分 ETH 轉入另一個帳戶/錢包。為此,我們要在 index.js 檔案中再加入一些實用功能。你可以將以下內容複製並貼到你的程式碼編輯器中:

var ethers = require('ethers');  
var url = 'ADD_YOUR_ETHEREUM_NODE_URL';
var customHttpProvider = new ethers.providers.JsonRpcProvider(url);
var privateKey = "0x0111111111111111111122222222222222222223333333333333333333344445";
var wallet = new ethers.Wallet(privateKey);
console.log("Address: " + wallet.address);
tx = {
to: "0x6E0d01A76C3Cf4288372a29124A26D4353EE51BE",
value: ethers.utils.parseEther("0.05"),
chainId: 42,
nonce: 3
}
customHttpProvider.estimateGas(tx).then(function(estimate) {
tx.gasLimit = estimate;
tx.gasPrice = ethers.utils.parseUnits("0.14085197", "gwei");
wallet.signTransaction(tx).then((signedTX)=>{
customHttpProvider.sendTransaction(signedTX).then(console.log);
});
});

因此,請將 `ADD_YOUR_ETHEREUM_NODE_URL` 替換為上文所述的 HTTP 提供者。 

關於上述程式碼的簡要說明——我們先導入先前安裝的 ethers 函式庫(第 1 行),設定以太坊節點網址(第 2 行),建立 ethers 的 JsonRpcProvider 實例(第 3 行),並建立專屬於我們錢包的私鑰;您需要自行建立一個私鑰,數字可以是任意數值,但請確保位數相同(第 4 行), 使用私鑰透過 ethers 建立錢包實例(第 5 行),在控制台以「Address」字樣輸出錢包地址(第 6 行),建立交易物件並新增 'to' 欄位,填入收件者的地址(您可使用 `var wallet = Wallet.createRandom();` 產生隨機地址)` 產生隨機地址;新增 'value' 欄位以指定要傳送的 ETH 數量;'chainId' 欄位此處設定為 42(因我們使用 Kovan 鏈);'nonce' 欄位設定為 3(第 7-12 行);透過我們的節點估算 gasLimit 並設定 gas 價格(第 13-15 行), 使用錢包的私鑰對交易物件進行簽名並發送,同時將交易記錄輸出至控制台(第 16-18 行)。

我們來執行這段程式碼:

$ node index.js

我們會得到類似以下的輸出結果:

Node.js 的 index.js 輸出內容

複製哈希欄位的字串(例如 '0xe49c8122656c612bf5f1e10b251f56671acf01d831b6876c37c5a52053035642'),並將其貼上至Kovan Etherscan的搜尋框中,以查看該交易的状态。 您會發現該筆交易尚未被加入區塊鏈上的新區塊中,且狀態顯示為「待處理」。這是因為我們輸入的 gas 值過低所致。

現在,讓我們嘗試傳送一筆具有相同 nonce 的交易,但這次要增加 gas 值;請將程式碼第 15 行的 gasPrice 值從 '0.14085197' 改為 '2.14085197',然後重新執行程式碼:

$ node index.js 

請從新的輸出結果中複製哈希字串,並將其貼上至Kovan Etherscan的搜尋欄中,以檢查交易狀態。這次,由於我們在發送交易時已將 gasPrice 值適當調高,因此該交易將會被納入區塊,並顯示為成功狀態。

注意:必須特別留意,這兩筆交易中的「nonce」值必須相同。如前所述,nonce 是指向以太坊地址所擁有交易筆數的指標。若要重新提交一筆 gas 費用更高的交易,您必須使用與原始交易相同的 nonce。若您使用較高的 nonce,那將被視為一筆新的交易,從而導致您消耗比預期更多的 ETH。

結論

因此,正如我們從上述例子所見,一筆交易若要獲得確認,其 gas 費用必須具有競爭力。區塊鏈的礦工會根據可用的區塊空間,以及所有交易為佔用該區塊空間所願意支付的費用來設定 gas 費用;當某筆交易的 gas 費用低於閾值時,該交易便無法獲得確認。相較於其他交易,gas 費用較高的交易會更快獲得確認。

訂閱我們的電子報,獲取更多關於以太坊的文章與指南。如有任何意見回饋,歡迎透過Twitter 聯繫我們;若您有任何疑問,也隨時歡迎透過Discord 上的社群伺服器與我們聊天。那裡聚集了最酷的開發者們,謝謝 :)

分享這份指南