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