Unified Payment Verifier
Overview
UnifiedPaymentVerifierV4 verifies the payment attestations that the Attestation Service signs for Buyer TEE Verification and Seller Autopilot. Every registered payment method routes to it, for OrchestratorV4 and OrchestratorV3 intents. It checks the witness signatures through MultiAttestationVerifier, matches the attestation to the on-chain intent, records a nullifier so a payment can settle only one intent, caps the release amount at the intent amount, and returns the signed settlement data to the orchestrator.
Address: 0x7bE50E6206a9b3AdF36dbEAFac0e45Cc03A72048 on Base. Only registered orchestrators can call verifyPayment.
UnifiedPaymentVerifierV3 is no longer routed. The original UnifiedPaymentVerifier serves only the deprecated V1 orchestrator. See Deployments.
Typed data
- Primary type:
PaymentAttestation(bytes32 intentHash,uint256 releaseAmount,bytes32 dataHash) - EIP-712 domain:
name = "UnifiedPaymentVerifier",version = "1",chainId,verifyingContract= theUnifiedPaymentVerifierV4address
fulfillIntent takes paymentProof = abi.encode(PaymentAttestation):
struct PaymentAttestation {
bytes32 intentHash; // binds the attestation to the intent
uint256 releaseAmount; // token amount to release, before fees
bytes32 dataHash; // keccak256(data)
bytes[] signatures; // witness signatures
bytes data; // abi.encode(PaymentDetails, IntentSnapshot, bytes settlementData)
bytes metadata; // not signed; current responses identify the source path (buyer-tee or seller-tee)
}
struct PaymentDetails {
bytes32 method; // payment method hash
bytes32 payeeId; // hashed recipient ID
uint256 amount; // fiat minor units, e.g. cents
bytes32 currency; // currency code hash
uint256 timestamp; // payment time, milliseconds
bytes32 paymentId; // hashed platform transaction ID
}
struct IntentSnapshot {
bytes32 intentHash;
uint256 amount; // intent amount
bytes32 paymentMethod;
bytes32 fiatCurrency;
bytes32 payeeDetails; // must match the intent's payeeId
uint256 conversionRate; // 1e18 precision
uint256 signalTimestamp; // seconds
uint256 timestampBuffer; // allowed payment-time buffer
bytes32 payerCommitmentHash; // keccak256 of the intent's payerCommitment, zero when empty
address owner; // the address that signaled the intent
}
settlementData is abi.encode(uint256 disputeWindow) in seconds. The verifier returns it uninterpreted; the OrchestratorV4 settlement policy uses it. See Stake to Take.
Verification flow
- The attestation's
intentHashmatches the intent being fulfilled, andreleaseAmountis not zero. - The payment method is registered on the verifier and matches the snapshot.
paymentId,amountandcurrencyare not zero. - The snapshot matches the on-chain intent: amount, payment method, currency, payee, conversion rate, signal time, payer commitment hash and owner. The timestamp buffer is at most 48 hours.
keccak256(data) == dataHash, and the witness signatures over the EIP-712 digest satisfyMultiAttestationVerifier.- The nullifier
keccak256(paymentMethod || paymentId)must be unused; the verifier records it. PaymentVerifiedis emitted, andreleaseAmountis capped at the intent amount.
Governance
addPaymentMethod(method)andremovePaymentMethod(method)are owner-only.getPaymentMethods()lists registered methods.setAttestationVerifier(address)replaces the witness verifier and emitsAttestationVerifierUpdated.
Source: UnifiedPaymentVerifierV4.sol.