Overview
The Payment Verification System validates that buyers have completed off-chain fiat payments before releasing on-chain assets. The zkp2p protocol uses a unified verifier architecture that supports multiple payment methods (Venmo, PayPal, Wise, etc.) through a single configurable contract.The system replaced individual payment verifiers (VenmoVerifier, PayPalVerifier, etc.) with the UnifiedPaymentVerifier for easier maintenance and upgrades.
Architecture Overview
Key Components
1. UnifiedPaymentVerifier
The main verifier contract that validates payment attestations (located atcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol).
Responsibilities:
- Decode payment attestations
- Validate intent snapshots against on-chain intent data
- Verify EIP-712 attestation signatures via AttestationVerifier
- Nullify payments to prevent double-spending
- Calculate release amounts (supporting partial fulfillment)
- Emit payment details for off-chain reconciliation
2. AttestationVerifier
Pluggable verifier for attestation signatures from off-chain services (witnesses, TEE, etc.). Interface (fromcontracts/interfaces/IAttestationVerifier.sol:16):
3. NullifierRegistry
Prevents double-spending by tracking used payment IDs (fromcontracts/registries/NullifierRegistry.sol).
Key Functions:
Payment Verification Flow
Data Structures
PaymentAttestation
The top-level structure submitted as payment proof (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:85):
PaymentDetails
Detailed information about the off-chain payment (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:65):
IntentSnapshot
Snapshot of intent parameters at signal time (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:74):
Verification Process
Step 1: Decode Attestation
Step 2: Decode Payload
attestation.data field contains both payment details and intent snapshot.
Step 3: Validate Payment Method
Step 4: Validate Intent Snapshot
The verifier reads the intent from the Orchestrator and validates every field (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:220):
Why validate the snapshot? This ensures the attestation service is verifying the payment against the exact same intent parameters that were locked on-chain. Any mismatch indicates tampering.
Step 5: Verify Attestation
The verifier constructs an EIP-712 digest and validates signatures (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:183):
EIP-712 Domain
The domain separator is computed at deployment (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:106):
EIP-712 Type Hash
Step 6: Nullify Payment
To prevent double-spending, the payment ID is nullified (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:242):
The nullifier includes both payment method and payment ID to prevent collisions (e.g., Venmo transaction #123 vs PayPal transaction #123).
Step 7: Calculate Release Amount
The release amount can be capped to the intent amount (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:250):
Step 8: Emit Payment Details
Payment details are emitted for off-chain reconciliation and indexing (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:260):
Step 9: Return Result
Base Verifier Architecture
TheBaseUnifiedPaymentVerifier (from contracts/unifiedVerifier/BaseUnifiedPaymentVerifier.sol) provides shared functionality:
Payment Method Management
Attestation Verifier Management
Orchestrator Authorization
Only whitelisted orchestrators can callverifyPayment() (from contracts/unifiedVerifier/BaseUnifiedPaymentVerifier.sol:48):
Nullifier Registry
The NullifierRegistry prevents double-spending of payments (fromcontracts/registries/NullifierRegistry.sol).
Write Permissions
Only addresses with write permissions can add nullifiers:Adding Nullifiers
Payment Method Registry
The PaymentVerifierRegistry (fromcontracts/registries/PaymentVerifierRegistry.sol) maps payment methods to verifiers and supported currencies.
Adding Payment Methods
Managing Currencies
Querying
Attestation Service Integration
The UnifiedPaymentVerifier is designed to work with off-chain attestation services that:- Monitor Off-Chain Payments: Watch for payments on Venmo, PayPal, Wise, etc.
- Extract Payment Details: Parse amount, currency, timestamp, payment ID, etc.
- Fetch Intent Data: Read intent parameters from Orchestrator
- Calculate Release Amount: Apply conversion rate and handle partial fulfillment
- Sign Attestation: Create EIP-712 signature over PaymentAttestation struct
- Submit to Orchestrator: Anyone can call
fulfillIntent()with the signed attestation
Attestation Service Types
TEE-based
Trusted Execution Environments (SGX, TDX) verify payments in hardware enclaves
Multi-Witness
Multiple independent attestors sign payment verification (threshold signatures)
ZK Proofs
Zero-knowledge proofs of email receipts or bank statements
Hybrid
Combination of TEE + ZK or TEE + multi-witness for added security
Security Considerations
Timestamp Buffer
ThetimestampBuffer in IntentSnapshot limits how old a payment can be relative to the intent signal time:
- Max buffer: 48 hours (
MAX_TIMESTAMP_BUFFER = 48 * 60 * 60 * 1000at line 31)
Data Hash Integrity
The attestation includes adataHash that must match the actual data:
Orchestrator-Only Access
The verifier can only be called by whitelisted orchestrators (fromcontracts/unifiedVerifier/UnifiedPaymentVerifier.sol:128):
Events
Upgradeability
The payment verification system is designed for easy upgrades:- Verifier Replacement: Deploy new UnifiedPaymentVerifier, update PaymentVerifierRegistry
- Attestation Verifier: Update via
setAttestationVerifier()without redeploying main verifier - Payment Methods: Add/remove payment methods via registry without contract changes
No Critical State: The UnifiedPaymentVerifier holds no critical state (besides configuration). All intents and deposits live in Orchestrator and Escrow.
Related Contracts
- Orchestrator - Calls verifyPayment during fulfillment
- Intent Lifecycle - Shows where verification fits in the flow
- Registry System - Payment method and currency management