Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
PRIVATE_KEY=<your_private_key>
RPC_URL_SEPOLIA=<your_sepolia_rpc_url>
RPC_URL_FUJI=<your_fuji_rpc_url>
ETHERSCAN_KEY=<your_etherscan_api_key>
6 changes: 0 additions & 6 deletions blockchain/.env.example

This file was deleted.

4 changes: 0 additions & 4 deletions client/.env.example

This file was deleted.

249 changes: 249 additions & 0 deletions client/WALLET_FEATURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# Wallet Management Feature

## 📋 Overview

A comprehensive Wallet Management page has been implemented for the Agora-Blockchain voting platform. This feature allows users to view, manage, and interact with their connected Web3 wallets.

## ✨ Features Implemented

### 1. **Wallet Connection & Display**
- Real-time wallet connection status
- Display of connected wallet address with copy-to-clipboard functionality
- Wallet connector identification (MetaMask, WalletConnect, Coinbase Wallet, etc.)
- ENS name and avatar support

### 2. **Balance Overview**
- Native token balance display (ETH, AVAX, etc.)
- Real-time balance updates using wagmi hooks
- Network-specific balance information
- Token decimals and full balance details

### 3. **Network Management**
- Visual network selector with supported chains:
- Sepolia Testnet (Ethereum)
- Avalanche Fuji Testnet
- One-click network switching
- Clear indication of active network
- Warning for unsupported networks

### 4. **Wallet Information**
- ENS identity display with avatar
- Wallet type and address format verification
- Connection status indicators
- Security information about the connected wallet

### 5. **Voting History**
- Placeholder for voting transaction history
- Ready for integration with blockchain voting records
- Statistics summary (total votes, elections participated, networks used)
- Transaction hash links to block explorers

### 6. **Security Tips**
- Expandable security tips section
- Best practices for wallet security
- Warnings about phishing and scams
- Guidelines for safe Web3 interactions

### 7. **User Experience**
- Beautiful gradient UI with Tailwind CSS
- Smooth animations using Framer Motion
- Responsive design (mobile, tablet, desktop)
- Toast notifications for user actions
- Loading states and skeleton screens

## 🏗️ Architecture

### File Structure
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add language specification to the fenced code block.

The fenced code block at line 57 is missing a language identifier. While this is a file structure representation rather than executable code, it's best practice to specify the language or use text for non-code blocks to maintain consistency and satisfy linting rules.

Apply this diff:

-```
+```text
 client/app/
 ├── wallet/
 │   └── page.tsx                    # Main wallet management page

Based on static analysis hints.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

57-57: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In client/WALLET_FEATURE.md around line 57, the fenced code block is missing a
language identifier; update the block to specify a language (use "text" for this
file-structure snippet) and replace the existing triple-backtick fence with
```text so the snippet reads as a text fenced code block and satisfies linting
and consistency rules.

client/app/
├── wallet/
│ └── page.tsx # Main wallet management page
└── components/
└── Wallet/
├── WalletInfo.tsx # Wallet details and ENS info
├── BalanceCard.tsx # Token balance display
├── NetworkSelector.tsx # Network switching UI
├── VotingHistory.tsx # Voting transaction history
└── SecurityTips.tsx # Security guidelines
```

### Technology Stack
- **Next.js 14** - App Router
- **wagmi** - React Hooks for Ethereum
- **RainbowKit** - Wallet connection UI
- **viem** - Ethereum library
- **Framer Motion** - Animations
- **Heroicons** - Icons
- **Tailwind CSS** - Styling
- **react-hot-toast** - Notifications

## 🎨 UI Components

### WalletInfo
Displays detailed wallet information including:
- ENS avatar and name
- Wallet type and status
- Address format verification
- Security information

### BalanceCard
Shows comprehensive balance information:
- Native token balance with 4 decimal precision
- Network-specific token symbols
- Gradient backgrounds based on network
- Full balance and decimals

### NetworkSelector
Provides network switching functionality:
- Grid layout of supported networks
- Visual indication of active network
- One-click network switching
- Warning for unsupported networks

### VotingHistory
Tracks user's voting participation:
- List of voting transactions
- Election names and timestamps
- Transaction hash links
- Statistics summary

### SecurityTips
Educational component for security:
- Expandable accordion design
- Key security guidelines
- Warning about phishing
- Platform-specific safety notes

## 🔗 Integration Points

### wagmi Hooks Used
- `useAccount()` - Current wallet account info
- `useBalance()` - Token balance
- `useEnsName()` - ENS name resolution
- `useEnsAvatar()` - ENS avatar
- `useChainId()` - Current network ID
- `useSwitchChain()` - Network switching
- `useDisconnect()` - Wallet disconnection

### RainbowKit Integration
- ConnectButton for wallet connection
- Automatic wallet provider detection
- Support for multiple wallet types

## 🚀 Usage

### Accessing the Wallet Page
1. Navigate to `/wallet` route
2. Or click "Wallet" in the navigation menu

### Wallet Connection
If not connected:
1. Click the "Connect Wallet" button
2. Select your preferred wallet provider
3. Approve the connection

If connected:
1. View wallet details, balance, and history
2. Switch networks as needed
3. Disconnect when finished

### Network Switching
1. Scroll to the "Network Selection" section
2. Click on the desired network card
3. Approve the network switch in your wallet

## 🔧 Future Enhancements

### Planned Features
1. **Voting History Integration**
- Fetch actual voting records from blockchain
- Filter by date, network, or election
- Export voting history

2. **Multi-Wallet Support**
- Connect multiple wallets simultaneously
- Set default wallet for transactions
- Switch between connected wallets

3. **Token Management**
- Display ERC-20 token balances
- Token transfer functionality
- Token approval management

4. **Transaction History**
- Complete transaction history
- Filter and search capabilities
- CSV export functionality

5. **Advanced Security**
- Wallet health checks
- Connection permissions audit
- Security score indicators

6. **Analytics Dashboard**
- Voting participation metrics
- Network usage statistics
- Gas fee analytics

## 📝 Code Examples

### Using Wallet Info in Other Components
```tsx
import { useAccount, useBalance } from 'wagmi';

function MyComponent() {
const { address, isConnected } = useAccount();
const { data: balance } = useBalance({ address });

return (
<div>
{isConnected && (
<p>Balance: {balance?.formatted} {balance?.symbol}</p>
)}
</div>
);
}
```

### Network Switching
```tsx
import { useSwitchChain } from 'wagmi';
import { sepolia } from 'wagmi/chains';

function SwitchNetwork() {
const { switchChain } = useSwitchChain();

const handleSwitch = () => {
switchChain({ chainId: sepolia.id });
};

return <button onClick={handleSwitch}>Switch to Sepolia</button>;
}
```

## 🐛 Known Issues

1. **Voting History**: Currently uses mock data - needs integration with blockchain indexer or backend API
2. **ENS Resolution**: May be slow on some networks - consider caching
3. **Balance Updates**: Real-time updates depend on RPC endpoint reliability

## 🤝 Contributing

When extending this feature:
1. Follow the existing component structure
2. Use wagmi hooks for blockchain interactions
3. Maintain responsive design patterns
4. Add loading states for async operations
5. Include error handling with user-friendly messages

## 📄 License

This feature is part of the Agora-Blockchain project and follows the same license.

## 👥 Credits

Developed as part of the GSOC contribution to Agora-Blockchain.

---

For more information, see the main project README or visit the [documentation](../README.md).
20 changes: 15 additions & 5 deletions client/app/components/Cards/ElectionMini.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import React from "react";
import React, { useEffect } from "react";
import { motion } from "framer-motion";
import SkeletonElection from "../Helper/SkeletonElection";
import { FaRegUser } from "react-icons/fa6";
Expand Down Expand Up @@ -30,11 +30,21 @@ const ElectionMini = ({
electionAddress: electionAddress,
});

if (isLoading || electionInfo == undefined) return <SkeletonElection />;
const isStarting = Math.floor(Date.now() / 1000) < Number(electionInfo[0]);
const isEnded = Math.floor(Date.now() / 1000) > Number(electionInfo[1]);
// Calculate election status (safe to do even if electionInfo is undefined)
const isStarting = electionInfo ? Math.floor(Date.now() / 1000) < Number(electionInfo[0]) : false;
const isEnded = electionInfo ? Math.floor(Date.now() / 1000) > Number(electionInfo[1]) : false;
const electionStat = isStarting ? 1 : isEnded ? 3 : 2;
update?.(electionAddress, electionStat);

// Move state update to useEffect to avoid updating parent during render
// This must be called before any conditional returns (Rules of Hooks)
useEffect(() => {
if (update && electionInfo) {
update(electionAddress, electionStat);
}
}, [electionAddress, electionStat, update, electionInfo]);

// Early return AFTER all hooks have been called
if (isLoading || electionInfo == undefined) return <SkeletonElection />;

return (
<motion.div
Expand Down
6 changes: 5 additions & 1 deletion client/app/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ import {
HomeIcon,
XMarkIcon,
Bars3Icon,
WalletIcon,
QuestionMarkCircleIcon,
} from "@heroicons/react/24/outline";
import Web3Connect from "../Helper/Web3Connect";
import Image from "next/image";

const menuItems = [
{ name: "Home", href: "/", icon: HomeIcon },
{ name: "Create", href: "/create", icon: PlusCircleIcon },
{ name: "Wallet", href: "/wallet", icon: WalletIcon },
{ name: "Profile", href: "/profile", icon: UserIcon },
{ name: "Help", href: "/help", icon: QuestionMarkCircleIcon },
];

const Header = () => {
Expand All @@ -40,7 +44,7 @@ const Header = () => {
<Image
width={32}
height={32}
className="h-8 w-auto"
style={{ width: 'auto', height: '32px' }}
src="/aossie.png"
alt="Agora Blockchain"
/>
Expand Down
54 changes: 54 additions & 0 deletions client/app/components/Help/CategoryCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use client";

import React from "react";
import { motion } from "framer-motion";

interface Category {
id: string;
title: string;
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>;
color: string;
description: string;
}

interface CategoryCardProps {
category: Category;
index: number;
isSelected: boolean;
onClick: () => void;
}

export default function CategoryCard({
category,
index,
isSelected,
onClick,
}: CategoryCardProps) {
const Icon = category.icon;

return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.98 }}
onClick={onClick}
className={`cursor-pointer rounded-xl p-6 shadow-md transition-all ${
isSelected
? "bg-indigo-50 border-2 border-indigo-500"
: "bg-white border-2 border-transparent hover:shadow-lg"
}`}
>
<div
className={`inline-flex items-center justify-center w-12 h-12 rounded-lg mb-4 ${category.color}`}
>
<Icon className="h-6 w-6" />
</div>
<h3 className="text-lg font-semibold text-gray-900 mb-2">
{category.title}
</h3>
<p className="text-sm text-gray-600">{category.description}</p>
</motion.div>
);
}
Loading