Technology Stack and Architecture

Referenced Files in This Document - server.py - app/core/config.py - app/db/engine.py - app/db/async_session.py - app/blockchain/manager.py - app/blockchain/base.py - app/api/v1/payments.py - app/services/blockchain/scanner.py - app/workers/listener.py - docker-compose.yml - requirements.txt - pyproject.toml - alembic.ini - app/db/models/payment.py - app/utils/crypto.py

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion

Introduction

This document describes the technology stack and system architecture of cTrip, a multi-chain cryptocurrency payment gateway. The system is built on FastAPI as the web framework foundation, with PostgreSQL and SQLite for data persistence and SQLAlchemy 2.0 for async ORM operations. Background tasks are processed using ARQ with Redis, blockchain interactions leverage Web3.py, and Alembic manages database migrations. The architecture follows a layered pattern separating API, service, blockchain, and database layers. Async/await patterns are used throughout, and the system is containerized with Docker. Background workers are decomposed into microservice-like actors for payment listening, sweeping, and webhook dispatch.

Project Structure

The repository is organized into feature-focused packages: - app/api: FastAPI routers and HTTP endpoints - app/services: Business logic and orchestration - app/blockchain: Blockchain abstraction and chain-specific implementations - app/db: SQLAlchemy models, async engines, and sessions - app/workers: ARQ tasks for background jobs - alembic: Database migration scripts and configuration - Root configuration and deployment files for Docker and project metadata

graph TB subgraph "Application" API["API Layer
FastAPI Routers"] Services["Service Layer
Business Logic"] Blockchain["Blockchain Layer
Web3 Integrations"] DB["Database Layer
SQLAlchemy ORM"] Workers["Background Workers
ARQ Tasks"] end subgraph "External Systems" Postgres["PostgreSQL"] Redis["Redis"] Chains["Ethereum RPC Nodes"] end API --> Services Services --> DB Services --> Blockchain Workers --> DB Workers --> Blockchain Workers --> Redis Blockchain --> Chains DB --> Postgres

Diagram sources - server.py - app/api/v1/payments.py - app/services/blockchain/scanner.py - app/db/engine.py - docker-compose.yml

Section sources - server.py - docker-compose.yml

Core Components

  • Web Framework: FastAPI with lifespan for startup initialization and router composition
  • Configuration: Centralized settings with environment-aware database and RPC configuration
  • Database: SQLAlchemy 2.0 async engine with asyncpg for PostgreSQL and aiosqlite for SQLite
  • Blockchain: Web3.py-based async client with POA middleware support and caching; ChainSniper for WebSocket-based real-time block detection
  • Background Tasks: ARQ (async task queue) with Redis for cron jobs and on-demand tasks
  • Migration Tooling: Alembic for schema evolution
  • Containerization: Docker Compose for local development with Postgres, Redis, and worker processes

Section sources - server.py - app/core/config.py - app/db/engine.py - app/blockchain/base.py - docker-compose.yml - requirements.txt - pyproject.toml - alembic.ini

Architecture Overview

The system follows a layered architecture: - API Layer: Exposes HTTP endpoints for payment creation and health checks - Service Layer: Implements business logic, including blockchain scanning and confirmation workflows - Blockchain Layer: Provides chain abstraction and async Web3 integrations - Database Layer: Manages persistent state with async ORM and migrations - Background Workers: Microservice-like actors for continuous monitoring and event dispatch

graph TB Client["Client"] API["FastAPI App
server.py"] PaymentsAPI["Payments Router
payments.py"] ScannerSvc["ScannerService
scanner.py"] DBEngine["Async Engine
engine.py"] AsyncSession["Async Session
async_session.py"] BlockMgr["Blockchain Manager
manager.py"] BaseBC["BlockchainBase
base.py"] WorkerListener["Worker Listener
listener.py"] Redis["Redis Broker"] Postgres["PostgreSQL"] Client --> API API --> PaymentsAPI PaymentsAPI --> AsyncSession PaymentsAPI --> ScannerSvc ScannerSvc --> DBEngine ScannerSvc --> BlockMgr BlockMgr --> BaseBC WorkerListener --> Redis WorkerListener --> DBEngine AsyncSession --> DBEngine DBEngine --> Postgres

Diagram sources - server.py - app/api/v1/payments.py - app/services/blockchain/scanner.py - app/db/engine.py - app/db/async_session.py - app/blockchain/manager.py - app/blockchain/base.py - app/workers/listener.py

Detailed Component Analysis

FastAPI Application Lifecycle and Entrypoint

  • Lifespan initializes blockchain clients, HD wallet manager, and seeds chain states
  • Registers health and payment routers
  • Triggers background workers via ARQ on startup
sequenceDiagram participant Proc as "Process" participant App as "FastAPI App" participant Life as "Lifespan" participant BC as "Blockchain Manager" participant HD as "HDWalletManager" participant Seed as "Seed Chain States" participant Worker as "ARQ Workers" Proc->>App : Start App->>Life : Initialize lifespan Life->>BC : get_blockchains() Life->>HD : Create HD wallet manager Life->>Seed : add_chain_states() Life->>Worker : listen_for_payments.send() Life->>Worker : sweep_funds.send() App-->>Proc : Ready

Diagram sources - server.py - app/blockchain/manager.py - app/utils/crypto.py

Section sources - server.py

Configuration Management

  • Centralized settings with environment detection and dynamic database URL selection
  • RPC and Redis URLs, chain configurations loaded from YAML, and secret validation
  • Private key and secret key validation for production safety
flowchart TD Start(["Load Settings"]) --> EnvCheck{"Environment"} EnvCheck --> |Production| ProdURL["Use Production DB URL"] EnvCheck --> |Other| DevURL["Use Dev DB URL"] ProdURL --> DBURL["Computed database_url"] DevURL --> DBURL DBURL --> RPC["RPC URL"] DBURL --> RedisCfg["Redis URL"] DBURL --> Chains["Load chains.yaml"] Chains --> Secrets["Private Key & Secret Key Validation"] Secrets --> End(["Settings Ready"])

Diagram sources - app/core/config.py - app/core/config.py - app/core/config.py

Section sources - app/core/config.py

Database Layer and Async ORM

  • Dynamic URL construction switching between PostgreSQL and SQLite based on environment
  • Asynchronous engine creation with asyncpg for PostgreSQL and aiosqlite for SQLite
  • Async session factory for dependency injection in services and workers
classDiagram class EngineFactory { +get_database_url() str +make_async_url(url) str } class AsyncSessionLocal { +get_async_db() AsyncGenerator } EngineFactory <.. AsyncSessionLocal : "bind async_engine"

Diagram sources - app/db/engine.py - app/db/async_session.py

Section sources - app/db/engine.py - app/db/async_session.py

Blockchain Abstraction and Chain Management

  • BlockchainBase encapsulates async Web3 operations, gas estimation, and transaction building
  • Manager constructs chain instances from configuration or falls back to Anvil
  • Supports POA networks and caches gas prices for performance
classDiagram class BlockchainBase { +provider_url : str +chain_id : int +use_poa : bool +is_connected() bool +get_balance(address) int +get_token_balance(token, address) int +get_gas_price(use_cache) int +estimate_gas(tx) int +build_transaction(...) Dict +send_transaction(tx, pk) str +get_receipt(hash, timeout) Any +get_latest_block() int } class Manager { +get_blockchains() Dict[str, BlockchainBase] } Manager --> BlockchainBase : "instantiates per chain"

Diagram sources - app/blockchain/base.py - app/blockchain/manager.py

Section sources - app/blockchain/base.py - app/blockchain/manager.py

API Layer: Payment Creation Workflow

  • Endpoint validates chain and optional token, derives a new payment address via HD wallet, persists the record, and returns the created entity
  • Uses synchronous SQLAlchemy session for write operations
sequenceDiagram participant Client as "Client" participant API as "Payments Router" participant DB as "SQLAlchemy Session" participant HD as "HDWalletManager" participant BC as "Blockchain Manager" Client->>API : POST /api/v1/payments API->>BC : get_blockchains() API->>HD : get_address(index=0) API->>DB : Create Payment record API->>DB : Commit and refresh API-->>Client : 201 PaymentRead

Diagram sources - app/api/v1/payments.py - app/utils/crypto.py

Section sources - app/api/v1/payments.py - app/utils/crypto.py

Service Layer: Blockchain Scanning and Confirmation

  • ScannerService scans blocks for native and ERC20 transfers matching pending payments
  • Applies confirmation thresholds and updates statuses, optionally triggering webhooks
  • Uses async ORM for state and payment queries
flowchart TD Start(["Scan Chain"]) --> LoadState["Load ChainState with lock"] LoadState --> GetLatest["Get latest block number"] GetLatest --> Range["Compute from/to block range"] Range --> ScanBlocks["Iterate blocks in range"] ScanBlocks --> Native["Check native transfers"] ScanBlocks --> ERC20["Fetch ERC20 logs"] Native --> UpdatePending["Mark matched payments as detected"] ERC20 --> UpdatePending UpdatePending --> ConfirmLoop["Confirm payments by block delta"] ConfirmLoop --> Webhook{"Webhook configured?"} Webhook --> |Yes| Dispatch["Send webhook task"] Webhook --> |No| Skip["Skip webhook"] Dispatch --> Commit["Commit changes"] Skip --> Commit Commit --> End(["Complete"])

Diagram sources - app/services/blockchain/scanner.py

Section sources - app/services/blockchain/scanner.py

Background Workers: ARQ Tasks

  • Worker tasks run in a separate process started via python run_worker.py.
  • On startup, ChainSniper WebSocket listeners are launched for real-time block detection.
  • ARQ cron jobs handle periodic confirmation checks and sweeping.
  • Redis serves as the task queue backend for ARQ.
sequenceDiagram participant Startup as "Worker Startup" participant Sniper as "ChainSniper (WebSocket)" participant Cron as "ARQ Cron" participant Scanner as "ScannerService" participant DB as "Async Session" participant Chain as "BlockchainBase" Startup->>Scanner : "start_listeners()" Scanner->>Sniper : "Create task per chain (ws:// URL)" Sniper->>DB : "Detect payments → DETECTED" Cron->>Scanner : "confirm_payments(chain_name)" Scanner->>Chain : "get latest block number" Scanner->>DB : "Update DETECTED → CONFIRMED"

Diagram sources - app/workers/listener.py - app/services/blockchain/scanner.py - app/db/async_session.py

Section sources - app/workers/listener.py

  • Payment entity tracks chain, address, amount, status, confirmations, and expiry
  • Enumerated status supports pending, detected, confirmed, paid, expired, settled, failed
  • Relationship to Token for ERC20 tracking
erDiagram PAYMENTS { uuid id PK uuid token_id FK string chain string address numeric amount enum status integer confirmations integer detected_in_block timestamp expires_at timestamp created_at } TOKENS { uuid id PK string address string name string symbol integer decimals string chain timestamp created_at } PAYMENTS }o--|| TOKENS : "optional token reference"

Diagram sources - app/db/models/payment.py

Section sources - app/db/models/payment.py

Dependency Analysis

  • Runtime dependencies include FastAPI, SQLAlchemy 2.0, Web3.py, ARQ, Redis, Alembic, and Pydantic settings
  • Project metadata declares optional dev dependencies for testing and linting
  • Alembic configuration references the project’s env to resolve database URLs
graph LR FastAPI["fastapi"] --> App["Application"] SQLAlchemy["sqlalchemy>=2.0.45"] --> App Web3["web3>=7.14.0"] --> App ARQ["arq>=0.27.0"] --> App ChainSniper["chain-sniper>=0.1.1"] --> App RedisLib["redis>=5.3.1"] --> App Alembic["alembic>=1.18.1"] --> App Pydantic["pydantic>=2.12.5"] Settings["pydantic-settings>=2.12.0"] --> App Uvicorn["uvicorn>=0.40.0"] --> App AsyncPG["asyncpg>=0.31.0"] --> App AioSQLite["aiosqlite>=0.22.1"] --> App YAML["pyyaml>=6.0.3"] --> App HTTPX["httpx>=0.28.1"] --> App

Diagram sources - requirements.txt - pyproject.toml

Section sources - requirements.txt - pyproject.toml - alembic.ini

Performance Considerations

  • Async ORM and engines reduce blocking I/O and improve throughput under concurrent loads
  • Gas price caching and batched block scanning minimize RPC calls and network latency
  • Redis-backed ARQ tasks enable decoupled, scalable background processing
  • Environment-aware database selection allows lightweight SQLite for development and robust asyncpg for production
  • Containerization simplifies scaling and resource isolation

Troubleshooting Guide

  • Health endpoint: Verify application readiness via the root endpoint and blockchain connectivity
  • Database migrations: Use Alembic to upgrade/downgrade schemas; ensure DATABASE_URL is set correctly
  • Worker scheduling: Confirm Redis availability and that ARQ tasks are started with the correct broker URL
  • Chain configuration: Validate chains.yaml and RPC URLs; ensure POA middleware is enabled when required
  • Secrets: Ensure private keys and secret keys meet validation criteria for production environments

Section sources - server.py - alembic.ini - docker-compose.yml - app/core/config.py

Conclusion

cTrip’s architecture leverages modern asynchronous technologies to deliver a scalable, maintainable payment infrastructure across multiple blockchains. FastAPI and SQLAlchemy 2.0 provide a responsive API and robust ORM, while Web3.py and ARQ enable efficient blockchain interactions and background processing. Alembic ensures safe schema evolution, and Docker facilitates reproducible deployments. The layered design and microservice-like workers promote separation of concerns and operational flexibility.