Skip to content

liquidationEngine

---
config:
  theme: dark
---
sequenceDiagram
    participant App as app.ts
    participant LS as LiquidationService
    participant DB as PrismaClient (Database)
    participant RE as Risk Engine API
    participant R as Redis

    Note over App: Application starts

    App->>App: Check environment vars
    App->>R: getRedisClient()
    App->>R: waitForRedisReady()
    R-->>App: Redis ready
    App->>DB: getPrisma()
    DB-->>App: Prisma client initialized
    App->>LS: new LiquidationService(redis, prisma)

    App->>LS: start()
    activate LS

    LS->>LS: isRunning = true
    LS->>LS: Promise.all(MARKETS.map(market => startMarketProcessing(market)))

    Note over LS: For each market in parallel (BTC_USDC, ETH_USDC, ARB_USDC)

    loop While isRunning is true
        LS->>LS: Record cycle start time (startTime)
        LS->>LS: stats[market].lastRunTimestamp = startTime

        Note over LS: Try-catch block for entire cycle
        LS->>DB: fetchMarginAccountsForMarket(market)
        Note over DB: Find pair, then get all margin accounts for this pair
        DB-->>LS: Return accounts with positions, pair and smartAccount info

        LS->>LS: Update stats (cyclesRun++, accountsProcessed = accounts.length)

        alt accounts.length > 0
            LS->>LS: Filter accounts with/without positions
            LS->>LS: Update stats for accountsWithPositions & accountsWithoutPositions

            alt accountsWithPositions.length > 0
                LS->>LS: Reset successfulRiskChecks & failedRiskChecks stats
                LS->>LS: buildRiskEngineRequest(market, accountsWithPositions)
                LS->>RE: POST /private/calculate_margin_risk with request payload
                RE-->>LS: Return margin portfolios response

                LS->>LS: Split into successfulPortfolios & failedPortfolios
                LS->>LS: Update successfulRiskChecks & failedRiskChecks stats

                alt failedPortfolios.length > 0
                    LS->>LS: Log detailed failure information including request payload
                end

                alt successfulPortfolios.length > 0
                    Note over LS: updateAccountsInRedis try-catch block

                    LS->>LS: Prepare all AccountState objects

                    LS->>R: Create SET transaction using redis.multi()
                    loop For each successful portfolio
                        LS->>R: Add SET operation to transaction for each account state
                    end
                    LS->>R: Execute SET transaction (batch operation)
                    R-->>LS: Transaction results

                    LS->>LS: Prepare account publish events
                    LS->>R: Promise.all for publishing all account updates
                    R-->>LS: All publish operations complete

                    LS->>LS: Log success or error (continue on error)
                end
            end

            alt accountsWithoutPositions.length > 0
                Note over LS: updateEmptyAccountsInRedis try-catch block

                LS->>LS: Prepare all empty account entries with calculated equity

                LS->>R: Create SET transaction using redis.multi()
                loop For all empty accounts at once
                    LS->>R: Add SET operations to transaction
                end
                LS->>R: Execute SET transaction (batch operation)
                R-->>LS: SET transaction results

                LS->>R: Create PUBLISH transaction using redis.multi()
                loop For all empty accounts at once
                    LS->>R: Add PUBLISH operations to transaction
                end
                LS->>R: Execute PUBLISH transaction (batch operation)
                R-->>LS: PUBLISH transaction results

                LS->>LS: Update stats and log results (continue on error)
            end
        end

        LS->>LS: Calculate elapsedTime = timestamp - startTime
        LS->>LS: stats[market].lastCycleDurationMs = elapsedTime
        LS->>LS: waitTime = Math.max(0, MIN_INTERVAL_MS - elapsedTime)
        alt waitTime > 0
            LS->>LS: await delay(waitTime)
        end
    end

    Note over App: On SIGTERM signal
    App->>LS: stop()
    LS->>LS: isRunning = false
    App->>R: disconnect()
    App->>App: Exit after delay

    deactivate LS