mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-25 21:08:00 +00:00
feat: Integrate Polkadot.js API and wallet connection
Major Changes: - Added @polkadot/api and related dependencies - Created PolkadotContext for blockchain connection - Implemented NetworkStats component with live data - Added PolkadotWalletButton for wallet integration - Connected to local validator node (ws://127.0.0.1:9944) Features: - Live block number and hash display - Real-time validator count - Network connection status monitoring - Polkadot.js extension integration - Multi-account support - Account switching capability Technical: - RPC endpoint: ws://127.0.0.1:9944 - Auto-reconnect on disconnect - TypeScript integration - React hooks for state management
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { usePolkadot } from '@/contexts/PolkadotContext';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Activity, Wifi, WifiOff, Users, Box, TrendingUp } from 'lucide-react';
|
||||
|
||||
export const NetworkStats: React.FC = () => {
|
||||
const { api, isApiReady, error } = usePolkadot();
|
||||
const [blockNumber, setBlockNumber] = useState<number>(0);
|
||||
const [blockHash, setBlockHash] = useState<string>('');
|
||||
const [finalizedBlock, setFinalizedBlock] = useState<number>(0);
|
||||
const [validatorCount, setValidatorCount] = useState<number>(0);
|
||||
const [peers, setPeers] = useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!api || !isApiReady) return;
|
||||
|
||||
let unsubscribeNewHeads: () => void;
|
||||
let unsubscribeFinalizedHeads: () => void;
|
||||
|
||||
const subscribeToBlocks = async () => {
|
||||
try {
|
||||
// Subscribe to new blocks
|
||||
unsubscribeNewHeads = await api.rpc.chain.subscribeNewHeads((header) => {
|
||||
setBlockNumber(header.number.toNumber());
|
||||
setBlockHash(header.hash.toHex());
|
||||
});
|
||||
|
||||
// Subscribe to finalized blocks
|
||||
unsubscribeFinalizedHeads = await api.rpc.chain.subscribeFinalizedHeads((header) => {
|
||||
setFinalizedBlock(header.number.toNumber());
|
||||
});
|
||||
|
||||
// Get validator count
|
||||
const validators = await api.query.session.validators();
|
||||
setValidatorCount(validators.length);
|
||||
|
||||
// Get peer count
|
||||
const health = await api.rpc.system.health();
|
||||
setPeers(health.peers.toNumber());
|
||||
|
||||
} catch (err) {
|
||||
console.error('Failed to subscribe to blocks:', err);
|
||||
}
|
||||
};
|
||||
|
||||
subscribeToBlocks();
|
||||
|
||||
return () => {
|
||||
if (unsubscribeNewHeads) unsubscribeNewHeads();
|
||||
if (unsubscribeFinalizedHeads) unsubscribeFinalizedHeads();
|
||||
};
|
||||
}, [api, isApiReady]);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<Card className="bg-red-950/50 border-red-900">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-red-400">
|
||||
<WifiOff className="w-5 h-5" />
|
||||
Network Disconnected
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-red-300 text-sm">{error}</p>
|
||||
<p className="text-red-400 text-xs mt-2">
|
||||
Make sure your validator node is running at ws://127.0.0.1:9944
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isApiReady) {
|
||||
return (
|
||||
<Card className="bg-gray-900 border-gray-800">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Activity className="w-5 h-5 animate-pulse" />
|
||||
Connecting to Network...
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{/* Connection Status */}
|
||||
<Card className="bg-gray-900 border-gray-800">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm font-medium text-gray-400 flex items-center gap-2">
|
||||
<Wifi className="w-4 h-4 text-green-500" />
|
||||
Network Status
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center justify-between">
|
||||
<Badge className="bg-green-500/20 text-green-400 border-green-500/50">
|
||||
Connected
|
||||
</Badge>
|
||||
<span className="text-xs text-gray-500">{peers} peers</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Latest Block */}
|
||||
<Card className="bg-gray-900 border-gray-800">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm font-medium text-gray-400 flex items-center gap-2">
|
||||
<Box className="w-4 h-4 text-blue-500" />
|
||||
Latest Block
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-1">
|
||||
<div className="text-2xl font-bold text-white">
|
||||
#{blockNumber.toLocaleString()}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 font-mono truncate">
|
||||
{blockHash.slice(0, 10)}...{blockHash.slice(-8)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Finalized Block */}
|
||||
<Card className="bg-gray-900 border-gray-800">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm font-medium text-gray-400 flex items-center gap-2">
|
||||
<TrendingUp className="w-4 h-4 text-purple-500" />
|
||||
Finalized Block
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-white">
|
||||
#{finalizedBlock.toLocaleString()}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 mt-1">
|
||||
{blockNumber - finalizedBlock} blocks behind
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Validators */}
|
||||
<Card className="bg-gray-900 border-gray-800">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm font-medium text-gray-400 flex items-center gap-2">
|
||||
<Users className="w-4 h-4 text-yellow-500" />
|
||||
Active Validators
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-white">
|
||||
{validatorCount}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 mt-1">
|
||||
Securing the network
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user