使用Java和Web3j在Alchemy API中生成UserOperation签名报错求助
解决UserOperation签名无效(-32507错误)的问题
你的代码存在三个核心问题,直接导致签名验证失败:
1. 错误解析UserOperation哈希
userOperationHash是十六进制格式的哈希字符串,你直接调用getBytes(StandardCharsets.UTF_8)会把字符串本身(比如"0xabc123...")转成字节,而非解析十六进制对应的原始哈希值,这会让你签名的内容完全偏离预期。
2. 错误添加签名前缀
web3j的signMessage(byte[] message, ECKeyPair key)默认会给消息加上EIP-191前缀(即"\x19Ethereum Signed Message:\n" + 消息长度),但UserOperation的哈希已经是通过EIP-712规范计算出的结构化数据摘要,不需要额外添加前缀——直接对原始哈希签名即可。
3. V值格式不匹配
web3j返回的SignatureData中V值为27或28,但部分EIP-4337账户实现要求V值为0或1(对应减去27),否则会被判定为无效签名。
修正后的代码
import org.web3j.crypto.ECKeyPair; import org.web3j.crypto.Sign; import org.web3j.crypto.SignatureData; import org.web3j.utils.Numeric; public class UserOpSigner { private static String privateKey; // 替换为你的私钥 public static String signUserOperation(String userOperationHash) { // 解析十六进制哈希为原始字节数组(先去掉0x前缀) byte[] hashBytes = Numeric.hexStringToByteArray(stripHexPrefix(userOperationHash)); ECKeyPair ecKeyPair = ECKeyPair.create(Numeric.hexStringToByteArray(stripHexPrefix(privateKey))); // 直接对原始哈希签名(不添加EIP-191前缀) SignatureData signatureData = Sign.signMessage(hashBytes, ecKeyPair, false); // 调整V值:将27/28转为0/1(部分账户实现可跳过此步,根据实际情况调整) byte adjustedV = (byte) (signatureData.getV()[0] - 27); signatureData = new SignatureData(adjustedV, signatureData.getR(), signatureData.getS()); return signatureDataToHex(signatureData); } public static String signatureDataToHex(SignatureData signature) { String r = Numeric.toHexStringNoPrefix(signature.getR()); String s = Numeric.toHexStringNoPrefix(signature.getS()); String v = Numeric.toHexStringNoPrefix(signature.getV()); // 确保R、S长度为64位,V为2位(补零避免格式错误) r = padHexString(r, 64); s = padHexString(s, 64); v = padHexString(v, 2); return r + s + v; } private static String stripHexPrefix(String hexString) { if (hexString.startsWith("0x")) { return hexString.substring(2); } return hexString; } // 补零确保十六进制字符串长度符合规范 private static String padHexString(String hex, int length) { if (hex.length() >= length) { return hex; } return "0".repeat(length - hex.length()) + hex; } }
关键修正点说明
- 哈希解析:用
Numeric.hexStringToByteArray将十六进制哈希转成原始字节,而非直接取UTF-8字节。 - 签名方式:调用
Sign.signMessage(hashBytes, ecKeyPair, false),第三个参数false表示不添加EIP-191前缀,直接对哈希签名。 - V值调整:将web3j返回的27/28转为0/1,适配大部分EIP-4337账户的签名验证逻辑(如果你的账户接受27/28,可跳过此步)。
- 补零处理:确保R、S为64位十六进制,V为2位,避免因长度不足导致签名格式错误。
内容的提问来源于stack exchange,提问作者Ken Yurino
相关产品推荐
相关产品推荐

