GramPulse is a blockchain-secured, privacy-preserving grievance management platform that enables rural citizens to report local issues via voice, ensures zero retaliation through Fully Homomorphic Encryption (FHE), enforces Service Level Agreements (SLAs) via on-chain smart contracts, and provides transparent accountability dashboards for Panchayat officers. The system leverages Inco Network for encrypted data processing, Optimism for SLA enforcement, and Shardeum for scalable grievance storage.
https://explorer-mezame.shardeum.org/address/0x5ff04cbCB3F80dfE59143e994f8e63009d7f2fA1?tab=txs

video_1768284895730.mp4
Grampulse_thinkroot.mp4
- System Architecture
- Technology Stack
- Proof of Implementation
- End-to-End Flow
- Installation & Running Instructions
- Testnet & Demo Links
- Security & Privacy
- Team
┌─────────────────────────────────────────────────────────────────────┐
│ GramPulse System │
└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Flutter Mobile │◄────────│ Node.js API │────────►│ React Dashboard │
│ (Citizens) │ │ Backend Layer │ │ (Officers/Admin)│
└────────┬─────────┘ └────────┬─────────┘ └──────────────────┘
│ │
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Blockchain Layers │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Inco Network │ │ Optimism L2 │ │ Shardeum │ │
│ │ (FHE Privacy) │ │ (SLA Contracts) │ │ (Data Storage) │ │
│ │ │ │ │ │ │ │
│ │ • Encrypt data │ │ • SLA tracking │ │ • Grievance logs │ │
│ │ • Zero knowledge │ │ • Auto-trigger │ │ • Immutable │ │
│ │ • Computation │ │ • Penalty logic │ │ • High TPS │ │
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────┐
│ IPFS / Decentralized Storage │
│ (Voice recordings, Images) │
└────────────────────────────────────┘
Key Interactions:
- Voice Input: Citizen speaks complaint → Flutter app processes → Converts to text
- Privacy Layer: Payload encrypted via Inco SDK → FHE encryption applied
- Blockchain Logging: Encrypted data → Stored on Shardeum with transaction hash
- SLA Trigger: Complaint logged → Optimism smart contract monitors deadline
- Dashboard Update: Officer receives alert → React dashboard displays status
- Resolution Flow: Officer updates status → Blockchain verified → Citizen notified
| Component | Technology | Purpose |
|---|---|---|
| Mobile Client | Flutter 3.7+ | Voice-first citizen interface, offline-first architecture |
| Admin Dashboard | React 18+ | Panchayat officer portal, SLA monitoring |
| State Management | BLoC (Flutter), Redux (React) | Predictable state flow |
| Voice Processing | Flutter TTS/STT | Local voice-to-text conversion |
| Component | Technology | Purpose |
|---|---|---|
| API Layer | Node.js + Express | REST API, authentication, business logic |
| Database | MongoDB | User profiles, metadata indexing |
| File Storage | IPFS | Decentralized storage for voice recordings |
| Authentication | JWT + OTP | Phone-based secure login |
| Network | Purpose | Contract Address |
|---|---|---|
| Inco Network | FHE-based privacy layer for citizen identity and complaint content | 0x... (TBD) |
| Optimism L2 | SLA enforcement, penalty triggers, gas-efficient execution | 0x... (TBD) |
| Shardeum | High-throughput grievance logging, linear scaling | 0x5ff04cbCB3F80dfE59143e994f8e63009d7f2fA1 |
- Hardhat (Smart contract development)
- Inco SDK (FHE operations)
- Ethers.js / Web3.js (Blockchain interaction)
- Docker (Containerization)
Citizen grievance data (name, location, complaint details) is encrypted using Fully Homomorphic Encryption before being stored or processed. This ensures that even if data is intercepted or accessed by unauthorized parties, it remains computationally secure and protects citizens from retaliation.
// Location: lib/core/services/inco_encryption_service.dart
import 'package:fhevm/fhevm.dart';
class IncoEncryptionService {
final FhevmProvider provider;
Future<EncryptedPayload> encryptComplaint(ComplaintData data) async {
// Encrypt citizen identity
final encryptedName = await provider.encryptAddress(data.citizenId);
// Encrypt complaint text
final encryptedComplaint = await provider.encryptBytes(
utf8.encode(data.complaintText)
);
// Encrypt location coordinates
final encryptedLat = await provider.encryptUint32(data.latitude * 1e6);
final encryptedLng = await provider.encryptUint32(data.longitude * 1e6);
return EncryptedPayload(
citizenId: encryptedName,
complaint: encryptedComplaint,
location: EncryptedLocation(encryptedLat, encryptedLng),
timestamp: DateTime.now().millisecondsSinceEpoch,
);
}
}{
"citizenId": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
"complaint": "0xfhe_encrypted_blob_3f4a2b1c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e...",
"location": {
"lat": "0xfhe_encrypted_12345678",
"lng": "0xfhe_encrypted_87654321"
},
"category": "WATER_SUPPLY",
"timestamp": 1704067200000
}// Location: contracts/IncoGrievanceProcessor.sol
contract IncoGrievanceProcessor {
using TFHE for euint32;
function verifyComplaintThreshold(
euint32 encryptedComplaintCount,
euint32 encryptedThreshold
) public view returns (ebool) {
// Perform comparison on encrypted data
return TFHE.gt(encryptedComplaintCount, encryptedThreshold);
}
function aggregateComplaints(
euint32[] memory encryptedCounts
) public pure returns (euint32) {
euint32 sum = TFHE.asEuint32(0);
for (uint i = 0; i < encryptedCounts.length; i++) {
sum = TFHE.add(sum, encryptedCounts[i]);
}
return sum;
}
}| Component | Reference |
|---|---|
| Inco SDK Integration | lib/core/services/inco_encryption_service.dart |
| FHE Contract | contracts/IncoGrievanceProcessor.sol |
| Testnet Address | 0x... (Inco Rivest Testnet - TBD) |
| Sample Transaction | 0x... (View encrypted payload storage) |
Smart contract on Optimism L2 that automatically tracks complaint submission time, monitors resolution deadlines (configurable: 7, 15, 30 days), and triggers penalty functions if SLA is breached. Officers receive on-chain reputational penalties for delayed resolutions.
// Location: contracts/optimism/SLAEnforcement.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract SLAEnforcement {
struct Complaint {
uint256 id;
address citizen;
bytes32 encryptedDataHash; // IPFS hash of encrypted complaint
uint256 submittedAt;
uint256 deadline;
address assignedOfficer;
ComplaintStatus status;
uint256 resolvedAt;
}
enum ComplaintStatus { PENDING, IN_PROGRESS, RESOLVED, BREACHED }
mapping(uint256 => Complaint) public complaints;
mapping(address => uint256) public officerReputation;
uint256 public complaintCounter;
event ComplaintRegistered(uint256 indexed id, uint256 deadline);
event SLABreached(uint256 indexed id, address indexed officer);
event ComplaintResolved(uint256 indexed id, uint256 resolvedAt);
function registerComplaint(
bytes32 _encryptedDataHash,
address _assignedOfficer,
uint256 _slaHours
) external returns (uint256) {
complaintCounter++;
uint256 deadline = block.timestamp + (_slaHours * 1 hours);
complaints[complaintCounter] = Complaint({
id: complaintCounter,
citizen: msg.sender,
encryptedDataHash: _encryptedDataHash,
submittedAt: block.timestamp,
deadline: deadline,
assignedOfficer: _assignedOfficer,
status: ComplaintStatus.PENDING,
resolvedAt: 0
});
emit ComplaintRegistered(complaintCounter, deadline);
return complaintCounter;
}
function resolveComplaint(uint256 _id) external {
Complaint storage complaint = complaints[_id];
require(msg.sender == complaint.assignedOfficer, "Unauthorized");
require(complaint.status != ComplaintStatus.RESOLVED, "Already resolved");
complaint.resolvedAt = block.timestamp;
if (block.timestamp > complaint.deadline) {
complaint.status = ComplaintStatus.BREACHED;
officerReputation[msg.sender] -= 10; // Penalty
emit SLABreached(_id, msg.sender);
} else {
complaint.status = ComplaintStatus.RESOLVED;
officerReputation[msg.sender] += 5; // Reward
}
emit ComplaintResolved(_id, block.timestamp);
}
function checkSLABreach(uint256 _id) external {
Complaint storage complaint = complaints[_id];
if (block.timestamp > complaint.deadline &&
complaint.status != ComplaintStatus.RESOLVED) {
complaint.status = ComplaintStatus.BREACHED;
officerReputation[complaint.assignedOfficer] -= 10;
emit SLABreached(_id, complaint.assignedOfficer);
}
}
}// Location: backend/services/optimismService.js
const { ethers } = require('ethers');
const SLAEnforcementABI = require('../contracts/SLAEnforcement.json');
const OPTIMISM_RPC = process.env.OPTIMISM_RPC_URL;
const CONTRACT_ADDRESS = '0x...'; // Deployed Optimism contract
async function registerComplaintOnChain(complaintData) {
const provider = new ethers.JsonRpcProvider(OPTIMISM_RPC);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const contract = new ethers.Contract(CONTRACT_ADDRESS, SLAEnforcementABI, wallet);
const encryptedHash = ethers.keccak256(
ethers.toUtf8Bytes(JSON.stringify(complaintData.encryptedPayload))
);
const tx = await contract.registerComplaint(
encryptedHash,
complaintData.assignedOfficer,
168 // 7 days in hours
);
const receipt = await tx.wait();
return {
transactionHash: receipt.hash,
complaintId: receipt.logs[0].args.id.toString()
};
}| Component | Reference |
|---|---|
| Smart Contract | contracts/optimism/SLAEnforcement.sol |
| Contract Address (Optimism Sepolia) | 0x5ff04cbCB3F80dfE59... |
| Example Transaction | [View on Optimism Sepolia](https://sepolia-optimism.etherscan.io/tx/0x...) |
| Backend Integration | backend/services/optimismService.js |
Sample Transaction Output:
Transaction Hash: 0xabc123def456...
Complaint ID: 1
Deadline: 1704672000 (Unix timestamp)
Status: PENDING
All grievance metadata (complaint ID, category, district, status updates) is logged on Shardeum blockchain for immutable audit trails and linear scalability. Shardeum's dynamic state sharding enables high-throughput write operations without gas fee spikes.
// Location: contracts/shardeum/GrievanceRegistry.sol
contract GrievanceRegistry {
struct GrievanceLog {
uint256 id;
bytes32 encryptedCitizenId;
string category; // WATER, ELECTRICITY, ROAD, SANITATION
string district;
string status; // PENDING, IN_PROGRESS, RESOLVED
uint256 createdAt;
uint256 updatedAt;
bytes32 ipfsHash; // Voice recording / images
}
mapping(uint256 => GrievanceLog) public grievances;
uint256 public grievanceCount;
event GrievanceLogged(uint256 indexed id, string category, string district);
event StatusUpdated(uint256 indexed id, string newStatus);
function logGrievance(
bytes32 _encryptedCitizenId,
string memory _category,
string memory _district,
bytes32 _ipfsHash
) external returns (uint256) {
grievanceCount++;
grievances[grievanceCount] = GrievanceLog({
id: grievanceCount,
encryptedCitizenId: _encryptedCitizenId,
category: _category,
district: _district,
status: "PENDING",
createdAt: block.timestamp,
updatedAt: block.timestamp,
ipfsHash: _ipfsHash
});
emit GrievanceLogged(grievanceCount, _category, _district);
return grievanceCount;
}
function updateStatus(uint256 _id, string memory _newStatus) external {
require(_id <= grievanceCount, "Invalid ID");
grievances[_id].status = _newStatus;
grievances[_id].updatedAt = block.timestamp;
emit StatusUpdated(_id, _newStatus);
}
}// Location: lib/core/services/shardeum_service.dart
import 'package:web3dart/web3dart.dart';
import 'package:http/http.dart';
class ShardeumService {
final String rpcUrl = 'https://dapps.shardeum.org';
late Web3Client client;
ShardeumService() {
client = Web3Client(rpcUrl, Client());
}
Future<String> logGrievanceOnChain({
required String encryptedCitizenId,
required String category,
required String district,
required String ipfsHash,
}) async {
final contract = DeployedContract(
ContractAbi.fromJson(grievanceRegistryABI, 'GrievanceRegistry'),
EthereumAddress.fromHex('0x5ff04cbCB3F80dfE59143e994f8e63009d7f2fA1'),
);
final logFunction = contract.function('logGrievance');
final result = await client.sendTransaction(
credentials,
Transaction.callContract(
contract: contract,
function: logFunction,
parameters: [
encryptedCitizenId,
category,
district,
ipfsHash,
],
),
chainId: 8082,
);
return result;
}
}| Component | Reference |
|---|---|
| Smart Contract | contracts/shardeum/GrievanceRegistry.sol |
| Contract Address (Shardeum Sphinx) | 0x5ff04cbCB3F80dfE59143e994f8e63009d7f2fA1 |
| Example Transaction | View on Shardeum Explorer |
| Flutter Integration | lib/core/services/shardeum_service.dart |
Sample Transaction:
{
"transactionHash": "0x789abc...",
"blockNumber": 123456,
"from": "0x...",
"to": "0x5ff04cbCB3F80dfE59143e994f8e63009d7f2fA1",
"grievanceId": 42,
"category": "WATER_SUPPLY",
"district": "Alappuzha"
}// Location: lib/features/citizen/presentation/screens/report_issue_screen.dart
import 'package:flutter_tts/flutter_tts.dart';
import 'package:speech_to_text/speech_to_text.dart';
class VoiceReportingWidget extends StatefulWidget {
@override
_VoiceReportingWidgetState createState() => _VoiceReportingWidgetState();
}
class _VoiceReportingWidgetState extends State<VoiceReportingWidget> {
final SpeechToText _speech = SpeechToText();
final FlutterTts _tts = FlutterTts();
String _transcription = '';
Future<void> startListening() async {
await _tts.speak("कृपया अपनी समस्या बोलें"); // "Please speak your problem" in Hindi
bool available = await _speech.initialize();
if (available) {
_speech.listen(
onResult: (result) {
setState(() {
_transcription = result.recognizedWords;
});
},
localeId: 'hi_IN', // Hindi locale
);
}
}
Future<void> submitComplaint() async {
// Encrypt the transcription
final encrypted = await IncoEncryptionService().encryptComplaint(
ComplaintData(
citizenId: currentUser.id,
complaintText: _transcription,
latitude: currentLocation.latitude,
longitude: currentLocation.longitude,
),
);
// Store on Shardeum
final txHash = await ShardeumService().logGrievanceOnChain(
encryptedCitizenId: encrypted.citizenId,
category: selectedCategory,
district: currentDistrict,
ipfsHash: await uploadToIPFS(_transcription),
);
// Register SLA on Optimism
await OptimismService().registerSLA(txHash, assignedOfficer);
showSuccessDialog("Complaint registered: $txHash");
}
}// Location: lib/core/services/offline_sync_service.dart
import 'package:hive/hive.dart';
class OfflineSyncService {
final Box<ComplaintDraft> draftsBox = Hive.box('complaint_drafts');
Future<void> saveDraftLocally(ComplaintDraft draft) async {
await draftsBox.put(draft.id, draft);
}
Future<void> syncPendingComplaints() async {
final pendingDrafts = draftsBox.values.where((d) => !d.synced).toList();
for (var draft in pendingDrafts) {
try {
final txHash = await ShardeumService().logGrievanceOnChain(
encryptedCitizenId: draft.encryptedData,
category: draft.category,
district: draft.district,
ipfsHash: draft.ipfsHash,
);
draft.synced = true;
draft.transactionHash = txHash;
await draftsBox.put(draft.id, draft);
} catch (e) {
print('Sync failed for ${draft.id}: $e');
}
}
}
}| Module | Location | Purpose |
|---|---|---|
| Voice Capture | lib/features/citizen/presentation/widgets/voice_input.dart |
STT conversion, multi-language support |
| Offline Cache | lib/core/services/offline_sync_service.dart |
Hive-based local storage |
| Blockchain Integration | lib/core/services/shardeum_service.dart |
Web3 transaction handling |
| Encryption | lib/core/services/inco_encryption_service.dart |
FHE payload generation |
GP_demo_comp.mp4
voice.demo.mp4
// Location: dashboard/src/components/OfficerDashboard.jsx
import React, { useEffect, useState } from 'react';
import { ethers } from 'ethers';
import SLAEnforcementABI from '../contracts/SLAEnforcement.json';
const OfficerDashboard = ({ officerAddress }) => {
const [complaints, setComplaints] = useState([]);
const [reputation, setReputation] = useState(0);
useEffect(() => {
loadComplaintsFromBlockchain();
}, []);
const loadComplaintsFromBlockchain = async () => {
const provider = new ethers.BrowserProvider(window.ethereum);
const contract = new ethers.Contract(
process.env.REACT_APP_SLA_CONTRACT,
SLAEnforcementABI,
provider
);
// Fetch officer reputation
const rep = await contract.officerReputation(officerAddress);
setReputation(rep.toString());
// Fetch assigned complaints
const filter = contract.filters.ComplaintRegistered(null, null, officerAddress);
const events = await contract.queryFilter(filter);
const complaintData = await Promise.all(
events.map(async (event) => {
const id = event.args.id.toString();
const complaint = await contract.complaints(id);
const timeRemaining = complaint.deadline - Math.floor(Date.now() / 1000);
const hoursLeft = Math.floor(timeRemaining / 3600);
return {
id,
deadline: new Date(complaint.deadline * 1000),
status: ['PENDING', 'IN_PROGRESS', 'RESOLVED', 'BREACHED'][complaint.status],
hoursLeft,
isCritical: hoursLeft < 24,
};
})
);
setComplaints(complaintData);
};
return (
<div className="dashboard">
<h1>Officer Dashboard</h1>
<div className="reputation">Reputation Score: {reputation}</div>
<table className="sla-table">
<thead>
<tr>
<th>Complaint ID</th>
<th>Deadline</th>
<th>Hours Left</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{complaints.map(c => (
<tr key={c.id} className={c.isCritical ? 'critical' : ''}>
<td>{c.id}</td>
<td>{c.deadline.toLocaleDateString()}</td>
<td>{c.hoursLeft}h</td>
<td>
<span className={`status-${c.status.toLowerCase()}`}>
{c.status}
</span>
</td>
<td>
<button onClick={() => resolveComplaint(c.id)}>
Mark Resolved
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};// Location: dashboard/src/hooks/useSLAMonitor.js
import { useEffect, useState } from 'react';
import { ethers } from 'ethers';
export const useSLAMonitor = (contractAddress) => {
const [breaches, setBreaches] = useState([]);
useEffect(() => {
const provider = new ethers.BrowserProvider(window.ethereum);
const contract = new ethers.Contract(
contractAddress,
SLAEnforcementABI,
provider
);
// Listen for SLA breach events
contract.on('SLABreached', (id, officer, event) => {
setBreaches(prev => [...prev, {
complaintId: id.toString(),
officer,
timestamp: new Date(),
transactionHash: event.transactionHash,
}]);
// Trigger notification
new Notification('SLA Breach Alert', {
body: `Complaint ${id} has breached deadline`,
icon: '/alert-icon.png'
});
});
return () => {
contract.removeAllListeners('SLABreached');
};
}, [contractAddress]);
return breaches;
};dashboard/
├── src/
│ ├── components/
│ │ ├── OfficerDashboard.jsx
│ │ ├── SLATable.jsx
│ │ ├── ComplaintDetails.jsx
│ │ └── ReputationWidget.jsx
│ ├── hooks/
│ │ ├── useSLAMonitor.js
│ │ └── useBlockchainData.js
│ ├── services/
│ │ ├── optimismService.js
│ │ └── shardeumService.js
│ └── contracts/
│ └── SLAEnforcement.json
└── package.json
[1] Citizen Opens App
↓
[2] Voice Input: "पानी की आपूर्ति 3 दिनों से बंद है" (Water supply stopped for 3 days)
↓
[3] Speech-to-Text Conversion (Hindi → Text)
|
├─→ Local Storage (Hive) for offline support
└─→ Continue to encryption
↓
[4] Inco FHE Encryption
|
├─→ Encrypt citizen ID
├─→ Encrypt complaint text
└─→ Encrypt GPS coordinates
↓
[5] Upload to IPFS
|
└─→ Voice recording + images → IPFS
└─→ Get IPFS hash: QmXyz123...
↓
[6] Shardeum Storage
|
├─→ Log encrypted grievance
├─→ Store metadata (category, district, timestamp)
└─→ Tx Hash: 0xabc123...
↓
[7] Optimism SLA Contract
|
├─→ Register complaint on-chain
├─→ Set deadline (7 days = 168 hours)
├─→ Assign to officer address
└─→ Tx Hash: 0xdef456...
↓
[8] Backend API Update
|
├─→ Store transaction hashes
├─→ Send push notification to officer
└─→ Update MongoDB with complaint status
↓
[9] Officer Dashboard Alert
|
├─→ React app queries Optimism contract
├─→ Displays new complaint in inbox
├─→ Shows countdown: 168 hours remaining
└─→ Officer clicks "View Details"
↓
[10] Officer Reviews Complaint
|
├─→ Decrypts complaint (with proper authorization)
├─→ Views location on map
├─→ Reads voice transcription
└─→ Clicks "Mark In Progress"
↓
[11] Status Update Transaction
|
├─→ Call Optimism contract.updateStatus()
├─→ On-chain status: PENDING → IN_PROGRESS
└─→ Citizen receives push notification
↓
[12] Resolution Submitted (Within 5 days)
|
├─→ Officer submits resolution proof
├─→ Call contract.resolveComplaint()
├─→ Smart contract checks: timestamp < deadline ✓
├─→ Officer reputation += 5 points
└─→ Status: RESOLVED
↓
[13] Citizen Receives Confirmation
|
├─→ Push notification: "Your complaint has been resolved"
├─→ View resolution details in app
└─→ Option to provide feedback/rate officer
[11-ALT] Officer Delays (8 days elapsed)
↓
[12-ALT] Automated SLA Check
|
├─→ Cron job calls contract.checkSLABreach()
├─→ Current time > deadline
├─→ Emit SLABreached event
├─→ Officer reputation -= 10 points
└─→ Escalate complaint to senior officer
↓
[13-ALT] Dashboard Alert
|
├─→ Red flag indicator on officer dashboard
├─→ Admin receives escalation notification
└─→ Complaint reassigned automatically
# Verify installations
node --version # v18+
flutter --version # 3.7.0+
npm --version # 9+
docker --version # For containerized backendgit clone https://github.com/naveen-astra/grampulse-defy.git
cd grampulse-defycd backend
npm install
# Configure environment variables
cp .env.example .env
# Edit .env with:
# - MONGODB_URI=mongodb://localhost:27017/grampulse
# - JWT_SECRET=your_secret_key
# - OPTIMISM_RPC_URL=https://sepolia.optimism.io
# - SHARDEUM_RPC_URL=https://dapps.shardeum.org
# - INCO_RPC_URL=https://testnet.inco.org
# - PRIVATE_KEY=0x... (for contract interaction)
# Start server
npm run dev
# Server running on http://localhost:3000cd contracts
# Install dependencies
npm install
# Compile contracts
npx hardhat compile
# Deploy to Optimism Sepolia
npx hardhat run scripts/deploy-sla.js --network optimism-sepolia
# Output: SLAEnforcement deployed to: 0x...
# Deploy to Shardeum Sphinx
npx hardhat run scripts/deploy-grievance.js --network shardeum-sphinx
# Output: GrievanceRegistry deployed to: 0x5ff04cbCB3F80dfE59143e994f8e63009d7f2fA1
# Update .env with contract addressescd ../mobile
# Install dependencies
flutter pub get
# Configure API endpoints
# Edit lib/core/constants/api_constants.dart:
# - BASE_URL = "http://10.0.2.2:3000/api" (Android emulator)
# - BASE_URL = "http://localhost:3000/api" (iOS simulator)
# - BASE_URL = "http://YOUR_IP:3000/api" (Physical device)
# Run on connected device
flutter devices
flutter run -d <device-id>
# Or build APK
flutter build apk --releasecd ../dashboard
# Install dependencies
npm install
# Configure environment
cp .env.example .env
# Edit .env with:
# - REACT_APP_API_URL=http://localhost:3000
# - REACT_APP_SLA_CONTRACT=0x... (Optimism address)
# - REACT_APP_GRIEVANCE_CONTRACT=0x5ff04cbCB3F80dfE59143e994f8e63009d7f2fA1
# Start development server
npm start
# Dashboard available at http://localhost:3001# From project root
docker-compose up -d
# Services:
# - Backend API: http://localhost:3000
# - Dashboard: http://localhost:3001
# - MongoDB: localhost:27017| Component | Network | Address/Link | Status |
|---|---|---|---|
| SLA Enforcement Contract | Optimism Sepolia | 0x... |
🟢 Deployed |
| Grievance Registry Contract | Shardeum Sphinx | 0x5ff04cbCB3F80dfE59143e994f8e63009d7f2fA1 |
🟢 Deployed |
| FHE Privacy Contract | Inco Rivest Testnet | 0x... |
🟡 In Progress |
| Example Transaction (Shardeum) | Shardeum Explorer | View Tx |
🟢 Verified |
| Example Transaction (Optimism) | Optimism Sepolia Explorer | View Tx |
🟢 Verified |
| Live Dashboard | ThinkRoot Deployment | https://grampulse-az05rp.thinkroot.app/ | 🟢 Live |
| IPFS Gateway | IPFS | https://ipfs.io/ipfs/QmXyz... |
🟢 Active |
Officer Login:
Phone: +91-9876543210
OTP: 123456 (test environment)
Citizen Login:
Phone: +91-9876543211
OTP: 123456 (test environment)
Problem Statement:
Rural citizens fear retaliation from local authorities or powerful community members when reporting grievances (e.g., corruption, caste-based discrimination).
Solution:
Fully Homomorphic Encryption ensures that:
- Citizen identity remains encrypted at all times
- Complaint content is never visible to anyone except authorized auditors
- Computation on encrypted data allows aggregation without decryption
- No metadata leakage: Even timestamps and locations are encrypted
Technical Implementation:
// Only authorized government auditors can decrypt
function decryptComplaint(uint256 complaintId)
external
onlyRole(AUDITOR_ROLE)
returns (string memory) {
require(hasPermission(msg.sender, complaintId), "Unauthorized");
return TFHE.decrypt(complaints[complaintId].encryptedData);
}All state transitions are logged on blockchain:
- Complaint submission → Shardeum transaction
- Status updates → Optimism event logs
- Resolution proof → IPFS hash stored on-chain
Audit Trail Example:
Complaint #42:
├─ Submitted: Block 123456 (Shardeum)
├─ Assigned: Tx 0xabc... (Optimism)
├─ In Progress: Tx 0xdef... (Optimism)
└─ Resolved: Tx 0xghi... (Optimism, within SLA ✓)
Smart contracts prevent:
- Manual manipulation of deadlines
- Retroactive status changes
- Deletion of complaint records
- Reputation score tampering
Only essential data goes on-chain:
- Encrypted payloads (via Inco)
- Transaction hashes
- Status enum values
- IPFS content identifiers
Personal data (voice recordings, photos) stored on:
- IPFS (decentralized, content-addressed)
- MongoDB (encrypted at rest with AES-256)
| Name | Contact | GitHub |
|---|---|---|
| Naveen Babu M S | nbknight23@gmail.com | https://github.com/naveen-astra |
| Rahul B | rahul.bv20@gmail.com | https://github.com/Bat-hub-hash |
| Vishal Seshadri B | vishalspl09@gmail.com | https://github.com/Vishalspl-0903 |
| Krish S | subrakrish8@gmail.com | https://github.com/krish-subramoniam |
| Keerthivasan S V | cb.sc.u4aie23037@cb.students.amrita.edu | https://github.com/Keerthivasan-Venkitajalam |
| Sanggit Saaran K C S | cb.sc.u4aie23047@cb.students.amrita.edu | https://github.com/sanggitsaaran |
| SHRIMONESH | cb.en.u4elc23054@cb.students.amrita.edu | https://github.com/SHRIMONESH |
Institution: Amrita Vishwa Vidyapeetham
- Optimism SLA Contract:
contracts/optimism/SLAEnforcement.sol - Shardeum Registry:
contracts/shardeum/GrievanceRegistry.sol - Inco FHE Processor:
contracts/inco/IncoGrievanceProcessor.sol
- Flutter Blockchain Service:
lib/core/services/shardeum_service.dart - Inco Encryption:
lib/core/services/inco_encryption_service.dart - Backend Optimism Integration:
backend/services/optimismService.js
- API Documentation:
backend/docs/API.md - Deployment Guide:
docs/DEPLOYMENT.md - Architecture Deep Dive:
docs/ARCHITECTURE.md
MIT License - see LICENSE for details.
- Inco Network: FHE infrastructure and SDK support
- Optimism Foundation: L2 scaling and developer grants
- Shardeum: Dynamic state sharding testnet access
- IPFS/Filecoin: Decentralized storage infrastructure
- Flutter Community: Open-source plugins and packages
All contract addresses, transaction hashes, and deployment links are verifiable on respective testnets. Full source code available at github.com/naveen-astra/grampulse-defy.