This document catalogs all known limitations, simplifications, and potential divergences between the Flash Risk Engine and the production Flash Trade program.
The Flash Trade core program is maintained in a private repository (perpetuals-closed.git). The production on-chain program may contain logic not present in the publicly available reference implementation (flash-perpetuals) or SDK (flash-sdk-rust).
All formulas in this engine are derived from:
- The open-source reference implementation
- The Rust SDK reader functions
- The TypeScript SDK IDL and state structures
There is no guarantee that the production program implements these formulas identically.
Impact: Medium
Production uses the degen_size_usd field on position accounts to select between two leverage thresholds:
custody.pricing.maxLeverage-- Standard thresholdcustody.pricing.maxDegenLeverage-- Higher threshold for degen positions
This engine always uses maxLeverage. Consequences:
- Some degen positions may appear liquidatable in this engine when they are not (false positives)
- Some non-degen positions near the maxDegenLeverage threshold may appear safe when they are actually liquidatable under the standard threshold (false negatives -- though this is unlikely given the threshold ordering)
Impact: Low to Medium
The price_impact_usd field exists on position accounts and has a corresponding price_impact_set flag. Production may adjust entry prices based on market impact at position open time.
This engine uses the stored entryPrice as-is. If production adjusts PnL calculations using price_impact_usd, the PnL and derived values (margin, leverage, liquidation price) computed by this engine will differ slightly.
Impact: Unknown
Two fields on position accounts are not used by this engine:
unsettled_value_usd-- May represent unrealized value adjustmentsunsettled_fees_usd-- May represent unpaid fee obligations
If production includes these in margin calculations, this engine's margin and leverage values will differ by the unsettled amounts.
Impact: Low
Production may integrate Lazer oracle feeds (the lazerFeedId and lazerPrice fields exist on CustomOracle accounts) and depeg adjustments. This engine uses only the primary Custom Oracle price, EMA, and confidence values.
Impact: Low
This engine computes close fees as:
close_fee_usd = size_usd * close_position_fee / RATE_POWER
Production may compute them as:
close_fee = exit_fee_amount * token_ema_price
The difference depends on whether EMA price diverges from the spot-based exit price used to compute size_usd.
The on-chain borrow rate state (currentRate, cumulativeLockFee, lastUpdate) is updated only when a transaction touches the custody account. Between transactions, the stored rate becomes stale.
This engine extrapolates the cumulative lock fee from the last update time to the current wall-clock time, matching the SDK approach. However, during periods of rapid utilization changes (many transactions), the stored rate may have been updated multiple times since lastUpdate, and this engine cannot observe the intermediate states.
Oracle prices are checked against maxPriceAgeSec from the custody's oracle parameters. The isStale flag is set but does not cause the engine to reject the price. Stale prices are used as-is, which matches how the reference implementation behaves (staleness rejection is handled at the instruction level, not in the reader).
Profit is capped at locked_value_usd, which is computed from the position's locked_amount in collateral token units multiplied by the collateral oracle's midpoint price. Production may use a different pricing method for the locked value.
All BN divisions truncate toward zero (floor division for positive values). The Rust program uses the same truncation behavior. However, the exact point of truncation may differ if the production program combines or reorders operations differently.
The liquidation price uses static estimates for interest and close fee at the time of computation. If significant time passes or the borrow rate changes, the actual liquidation price will drift from this estimate. This is inherent to any snapshot-based liquidation price calculation.
This engine computes the current risk state. It does not:
- Predict future price movements
- Forecast liquidation cascades
- Estimate time-to-liquidation under assumed volatility
- Model funding rate dynamics
This engine is read-only. It does not:
- Submit liquidation transactions
- Manage positions
- Interact with the program as a signer
This engine operates on the current on-chain state. It does not:
- Query historical account states
- Reconstruct past risk metrics
- Track risk metric changes over time (except via the
--subscribelive mode, which monitors real-time changes)