Skip to content

Multi-Chain Integration

Relevant Source Files

This document describes the multi-chain architecture of the SN106 validator system, covering how the system integrates with multiple blockchain networks and manages data collection across different DeFi protocols. The system currently supports Solana with planned support for Ethereum and Base networks.

For information about the overall validator engine orchestration, see Validator Engine. For details about weight submission mechanisms, see Weight Submission System.

The SN106 validator implements a flexible multi-chain architecture that allows data collection from multiple blockchain networks while maintaining a unified reward calculation system. The architecture supports both active chains (Solana) and planned chains (Ethereum, Base) through a configurable chain filtering system.

graph TB
    subgraph "Configuration Layer"
        ENV_CONFIG["ENV.ENABLED_CHAINS"]
        CHAIN_CONFIG["CONFIG.getEnabledChains()"]
        CHAIN_FILTER["CONFIG.isChainEnabled()"]
    end
    
    subgraph "Chain Implementations"
        SOLANA_IMPL["Solana Implementation"]
        ETH_IMPL["Ethereum Implementation"]
        BASE_IMPL["Base Implementation"]
    end
    
    subgraph "Protocol Integrations"
        RAYDIUM["Raydium CLMM"]
        UNISWAP_ETH["Uniswap V3 (Ethereum)"]
        UNISWAP_BASE["Uniswap V3 (Base)"]
    end
    
    subgraph "Data Collection"
        NFT_POSITIONS["NFT Position Data"]
        TICK_DATA["Current Tick Data"]
        POOL_STATE["Pool State Information"]
    end
    
    subgraph "Unified Processing"
        DATA_AGGREGATION["Data Aggregation"]
        EMISSIONS_CALC["Emissions Calculation"]
        WEIGHT_SUBMISSION["Weight Submission"]
    end
    
    ENV_CONFIG --> CHAIN_CONFIG
    CHAIN_CONFIG --> CHAIN_FILTER
    
    CHAIN_FILTER --> SOLANA_IMPL
    CHAIN_FILTER --> ETH_IMPL
    CHAIN_FILTER --> BASE_IMPL
    
    SOLANA_IMPL --> RAYDIUM
    ETH_IMPL --> UNISWAP_ETH
    BASE_IMPL --> UNISWAP_BASE
    
    RAYDIUM --> NFT_POSITIONS
    UNISWAP_ETH --> NFT_POSITIONS
    UNISWAP_BASE --> NFT_POSITIONS
    
    RAYDIUM --> TICK_DATA
    UNISWAP_ETH --> TICK_DATA
    UNISWAP_BASE --> TICK_DATA
    
    NFT_POSITIONS --> DATA_AGGREGATION
    TICK_DATA --> DATA_AGGREGATION
    POOL_STATE --> DATA_AGGREGATION
    
    DATA_AGGREGATION --> EMISSIONS_CALC
    EMISSIONS_CALC --> WEIGHT_SUBMISSION

Sources: config/environment.ts:87-96 , README.md:156-159

The multi-chain configuration system is centralized in the environment configuration module, providing type-safe access to chain-specific settings and a unified interface for managing multiple blockchain networks.

graph TD
    subgraph "Environment Variables"
        ENABLED_CHAINS_ENV["ENABLED_CHAINS='SOLANA,ETHEREUM,BASE'"]
        SOLANA_ENV["SOLANA_RPC_ENDPOINT"]
        ETH_ENV["ETHEREUM_RPC_URL"]
        BASE_ENV["BASE_RPC_URL"]
    end
    
    subgraph "Type System"
        SUPPORTED_CHAIN["type SupportedChain = 'solana'"]
        CONFIG_TYPE["CONFIG object with typed chains"]
    end
    
    subgraph "Chain-Specific Configs"
        SOLANA_CONFIG["CONFIG.SOLANA"]
        ETH_CONFIG["CONFIG.ETHEREUM"]
        BASE_CONFIG["CONFIG.BASE"]
    end
    
    subgraph "Chain Properties"
        SOL_PROPS["RPC_ENDPOINT, PROGRAM_ID, CLMM_PROGRAM_ID"]
        ETH_PROPS["RPC_URL, SN106_CONTRACT_ADDRESS, UNISWAP_V3_*"]
        BASE_PROPS["RPC_URL, SN106_CONTRACT_ADDRESS, UNISWAP_V3_*"]
    end
    
    ENABLED_CHAINS_ENV --> SUPPORTED_CHAIN
    SOLANA_ENV --> SOLANA_CONFIG
    ETH_ENV --> ETH_CONFIG
    BASE_ENV --> BASE_CONFIG
    
    SOLANA_CONFIG --> SOL_PROPS
    ETH_CONFIG --> ETH_PROPS
    BASE_CONFIG --> BASE_PROPS
    
    CONFIG_TYPE --> SOLANA_CONFIG
    CONFIG_TYPE --> ETH_CONFIG
    CONFIG_TYPE --> BASE_CONFIG

The configuration system provides individual chain configurations with protocol-specific parameters:

ChainProtocolConfiguration Properties
SolanaRaydium CLMMRPC_ENDPOINT, PROGRAM_ID, CLMM_PROGRAM_ID
EthereumUniswap V3RPC_URL, SN106_CONTRACT_ADDRESS, UNISWAP_V3_FACTORY_ADDRESS, UNISWAP_V3_POSITION_MANAGER_ADDRESS, MULTICALL_ADDRESS
BaseUniswap V3RPC_URL, SN106_CONTRACT_ADDRESS, UNISWAP_V3_FACTORY_ADDRESS, UNISWAP_V3_POSITION_MANAGER_ADDRESS, MULTICALL_ADDRESS

Sources: config/environment.ts:20-42 , config/environment.ts:99-122

The system implements a dynamic chain filtering mechanism that allows validators to operate on specific blockchain networks while maintaining compatibility with the full multi-chain architecture.

graph TD
    subgraph "Chain Selection Process"
        ENV_VAR["ENV.ENABLED_CHAINS"]
        PARSE_CHAINS["chainsEnv.toUpperCase().split(',')"]
        ALL_CHAINS["allChains: ['solana']"]
        FILTER_LOGIC["return allChains"]
    end
    
    subgraph "Functions"
        GET_ENABLED["CONFIG.getEnabledChains()"]
        IS_ENABLED["CONFIG.isChainEnabled(chain)"]
        VALIDATION["validateEnvironment()"]
    end
    
    subgraph "Usage Examples"
        VALIDATOR_CHECK["if (CONFIG.isChainEnabled('solana'))"]
        CHAIN_LOOP["for (const chain of CONFIG.getEnabledChains())"]
    end
    
    ENV_VAR --> PARSE_CHAINS
    PARSE_CHAINS --> ALL_CHAINS
    ALL_CHAINS --> FILTER_LOGIC
    
    FILTER_LOGIC --> GET_ENABLED
    GET_ENABLED --> IS_ENABLED
    
    IS_ENABLED --> VALIDATOR_CHECK
    GET_ENABLED --> CHAIN_LOOP
    
    VALIDATION --> ENV_VAR

The current implementation only returns Solana as an enabled chain, with Ethereum and Base support planned for future releases. The getEnabledChains() function in config/environment.ts:87-92 implements this logic by filtering against available chain implementations.

Sources: config/environment.ts:87-96 , config/environment.ts:72

Each blockchain network integrates with different DeFi protocols for concentrated liquidity provision. The system abstracts these protocol differences through a unified data collection interface.

graph LR
    subgraph "Solana Integration"
        SOLANA_CHAIN["Solana Mainnet"]
        RAYDIUM_PROTOCOL["Raydium CLMM Protocol"]
        SOL_PROGRAM["SN106_SVM_PROGRAM_ID"]
        CLMM_PROGRAM["RAYDIUM_CLMM_PROGRAM_ID"]
    end
    
    subgraph "Ethereum Integration"
        ETH_CHAIN["Ethereum Mainnet"]
        UNISWAP_V3_ETH["Uniswap V3 Protocol"]
        ETH_CONTRACT["SN106_CONTRACT_ADDRESS"]
        UNI_FACTORY_ETH["UNISWAP_V3_FACTORY_ADDRESS"]
        UNI_MANAGER_ETH["UNISWAP_V3_POSITION_MANAGER_ADDRESS"]
    end
    
    subgraph "Base Integration"
        BASE_CHAIN["Base Network"]
        UNISWAP_V3_BASE["Uniswap V3 Protocol"]
        BASE_CONTRACT["BASE_SN106_CONTRACT_ADDRESS"]
        UNI_FACTORY_BASE["BASE_UNISWAP_V3_FACTORY_ADDRESS"]
        UNI_MANAGER_BASE["BASE_UNISWAP_V3_POSITION_MANAGER_ADDRESS"]
    end
    
    SOLANA_CHAIN --> RAYDIUM_PROTOCOL
    RAYDIUM_PROTOCOL --> SOL_PROGRAM
    RAYDIUM_PROTOCOL --> CLMM_PROGRAM
    
    ETH_CHAIN --> UNISWAP_V3_ETH
    UNISWAP_V3_ETH --> ETH_CONTRACT
    UNISWAP_V3_ETH --> UNI_FACTORY_ETH
    UNISWAP_V3_ETH --> UNI_MANAGER_ETH
    
    BASE_CHAIN --> UNISWAP_V3_BASE
    UNISWAP_V3_BASE --> BASE_CONTRACT
    UNISWAP_V3_BASE --> UNI_FACTORY_BASE
    UNISWAP_V3_BASE --> UNI_MANAGER_BASE

Each protocol requires specific contract addresses and program IDs configured through environment variables. The system uses different data fetching strategies:

  • Solana/Raydium: Direct program account fetching and CLMM pool state reading
  • Ethereum/Base/Uniswap V3: Multicall-optimized contract interaction for position and pool data

Sources: config/environment.ts:26-42 , README.md:156-159

The multi-chain architecture implements a unified data model that normalizes position and tick data from different protocols into a common format for emissions calculation.

graph TD
    subgraph "Chain-Specific Data Collection"
        SOL_POSITIONS["fetchSolanaPositions()"]
        ETH_POSITIONS["fetchEthereumPositions()"]
        BASE_POSITIONS["fetchBasePositions()"]
        
        SOL_TICKS["fetchSolanaTicks()"]
        ETH_TICKS["fetchEthereumTicks()"]
        BASE_TICKS["fetchBaseTicks()"]
    end
    
    subgraph "Data Normalization"
        UNIFIED_POSITIONS["NFTPosition[]"]
        UNIFIED_TICKS["PoolTickData{}"]
        CHAIN_PREFIXES["Chain-specific pool identifiers"]
    end
    
    subgraph "Unified Processing"
        POOL_WEIGHTS["calculatePoolWeights()"]
        NFT_EMISSIONS["calculateNFTEmissions()"]
        WEIGHT_AGGREGATION["aggregateMinerWeights()"]
    end
    
    SOL_POSITIONS --> UNIFIED_POSITIONS
    ETH_POSITIONS --> UNIFIED_POSITIONS
    BASE_POSITIONS --> UNIFIED_POSITIONS
    
    SOL_TICKS --> UNIFIED_TICKS
    ETH_TICKS --> UNIFIED_TICKS
    BASE_TICKS --> UNIFIED_TICKS
    
    UNIFIED_POSITIONS --> CHAIN_PREFIXES
    UNIFIED_TICKS --> CHAIN_PREFIXES
    
    CHAIN_PREFIXES --> POOL_WEIGHTS
    UNIFIED_POSITIONS --> NFT_EMISSIONS
    UNIFIED_TICKS --> NFT_EMISSIONS
    
    POOL_WEIGHTS --> WEIGHT_AGGREGATION
    NFT_EMISSIONS --> WEIGHT_AGGREGATION

The data unification strategy ensures that position NFTs and tick data from different chains can be processed through the same emissions calculation algorithms while maintaining chain-specific pool identification through prefixed pool identifiers.

Sources: docs/ARCHITECTURE.md:222-267 , docs/ARCHITECTURE.md:493-531

The system exposes a comprehensive configuration interface that provides type-safe access to multi-chain settings and validation mechanisms.

graph TD
    subgraph "ENV Object (Raw Environment)"
        ENV_ENABLED["ENV.ENABLED_CHAINS"]
        ENV_SOLANA["ENV.SOLANA_RPC_ENDPOINT"]
        ENV_ETH["ENV.ETHEREUM_RPC_URL"]
        ENV_BASE["ENV.BASE_RPC_URL"]
    end
    
    subgraph "CONFIG Object (Validated)"
        CONFIG_CHAINS["CONFIG.getEnabledChains()"]
        CONFIG_CHECK["CONFIG.isChainEnabled()"]
        CONFIG_SOL["CONFIG.SOLANA"]
        CONFIG_ETH["CONFIG.ETHEREUM"]
        CONFIG_BASE["CONFIG.BASE"]
    end
    
    subgraph "Validation Functions"
        VALIDATE_ENV["validateEnvironment()"]
        REQUIRED_CHECK["required.filter()"]
        MISSING_WARN["console.warn()"]
    end
    
    ENV_ENABLED --> CONFIG_CHAINS
    ENV_SOLANA --> CONFIG_SOL
    ENV_ETH --> CONFIG_ETH
    ENV_BASE --> CONFIG_BASE
    
    CONFIG_CHAINS --> CONFIG_CHECK
    
    VALIDATE_ENV --> REQUIRED_CHECK
    REQUIRED_CHECK --> MISSING_WARN
    
    CONFIG_SOL --> VALIDATE_ENV
    CONFIG_ETH --> VALIDATE_ENV
    CONFIG_BASE --> VALIDATE_ENV

The configuration system provides several key interfaces:

  • CONFIG.getEnabledChains(): Returns array of enabled chains based on environment configuration
  • CONFIG.isChainEnabled(chain): Checks if a specific chain is enabled
  • validateEnvironment(): Validates required environment variables and warns about missing values
  • Chain-specific configuration objects with typed properties for each protocol

Sources: config/environment.ts:154-166 , config/environment.ts:77-149

Each blockchain network implementation includes network-specific optimizations and features tailored to the characteristics of the underlying protocol and infrastructure.

FeatureSolanaEthereumBase
RPC OptimizationDirect account fetchingMulticall batchingMulticall batching
Connection PoolingWebSocket supportHTTP connection reuseHTTP connection reuse
Batch ProcessingAccount batch loadingContract call batchingContract call batching
Error HandlingSolana-specific error codesEVM revert handlingEVM revert handling
Rate LimitingSolana RPC limitsEthereum node limitsBase node limits

The system implements chain-specific timeouts, retry logic, and batch sizes optimized for each network’s characteristics through the performance configuration in config/environment.ts:57-68 .

Sources: config/environment.ts:57-68 , README.md:77-80 , docs/ARCHITECTURE.md:664-683

The multi-chain architecture is designed for easy extension to support additional blockchain networks and DeFi protocols through a standardized integration pattern.

graph TD
    subgraph "Integration Requirements"
        NEW_CHAIN["New Chain Integration"]
        CHAIN_CONFIG["Add to ENABLED_CHAINS"]
        ENV_VARS["Environment Variables"]
        TYPE_DEF["Update SupportedChain type"]
    end
    
    subgraph "Implementation Pattern"
        DATA_FETCH["Implement data fetching"]
        TICK_FETCH["Implement tick data fetching"]
        ERROR_HANDLE["Chain-specific error handling"]
        BATCH_OPT["Optimize batch processing"]
    end
    
    subgraph "Validation Steps"
        CONFIG_VAL["Add to validateEnvironment()"]
        CHAIN_CHECK["Update isChainEnabled()"]
        INTEGRATION_TEST["Integration testing"]
    end
    
    NEW_CHAIN --> CHAIN_CONFIG
    NEW_CHAIN --> ENV_VARS
    NEW_CHAIN --> TYPE_DEF
    
    CHAIN_CONFIG --> DATA_FETCH
    ENV_VARS --> TICK_FETCH
    TYPE_DEF --> ERROR_HANDLE
    
    DATA_FETCH --> BATCH_OPT
    TICK_FETCH --> CONFIG_VAL
    ERROR_HANDLE --> CHAIN_CHECK
    
    CONFIG_VAL --> INTEGRATION_TEST
    CHAIN_CHECK --> INTEGRATION_TEST
    BATCH_OPT --> INTEGRATION_TEST

To add a new chain, developers must:

  1. Add the chain identifier to the SupportedChain type in config/environment.ts:72
  2. Add chain-specific environment variables and configuration objects
  3. Update the getEnabledChains() function to include the new chain
  4. Implement chain-specific data fetching functions following the established pattern
  5. Add validation requirements to validateEnvironment() function

Sources: config/environment.ts:72 , config/environment.ts:87-96 , config/environment.ts:154-166