You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:24:55