EIP3009调用失败:签名无效问题排查求助
调用EIP3009的transferWithAuthorization(委托转账)功能时,交易报错:Fail with error 'FiatTokenV2: invalid signature'。交易哈希为0x405cb5c8a6f0295d1194bf6ce794f906537cefb5b65ab2005d674812e7f66c35,合约地址为0x1c7d4b196cb0c7b01d743fbc6116a902379c7238。怀疑链下签名存在问题,附上Python代码请求排查:
chain_id = 11155111 # Sepolia chain id full_message = { "types": { "EIP712Domain": [ {"name": "name", "type": "string"}, {"name": "version", "type": "string"}, {"name": "chainId", "type": "uint256"}, {"name": "verifyingContract", "type": "address"}, ], "TransferWithAuthorization": [ {"name": "from", "type": "address"}, {"name": "to", "type": "address"}, {"name": "value", "type": "uint256"}, {"name": "validAfter", "type": "uint256"}, {"name": "validBefore", "type": "uint256"}, {"name": "nonce", "type": "bytes32"}, ], }, "primaryType": "TransferWithAuthorization", "domain": { "name": "USDC", "version": "2", "chainId": chain_id, "verifyingContract": contract_address, }, "message": { "from": token_owner_address, "to": recipient_address, "value": value, "validAfter": validAfter, "validBefore": validBefore, "nonce": "0x" + secrets.token_hex(32), }, } # Get signable bytes according to EIP-712 signed_message = Account.sign_typed_data(token_owner_private_key, full_message=full_message) v = signed_message.v r_hex = hex(signed_message.r) s_hex = hex(signed_message.s) contract = w3.eth.contract(address=w3.to_checksum_address(contract_address), abi=abi) tx = contract.functions.transferWithAuthorization( token_owner_address, recipient_address, value, validAfter, validBefore, nonce, v, r_hex, s_hex ).build_transaction({ "from": fee_payer_address, "nonce": w3.eth.get_transaction_count(fee_payer_address), "gas": 200000, "gasPrice": w3.to_wei("10", "gwei"), "chainId": chain_id }) signed_tx = w3.eth.account.sign_transaction(tx, private_key=fee_payer_private_key) tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
可能的问题点及修正建议
Nonce一致性问题:代码中签名时生成的nonce是临时值,但调用合约时传入的
nonce变量未明确和签名值绑定。需确保签名与合约调用使用完全相同的nonce,建议生成后存入变量并同步到message和调用参数中:nonce = "0x" + secrets.token_hex(32) full_message["message"]["nonce"] = nonceR/S参数格式错误:
Account.sign_typed_data返回的r和s是整数,代码中用hex()转成十六进制字符串后传入合约,但合约要求bytes32类型。直接传入整数即可,web3.py会自动处理格式转换:r = signed_message.r s = signed_message.s # 调用合约时直接传r、s整数 tx = contract.functions.transferWithAuthorization(..., r, s).build_transaction(...)Domain参数校验:确认合约实际的
name和version是否为"USDC"和"2",可通过调用合约的name()、version()方法获取准确值,不一致会导致EIP-712签名验证失败。地址格式问题:确保
token_owner_address、contract_address等均为校验和格式(checksum address),签名与合约调用的地址格式需完全一致。私钥与地址匹配:验证
token_owner_private_key对应的地址确实是token_owner_address,私钥地址不匹配会直接导致签名无效。
内容的提问来源于stack exchange,提问作者Itai Bar

