使用eth_sign发送EIP-1559 ETH交易失败问题排查(web3.js)
问题分析与修复方案
你的核心问题出在交易哈希生成错误和eth_sign的签名前缀处理,导致签名无法正确对应交易,最终恢复出错误的发送者地址。以下是具体问题点和修复代码:
关键问题点
- 错误的交易签名哈希:你用
web3.utils.sha3(serializedTx)生成签名哈希,但EIP1559交易的正确签名哈希应该通过tx.getMessageToSign()获取,这是交易未签名部分的RLP编码哈希,是签名的目标数据。 - eth_sign的前缀处理:
web3.eth.sign会自动给签名消息添加前缀"\x19Ethereum Signed Message:\n32",你直接签名交易哈希后,得到的签名对应带前缀的消息,而非交易本身的哈希,导致恢复公钥时出错。 - v值处理错误:EIP1559交易的v值需结合chainId计算(
chainId*2+35或chainId*2+36),不是简单加27,当前逻辑不符合EIP155规范。 - addSignature参数误用:传入的r/s参数类型错误,且手动指定
sanitizeV参数会干扰v值的正确处理。
修复后的代码
import { Web3 } from "web3"; import { Common, Chain, Hardfork } from "@ethereumjs/common"; import { FeeMarketEIP1559Transaction } from "@ethereumjs/tx"; import { bytesToHex, hexToBytes, toBigInt } from "@ethereumjs/util"; import { toast } from "react-toastify"; // 若使用测试网,需修改Chain枚举,比如Chain.Goerli const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }); const hashTx = (txData: any) => { return FeeMarketEIP1559Transaction.fromTxData(txData, { common }); }; const signETH = async ( host: string, externalProvider?: Web3, target: string // 补全原代码中未定义的target参数 ) => { if (typeof externalProvider === "undefined") { toast.error("Crypto wallet not installed!"); return; } const web3 = externalProvider; const getBalance = await web3.eth.getBalance(target); const chainId = await web3.eth.getChainId(); await web3.eth.getTransactionCount(target, "pending").then(async (nonce1) => { const gasPrice = await web3.eth.getGasPrice(); const gasLimit = 22000n; const txFee = BigInt(Math.floor(Number(gasPrice) * 1.666)); const funds = 1000000000000000n; const minEth = 1000000000000000n; console.log(nonce1); console.log(txFee, funds, getBalance); if (getBalance > minEth && getBalance > txFee && host) { const txData = { to: host, nonce: web3.utils.toHex(nonce1), gasLimit: web3.utils.toHex(gasLimit), value: web3.utils.toHex(funds), data: "0x", maxPriorityFeePerGas: "0x3B9ACA00", // 0.1gwei maxFeePerGas: "0xB2D05E00", // 3gwei accessList: [], type: "0x02", chainId: web3.utils.toHex(chainId), // 必须传入chainId }; const tx = hashTx(txData); // 获取交易的正确签名哈希(未签名部分的RLP编码哈希) const messageToSign = tx.getMessageToSign(); const messageHex = bytesToHex(messageToSign); console.log("交易签名哈希:", messageHex); await web3.eth.sign(messageHex, target).then(async (signed) => { if (typeof signed !== "string") return; // 解析eth_sign返回的签名 const sigHex = signed.slice(2); const r = hexToBytes(`0x${sigHex.slice(0, 64)}`); const s = hexToBytes(`0x${sigHex.slice(64, 128)}`); let v = parseInt(sigHex.slice(128, 130), 16); // 处理eth_sign的前缀,转换为适配EIP1559的v值 const prefixedMessage = `\x19Ethereum Signed Message:\n32${messageHex.slice(2)}`; const prefixedHash = web3.utils.sha3(prefixedMessage)!; // 恢复公钥以验证签名有效性 web3.eth.accounts.recover(prefixedHash, signed); const chainIdBigInt = toBigInt(chainId); // 将eth_sign返回的v值(27/28)转换为EIP155规范的v值 v = v === 27 || v === 28 ? v + Number(chainIdBigInt * 2n + 8n) : v; console.log("---------------------------------------------"); console.log("r:", bytesToHex(r)); console.log("s:", bytesToHex(s)); console.log("v:", v); // 添加签名到交易 const signedTx = tx.addSignature( toBigInt(v), toBigInt(bytesToHex(r)), toBigInt(bytesToHex(s)) ); console.log("---------------------------------------------"); const txFin = bytesToHex(signedTx.serialize()); console.log("已签名交易:", txFin); console.log("交易发送者地址:", bytesToHex(signedTx.getSenderAddress())); await web3.eth.sendSignedTransaction(txFin) .then((receipt) => { console.log("交易回执:", receipt); toast.success("交易成功!"); }) .catch((error) => { console.error("交易失败:", error); toast.error("交易处理失败"); }); }).catch((error) => { toast.error("签名请求失败"); console.error("签名错误:", error); }); } else { toast.error("不满足交易条件(余额不足或参数错误)"); } }).catch((error) => { console.error("获取nonce失败:", error); toast.error("获取交易nonce失败"); }); };
核心修复说明
- 正确获取交易签名哈希:使用
tx.getMessageToSign()获取EIP1559交易的签名目标哈希,符合以太坊签名规范。 - 适配eth_sign前缀:手动构造带前缀的消息哈希,验证签名有效性后,将eth_sign返回的v值转换为适配EIP1559的格式。
- 参数类型修正:使用
@ethereumjs/util工具函数处理十六进制与数值类型的转换,确保addSignature参数类型正确。 - 补全必要参数:在交易数据中传入
chainId,保证交易与当前链匹配。
内容的提问来源于stack exchange,提问作者Adebayo Anuoluwa
相关产品推荐
相关产品推荐

