For Validators
This document provides a comprehensive guide for setting up and operating a validator in the SN106 Bittensor subnet system. Validators are responsible for evaluating miner performance by analyzing their concentrated liquidity positions across multiple blockchain networks and submitting calculated weights to the Subtensor chain every 20 minutes.
For information about how miners participate in the system, see For Miners. For general system architecture details, see System Architecture.
System Requirements
Section titled “System Requirements”Hardware Specifications
Section titled “Hardware Specifications”| Component | Minimum | Recommended |
|---|---|---|
| CPU | 4 cores | 8 cores |
| RAM | 8GB | 16GB |
| Storage | 50GB+ SSD | 100GB+ SSD |
| Network | 50+ Mbps stable connection | 100+ Mbps high-speed |
| OS | Linux/macOS/Windows | Ubuntu 22.04 LTS |
Software Dependencies
Section titled “Software Dependencies”| Dependency | Version | Purpose |
|---|---|---|
| Node.js | v18.0.0+ | Runtime environment |
| npm | v8.0.0+ | Package management |
| Git | Latest | Repository access |
Blockchain Access Requirements
Section titled “Blockchain Access Requirements”The validator requires RPC access to multiple blockchain networks:
- Solana RPC: Mainnet/devnet access for position data
- Subtensor: Bittensor network RPC for weight submission
- Ethereum RPC: Coming soon for Uniswap V3 integration
- Base RPC: Coming soon for Base network integration
Sources: README.md:53-81
Installation & Setup
Section titled “Installation & Setup”Repository Setup
Section titled “Repository Setup”# Clone the repositorygit clone <repository-url>cd sn106
# Install dependenciesnpm installEnvironment Configuration
Section titled “Environment Configuration”Copy the environment template and configure required variables:
cp .env.example .envnano .envThe configuration system uses a typed environment loader that validates and provides default values for missing variables.
Validator Configuration System
Section titled “Validator Configuration System”The SN106 validator uses a centralized configuration system that loads environment variables and provides typed access throughout the application.
graph TD
subgraph "Configuration Loading"
ENV_FILE[".env File"]
DOTENV["dotenv.config()"]
ENV_OBJ["ENV Object<br/>Raw Environment Variables"]
end
subgraph "Configuration Processing"
CONFIG_OBJ["CONFIG Object<br/>Typed & Validated"]
VALIDATION["validateEnvironment()"]
DEFAULTS["Default Value Assignment"]
end
subgraph "Chain Configuration"
ENABLED_CHAINS["getEnabledChains()"]
CHAIN_CHECK["isChainEnabled()"]
SOLANA_CFG["CONFIG.SOLANA"]
ETH_CFG["CONFIG.ETHEREUM"]
BASE_CFG["CONFIG.BASE"]
end
subgraph "Runtime Configuration"
SUBTENSOR_CFG["CONFIG.SUBTENSOR"]
VALIDATOR_CFG["CONFIG.VALIDATOR"]
PERFORMANCE_CFG["CONFIG.PERFORMANCE"]
BITTENSOR_CFG["CONFIG.BITTENSOR"]
end
ENV_FILE --> DOTENV
DOTENV --> ENV_OBJ
ENV_OBJ --> CONFIG_OBJ
ENV_OBJ --> VALIDATION
ENV_OBJ --> DEFAULTS
CONFIG_OBJ --> ENABLED_CHAINS
CONFIG_OBJ --> CHAIN_CHECK
CONFIG_OBJ --> SOLANA_CFG
CONFIG_OBJ --> ETH_CFG
CONFIG_OBJ --> BASE_CFG
CONFIG_OBJ --> SUBTENSOR_CFG
CONFIG_OBJ --> VALIDATOR_CFG
CONFIG_OBJ --> PERFORMANCE_CFG
CONFIG_OBJ --> BITTENSOR_CFG
Sources: config/environment.ts:1-169
Core Environment Variables
Section titled “Core Environment Variables”Subtensor Configuration
Section titled “Subtensor Configuration”# WebSocket endpoint for Subtensor chainSUBTENSOR_WS_URL=wss://your-subtensor-endpoint
# Validator hotkey (supports multiple formats)VALIDATOR_HOTKEY_URI=your-hotkey-uri-or-mnemonic
# Network UID for SN106NETUID=106Solana Configuration
Section titled “Solana Configuration”# Solana RPC endpointSOLANA_RPC_ENDPOINT=https://your-solana-rpc
# SN106 smart contract program IDSN106_SVM_PROGRAM_ID=DtZgqA3dvVK1m1CUEnkipEHyDtPzAmxb98SU9sqYDpDE
# Raydium CLMM program IDRAYDIUM_CLMM_PROGRAM_ID=DRayAUgENGQBKVaX8owNhgzkEDyoHTGVEGHVJT1E9pfHValidator Behavior Configuration
Section titled “Validator Behavior Configuration”# Execution interval in minutes (default: 20)VALIDATOR_INTERVAL_MINUTES=20
# EMA smoothing parametersUSE_EMA=trueEMA_ALPHA=0.3EMA_EPSILON=1e-6
# Enabled blockchain networksENABLED_CHAINS=SOLANA,ETHEREUM,BASEThe VALIDATOR_HOTKEY_URI supports multiple input formats for backward compatibility:
- Mnemonic:
word1 word2 word3 ... word12 - Private Key:
0x1234...(hex format) - URI:
//Aliceor other Polkadot-style URIs
Sources: config/environment.ts:44-51 , README.md:104-132
Validator Execution Flow
Section titled “Validator Execution Flow”The validator operates on a scheduled 20-minute cycle, executing a comprehensive data collection and weight calculation pipeline.
graph TD
subgraph "Initialization Phase"
START["runValidator()"]
LOG_CHAINS["Log Enabled Chains"]
INIT_CLIENT["subtensorClient.initialize()"]
EMA_INIT["Initialize EMA State<br/>global.__sn106EmaWeights"]
end
subgraph "Data Collection Phase"
FETCH_HOTKEYS["getHotkeyToUidMap()"]
FETCH_POSITIONS["getAllNFTPositions()"]
FETCH_TICKS["getCurrentTickPerPool()"]
FETCH_PRICES["getSubnetAlphaPrices()"]
end
subgraph "Weight Calculation Phase"
POOL_WEIGHTS["calculatePoolWeightsWithReservedPools()"]
NFT_EMISSIONS["calculatePoolwiseNFTEmissions()"]
MINER_AGGREGATION["Aggregate Per-Miner Emissions"]
POLICY_APPLICATION["Apply Distribution Policy"]
end
subgraph "EMA Processing"
EMA_CHECK["CONFIG.VALIDATOR.USE_EMA?"]
EMA_UPDATE["updateEma()"]
EMA_APPLY["Apply EMA Weights"]
RAW_WEIGHTS["Use Raw Weights"]
end
subgraph "Weight Submission"
PREPARE_WEIGHTS["Prepare Final Weights"]
SUBMIT_WEIGHTS["setWeightsOnSubtensor()"]
LOG_COMPLETE["Log Completion"]
end
subgraph "Scheduling"
TIMER["setInterval()<br/>20-minute cycles"]
SHUTDOWN["Graceful Shutdown<br/>SIGINT/SIGTERM"]
end
START --> LOG_CHAINS
LOG_CHAINS --> INIT_CLIENT
INIT_CLIENT --> EMA_INIT
EMA_INIT --> FETCH_HOTKEYS
FETCH_HOTKEYS --> FETCH_POSITIONS
FETCH_POSITIONS --> FETCH_TICKS
FETCH_TICKS --> FETCH_PRICES
FETCH_PRICES --> POOL_WEIGHTS
POOL_WEIGHTS --> NFT_EMISSIONS
NFT_EMISSIONS --> MINER_AGGREGATION
MINER_AGGREGATION --> POLICY_APPLICATION
POLICY_APPLICATION --> EMA_CHECK
EMA_CHECK -->|true| EMA_UPDATE
EMA_CHECK -->|false| RAW_WEIGHTS
EMA_UPDATE --> EMA_APPLY
EMA_APPLY --> PREPARE_WEIGHTS
RAW_WEIGHTS --> PREPARE_WEIGHTS
PREPARE_WEIGHTS --> SUBMIT_WEIGHTS
SUBMIT_WEIGHTS --> LOG_COMPLETE
TIMER --> START
SHUTDOWN --> INIT_CLIENT
Sources: validator/index.ts:17-181
Distribution Policy Logic
Section titled “Distribution Policy Logic”The validator implements a sophisticated weight distribution policy based on miner position quality:
- In-Range Miners: If any miner has positions within the current trading range, only those miners receive non-zero weights
- All Out-of-Range: If all positions are out-of-range, uniform weights are distributed across all UIDs
- EMA Smoothing: When enabled, weights are smoothed using exponential moving averages with configurable
EMA_ALPHA
graph TD
subgraph "Policy Decision Tree"
CHECK_POSITIVE["hasPositiveEmission<br/>Any miner with emission > 0?"]
INIT_ZERO["Initialize all UIDs to 0"]
EMA_DECISION["CONFIG.VALIDATOR.USE_EMA?"]
APPLY_EMA["Apply EMA to eligible miners<br/>updateEma(emaWeights, eligible)"]
ASSIGN_RAW["Assign raw weights<br/>to positive miners only"]
UNIFORM_FALLBACK["setWeightsOnSubtensor<br/>handles uniform distribution"]
end
subgraph "EMA Weight Management"
EMA_STATE["global.__sn106EmaWeights<br/>Persistent EMA state"]
EMA_UPDATE["nextEma = updateEma(prev, curr)"]
EMA_THRESHOLD["Filter by EMA_EPSILON<br/>Remove near-zero weights"]
EMA_SAVE["Save updated EMA state"]
end
CHECK_POSITIVE -->|true| INIT_ZERO
CHECK_POSITIVE -->|false| UNIFORM_FALLBACK
INIT_ZERO --> EMA_DECISION
EMA_DECISION -->|true| APPLY_EMA
EMA_DECISION -->|false| ASSIGN_RAW
APPLY_EMA --> EMA_STATE
EMA_STATE --> EMA_UPDATE
EMA_UPDATE --> EMA_THRESHOLD
EMA_THRESHOLD --> EMA_SAVE
EMA_SAVE --> UNIFORM_FALLBACK
ASSIGN_RAW --> UNIFORM_FALLBACK
Sources: validator/index.ts:110-158
Running the Validator
Section titled “Running the Validator”Start Validation Process
Section titled “Start Validation Process”# Start the validatornpm run validatorThe validator will:
- Initialize connection to Subtensor chain using
subtensorClient.initialize() - Begin 20-minute execution cycles using
setInterval() - Log operation status and weight submissions to console
- Save weight history to
weights/weights_history.json
Graceful Shutdown
Section titled “Graceful Shutdown”The validator handles shutdown signals gracefully:
# Graceful shutdown (CTRL+C)SIGINT -> subtensorClient.shutdown() -> process.exit(0)
# Termination signalSIGTERM -> subtensorClient.shutdown() -> process.exit(0)Sources: validator/index.ts:166-176
Weight Calculation Architecture
Section titled “Weight Calculation Architecture”The validator implements a multi-stage weight calculation system that evaluates NFT position quality and subnet performance.
graph TB
subgraph "Input Data Sources"
POSITIONS_DATA["getAllNFTPositions()<br/>Multi-chain NFT data"]
TICK_DATA["getCurrentTickPerPool()<br/>Current market state"]
ALPHA_PRICES["getSubnetAlphaPrices()<br/>Subnet performance"]
HOTKEY_MAP["getHotkeyToUidMap()<br/>Miner identities"]
end
subgraph "Pool Weight Calculation"
RESERVED_LOGIC["Reserved Share Logic<br/>25% for subnet 0 pools"]
SUBNET_WEIGHTS["Subnet Weight Calculation<br/>Based on alpha prices"]
POOL_WEIGHTS_CALC["calculatePoolWeightsWithReservedPools()"]
end
subgraph "NFT Scoring Engine"
WIDTH_SCORE["Position Width Analysis<br/>Concentration bonus"]
DISTANCE_SCORE["Distance from Current Tick<br/>Market proximity penalty"]
LIQUIDITY_SCORE["Liquidity Amount<br/>Capital contribution"]
COMBINED_SCORE["Combined NFT Score"]
end
subgraph "Emission Distribution"
POOL_ALLOCATION["Pool-wise Allocation<br/>Based on pool weights"]
NFT_COMPETITION["Intra-pool Competition<br/>NFTs compete within pools"]
EMISSION_CALC["calculatePoolwiseNFTEmissions()"]
end
subgraph "Miner Aggregation"
PER_MINER["Aggregate emissions per miner<br/>Sum of all NFT emissions"]
POLICY_CHECK["Distribution policy check<br/>In-range vs out-of-range"]
FINAL_WEIGHTS["Final miner weights"]
end
POSITIONS_DATA --> POOL_WEIGHTS_CALC
TICK_DATA --> POOL_WEIGHTS_CALC
ALPHA_PRICES --> POOL_WEIGHTS_CALC
POOL_WEIGHTS_CALC --> RESERVED_LOGIC
RESERVED_LOGIC --> SUBNET_WEIGHTS
POSITIONS_DATA --> WIDTH_SCORE
TICK_DATA --> DISTANCE_SCORE
POSITIONS_DATA --> LIQUIDITY_SCORE
WIDTH_SCORE --> COMBINED_SCORE
DISTANCE_SCORE --> COMBINED_SCORE
LIQUIDITY_SCORE --> COMBINED_SCORE
SUBNET_WEIGHTS --> POOL_ALLOCATION
COMBINED_SCORE --> NFT_COMPETITION
POOL_ALLOCATION --> EMISSION_CALC
NFT_COMPETITION --> EMISSION_CALC
EMISSION_CALC --> PER_MINER
PER_MINER --> POLICY_CHECK
POLICY_CHECK --> FINAL_WEIGHTS
HOTKEY_MAP --> FINAL_WEIGHTS
Sources: validator/index.ts:71-108
Monitoring & Maintenance
Section titled “Monitoring & Maintenance”Log Monitoring
Section titled “Log Monitoring”The validator provides comprehensive logging through the logger utility:
- Startup: Chain configuration and initialization status
- Data Collection: Position counts, tick data, and price information
- Weight Calculation: Pool weights, NFT emissions, and policy decisions
- Submission: Weight submission results and completion status
- Errors: Detailed error messages for troubleshooting
Weight History Tracking
Section titled “Weight History Tracking”All weight submissions are automatically saved to weights/weights_history.json for audit and analysis purposes. This file contains:
- Timestamp of each submission
- Final weight values sent to Subtensor
- Policy decisions (in-range vs uniform distribution)
Health Monitoring
Section titled “Health Monitoring”Key indicators to monitor:
| Metric | Expected Behavior | Troubleshooting |
|---|---|---|
| Execution Cycle | Every 20 minutes | Check VALIDATOR_INTERVAL_MINUTES |
| Position Count | > 0 for active miners | Verify chain connectivity |
| Weight Submission | Successful every cycle | Check VALIDATOR_HOTKEY_URI |
| EMA State | Persistent across runs | Monitor global.__sn106EmaWeights |
Performance Configuration
Section titled “Performance Configuration”The validator includes several performance optimization settings:
# Retry configurationMAX_RETRIES=3RETRY_BASE_DELAY_MS=1000MAX_RETRY_DELAY_MS=5000
# Batch processingPOSITION_BATCH_SIZE=100MAX_CONCURRENT_BATCHES=3HOTKEY_BATCH_SIZE=8
# TimeoutsRPC_TIMEOUT_MS=30000Sources: config/environment.ts:57-68 , README.md:149-153
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”| Issue | Symptoms | Solution |
|---|---|---|
| Missing Environment Variables | Warning messages at startup | Configure required variables in .env |
| RPC Connection Failures | Timeout errors in logs | Verify RPC endpoints and network connectivity |
| Weight Submission Failures | Error in setWeightsOnSubtensor() | Check VALIDATOR_HOTKEY_URI format and permissions |
| EMA State Loss | Inconsistent weight smoothing | Ensure validator process persistence |
Environment Validation
Section titled “Environment Validation”The configuration system automatically validates required environment variables using validateEnvironment() and provides warnings for missing values with fallback to defaults.
Connection Management
Section titled “Connection Management”The validator uses subtensorClient for connection management with automatic initialization and graceful shutdown handling to prevent resource leaks.
Sources: config/environment.ts:154-169 , validator/index.ts:29-30