Trustless, oracle-driven parametric insurance. Policies live on-chain. Payouts are automatic, instant, and verifiable.
Traditional insurance is broken for the digital age:
- Claims take weeks or months to process
- Adjusters can deny valid claims subjectively
- Paperwork and middlemen eat into premiums
- The unbanked and underinsured have no accessible options
blockPolicy eliminates every one of these problems. When a real-world event (heavy rain, flight delay, earthquake) breaches a pre-agreed threshold, the oracle triggers an instant, cryptographically-verifiable payout — no claims forms, no adjusters, no waiting. The smart contract is the insurer.
- Every policy is a deployed Algorand smart contract (ARC-4 compliant)
- Policy parameters (coverage type, threshold, payout amount, dates) are stored in global state — immutable, transparent, tamper-proof
- The oracle's identity is verified by an OracleRegistry contract before any payout executes
- All policy activations emit an on-chain audit trail as a 0-ALGO self-send with the policy SHA-256 hash in the note field
- policyholder's payout amount is escrowed in the PolicyContract at purchase time
- On trigger, the oracle calls
trigger_payout()→ inner ALGO transfer executes atomically inside the AVM - ALGO is routed through the LiquidityPool (
deposit()+fund_payout()in an atomic group) — the pool earns a dynamic 3–12% APY based on active coverage utilisation - Fallback path: direct oracle→user transfer if the pool route ever fails
- For every trigger, 2+ independent real-world data sources are polled simultaneously
- Payout only executes if ≥ 2/3 sources agree the threshold was breached — prevents single-point manipulation
- Coverage data sources per policy type:
| Coverage | Source 1 | Source 2 |
|---|---|---|
| 🌧 Weather (Rainfall) | Open-Meteo (free, no key) | WeatherAPI |
| OpenSky Network | AviationStack | |
| 🌍 Natural Disaster | USGS Earthquake Catalog | — |
- Multi-step KYC with email OTP verification (6-digit, 10-minute expiry, stored in-memory)
- Aadhaar e-KYC simulation (UIDAI-style 12-digit Aadhaar number + OTP flow)
- Document upload pinned to IPFS via Pinata — CID stored on-chain and on the KYC record
- KYC approval issues an on-chain Algorand proof transaction (note:
BLOCKPOLICY:KYC:APPROVED) from the platform wallet to the user's wallet - Automated transactional emails at every KYC lifecycle event (submitted → approved → rejected) via Gmail OAuth2 or SMTP
- Email sent on: KYC submission, KYC approval, KYC rejection, payout execution
- Payout emails include the exact ALGO amount, TX ID, and a direct Pera Explorer link
- Gmail OAuth2 (freshed access token per send) + SMTP App Password fallback
- Graceful no-op if no email credentials are configured (logs to console)
- Pinnable/collapsible sidebar — collapses to 68px icon rail, expands to 228px; pin preference persisted in
localStorage - Animated hero homepage with real-time live stats fetched from the backend (
/api/dashboard/stats,/api/pool/stats) - Live pulsing network indicator, floating logo, gradient text, glass-morphism cards, radial-gradient blob backgrounds
- 30-second auto-refresh on My Policies page + manual refresh button
- Payout TX links displayed inline on policy cards; KYC status colour-coded in the sidebar wallet section
- Fully mobile-responsive with CSS transitions
- Input validation on every API endpoint: Algorand address format, payout amount bounds (1–1000 ALGO), date ordering, coverage type whitelist
- Express rate limiting: 200 req/15 min general; tighter 15 req/min on oracle + trigger endpoints
- Double-trigger prevention: in-memory
PayoutLocksSet — concurrent payout calls on the same policy return HTTP 429 - OracleRegistry whitelist enforced at the smart contract level — only the registered oracle address can call
trigger_payout() ADMIN_KEYheader-gated admin endpoints; all secrets in.env(gitignored)- CORS restricted to known frontend origins + wildcard
*.vercel.appfor Vercel preview deployments - Document uploads validated by MIME type (JPEG, PNG, WEBP, PDF only; 10 MB cap)
- Hourly cron (
node-cron): polls all active oracle-created policies, evaluates consensus, triggers payouts automatically — no manual intervention needed - Daily midnight cron: scans for policies past their
end_date, callsexpire_policy()on-chain, forwards remaining balance to the policyholder's wallet
- Frontend deployed on Vercel (Vite SPA with SPA rewrites): parametric-insurance-omega.vercel.app
- Backend deployed on Vercel (
@vercel/nodeserverless): backend-rouge-iota.vercel.app - Multi-wallet support: Pera Wallet, Lute Wallet (BIP39/SLIP-0010 HD key derivation for 24-word mnemonics)
| URL | |
|---|---|
| 🌐 Frontend | parametric-insurance-omega.vercel.app |
| ⚙️ Backend API | backend-rouge-iota.vercel.app |
| Smart Contract | App ID | Explorer |
|---|---|---|
| OracleRegistry | 756705409 |
View on Pera Explorer |
| LiquidityPool | 756705422 |
View on Pera Explorer |
Network: Algorand Testnet · Node: https://testnet-api.algonode.cloud
User connects Pera / Lute wallet → completes KYC → buys policy (1 tx sign)
↓
Oracle creates PolicyContract on-chain (oracle is creator for payout authority)
User funds the contract (payout amount + min balance buffer) via signed payment tx
↓
Hourly cron / manual trigger: oracle polls 2+ real-world data APIs
↓
Consensus engine: ≥ 2/3 sources agree threshold is breached?
↓ YES ↓ NO
oracle calls trigger_payout() Policy remains active
→ inner ALGO transfer (AVM) until end_date
→ oracle deposits to LiquidityPool
→ LiquidityPool.fund_payout() → user wallet credited
→ On-chain audit trail recorded
→ Payout confirmation email sent
↓
Daily cron: expired policies → expire_policy() on-chain → balance returned to user
blockPolicy/
├── blockPolicy.jsx # React frontend (single-file SPA, Vite)
├── index.html
├── vite.config.js
├── contract_ids.json # Deployed App IDs (testnet)
│
├── backend/
│ ├── server.js # Express API + oracle engine
│ └── data/
│ ├── policies.json # Policy store (persistent)
│ └── kyc_applications.json
│
└── contracts/
├── policy_contract.py # PolicyContract (Beaker/PyTeal)
├── oracle_registry.py # OracleRegistry
├── liquidity_pool.py # LiquidityPool
├── deploy.py # Python deployer
├── deploy.js # Node.js deployer
└── artifacts/ # Compiled ABI + TEAL (ARC-4)
├── PolicyContract.json
├── OracleRegistry.json
└── LiquidityPool.json
PolicyContract — one app per policy; stores coverage parameters, threshold, payout amount, and policy status in global state. The oracle (creator) calls trigger_payout() which executes an inner payment to the insured wallet.
OracleRegistry — maintains a whitelist of approved oracle addresses. The PolicyContract verifies the caller is a registered oracle before executing any payout.
LiquidityPool — holds pooled ALGO reserves. Accepts deposit() calls and routes payouts via fund_payout(recipient, amount), keeping an on-chain audit trail.
- Multi-source consensus: reads 2+ independent data APIs per trigger; requires ≥ 2/3 agreement
- Rate limiting: 15 oracle trigger requests/minute (tighter than general API)
- Double-trigger protection: in-memory
PayoutLocksSet prevents re-entrancy - Daily expiry cron: marks expired policies at midnight UTC
- Blockchain audit trail: every policy activation is recorded as a 0-ALGO self-send with the policy hash in the note field
Single-file React SPA (blockPolicy.jsx) using Vite. Connects to any Algorand wallet via the Pera Wallet Connect SDK. No npm dependencies beyond React and algosdk.
Key pages:
- Buy Policy — select coverage type, location, threshold, dates; sign one transaction
- My Policies — live-refreshing list (30-second poll + manual refresh); shows paid/active/expired status and payout TX links
- Policy Explorer — browse all on-chain policies; filter by type or wallet address
- Oracle Demo — manually fetch oracle data and trigger policy checks
- Dashboard — pool balance, APY, total policies, payout statistics
- Admin Panel — KYC review and approval
Users complete a lightweight KYC check before purchasing a policy:
- Submit name, date of birth, email, phone, Aadhaar reference, and a document upload
- Admin approves/rejects via the Admin Panel
- Approval issues a KYC token stored in localStorage and on the backend
owner_emailis stored on the policy record at creation time, so payout confirmation emails are sent even for wallets not directly in the KYC store
- Node.js ≥ 18
- Python 3.10+ with
pip - Algorand Testnet wallet (use Pera Wallet)
git clone https://github.com/zainab-06-p/blockPolicy.git
cd blockPolicy
npm install # frontend dev deps
cd backend && npm install# backend/.env
ORACLE_MNEMONIC="word1 word2 ... word25" # funded testnet oracle wallet
WEATHERAPI_KEY=your_key # weatherapi.com (free tier)
AVIATIONSTACK_KEY=your_key # aviationstack.com (free tier)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your@gmail.com
SMTP_PASS=your_app_password
FRONTEND_URL=http://localhost:5173cd contracts
python deploy.py # outputs contract_ids.json# Terminal 1 — backend
cd backend && npm start
# Terminal 2 — frontend
npm run devOpen http://localhost:5173, connect your Pera Wallet (testnet), complete KYC, and buy a policy.
| Area | Implementation |
|---|---|
| Address validation | Every endpoint rejects malformed Algorand addresses before any processing |
| Amount bounds | Payout must be 1–1,000 ALGO; checked server-side and encoded into contract args |
| Oracle whitelist | OracleRegistry on-chain box storage; contract rejects calls from unregistered oracles |
| Re-entrancy guard | PayoutLocks Set blocks concurrent triggers on the same policy (HTTP 429) |
| Rate limiting | 200 req/15 min general API; 15 req/min oracle endpoints (express-rate-limit) |
| Secrets management | All mnemonics, API keys, and admin keys live in .env — gitignored, never in source |
| CORS | Allowlist: exact known origins + *.vercel.app pattern only |
| File uploads | MIME-type whitelist (JPEG/PNG/WEBP/PDF) + 10 MB cap enforced by multer |
| Admin endpoints | X-Admin-Key header required; key set only via environment variable |
| IPFS metadata | KYC document CIDs pinned via Pinata; metadata includes compliance note for AML/PMLA |
| Layer | Technology |
|---|---|
| Smart Contracts | PyTeal + Beaker (ARC-4 ABI, inner transactions, box storage) |
| Blockchain | Algorand Testnet via algonode.cloud |
| Backend | Node.js + Express (serverless on Vercel) |
| Oracle Data | Open-Meteo · WeatherAPI · OpenSky · AviationStack · USGS |
| IPFS | Pinata (JWT auth) with local-simulation fallback |
| Gmail OAuth2 (fresh token per send) + SMTP App Password fallback | |
| Frontend | React + Vite (single-file SPA, no build-time framework overhead) |
| Wallet | Pera Wallet Connect + Lute Connect (BIP39/SLIP-0010 HD wallets) |
| Deployment | Vercel (frontend + backend, separate projects) |
| Scheduling | node-cron (hourly oracle poll, daily expiry sweep) |
Built for the Algorand Hackathon — parametric insurance reimagined as trustless, instant, on-chain coverage.
| # | Name |
|---|---|
| 1 | Zainab Pirjade |
| 2 | Akshata Deshpande |
| 3 | Saanvi Gawade |
| 4 | Sakshi Badakh |
blockPolicy — Because insurance should be as trustless as the blockchain it runs on.
git clone https://github.com/zainab-06-p/BlockPolicy.git && cd BlockPolicy && cp backend/.env.example backend/.env && cd backend && npm install && npm startThen in a second terminal from the project root:
npm install && npm run devOpen http://localhost:5173 — connect Pera/Lute wallet (Algorand Testnet), complete KYC, buy a policy.
- Who — Anyone who needs insurance: farmers, travelers, disaster-affected communities, and the 1.4B unbanked with no access to traditional insurers.
- What — Traditional insurance pays out slowly, subjectively, and opaquely — claims take weeks, adjusters can deny valid claims, and paperwork costs more than the premium.
- Why now — Algorand's 3.5-second finality, sub-cent fees, and AVM inner transactions make fully automated, trustless insurance economically viable for the first time.
- Our fix — blockPolicy encodes the entire insurance contract on-chain. When a real-world oracle confirms a trigger event, the payout executes atomically — no human, no delay, no denial.
blockPolicy is parametric insurance powered by Algorand smart contracts — policies that pay themselves. Connect your wallet, choose your coverage (weather, flight, or disaster), and receive an automatic ALGO payout the moment the oracle confirms your trigger condition. Try it live at parametric-insurance-omega.vercel.app — no signup, no bank account, just a testnet wallet.
| Decision | Why |
|---|---|
| Algorand over Ethereum | 3.5s finality, ~0.001 ALGO fees, fork-free PPoS consensus, and carbon-negative — essential for micro-insurance to be economically viable |
| PyTEAL / AVM smart contracts | AVM inner transactions allow the PolicyContract to push ALGO to the beneficiary atomically without a custodian |
| Oracle as app creator | Algorand's trigger_payout() requires the caller to be the creator; making the oracle the creator is the simplest, most secure authority model |
| Pinata IPFS for persistence | Vercel serverless containers are stateless and ephemeral — IPFS gives us a distributed, persistent store that survives cold starts and cross-container reads |
| Multi-source oracle consensus (≥2/3) | Single data source is a single point of manipulation; requiring agreement from 2+ independent APIs makes the trigger tamper-resistant |
| Read-merge-write on saveStore | Prevents stale warm containers from overwriting policies written by other containers — solves the distributed cache invalidation problem without a real database |
| Nodemailer built-in OAuth2 (no googleapis) | Manual googleapis token fetch silently fails on Vercel cold starts; nodemailer's built-in refresh token handling is synchronous and reliable |
| React single-file SPA | Keeps the frontend portable and auditable in one file — judges and reviewers can read the entire UI logic without navigating a complex component tree |
| Resource | Usage | License |
|---|---|---|
| Algorand Developer Docs | AVM inner transactions, ARC-4 ABI, PyTEAL patterns | Apache 2.0 |
| Open-Meteo | Free weather API (rainfall data) — no API key required | CC BY 4.0 |
| WeatherAPI | Rainfall data second source | Free tier (attribution required) |
| OpenSky Network | Flight status data | Creative Commons |
| AviationStack | Flight delay data second source | Free tier |
| USGS Earthquake Catalog | Seismic/disaster data | Public Domain (US Govt) |
| Pinata | IPFS document pinning for KYC | Commercial (free tier) |
| algosdk | Algorand JS SDK | MIT |
| py-algorand-sdk | Algorand Python SDK for contract deployment | MIT |
| nodemailer | Email transport | MIT |
| express-rate-limit | API rate limiting | MIT |
| Pera Wallet Connect | Wallet integration | MIT |
| Lute Connect | Lute wallet integration | MIT |
| # | Issue | Impact | How We Caught It | Fix Applied |
|---|---|---|---|---|
| 1 | Stale warm container cache — Vercel runs multiple lambda instances each with independent in-memory state; policies written by container A were invisible to container B | Policies disappeared from My Policies and Oracle Demo after creation | User reported "policy not found" despite successful payment deduction | 10-second TTL on cache + forced Pinata re-fetch + read-merge-write on every save |
| 2 | PINATA_JWT with \r\n suffix — Vercel stores env vars with Windows line endings; the trailing \r\n embedded in Authorization: Bearer <token> caused Node's HTTP client to throw "Invalid character in header content" |
All Pinata saves failed silently; policies and KYC docs were never persisted to IPFS | HTTP 500 on /api/kyc/upload-doc; console.warn logs showing the error |
Added .trim() to all Pinata and email env vars at read time |
| 3 | Payout email not delivered — sendPayoutForward called loadKycStore() synchronously before the KYC Pinata store had loaded on cold start; email was always null |
Payout emails silently skipped; user never notified | User reported no email received after confirmed on-chain payout | Added await ensureKycReady() before every loadKycStore() call in payout paths |
| 4 | Gmail OAuth2 silently failing — buildGmailTransport() used googleapis to manually fetch accessToken; this async call failed on cold starts causing transport = null and falling through to console-only logging |
All emails simulated (logged), never actually sent | POST /api/debug/email diagnostic endpoint returned "simulated": true |
Rewrote to nodemailer's built-in OAuth2 (passes only refreshToken; nodemailer fetches accessToken automatically and reliably) |
| 5 | Pinata overwrite by stale container — any savePolicies call from a container with a 2-policy stale cache silently overwrote Pinata, destroying newly added policies |
Recovered policy reappeared briefly then vanished again | Explorer showed correct count immediately after recovery, then wrong count 30s later | saveStore now does read-merge-write: loads current Pinata state before writing, preserves any policies the current container doesn't know about |