> For the complete documentation index, see [llms.txt](https://wiki.gen6.life/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wiki.gen6.life/technology-core/developer-resources/sdk-and-tooling/gen6-mw-and-chain-api-guide/07.-validator-dashboard.md).

# 07. Validator Dashboard

The Validator Dashboard provides monitoring and statistics for Gen6 network validators.

### Overview

**Purpose**: Track validator performance, status, and network participation.

**Key Features**:

* View validator status
* Track validator rewards
* List all validators on the network

**Location**: src/packages/validator-dashboard/

***

### API Endpoints

#### Get Validator Status

Fetch monitoring reports and statistics for a specific validator.

**Endpoint**: `GET /validator_status/{address}`

**Authentication**: Not required

**Parameters**:

* `address` (path): Validator Gen6 address (SS58-355)

**Implementation**:

```typescript
import axiosInstance from '@/packages/validator-dashboard/api/axiosInstance'
import type { MonitoringReport } from '@/packages/validator-dashboard/types'

export const getValidatorDashboardByAddress = async (address: string) => {
  const response = await axiosInstance.get<Array<MonitoringReport>>(
    `/validator_status/${address}`
  )
  return response.data
}
```

**Response**:

```typescript
export enum ValidatorStatus {
  OK = 'OK',
  FROZEN = 'Frozen',
  WARNED = 'Warned',
  SLASHED = 'Slashed',
  RESTORED = 'Restored',
  NEW = 'New'
}

interface MonitoringReport {
  validator_id: string
  status: ValidatorStatus
  ss58_address: string
  self_hosted: boolean
  share: number
  block: number
  time: number
}
```

**Example Response**:

```json
[
  {
    "validator_id": "123",
    "status": "OK",
    "ss58_address": "g6x123...",
    "self_hosted": true,
    "share": 1000,
    "block": 12345,
    "time": 1705320600
  }
]
```

**Usage**:

```typescript
import { useQuery } from '@tanstack/react-query'
import { getValidatorDashboardByAddress } from '@/packages/validator-dashboard/api/queries'

function ValidatorDashboard({ validatorAddress }: { validatorAddress: string }) {
  const { data, isLoading } = useQuery({
    queryKey: ['validator-dashboard', validatorAddress],
    queryFn: () => getValidatorDashboardByAddress(validatorAddress),
    enabled: !!validatorAddress,
    refetchInterval: 300000, // 5 minutes
    staleTime: 60000 // 1 minute
  })

  if (isLoading) return <div>Loading...</div>

  return (
    <Card>
      <CardHeader>
        <CardTitle>Validator {validatorAddress}</CardTitle>
      </CardHeader>
      <CardContent>
        <div className="grid grid-cols-2 gap-4">
          <div>
            <p className="text-sm text-muted-foreground">Status</p>
            <Badge variant={data.status === 'OK' ? 'success' : 'secondary'}>
              {data.status}
            </Badge>
          </div>

          <div>
            <p className="text-sm text-muted-foreground">Self Hosted</p>
            <p className="text-2xl font-bold">{data.self_hosted ? 'Yes' : 'No'}</p>
          </div>

          <div>
            <p className="text-sm text-muted-foreground">Share</p>
            <p className="text-2xl font-bold">{data.share}</p>
          </div>

          <div>
            <p className="text-sm text-muted-foreground">Block Height</p>
            <p className="text-2xl font-bold">{data.block}</p>
          </div>

           <div>
            <p className="text-sm text-muted-foreground">Last Update</p>
             <p className="text-md">{new Date(data.time * 1000).toLocaleString()}</p>
          </div>
        </div>
      </CardContent>
    </Card>
  )
}
```

***

#### List All Validators

Retrieve a list of all validator addresses on the network.

**Endpoint**: `GET /reward_addresses`

**Authentication**: Not required

**Implementation**:

```typescript
export const getAllValidators = async () => {
  const response = await axiosInstance.get<string[]>('/reward_addresses')
  return response.data
}
```

**Response**: Array of Gen6 addresses (string\[])

**Example Response**:

```json
["g6x123...", "g6x456...", "g6x789..."]
```

**Usage**:

```typescript
import { getAllValidators } from '@/packages/validator-dashboard/api/queries'

function ValidatorList() {
  const { data: validators, isLoading } = useQuery({
    queryKey: ['validators', 'all'],
    queryFn: getAllValidators,
    staleTime: 300000 // 5 minutes
  })

  if (isLoading) return <div>Loading...</div>

  return (
    <div>
      <h2>Active Validators ({validators?.length || 0})</h2>
      <div className="grid gap-4">
        {validators?.map(address => (
          <ValidatorCard key={address} address={address} />
        ))}
      </div>
    </div>
  )
}

function ValidatorCard({ address }: { address: string }) {
  const { data: dashboard } = useQuery({
    queryKey: ['validator-dashboard', address],
    queryFn: () => getValidatorDashboardByAddress(address)
  })

  return (
    <Card>
      <CardContent>
        <p className="font-mono text-sm">{address}</p>
        {dashboard && (
          <div className="flex gap-4 mt-2">
            <Badge variant={dashboard.status === 'active' ? 'success' : 'secondary'}>
              {dashboard.status}
            </Badge>
            <span className="text-sm">Uptime: {dashboard.uptime.toFixed(2)}%</span>
          </div>
        )}
      </CardContent>
    </Card>
  )
}

```

***

### Blockchain Data Subscription

The validator dashboard subscribes to real-time blockchain data for network statistics.

**Hook**: `useBlockchainData()`

**Location**: src/packages/validator-dashboard/hooks/useBlockchainData.tsx

**Returns**:

```typescript
interface BlockchainValidatorData {
  activeValidators: Array<string> // List of active validator addresses
  currentBlock: number // Current block number
  totalTransactions: string // Estimated total transactions
  avgTrxPerBlock: number // Average transactions per block
}
```

**Implementation**:

```typescript
import { useBlockchainData } from '@/packages/validator-dashboard/hooks/useBlockchainData'

function NetworkStats() {
  const { data: blockchainData, isLoading } = useBlockchainData()

  if (isLoading) return <div>Loading network data...</div>

  return (
    <div>
      <p>Current Block: {blockchainData?.currentBlock}</p>
      <p>Active Validators: {blockchainData?.activeValidators?.length}</p>
      <p>Avg Transactions/Block: {blockchainData?.avgTrxPerBlock}</p>
      <p>Total Transactions: {blockchainData?.totalTransactions}</p>
    </div>
  )
}
```

**Subscription Details**:

* Subscribes to new block headers (`api.rpc.chain.subscribeNewHeads`)
* Tracks last 20 blocks for transaction averaging
* Subscribes to validator set changes (`api.query.session.validators`)
* Automatically updates when blockchain state changes

**Usage in Dashboard**:

```typescript
function ValidatorDashboardPage() {
  // API data for specific validator
  const { data: validatorReports } = useValidatorDashboard(validatorAddress)

  // Real-time blockchain network data
  const { data: blockchainData, isLoading: isBlockchainLoading } =
    useBlockchainData()

  return (
    <div>
      <NetworkOverview blockchainData={blockchainData} />
      <ValidatorDetails reports={validatorReports} />
    </div>
  )
}
```

***

#### Query Account Balance

Get account information including balance for fee calculations.

**Blockchain Query**: `api.query.system.account()`

**Parameters**:

* `address`: SS58-355 encoded account address

**Implementation**:

```typescript
import { useQuery } from '@tanstack/react-query'

export const useAccountBalance = (address?: string) => {
  const { api } = useGen6()

  return useQuery({
    queryKey: ['accountBalance', address],
    queryFn: async () => {
      if (!api || !address) return null

      const account = await api.query.system.account(address)
      return account.toJSON()
    },
    enabled: !!api && !!address,
    staleTime: 30000
  })
}
```

**Response**:

```typescript
{
  nonce: number,
  consumers: number,
  providers: number,
  sufficients: number,
  data: {
    free: string,      // Free balance
    reserved: string,  // Reserved balance
    miscFrozen: string,
    feeFrozen: string
  }
}
```

**Usage**: Used internally for balance checking and fee estimation.

***

### Axios Configuration

**Location**: src/packages/validator-dashboard/api/axiosInstance.ts

**Configuration**:

```typescript
import axios from 'axios'
import { getValidatorsUrl } from '@/data/nodes'

export const axiosInstance = axios.create({
  baseURL: getValidatorsUrl(),
  headers: {
    'Content-Type': 'application/json'
  },
  withCredentials: false // No authentication required
})

// Response interceptor for error handling
axiosInstance.interceptors.response.use(
  (response) => response,
  (error) => {
    const message =
      error.response?.data?.error ||
      error.response?.data?.detail ||
      error.message

    return Promise.reject(new Error(message))
  }
)
```

**Note**: Validator Dashboard uses a separate API endpoint (Not from main MW).

***

### Query Keys

**TanStack Query Keys**:

```typescript
// All validators
;['validators', 'all'][
  // Specific validator dashboard
  ('validator-dashboard', address)
]
```

***

### Real-Time Monitoring

For live validator monitoring, use query refetching:

```typescript
function LiveValidatorMonitor({ address }: { address: string }) {
  const { data, isLoading, dataUpdatedAt } = useQuery({
    queryKey: ['validatorDashboard', address],
    queryFn: () => getValidatorDashboardByAddress(address),
    refetchInterval: 30000,        // Refetch every 30 seconds
    refetchOnWindowFocus: true,    // Refetch when user returns to tab
    refetchOnReconnect: true       // Refetch on network reconnect
  })

  const lastUpdate = new Date(dataUpdatedAt).toLocaleTimeString()

  return (
    <div>
      <ValidatorDashboard data={data} />
      <p className="text-xs text-muted-foreground mt-2">
        Last updated: {lastUpdate}
      </p>
    </div>
  )
}
```

***

### Validator Status Indicators

**Status Definitions**:

* **Active**: Currently participating in consensus, producing blocks
* **Inactive**: Not producing blocks (offline, slashed, etc...)

**Visual Indicators**:

```typescript
function ValidatorStatusBadge({ status }: { status: 'active' | 'inactive' }) {
  const config = {
    active: {
      variant: 'success' as const,
      icon: '🟢',
      label: 'Active'
    },
    inactive: {
      variant: 'secondary' as const,
      icon: '🔴',
      label: 'Inactive'
    }
  }

  const { variant, icon, label } = config[status]

  return (
    <Badge variant={variant}>
      {icon} {label}
    </Badge>
  )
}
```

***

### Rewards Display

Convert validator rewards to human-readable format:

```typescript
import { BN } from 'bn.js'

function ValidatorRewards({ rewards }: { rewards: string }) {
  const { api } = useGen6()
  const decimals = api.registry.chainDecimals[0]

  const rewardsBN = new BN(rewards).div(new BN(10).pow(new BN(decimals)))

  return (
    <div>
      <p className="text-sm text-muted-foreground">Total Rewards</p>
      <p className="text-2xl font-bold">{rewardsBN.toString()} GEN6</p>
    </div>
  )
}
```

***

### Complete Example

```typescript
function ValidatorMonitoringDashboard() {
  const { data: validators } = useQuery({
    queryKey: ['validators'],
    queryFn: getAllValidators,
    staleTime: 5 * 60 * 1000 // Cache for 5 minutes
  })

  const [selectedValidator, setSelectedValidator] = useState<string | null>(null)

  return (
    <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
      {/* Validator List */}
      <Card className="lg:col-span-1">
        <CardHeader>
          <CardTitle>Validators ({validators?.total_count || 0})</CardTitle>
        </CardHeader>
        <CardContent>
          <ScrollArea className="h-[600px]">
            {validators?.validators.map(address => (
              <button
                key={address}
                onClick={() => setSelectedValidator(address)}
                className="w-full text-left p-2 hover:bg-accent rounded"
              >
                <ValidatorListItem address={address} />
              </button>
            ))}
          </ScrollArea>
        </CardContent>
      </Card>

      {/* Detailed Dashboard */}
      <div className="lg:col-span-2">
        {selectedValidator ? (
          <LiveValidatorMonitor address={selectedValidator} />
        ) : (
          <Card>
            <CardContent className="flex items-center justify-center h-[600px]">
              <p className="text-muted-foreground">
                Select a validator to view details
              </p>
            </CardContent>
          </Card>
        )}
      </div>
    </div>
  )
}

function ValidatorListItem({ address }: { address: string }) {
  const { data } = useQuery({
    queryKey: ['validatorDashboard', address],
    queryFn: () => getValidatorDashboardByAddress(address),
    refetchInterval: 60000
  })

  return (
    <div className="flex items-center justify-between">
      <span className="font-mono text-xs truncate flex-1">
        {address.slice(0, 10)}...{address.slice(-8)}
      </span>
      {data && (
        <div className="flex items-center gap-2">
          <span className="text-xs">{data.uptime.toFixed(1)}%</span>
          <div className={`w-2 h-2 rounded-full ${
            data.status === 'active' ? 'bg-green-500' : 'bg-gray-400'
          }`} />
        </div>
      )}
    </div>
  )
}
```
