A working demonstration of Privacy-Preserving Origin Inspection (PPOI) integrated with real-time compliance verification using Self Protocol and Blockaid.
Repository: https://github.com/0x2kNJ/PPOI-test
Branch:self-protocol-demo
Status: ✅ Production-ready demonstration with working end-to-end flow
This demo shows how to create privacy-preserving financial transactions that include cryptographically-bound compliance data without revealing user information on-chain.
Key Features:
- Identity Verification via Self Protocol (government ID-based, privacy-preserving)
- Address Screening via Blockaid (OFAC, AML, sanctions checks)
- ZK Proofs for transaction privacy (using Barretenberg)
- Composite PPOI Notes that combine multiple verification sources
- Desktop-to-Mobile Flow with QR codes and real-time WebSocket updates
This is a focused integration demo showing how to implement Privacy-Preserving Origin Inspection (PPOI) with Self Protocol + Blockaid:
Frontend Demo (ui/)
- React + TypeScript UI demonstrating PPOI flow
- Self Protocol QR code integration (desktop → mobile)
- Blockaid address screening (real-time API calls)
- MetaMask wallet connection
- Real-time WebSocket updates
- Zero-knowledge proof generation (Barretenberg in browser)
Backend Services (backend/)
- Self Protocol callback server
- WebSocket server for real-time verification updates
- Express API for verification handling
Smart Contract Reference (contracts/)
PPOIVerifier.sol- Example PPOI verification contract- Included for reference and understanding the on-chain component
Documentation (docs/)
- Complete architecture documentation
- Integration guides
- API reference
- Developers: Learn how to integrate Self Protocol + Blockaid
- Integrators: See working example of privacy-preserving compliance
- Researchers: Study desktop-to-mobile verification flows
- Demo: Show privacy-preserving identity + address screening in action
This is a demo repository, not a full contract development environment. For complete smart contract infrastructure (circuits, deployment tools, testing framework), see the main PPOI development repository.
┌─────────────────────────────────────────────────────────┐
│ Frontend (React + Vite) │
│ - Wallet connection (MetaMask) │
│ - UTXO creation & commitment generation │
│ - QR code display for mobile verification │
│ - WebSocket client for real-time updates │
└────────────────────┬────────────────────────────────────┘
│
┌──────────┴──────────┐
│ │
┌─────────▼─────────┐ ┌────────▼─────────┐
│ Self Protocol │ │ Blockaid API │
│ (Identity Proofs) │ │ (Address Screen) │
└─────────┬─────────┘ └────────┬─────────┘
│ │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Backend (Express) │
│ - Verification │
│ - WebSocket server │
│ - Mock responses │
└─────────────────────┘
This demo integrates two complementary compliance verification systems:
Self Protocol (self.xyz) provides privacy-preserving identity verification using zero-knowledge proofs generated from government-issued IDs.
What it does:
- ✅ Verifies humanity - Proves the user is a real person (not a bot)
- ✅ Verifies age - Proves age threshold (e.g., 18+, 21+) without revealing exact age
- ✅ Verifies nationality - Proves citizenship without revealing passport details
- ✅ Privacy-preserving - Uses zk-SNARKs; no personal data leaves your phone
How it works:
- User scans QR code on desktop with Self Protocol mobile app
- App reads NFC chip from passport/ID and generates zero-knowledge proof
- Proof sent to backend; frontend receives real-time WebSocket notification
- Proof attached to PPOI note in UTXO commitment
SDKs Used:
@selfxyz/core- Backend verification SDK@selfxyz/qrcode- QR code generation for mobile handoff
Blockaid provides real-time blockchain security and compliance screening for wallet addresses.
What it does:
- 🛡️ Checks against OFAC sanctions lists and global watchlists
- 🛡️ Detects malicious addresses (phishing, scams, hacks)
- 🛡️ Provides risk scoring (LOW/MEDIUM/HIGH)
- 🛡️ Screens for AML violations and suspicious activity
How it works:
- User provides wallet address
- System queries Blockaid API with address and chain
- Returns compliance status and risk assessment
- Results attached to PPOI note in UTXO commitment
API Used:
- Blockaid REST API (
/v0/scan/ethereum/address)
Blockaid screens the address (on-chain history, sanctions)
Self Protocol verifies the person (identity, humanity, attributes)
Together, they provide comprehensive compliance coverage for privacy-preserving financial applications.
- View on GitHub - Source code and issues
- Architecture Documentation - System design and data flow
- Contributing Guide - How to contribute
- Transformation Summary - How this was built
- Node.js 18+
- MetaMask wallet
- Self Protocol mobile app (for identity verification)
- Cloudflare tunnel OR ngrok (for mobile app callback)
-
Install Dependencies
# Frontend cd ui npm install # Backend cd ../backend npm install
-
Configure Environment
# In demo/ui directory cp .env.example .env.demo # Edit .env.demo: VITE_BLOCKAID_API_KEY=your_blockaid_api_key VITE_SELF_CALLBACK_URL=https://your-tunnel-url.com/api/self-callback
-
Start Services
# Terminal 1: Start backend cd backend npm start # Terminal 2: Start Cloudflare tunnel cloudflared tunnel --url http://localhost:3001 # Copy the https:// URL and update VITE_SELF_CALLBACK_URL # Terminal 3: Start frontend cd ui npm start
-
Open Demo
http://localhost:4193
- User connects MetaMask
- System generates a UTXO (Unspent Transaction Output) with commitment
- Shielded address created for privacy
Blockaid (Address Screening):
- Checks address against OFAC sanctions lists
- Screens for malicious activity, phishing
- Risk scoring (LOW/MEDIUM/HIGH)
Self Protocol (Identity Verification):
- User scans QR code with Self Protocol mobile app
- App generates zero-knowledge proof from government ID
- Proof verifies attributes (age, nationality, humanity) without revealing identity
- Backend receives and validates proof via WebSocket
- Verification results encoded into JSON
- JSON attached to UTXO's
notefield - Commitment recalculated with PPOI data included
- Cryptographically binds compliance to transaction
- Barretenberg generates zero-knowledge proof
- Proof includes PPOI note in commitment
- Transaction privacy maintained on-chain
- Proof submitted to privacy pool contract
- Only commitment visible on-chain
- PPOI note encrypted within commitment
This is a focused integration demo with minimal structure for clarity:
ppoi-test/
├── ui/ # Frontend Demo Application
│ ├── src/
│ │ ├── components/
│ │ │ └── PPOIFlowDemo.tsx # Main PPOI flow component
│ │ └── services/
│ │ ├── blockaid.ts # Blockaid API client
│ │ └── self.ts # Self Protocol integration
│ ├── package.json
│ └── .env.demo # Environment configuration
│
├── backend/ # Self Protocol Mock Backend
│ ├── mock-server.js # Express server with WebSocket
│ └── package.json # Backend dependencies
│
├── contracts/ # Smart Contract Reference
│ └── PPOIVerifier.sol # PPOI verification contract (for reference)
│
├── docs/ # Documentation
│ └── ARCHITECTURE.md # System architecture
│
└── archive/ # Historical Documentation
├── status-updates/ # Progress updates
└── setup-guides/ # Old setup guides
Different compliance providers serve different purposes:
- Blockaid: Address-level risk (on-chain history, sanctions)
- Self Protocol: Identity-level attributes (age, nationality, humanity)
Combining them provides comprehensive compliance coverage.
Self Protocol's identity proofs require:
- Government-issued ID (stored securely on phone)
- NFC chip reading (mobile-only)
- Biometric authentication
QR codes enable seamless handoff from desktop to mobile.
- Mobile app sends proof to backend (HTTP POST)
- Backend needs to notify frontend (active tab)
- WebSocket provides instant, push-based updates
- Better UX than polling
This is a demonstration. In production:
- Use real Self Protocol backend verification
- Implement proper proof validation
- Store verification results securely
- Add rate limiting and authentication
POST /api/self-callback
- Receives Self Protocol verification results
- Validates proof (mocked in demo)
- Notifies frontend via WebSocket
GET /health
- Health check endpoint
- Returns:
{status: "ok", mock: true, websocket: true}
WebSocket ws://localhost:3001
- Client sends:
{type: "register", sessionId: "uuid"} - Server sends:
{type: "verification_result", sessionId: "uuid", ...result}
blockaid.ts
checkCompliance(address: string, chain: string): Promise<BlockaidComplianceCheck>self.ts
requestVerification(request: SelfVerificationRequest): Promise<SelfProofData>
generateSelfQRCode(request: SelfVerificationRequest): Promise<string>Frontend (.env.demo)
VITE_BLOCKAID_API_KEY= # Optional: For real Blockaid checks
VITE_SELF_CALLBACK_URL= # Required: Public URL for mobile callbackBackend
PORT=3001 # Server port (default: 3001)Cloudflare Tunnel (Free, No Account)
cloudflared tunnel --url http://localhost:3001ngrok (Requires Account)
ngrok http 3001localtunnel (Free, Open Source)
lt --port 3001- Enable Self Protocol and/or Blockaid toggles
- Connect wallet
- Create deposit
- Run verifications
- Attach PPOI note
- Generate ZK proof (note: requires proper Barretenberg setup)
The backend always returns successful verification. To test failures:
- Edit
backend/mock-server.js - Change
status: 'success'tostatus: 'error' - Restart backend
QR Code Not Working
- Ensure Cloudflare tunnel is running
- Check
VITE_SELF_CALLBACK_URLis set to tunnel URL (not localhost) - Verify backend is accessible:
curl https://your-tunnel-url.com/health
WebSocket Connection Failed
- Check backend is running on port 3001
- WebSocket always uses
ws://localhost:3001(not tunnel URL) - Frontend and backend must be on same machine
"Proof failed" in Self Protocol App
- Scroll through all disclosures in the app
- Tap each checkbox to acknowledge
- Some disclosures require scrolling to reveal the accept button
⚠️ Mock backend always returns success⚠️ No real proof validation⚠️ No authentication or rate limiting⚠️ Sensitive logs (proofs, keys) printed to console
- Implement real Self Protocol backend verification
- Validate cryptographic proofs properly
- Use secure WebSocket (wss://) with authentication
- Implement rate limiting and DDOS protection
- Store verification results in secure database
- Audit all crypto operations
- Follow GDPR/privacy regulations
# Install dependencies
cd ui && npm install
# Start dev server
npm run start # http://localhost:4193
# Build for production
npm run build
# Type check
npm run typecheck# Install dependencies
cd backend && npm install
# Start mock server
npm start # http://localhost:3001
# Test endpoints
curl http://localhost:3001/health# Terminal 1: Start backend
cd backend && npm start
# Terminal 2: Start Cloudflare tunnel
cloudflared tunnel --url http://localhost:3001
# Terminal 3: Update .env.demo with tunnel URL and start frontend
cd ui && npm start
# Browser: Open http://localhost:4193Contributions welcome! See CONTRIBUTING.md for guidelines.
Areas for improvement:
- Enhanced Self Protocol backend verification
- Additional ZK circuit optimizations
- Comprehensive integration tests
- Mobile-responsive UI improvements
- Multi-chain deployment support
- Gas optimization for contracts
MIT
Frontend
- React + TypeScript
- Vite (build tool)
- ethers.js (wallet integration)
- qrcode.react (QR code display)
Backend
- Node.js + Express
- WebSocket (ws package)
- Mock verification server
Integrations
- @selfxyz/core - Backend verification SDK
- @selfxyz/qrcode - QR code generation
- Blockaid API - Address screening
- Barretenberg - ZK proofs
Infrastructure
- Cloudflare Tunnel / ngrok - Public callback URLs
- WebSocket - Real-time frontend-backend communication
Built with contributions from:
- Self Protocol - Privacy-preserving identity verification using zk-SNARKs
- Blockaid - Real-time blockchain security and compliance
- Aztec/Barretenberg - ZK proof generation library
- Bermuda - Privacy pool SDK and architecture
Special thanks to the open-source community for tools like Vite, Express, and WebSocket that made this integration seamless.
Made with ❤️ for privacy-preserving finance