A peer-to-peer crypto escrow system that verifies fiat payments before releasing locked crypto assets. Built for the Monad Network.
P2P crypto buyers send fiat directly to sellers. If that fiat originates from fraud, the seller's bank account gets frozen — even if the seller is innocent. AegisP2P prevents this by requiring proof of a legitimate fiat payment before releasing escrowed crypto.
- Seller locks crypto in the escrow contract, specifying the buyer's address, fiat amount, and recipient identifier
- Buyer marks fiat as paid off-chain (simulated with Stripe/UPI in the mock)
- Seller generates a proof of the fiat payment on-chain using the Reclaim-style verification interface
- Contract verifies the proof via the configured verifier (MockReclaim in demo) and releases crypto to the buyer
- Refund available to the seller if the timeout (2 hours) expires without verification
| Layer | Technology |
|---|---|
| Blockchain | Monad Testnet (EVM, chain ID 10143) |
| Smart Contracts | Solidity ^0.8.26, OpenZeppelin |
| ZK Verification | Reclaim Protocol interface (mock in demo) |
| Frontend | Next.js 16, Tailwind CSS v4, Wagmi v2, RainbowKit v2 |
| Wallet Connectors | RainbowKit (MetaMask, OKX, WalletConnect, etc.) |
contracts/
├── contracts/
│ ├── AegisEscrow.sol # Core escrow contract
│ └── mocks/
│ └── MockReclaim.sol # Mock verifier for demo
├── scripts/
│ ├── deploy.js # Production deploy script
│ └── deploy-mock.js # Demo deploy (includes MockReclaim)
├── test/ # Contract tests
├── .env.example
└── hardhat.config.js
frontend/
├── src/
│ ├── app/
│ │ ├── page.tsx # Main UI
│ │ ├── layout.tsx # Root layout + providers
│ │ ├── providers.tsx # Wagmi + RainbowKit providers
│ │ └── api/reclaim/ # Reclaim webhook endpoint
│ ├── components/
│ │ ├── escrow/ # EscrowCard, EscrowList, CreateEscrowForm, etc.
│ │ ├── layout/ # Header
│ │ └── ui/ # LoadingSpinner, ConfirmModal
│ ├── hooks/ # useEscrows, useContractActions
│ ├── services/ # Verification + FiatPayment service abstractions
│ ├── lib/ # Contract ABI, legacy demoProof util
│ ├── config/ # Wagmi config, chain definitions
│ └── types/ # EscrowData, EscrowState
├── .env.example
└── package.json
All external services are mocked — no Stripe, no Reclaim oracle, no real API keys required.
- Connect your wallet (any EVM wallet via RainbowKit)
- Fill the form: buyer address, crypto amount, fiat amount, recipient, reference ID
- Click "Lock Crypto & Create Escrow" — sends a tx to the contract
- As buyer, click "Mark as Paid" — simulates off-chain fiat payment
- As seller, click "Verify & Release" — auto-generates a proof via
MockVerificationServiceand submits it - The contract validates the proof against
MockReclaim(always accepts) and releases crypto
IVerificationService IFiatPaymentService
↕ ↕
MockVerificationService MockFiatPaymentService
(generates fake proofs) (simulates payment)
Swapping to production:
- Replace
MockVerificationServicewith aReclaimVerificationServicethat calls the Reclaim SDK - Replace
MockFiatPaymentServicewith aStripePaymentServicethat creates actual payment intents - Deploy the real
ReclaimVerifiercontract and callsetReclaimVerifier()
- AegisEscrow: Core escrow logic — create, mark paid, verify & release, refund. Ownable, pausable, reentrancy-guarded.
- MockReclaim: Accepts any proof (unless
setShouldFail(true)is called). Implements theIReclaim.verifyProof()interface.
Deployed instances (Monad Testnet):
- AegisEscrow:
0x2CD627423A35E2E8BCE320041Ae0163004Ec0601 - MockReclaim:
0xa6fEcB7f1Feef414Ff978121e6F7913210BE00ea
See .env.example in each directory. Required:
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID— from https://cloud.walletconnect.com (optional, app works without it)NEXT_PUBLIC_ESCROW_CONTRACT_ADDRESS— deployed escrow addressPRIVATE_KEY(contracts/.env) — for running deploy scripts