The short version
A seller creates a deposit by locking USDC in EscrowV2 on Base and listing the fiat payment method, currency, payout identifier, and rate. A buyer chooses that liquidity, starts an onchain intent, pays the seller in the selected payment app, and submits payment evidence.
The protocol does not ask either side to trust a chat screenshot. Payment evidence is checked offchain by the attestation service, and the resulting EIP-712 PaymentAttestation is verified onchain before the contract releases USDC.
The fill lifecycle
- 01Seller deposits native USDC on Base into EscrowV2 and declares accepted payment methods, currencies, and payee details.
- 02Buyer selects the deposit and signals an intent through OrchestratorV3. That intent reserves the specific amount while the buyer pays.
- 03Buyer pays the seller directly in the selected fiat app. USDCtoFiat never receives or holds the fiat transfer.
- 04Payment evidence is verified against the intent: amount, currency, recipient, timestamp, payment method, and route constraints.
- 05The attestation service signs a PaymentAttestation. The onchain verifier checks the signature, snapshot values, and nullifier, then OrchestratorV3 releases USDC.
Why the contract can release safely
| Primitive | What it does | Why it matters |
|---|---|---|
| EscrowV2 | Holds seller USDC on Base | Neither USDCtoFiat nor the buyer can move it without contract rules |
| Intent hash | Identifies one buyer order | Binds fiat payment proof to the exact fill |
| PaymentAttestation | EIP-712 signed verification result | Lets one verifier contract handle multiple payment methods |
| Nullifier | One-time marker for a payment | Prevents the same payment from being claimed twice |
| Payee details hash | Hash of the seller's payout identifier | Binds payment to the seller. For most methods it is unsalted, so anyone who knows the handle can match it |
What is public
Your payout handle is not written to Base as plain text, but each deposit records a hash of it, and for most payment methods that hash is unsalted. Anyone who knows or guesses your Cashtag, Revtag, Zelle email or Venmo account ID can hash it and find every deposit that uses it, and ZKP2P's public maker lookup returns the handle registered for a hash. Treat your payout handle as public. Your payment-app login and account history are not posted to Base.
Your payout identifier is still visible to the counterparty who needs to pay you. That is unavoidable in any payment-app settlement flow: the buyer cannot send fiat without a destination.