Enhanced-tier verification of the original EIP-712 PINT signature
Enhanced-tier requests include the original signature alongside the JWT. This gives you independent cryptographic proof of the user’s authorisation — you can verify the signed intent directly without relying solely on the SIS attestation.
You only need this for Enhanced tier (requests with sr:us:pint:spend:execute scope). If the JWT’s verification_tier is "standard", skip this page — standard JWT verification is sufficient.
Recover the signer address from the X-Pint-Signature header and confirm it matches the wallet in the PINT:
import { recoverTypedDataAddress } from "viem";const pintSignature = request.headers.get("x-pint-signature") as `0x${string}`;const recoveredAddress = await recoverTypedDataAddress({ domain, types, primaryType: "PurchaseIntent", message, signature: pintSignature,});// For user-signed PINTs (secp256k1), the recovered address should match// the user's EOA or be a valid signer on the Safeif (recoveredAddress.toLowerCase() !== expectedSignerAddress.toLowerCase()) { throw new Error("PINT signature verification failed");}
from eth_account.messages import encode_typed_datafrom eth_account import Account# Reconstruct and encode the typed datasignable = encode_typed_data(domain_data, message_types, message_data, "PurchaseIntent")# Recover the signerpint_signature = request.headers.get("X-Pint-Signature")recovered = Account.recover_message(signable, signature=bytes.fromhex(pint_signature[2:]))if recovered.lower() != expected_signer.lower(): raise ValueError("PINT signature verification failed")
Confirm that the pint_signature claim in the JWT matches the X-Pint-Signature header. This ensures the JWT and the PINT signature are referring to the same authorisation:
if (jwtPayload.pint_signature !== pintSignature) { throw new Error("JWT pint_signature claim does not match X-Pint-Signature header");}
function verifyPintSignature( request: Request, jwtPayload: jose.JWTPayload): void { // 1. Get headers const pintSignature = request.headers.get("x-pint-signature"); const pintPayloadB64 = request.headers.get("x-pint-payload"); if (!pintSignature || !pintPayloadB64) { throw new Error("Enhanced tier requires X-Pint-Signature and X-Pint-Payload headers"); } // 2. Decode payload const pintPayload = JSON.parse( Buffer.from(pintPayloadB64, "base64").toString("utf-8") ); // 3. Reconstruct EIP-712 hash and verify signature const recoveredAddress = recoverTypedDataAddress({ domain: { name: "Sumvin Purchase Intent", version: "1", chainId: BigInt(1329), verifyingContract: pintPayload.wallet, }, types: { PurchaseIntent: [/* ... full type array ... */] }, primaryType: "PurchaseIntent", message: { wallet: pintPayload.wallet, nonce: BigInt(pintPayload.nonce), statement: pintPayload.statement, scopes: pintPayload.scopes, resources: pintPayload.resources, maxAmount: BigInt(pintPayload.maxAmount), maxAmountToken: pintPayload.maxAmountToken, expiresAt: BigInt(pintPayload.expiresAt), }, signature: pintSignature, }); // 4. Verify signer matches the wallet in the JWT if (recoveredAddress.toLowerCase() !== (jwtPayload.wallet as string).toLowerCase()) { throw new Error("PINT signature does not match JWT wallet"); } // 5. Cross-check JWT claim if (jwtPayload.pint_signature !== pintSignature) { throw new Error("JWT pint_signature does not match header"); }}
For agent-signed PINTs (signer_type: "agent"), standard ECDSA recovery won’t work. Agent keys use P-256, and verification happens via EIP-1271 isValidSignature on the Safe contract. If you need to verify agent-signed PINTs, you’ll need to make an on-chain call to the Safe contract.