Skip to content

Repository files navigation

blockPolicy — Parametric Insurance on Algorand

Trustless, oracle-driven parametric insurance. Policies live on-chain. Payouts are automatic, instant, and verifiable.

Live Demo Backend API Network


The Problem We Solve

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.


✨ Key Features

🔗 Fully On-Chain Policies

  • 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

⚡ Instant Automatic Payouts via LiquidityPool

  • 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

🔮 Multi-Source Oracle With Consensus

  • 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
✈️ Flight Delay OpenSky Network AviationStack
🌍 Natural Disaster USGS Earthquake Catalog

🪪 Compliant KYC Pipeline

  • 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

📧 Full Email Notification System

  • 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)

🎨 Premium UI / UX

  • 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

🛡️ Security-First Design

  • 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 PayoutLocks Set — 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_KEY header-gated admin endpoints; all secrets in .env (gitignored)
  • CORS restricted to known frontend origins + wildcard *.vercel.app for Vercel preview deployments
  • Document uploads validated by MIME type (JPEG, PNG, WEBP, PDF only; 10 MB cap)

⏰ Automated Background Jobs

  • 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, calls expire_policy() on-chain, forwards remaining balance to the policyholder's wallet

🌐 Deployed & Production-Ready



Live Deployment (Testnet)

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


How It Works

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

Architecture

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

Smart Contracts (PyTeal / Beaker)

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.

Backend Oracle Engine

  • 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 PayoutLocks Set 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

Frontend

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

KYC Flow

Users complete a lightweight KYC check before purchasing a policy:

  1. Submit name, date of birth, email, phone, Aadhaar reference, and a document upload
  2. Admin approves/rejects via the Admin Panel
  3. Approval issues a KYC token stored in localStorage and on the backend
  4. owner_email is stored on the policy record at creation time, so payout confirmation emails are sent even for wallets not directly in the KYC store

Getting Started

Prerequisites

  • Node.js ≥ 18
  • Python 3.10+ with pip
  • Algorand Testnet wallet (use Pera Wallet)

1. Clone & install

git clone https://github.com/zainab-06-p/blockPolicy.git
cd blockPolicy
npm install           # frontend dev deps
cd backend && npm install

2. Configure environment

# 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:5173

3. Deploy contracts (if redeploying)

cd contracts
python deploy.py        # outputs contract_ids.json

4. Run

# Terminal 1 — backend
cd backend && npm start

# Terminal 2 — frontend
npm run dev

Open http://localhost:5173, connect your Pera Wallet (testnet), complete KYC, and buy a policy.


Security Highlights

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

Tech Stack

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
Email 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)

Team

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.


🚀 Quickstart (1 command)

git clone https://github.com/zainab-06-p/BlockPolicy.git && cd BlockPolicy && cp backend/.env.example backend/.env && cd backend && npm install && npm start

Then in a second terminal from the project root:

npm install && npm run dev

Open http://localhost:5173 — connect Pera/Lute wallet (Algorand Testnet), complete KYC, buy a policy.


4-Line Problem Frame

  1. Who — Anyone who needs insurance: farmers, travelers, disaster-affected communities, and the 1.4B unbanked with no access to traditional insurers.
  2. What — Traditional insurance pays out slowly, subjectively, and opaquely — claims take weeks, adjusters can deny valid claims, and paperwork costs more than the premium.
  3. 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.
  4. 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.

3-Line Pitch

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 Log

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

📚 Evidence Log

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

⚠️ Risk Log

# 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 deliveredsendPayoutForward 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 failingbuildGmailTransport() 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

About

A trustless, multi-source oracle-driven parametric insurance platform built on Algorand. Features ARC-4 compliant PyTeal/Beaker smart contracts, atomic inner transaction payouts, an integrated liquidity pool, and a simulated Aadhaar KYC pipeline.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages