System Architecture
Purpose and Scope
Section titled “Purpose and Scope”This document explains the high-level architecture of the SN106 Bittensor subnet validator system, including its core components, data flow patterns, and multi-chain integration mechanisms. It covers the validator engine orchestration, emission calculation algorithms, and weight submission processes.
For detailed implementation specifics and code examples, see Technical Implementation. For user setup instructions, see Configuration and Docker Deployment.
High-Level System Overview
Section titled “High-Level System Overview”SN106 operates as a distributed validator system that incentivizes concentrated liquidity provision across multiple blockchain networks. The system evaluates NFT liquidity positions, calculates rewards based on position quality and subnet performance, then submits weight distributions to the Bittensor Subtensor chain every 20 minutes.
System Architecture Diagram
Section titled “System Architecture Diagram”graph TB
subgraph "External Dependencies"
SUBTENSOR["Subtensor Chain<br/>Weight Submission Target"]
SOLANA["Solana Network<br/>Raydium CLMM"]
ETHEREUM["Ethereum Network<br/>Uniswap V3<br/>(Coming Soon)"]
BASE["Base Network<br/>Uniswap V3<br/>(Coming Soon)"]
end
subgraph "Validator Core"
ENGINE["ValidatorEngine<br/>validator/index.ts<br/>runValidatorLoop()"]
TIMER["20-Minute Timer<br/>setInterval()"]
EMA["EMA Weight Manager<br/>updateEma()"]
end
subgraph "Data Collection Layer"
CHAINS["Chain Manager<br/>validator/chains/index.ts<br/>getEnabledChains()"]
POSITIONS["Position Fetcher<br/>fetchNFTPositionsFromAllChains()"]
TICKS["Tick Data Fetcher<br/>fetchCurrentTickDataForAllPools()"]
ALPHAS["Subnet Alpha Prices<br/>getSubnetAlphaPrices()"]
end
subgraph "Processing Engine"
POOLW["Pool Weight Calculator<br/>utils/poolWeights.ts<br/>calculatePoolWeights()"]
EMISSIONS["Emissions Calculator<br/>validator/calculations/emissions.ts<br/>calculatePoolwiseNFTEmissions()"]
AGGREGATOR["Weight Aggregator<br/>aggregateMinerWeights()"]
end
subgraph "Submission System"
POLICY["Distribution Policy<br/>hasPositiveEmission logic"]
WEIGHTS["Weight Preparation<br/>prepareWeightsForSubmission()"]
SUBMIT["Subtensor Submission<br/>utils/setWeights.ts<br/>setWeightsOnSubtensor()"]
end
TIMER --> ENGINE
ENGINE --> CHAINS
CHAINS --> POSITIONS
CHAINS --> TICKS
ENGINE --> ALPHAS
POSITIONS --> POOLW
TICKS --> POOLW
ALPHAS --> POOLW
POOLW --> EMISSIONS
POSITIONS --> EMISSIONS
TICKS --> EMISSIONS
EMISSIONS --> AGGREGATOR
AGGREGATOR --> POLICY
POLICY --> WEIGHTS
EMA --> WEIGHTS
WEIGHTS --> SUBMIT
SUBMIT --> SUBTENSOR
POSITIONS --> SOLANA
POSITIONS --> ETHEREUM
POSITIONS --> BASE
Sources: validator/index.ts:1-300 , validator/chains/index.ts:1-50 , utils/poolWeights.ts:1-100 , validator/calculations/emissions.ts:1-200 , utils/setWeights.ts:1-150
Core Components
Section titled “Core Components”Validator Engine
Section titled “Validator Engine”The ValidatorEngine in validator/index.ts orchestrates the entire validation cycle through runValidatorLoop(). It manages the 20-minute execution timer and coordinates all data collection, processing, and submission phases.
| Component | Function | File Location |
|---|---|---|
| Main Loop | runValidatorLoop() | validator/index.ts:50-100 |
| EMA Management | updateEma() | validator/index.ts:200-250 |
| Error Handling | Try-catch blocks with logging | validator/index.ts:150-200 |
Multi-Chain Data Collection
Section titled “Multi-Chain Data Collection”The chain management system supports multiple blockchain networks through a unified interface defined in validator/chains/index.ts .
Chain Configuration Table
Section titled “Chain Configuration Table”| Chain | Status | Program/Contract | Data Source |
|---|---|---|---|
| Solana | Active | SN106_SVM_PROGRAM_ID | Raydium CLMM |
| Ethereum | Coming Soon | SN106_CONTRACT_ADDRESS | Uniswap V3 |
| Base | Coming Soon | SN106_CONTRACT_ADDRESS | Uniswap V3 |
Chain Integration Architecture
Section titled “Chain Integration Architecture”graph TD
subgraph "Chain Management"
CONFIG["config/environment.ts<br/>ENABLED_CHAINS"]
FILTER["getEnabledChains()<br/>validator/chains/index.ts"]
end
subgraph "Solana Integration"
SOLANA_FETCH["fetchSolanaNFTPositions()<br/>validator/chains/solana.ts"]
SOLANA_TICKS["fetchSolanaCurrentTicks()<br/>validator/chains/solana.ts"]
RAYDIUM["Raydium CLMM Program<br/>RAYDIUM_CLMM_PROGRAM_ID"]
end
subgraph "Ethereum Integration"
ETH_FETCH["fetchEthereumNFTPositions()<br/>validator/chains/ethereum.ts"]
ETH_TICKS["fetchEthereumCurrentTicks()<br/>validator/chains/ethereum.ts"]
UNISWAP["Uniswap V3 Contracts<br/>UNISWAP_V3_FACTORY_ADDRESS"]
end
subgraph "Data Aggregation"
POSITIONS["NFTPosition[]<br/>Unified Position Array"]
TICKDATA["PoolTickData<br/>Record<string, PoolTickData>"]
end
CONFIG --> FILTER
FILTER --> SOLANA_FETCH
FILTER --> ETH_FETCH
SOLANA_FETCH --> RAYDIUM
SOLANA_TICKS --> RAYDIUM
ETH_FETCH --> UNISWAP
ETH_TICKS --> UNISWAP
SOLANA_FETCH --> POSITIONS
ETH_FETCH --> POSITIONS
SOLANA_TICKS --> TICKDATA
ETH_TICKS --> TICKDATA
Sources: validator/chains/index.ts:10-40 , validator/chains/solana.ts:1-200 , config/environment.ts:20-60
Weight Calculation and Distribution
Section titled “Weight Calculation and Distribution”NFT Position Scoring Algorithm
Section titled “NFT Position Scoring Algorithm”The emissions calculator in validator/calculations/emissions.ts implements a sophisticated scoring system that evaluates NFT positions based on three factors:
- Position Width: Calculated as
tickUpper - tickLower - Distance from Current Tick: Absolute difference between position center and current market tick
- Liquidity Amount: The actual liquidity value in the position
Scoring Implementation Flow
Section titled “Scoring Implementation Flow”graph TD
subgraph "NFT Position Input"
POSITION["NFTPosition<br/>tickLower, tickUpper, liquidity"]
CURRENT["currentTick<br/>from PoolTickData"]
end
subgraph "Scoring Calculations"
WIDTH["widthCalculation<br/>tickUpper - tickLower"]
CENTER["centerCalculation<br/>(tickLower + tickUpper) / 2"]
DISTANCE["distanceCalculation<br/>Math.abs(center - currentTick)"]
end
subgraph "Score Components"
WIDTH_PENALTY["widthPenalty<br/>1 / Math.pow(width, 1.2)"]
CENTER_WEIGHT["centerWeight<br/>1 / (1 + distanceFromCenter)"]
BASE_SCORE["baseScore<br/>widthPenalty * centerWeight"]
end
subgraph "Final Score"
FINAL["finalScore<br/>baseScore * position.liquidity"]
end
POSITION --> WIDTH
POSITION --> CENTER
CURRENT --> DISTANCE
CENTER --> DISTANCE
WIDTH --> WIDTH_PENALTY
DISTANCE --> CENTER_WEIGHT
WIDTH_PENALTY --> BASE_SCORE
CENTER_WEIGHT --> BASE_SCORE
BASE_SCORE --> FINAL
POSITION --> FINAL
Sources: validator/calculations/emissions.ts:50-100 , validator/calculations/emissions.ts:150-200
Pool Weight Distribution System
Section titled “Pool Weight Distribution System”The pool weight calculator in utils/poolWeights.ts implements a reserved-share logic that allocates rewards based on subnet performance while ensuring fair distribution within subnets.
Reserved Share Logic Table
Section titled “Reserved Share Logic Table”| Allocation Type | Percentage | Target |
|---|---|---|
| Reserved Share | 25% | Subnet 0 pools (no-alpha pools) |
| Proportional Share | 75% | Alpha token pools by subnet performance |
EMA Weight Smoothing
Section titled “EMA Weight Smoothing”The validator implements Exponential Moving Average smoothing to prevent sudden weight fluctuations:
graph LR
subgraph "EMA Configuration"
ALPHA["EMA_ALPHA<br/>config value: 0.3"]
EPSILON["EMA_EPSILON<br/>threshold: 0.001"]
end
subgraph "Weight Processing"
CURRENT["currentWeights<br/>Record<string, number>"]
PREVIOUS["previousWeights<br/>stored from last run"]
FORMULA["emaFormula<br/>α * current + (1-α) * previous"]
end
subgraph "Output"
SMOOTHED["smoothedWeights<br/>applied to submission"]
THRESHOLD["thresholdFiltering<br/>weights < epsilon set to 0"]
end
ALPHA --> FORMULA
CURRENT --> FORMULA
PREVIOUS --> FORMULA
FORMULA --> SMOOTHED
EPSILON --> THRESHOLD
SMOOTHED --> THRESHOLD
Sources: validator/index.ts:250-300 , config/environment.ts:80-120
Data Flow Architecture
Section titled “Data Flow Architecture”Complete Validation Cycle
Section titled “Complete Validation Cycle”The validator executes a complete cycle every 20 minutes through the following sequence:
- Initialization: Load configuration and enabled chains
- Data Collection: Fetch positions, ticks, and subnet prices
- Weight Calculation: Calculate pool weights and NFT emissions
- Distribution Policy: Apply in-range vs out-of-range logic
- Submission: Submit weights to Subtensor with burn mechanism
Distribution Policy Logic
Section titled “Distribution Policy Logic”graph TD
subgraph "Emission Analysis"
EMISSIONS["calculatePoolwiseNFTEmissions()<br/>returns NFTEmissionResult[]"]
CHECK["hasPositiveEmission<br/>Object.values().some(v => v > 0)"]
end
subgraph "Policy Decision"
POSITIVE{"hasPositiveEmission?"}
INRANGE["In-Range Policy<br/>Set all UIDs to 0<br/>Assign weights only to positive"]
OUTRANGE["Out-of-Range Policy<br/>Uniform distribution<br/>All UIDs get equal weight"]
end
subgraph "Weight Assignment"
ZERO["Initialize all known UIDs to 0"]
ASSIGN["Assign weights to miners with emissions > 0"]
UNIFORM["Apply uniform distribution fallback"]
end
EMISSIONS --> CHECK
CHECK --> POSITIVE
POSITIVE -->|"Yes"| INRANGE
POSITIVE -->|"No"| OUTRANGE
INRANGE --> ZERO
ZERO --> ASSIGN
OUTRANGE --> UNIFORM
Sources: validator/index.ts:300-350 , utils/setWeights.ts:50-100
Configuration Architecture
Section titled “Configuration Architecture”The system uses a typed configuration system in config/environment.ts that validates all environment variables at startup and provides defaults for optional settings.
Configuration Structure
Section titled “Configuration Structure”| Category | Environment Variable | Default | Purpose |
|---|---|---|---|
| Subtensor | SUBTENSOR_WS_URL | Required | WebSocket endpoint |
| Subtensor | VALIDATOR_HOTKEY_URI | Required | Private key/mnemonic/URI |
| Subtensor | NETUID | 106 | Subnet identifier |
| Performance | USE_EMA | true | Enable weight smoothing |
| Performance | EMA_ALPHA | 0.3 | Smoothing factor |
| Chains | ENABLED_CHAINS | ’SOLANA,ETHEREUM,BASE’ | Active chains |
| Burn | BURN_PERCENTAGE | 95 | Percentage burned to UID 0 |
Sources: config/environment.ts:1-150 , README.md:104-124