Перейти к содержанию

Deposit Flow Architecture

Детальный поток депозитов через HD Wallet архитектуру с мониторингом блокчейна.

HD Wallet Deposit Flow

sequenceDiagram
    participant User as 👤 User
    participant UserApp as 📱 User App
    participant API as 🌐 API
    participant HDService as 🏦 HD Wallet Service
    participant Monitor as 👁️ Blockchain Monitor
    participant Blockchain as ⛓️ Blockchain Network
    participant Database as 🗄️ PostgreSQL
    participant BalanceService as 💰 Balance Service

    Note over User,BalanceService: Step 1: Deposit Address Generation
    User->>UserApp: Request deposit address
    UserApp->>API: GET /user/deposit-address
    API->>HDService: GenerateDepositAddress(userID)
    HDService->>HDService: Derive address from XPUB
    HDService->>Database: Store address mapping
    Database->>HDService: Address stored
    HDService->>API: Return deposit address
    API->>UserApp: Deposit address
    UserApp->>User: Display deposit address + QR code

    Note over User,BalanceService: Step 2: User Makes Deposit
    User->>User: Copy deposit address
    User->>Blockchain: Send USDC to deposit address
    Blockchain->>Blockchain: Transaction included in block

    Note over User,BalanceService: Step 3: Blockchain Monitoring
    Monitor->>Monitor: Periodic block scan (every 15 seconds)
    Monitor->>Blockchain: Query new blocks
    Blockchain->>Monitor: Block data with transactions
    Monitor->>Monitor: Filter transactions to monitored addresses
    Monitor->>Database: Query monitored addresses (is_monitored = true)
    Database->>Monitor: User mappings for monitored addresses

    Note over User,BalanceService: Step 4: Transaction Processing
    Monitor->>Database: Create pending transaction
    Database->>Monitor: Transaction stored
    Monitor->>Monitor: Verify transaction confirmations

    alt Transaction Confirmed (3+ confirmations)
        Monitor->>Database: Update transaction status to "confirmed"
        Monitor->>BalanceService: ProcessDeposit(userID, amount)
        BalanceService->>Database: Update user balance
        Database->>BalanceService: Balance updated
        BalanceService->>Monitor: Deposit processed
        Monitor->>Database: Update transaction status to "processed"

        Note over User,BalanceService: Step 5: User Notification
        Monitor->>UserApp: WebSocket notification (if connected)
        UserApp->>User: Show deposit success notification
    else Transaction Failed
        Monitor->>Database: Update transaction status to "failed"
        Monitor->>UserApp: WebSocket notification (if connected)
        UserApp->>User: Show deposit failed notification
    end

HD Wallet Address Generation

graph TB
    subgraph "HD Wallet Architecture"
        MASTER["🔑 Master Private Key\n(Admin Only)"]
        XPUB["📖 Extended Public Key\n(In Config)"]

        subgraph "Address Derivation"
            PATH["🛤️ Derivation Path\nm/44'/60'/0'/0/user_index"]
            DERIVE[⚙️ Derive Function]
            ADDR[📍 Deposit Address]
        end

        subgraph "Database Storage"
            USER_MAP["👤 User Mapping\nuser_id → address"]
            ADDR_MAP["📍 Address Mapping\naddress → user_id"]
            MONITOR["👁️ Monitored Flag\nis_monitored column"]
        end
    end

    MASTER -.-> XPUB
    XPUB --> PATH
    PATH --> DERIVE
    DERIVE --> ADDR
    ADDR --> USER_MAP
    ADDR --> ADDR_MAP
    ADDR --> MONITOR

    classDef master fill:#FF6B6B,stroke:#E55B5B,color:#fff
    classDef xpub fill:#4ECDC4,stroke:#45B7B8,color:#fff
    classDef derive fill:#45B7D1,stroke:#3D8BDB,color:#fff
    classDef storage fill:#FFA07A,stroke:#FF8C69,color:#fff

    class MASTER master
    class XPUB xpub
    class PATH,DERIVE,ADDR derive
    class USER_MAP,ADDR_MAP,MONITOR storage

Blockchain Monitoring Process

flowchart TD
    START[🔄 Start Monitor] --> SCAN[🔍 Scan Latest Block]

    SCAN --> BLOCK{New Block?}
    BLOCK -->|No| WAIT[⏰ Wait 15 seconds]
    WAIT --> SCAN

    BLOCK -->|Yes| EXTRACT[📋 Extract Transactions]
    EXTRACT --> FILTER[🔍 Filter Our Addresses]

    FILTER --> FOUND{Relevant Tx Found?}
    FOUND -->|No| WAIT

    FOUND -->|Yes| VALIDATE[✅ Validate Transaction]
    VALIDATE --> AMOUNT_CHECK{Amount > 0?}
    AMOUNT_CHECK -->|No| IGNORE[❌ Ignore Transaction]
    IGNORE --> WAIT

    AMOUNT_CHECK -->|Yes| CONFIRM_CHECK[🔍 Check Confirmations]
    CONFIRM_CHECK --> CONF_COUNT{Confirmations >= 3?}

    CONF_COUNT -->|No| PENDING[⏳ Mark as Pending]
    PENDING --> WAIT

    CONF_COUNT -->|Yes| PROCESS[✅ Process Deposit]
    PROCESS --> UPDATE_BALANCE[💰 Update Balance]
    UPDATE_BALANCE --> NOTIFY[📢 Notify User]
    NOTIFY --> WAIT

    classDef process fill:#EBF5FB,stroke:#3498DB,color:#000
    classDef decision fill:#FFF3CD,stroke:#856404,color:#000
    classDef action fill:#D5F4E6,stroke:#27AE60,color:#000
    classDef wait fill:#F8D7DA,stroke:#721C24,color:#000

    class START,SCAN,EXTRACT,FILTER,VALIDATE,CONFIRM_CHECK,PROCESS,UPDATE_BALANCE,NOTIFY process
    class BLOCK,FOUND,AMOUNT_CHECK,CONF_COUNT decision
    class PENDING,IGNORE action
    class WAIT wait

Database Schema for Deposits

erDiagram
    USERS {
        uuid id PK
        string email
        string status
        timestamp created_at
        timestamp updated_at
    }

    WALLETS {
        uuid id PK
        uuid user_id FK
        string address
        integer network_id
        string type
        string currency
        decimal balance
        decimal pending_balance
        integer address_index
        boolean is_hd_generated
        boolean is_primary
        boolean is_monitored
        timestamp created_at
        timestamp updated_at
    }

    TRANSACTIONS {
        uuid id PK
        uuid user_id FK
        string type
        decimal amount
        string currency
        string status
        string blockchain_tx_hash
        string from_address
        string to_address
        integer confirmations
        timestamp created_at
        timestamp updated_at
    }

    USER_BALANCES {
        uuid id PK
        uuid user_id FK
        string currency
        decimal available
        decimal pending
        decimal invested
        decimal locked
        timestamp updated_at
    }


    USERS ||--o{ WALLETS : has
    USERS ||--o{ TRANSACTIONS : has
    USERS ||--|| USER_BALANCES : has

Transaction Status State Machine

stateDiagram-v2
    [*] --> Detected: Transaction found on blockchain

    Detected --> Pending: Initial confirmation
    Pending --> Confirmed: 3+ confirmations
    Pending --> Failed: Transaction reverted

    Confirmed --> Processing: Balance update started
    Processing --> Processed: Balance updated successfully
    Processing --> Failed: Balance update failed

    Failed --> Retry: Manual retry
    Retry --> Processing: Retry processing

    Processed --> [*]: Final state
    Failed --> [*]: Final state (manual intervention needed)

Deposit Processing Logic

flowchart TD
    subgraph "Deposit Processing Pipeline"
        DETECT[🔍 Detect Transaction]
        VALIDATE[✅ Validate Transaction]
        CONFIRM[🔍 Wait for Confirmations]
        PROCESS[⚙️ Process Deposit]
        UPDATE[💰 Update Balance]
        NOTIFY[📢 Notify User]
    end

    subgraph "Error Handling"
        RETRY[🔄 Retry Logic]
        ALERT[🚨 Admin Alert]
        MANUAL[👨‍💻 Manual Review]
    end

    DETECT --> VALIDATE
    VALIDATE --> CONFIRM
    CONFIRM --> PROCESS
    PROCESS --> UPDATE
    UPDATE --> NOTIFY

    VALIDATE -->|Invalid| RETRY
    CONFIRM -->|Failed| RETRY
    PROCESS -->|Failed| RETRY
    UPDATE -->|Failed| RETRY

    RETRY -->|Max Retries| ALERT
    ALERT --> MANUAL
    MANUAL --> PROCESS

    classDef pipeline fill:#E8F5E8,stroke:#4CAF50,color:#000
    classDef error fill:#FFE8E8,stroke:#F44336,color:#000

    class DETECT,VALIDATE,CONFIRM,PROCESS,UPDATE,NOTIFY pipeline
    class RETRY,ALERT,MANUAL error

Admin Deposit Consolidation

sequenceDiagram
    participant Admin as 🔧 Admin
    participant AdminApp as 🛠️ Admin App
    participant API as 🌐 API
    participant HDService as 🏦 HD Wallet Service
    participant MetaMask as 🦊 MetaMask
    participant Blockchain as ⛓️ Blockchain
    participant Database as 🗄️ Database

    Note over Admin,Database: Step 1: Admin Checks Pending Deposits
    Admin->>AdminApp: Open consolidation dashboard
    AdminApp->>API: GET /admin/pending-deposits
    API->>Database: Query pending deposits
    Database->>API: List of deposits to consolidate
    API->>AdminApp: Display pending deposits
    AdminApp->>Admin: Show consolidation opportunities

    Note over Admin,Database: Step 2: Admin Initiates Consolidation
    Admin->>AdminApp: Click "Consolidate Deposits"
    AdminApp->>API: POST /admin/consolidate-deposits
    API->>HDService: PrepareConsolidationTransactions()
    HDService->>HDService: Generate consolidation transactions
    HDService->>API: Return transaction details
    API->>AdminApp: Transaction details

    Note over Admin,Database: Step 3: Admin Signs Transactions
    AdminApp->>MetaMask: Request transaction signatures
    MetaMask->>Admin: Show transaction details
    Admin->>MetaMask: Approve transactions
    MetaMask->>AdminApp: Signed transactions
    AdminApp->>API: POST /admin/execute-consolidation
    API->>Blockchain: Submit consolidation transactions
    Blockchain->>API: Transaction hashes

    Note over Admin,Database: Step 4: Update Database
    API->>Database: Update transaction statuses
    Database->>API: Updates confirmed
    API->>AdminApp: Consolidation complete
    AdminApp->>Admin: Show success notification

Implementation Details

HD Wallet Service

func (s *HDWalletService) GenerateDepositAddress(userID string) (string, error) {
    // Get user's derivation index
    index, err := s.getUserDerivationIndex(userID)
    if err != nil {
        return "", err
    }

    // Derive address from XPUB
    derivationPath := fmt.Sprintf("m/44'/60'/0'/0/%d", index)
    address, err := s.deriveAddressFromXPUB(s.config.GetXPUB(), derivationPath)
    if err != nil {
        return "", err
    }

    // Store address mapping with monitoring enabled
    err = s.storeAddressMapping(userID, address, derivationPath, true)
    if err != nil {
        return "", err
    }

    return address, nil
}

Blockchain Monitor

func (m *BlockchainMonitor) ScanBlocks() {
    ticker := time.NewTicker(15 * time.Second)
    defer ticker.Stop()

    for {
        select {
        case <-ticker.C:
            latestBlock, err := m.client.GetLatestBlock()
            if err != nil {
                log.Error("Failed to get latest block", err)
                continue
            }

            // Get monitored addresses from database
            monitoredAddresses, err := m.getMonitoredAddresses()
            if err != nil {
                log.Error("Failed to get monitored addresses", err)
                continue
            }

            transactions := m.extractRelevantTransactions(latestBlock, monitoredAddresses)
            for _, tx := range transactions {
                if err := m.processTransaction(tx); err != nil {
                    log.Error("Failed to process transaction", err)
                }
            }
        }
    }
}

func (m *BlockchainMonitor) getMonitoredAddresses() ([]string, error) {
    query := `
        SELECT address 
        FROM wallets 
        WHERE is_monitored = true
    `

    var addresses []string
    err := m.db.Select(&addresses, query)
    if err != nil {
        return nil, fmt.Errorf("failed to get monitored addresses: %w", err)
    }

    return addresses, nil
}

Balance Update

func (s *BalanceService) ProcessDeposit(userID string, amount decimal.Decimal, currency string) error {
    return s.db.Transaction(func(tx *sql.Tx) error {
        // Get current balance
        balance, err := s.getBalance(tx, userID, currency)
        if err != nil {
            return err
        }

        // Update available balance
        balance.Available = balance.Available.Add(amount)
        balance.UpdatedAt = time.Now()

        // Save updated balance
        return s.updateBalance(tx, balance)
    })
}

Security Considerations

  1. XPUB Security: Extended public key безопасен для storage, не позволяет получить private keys
  2. Address Validation: Все сгенерированные адреса проверяются на корректность
  3. Confirmation Requirements: Минимум 3 подтверждения для обработки депозита
  4. Double Spending Protection: Проверка уникальности transaction hash
  5. Amount Validation: Проверка положительных сумм и корректных decimal значений
  6. Rate Limiting: Ограничение частоты запросов к blockchain RPC
  7. Monitoring Alerts: Автоматические уведомления при критических ошибках

Завершенный рефакторинг: Единая таблица wallets

Статус: ЗАВЕРШЕН (2025-07-16)
Источник: Wallet Repository Consolidation Analysis (supervisor/tasks/20250716-1730-wallet-repository-consolidation-analysis.md)

Решенные проблемы

Старая схема user_wallet_addresses с ограничением (user_id, wallet_type) не позволяла: - Иметь депозитные адреса в разных сетях (Ethereum И Tron) - Поддерживать множественные типы кошельков - Легко добавлять новые сети (Solana, Polygon)

Все проблемы решены с помощью новой единой таблицы wallets.

Реализованное решение: Единая таблица wallets

CREATE TABLE wallets (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id           UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,

    -- Основные поля кошелька
    address           VARCHAR(64) NOT NULL UNIQUE,
    network_id        INTEGER NOT NULL,         -- 1 (Ethereum), 8453 (Base), 84532 (Base Sepolia), 11155111 (Ethereum Sepolia), 1337 (Hardhat)
    type              VARCHAR(20) NOT NULL,     -- deposit, personal, trading
    currency          VARCHAR(10) NOT NULL DEFAULT 'USDC',

    -- HD Wallet поля
    derivation_path   VARCHAR(255),
    address_index     INTEGER,
    is_hd_generated   BOOLEAN DEFAULT false,

    -- Метаданные
    label             VARCHAR(100),
    status            VARCHAR(20) DEFAULT 'active',
    is_primary        BOOLEAN DEFAULT false,
    is_monitored      BOOLEAN DEFAULT true,

    -- Временные метки
    created_at        TIMESTAMP WITH TIME ZONE DEFAULT now(),
    updated_at        TIMESTAMP WITH TIME ZONE DEFAULT now()
);

Преимущества нового подхода

  1. Поддержка множественных сетей:

    -- Один пользователь может иметь кошельки во всех сетях
    user_id: uuid-1, network_id: 1,    type: 'deposit'    -- Ethereum
    user_id: uuid-1, network_id: 8453, type: 'deposit'    -- Base
    user_id: uuid-1, network_id: 84532, type: 'deposit'   -- Base Sepolia
    

  2. Упрощение архитектуры:

  3. Единый репозиторий вместо 4 разбросанных модулей
  4. Один интерфейс для всех типов кошельков
  5. Простое добавление новых сетей

  6. Легкая миграция данных:

    INSERT INTO wallets (user_id, address, network_id, type, derivation_path, address_index, is_hd_generated)
    SELECT user_id, wallet_address, network_id, wallet_type, derivation_path, address_index,
           CASE WHEN wallet_type = 'deposit' THEN true ELSE false END
    FROM user_wallet_addresses;
    

Обновленная архитектура deposit flow

После рефакторинга deposit flow будет работать с единой таблицей wallets:

// Обновленный мониторинг адресов
func (m *BlockchainMonitor) getMonitoredAddresses(network string) ([]string, error) {
    query := `
        SELECT address 
        FROM wallets 
        WHERE is_monitored = true AND network_id = $1
    `

    var addresses []string
    err := m.db.Select(&addresses, query, network)
    return addresses, err
}

// Создание депозитного адреса
func (s *WalletService) CreateDepositWallet(userID string, networkID int) (*Wallet, error) {
    wallet := &Wallet{
        UserID:        userID,
        NetworkID:     networkID,
        Type:          "deposit",
        Currency:      "USDC",
        IsHDGenerated: true,
        IsMonitored:   true,
        Status:        "active",
    }

    return s.walletRepo.CreateWallet(ctx, wallet)
}

Результаты реализации

  • Время реализации: ✅ Завершен за 1 день (планировалось 1-2 недели)
  • Упрощение миграции: ✅ На 70% упрощена
  • Поддержка новых сетей: ✅ Мгновенная (уже поддерживается Ethereum и Base)
  • Миграция данных: ✅ 100% (109 кошельков перенесены из старой таблицы)

Совместимость

✅ Рефакторинг проведен с полным сохранением существующего API и функциональности. Все текущие deposit flow процессы работают без изменений.

Текущее состояние базы данных

  • Старая таблица user_wallet_addresses: ✅ Удалена после миграции
  • Новая таблица wallets: ✅ Активна (109 записей)
  • Поддерживаемые сети: Ethereum, Base
  • Типы кошельков: deposit, personal