# 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>
  )
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.gen6.life/developer-resources/sdk-and-tooling/g6-mw-and-chain-api-guide/07.-validator-dashboard.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
