Architecture Overview
Referenced Files in This Document - manager.py - base.py - w3.py - ethereum.py - bsc.py - anvil.py - config.py - chains.yaml - scanner.py - sweeper.py - listener.py - chain.py - payment.py - token.py - ERC20.json
Table of Contents
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
Introduction
This document explains the blockchain integration layer architecture used to manage multiple chains (Ethereum, BSC, Anvil) with a unified interface. It covers: - Factory pattern implementation that instantiates chain-specific providers based on configuration - The base blockchain interface and shared functionality - Web3 provider management and connection handling - How configuration drives instantiation and runtime behavior - Error handling, fallback mechanisms, and chain availability monitoring - Architectural diagrams illustrating component interactions and data flow
Project Structure
The blockchain integration layer is organized around a factory that reads chain configuration and constructs chain-specific implementations. A thin Web3 accessor exposes per-chain AsyncWeb3 clients. Services consume these clients to scan blocks, detect payments, and settle transactions.
manager.py"] W3["get_w3()
w3.py"] BASE["BlockchainBase
base.py"] ETH["EthereumBlockchain
ethereum.py"] BSC["BSCBlockchain
bsc.py"] ANV["AnvilBlockchain
anvil.py"] end subgraph "Services" SCN["ScannerService
scanner.py"] SWP["SweeperService
sweeper.py"] LST["listen_for_payments()
listener.py"] end subgraph "Database Models" CHAIN["ChainState
chain.py"] PAY["Payment
payment.py"] TOK["Token
token.py"] end CFG --> YML CFG --> MAN MAN --> ETH MAN --> BSC MAN --> ANV MAN --> BASE W3 --> MAN SCN --> W3 SWP --> W3 LST --> SCN SCN --> CHAIN SCN --> PAY SCN --> TOK SWP --> PAY SWP --> TOK
Diagram sources - config.py - chains.yaml - manager.py - w3.py - base.py - ethereum.py - bsc.py - anvil.py - scanner.py - sweeper.py - listener.py - chain.py - payment.py - token.py
Section sources - manager.py - config.py - chains.yaml
Core Components
- Blockchain Manager Factory: Builds a dictionary of chain instances keyed by chain name, selecting implementations based on configuration and falling back to a default chain when none are configured.
- Base Provider Interface: Provides a shared set of async operations (connection checks, balance queries, gas estimation, transaction building, signing, sending, receipts, block number retrieval).
- Chain-Specific Implementations: Ethereum and BSC specialize base behavior with chain IDs and POA middleware; Anvil adds developer-focused capabilities.
- Web3 Accessor: Exposes per-chain AsyncWeb3 clients via a simple lookup.
- Services: ScannerService scans blocks and confirms payments; SweeperService settles confirmed payments; Listener schedules scanning cycles.
Section sources - manager.py - base.py - ethereum.py - bsc.py - anvil.py - w3.py - scanner.py - sweeper.py - listener.py
Architecture Overview
The integration layer follows a factory-driven composition: - Configuration (YAML + Settings) defines chains and RPC endpoints. - The factory selects a chain implementation and initializes a Web3 client with optional middleware. - Services request a chain’s Web3 client via the accessor and operate against the blockchain.
Diagram sources - config.py - chains.yaml - manager.py - w3.py - scanner.py
Detailed Component Analysis
Factory Pattern: Blockchain Manager
- Reads chain configurations from settings and builds a mapping from chain name to a BlockchainBase-derived instance.
- Supports Ethereum, BSC, and Anvil; falls back to Anvil if no chains are configured.
- Uses provider_url from configuration to initialize AsyncWeb3.
Diagram sources - manager.py
Section sources - manager.py
Base Blockchain Interface: Shared Functionality
- Initializes AsyncWeb3 with a timeout and optional POA middleware injection.
- Provides connectivity check, native and token balance retrieval, gas price caching, fee history, gas estimation with defaults, transaction building (EIP-1559 preferred), signing, sending, receipt polling, and latest block number.
Diagram sources - base.py
Section sources - base.py
Chain-Specific Implementations
- EthereumBlockchain: Sets chain_id to 1 and disables POA middleware.
- BSCBlockchain: Sets chain_id to 56 and enables POA middleware.
- AnvilBlockchain: Adds developer utilities (mine blocks, set balances, impersonate accounts, reset/fork) while inheriting base behavior.
Diagram sources - ethereum.py - bsc.py - anvil.py - base.py
Section sources - ethereum.py - bsc.py - anvil.py
Web3 Provider Management and Accessor
- get_blockchains() constructs a singleton-like cache of chain instances.
- get_w3(chain_name) returns the AsyncWeb3 client for a given chain, raising an error if the chain is not configured.
Diagram sources - w3.py - manager.py - base.py
Section sources - w3.py
Relationship Between Configuration and Instantiation
- settings.chains loads chain entries from chains.yaml.
- Each entry supplies a name and rpc_url; the factory maps names to implementations.
- If chains.yaml is missing or empty, the factory falls back to Anvil using a default RPC URL from settings.
Diagram sources - config.py - chains.yaml - manager.py
Section sources - config.py - chains.yaml - manager.py
Error Handling Patterns and Fallback Mechanisms
- Connection checks wrap AsyncWeb3 connectivity in a guarded method returning a boolean and logging errors.
- Gas estimation falls back to conservative defaults when RPC calls fail.
- Transaction building prefers EIP-1559 fee calculation; on failure, it falls back to legacy gas price.
- The factory provides a fallback chain when configuration yields no chains.
- Services handle missing chain state and skip scanning when appropriate.
Diagram sources - base.py
Section sources - base.py - base.py - base.py - manager.py
Chain Availability Monitoring and Health Checks
- is_connected() performs a basic connectivity probe via AsyncWeb3 and logs failures.
- Services rely on get_w3() to access a working provider; missing chains raise explicit errors.
- The listener schedules periodic scanning cycles and retries after each run.
Diagram sources - scanner.py - w3.py - base.py
Section sources - base.py - scanner.py - listener.py
Data Models and Service Interactions
- ChainState tracks the last scanned block per chain.
- Payment records payment requests with status transitions (pending → detected → confirmed → settled).
- Token defines token metadata per chain.
- ScannerService reads ChainState, queries blocks, detects native and ERC20 transfers, updates Payment statuses, and triggers webhooks.
- SweeperService uses the configured private key to settle confirmed payments.
Diagram sources - chain.py - token.py - payment.py
Section sources - chain.py - token.py - payment.py - scanner.py - sweeper.py
Dependency Analysis
- Configuration drives instantiation: settings.chains feeds the factory, which depends on chains.yaml.
- The factory depends on chain-specific implementations and the base class.
- The Web3 accessor depends on the factory’s cached instances.
- Services depend on the Web3 accessor and database models.
- Anvil implementation extends base behavior without affecting other chains.
Diagram sources - config.py - chains.yaml - manager.py - w3.py - scanner.py - sweeper.py - chain.py - payment.py - token.py
Section sources - config.py - manager.py - w3.py - scanner.py - sweeper.py
Performance Considerations
- Gas price caching reduces repeated RPC calls for fee estimation.
- Transaction building applies a small gas limit buffer to avoid frequent rejections.
- Block scanning batches blocks to limit work per cycle; adjust batch size based on network conditions.
- Consider adding connection pooling or retry/backoff for RPC endpoints if encountering rate limits or transient failures.
[No sources needed since this section provides general guidance]
Troubleshooting Guide
Common issues and resolutions: - Missing or invalid chains.yaml: The factory returns an empty set; a fallback Anvil instance is created. Verify chains.yaml path and content. - RPC endpoint unreachable: is_connected() logs errors and returns False; ensure endpoints are reachable and healthy. - Gas estimation failures: The library falls back to conservative defaults; inspect transaction parameters and network conditions. - Chain not configured error: get_w3() raises an error if the requested chain is not present; ensure settings.chains includes the chain name. - Scanning skips chains: If no ChainState exists for a chain, scanning is skipped; create ChainState records before scanning.
Section sources - manager.py - base.py - base.py - w3.py - scanner.py
Conclusion
The blockchain integration layer cleanly separates configuration, instantiation, and runtime operations: - Factory-driven instantiation ensures predictable chain-specific behavior. - A shared base class encapsulates common Web3 operations with robust fallbacks. - Services operate independently of chain specifics via a simple Web3 accessor. - Clear error handling and availability checks support resilient operation across heterogeneous networks.