Signature mismatches
Symptom
A meta-tx or mutual-resolve call reverts with SignatureValidationFailed (or "recovered address doesn't match expected").
Causes (in rough order of likelihood)
- Wrong typed-data structure. Hand-built typed-data drifts from the on-chain verifier.
- Wrong domain separator. Chain ID or verifying-contract mismatch.
- Hardware wallet quirk. Some HW wallets corrupt long typed-data; check firmware.
- EIP-1271 smart-account signature when the verifier expects EOA, or vice versa.
- Stale nonce. Signature for nonce N submitted at nonce N+1.
- Wrong signer. Someone other than the expected user signed.
Fix
Always use the SDK / MCP signing helpers
// CORRECT
const signed = await sdk.metaTx.signMetaTxCommitToOffer({ buyer, offerId })
// WRONG: do not hand-build
const signed = await wallet._signTypedData(domain, types, message) // domain drifts!The SDK builds the typed-data identically to the on-chain verifier. Hand-built typed-data is the #1 cause of mismatches.
Check the domain
The EIP-712 domain must match the on-chain verifier exactly:
{
name: "BosonProtocolDiamond",
version: "V2",
chainId: <actual chain id>,
verifyingContract: <Diamond address for this configId>,
}A chainId mismatch causes recovered addresses to be junk. If you're on Polygon production, the chainId must be 137 — not 1, not 80002.
For smart accounts
The Diamond accepts EIP-1271 signatures. If your buyer is a Safe, the signing flow is:
- Safe owners sign the inner data offline.
- Combine into a Safe signature blob.
- The blob is what gets passed as the meta-tx signature.
The Diamond calls IERC1271.isValidSignature(hash, sig) on the buyer address. Make sure your Safe is deployed at the address you're using.
Nonce check
const nonce = await diamond.getNonce(userAddress)
// ensure the signature you produce uses exactly this nonceDebugging
If SignatureValidationFailed is intermittent under concurrency, you have a nonce race. Serialize signing or generate fresh nonces.