@@ -108,13 +108,10 @@ import { StrictOraclePrice } from './oracles/strictOraclePrice';
108108import { calculateSpotFuelBonus , calculatePerpFuelBonus } from './math/fuel' ;
109109import { grpcUserAccountSubscriber } from './accounts/grpcUserAccountSubscriber' ;
110110import {
111- MarginCalculation as JsMarginCalculation ,
111+ MarginCalculation ,
112112 MarginContext ,
113113} from './marginCalculation' ;
114114
115- // Backwards compatibility: alias SDK MarginCalculation shape
116- export type UserMarginCalculation = JsMarginCalculation ;
117-
118115export type MarginType = 'Cross' | 'Isolated' ;
119116
120117export class User {
@@ -143,7 +140,7 @@ export class User {
143140 liquidationBuffer ?: BN ; // margin_buffer analog for buffer mode
144141 marginRatioOverride ?: number ; // mirrors context.margin_ratio_override
145142 }
146- ) : JsMarginCalculation {
143+ ) : MarginCalculation {
147144 const strict = opts ?. strict ?? false ;
148145 const enteringHighLeverage = opts ?. enteringHighLeverage ?? false ;
149146 const includeOpenOrders = opts ?. includeOpenOrders ?? true ; // TODO: remove this ??
@@ -165,7 +162,7 @@ export class User {
165162 . strictMode ( strict )
166163 . setMarginBuffer ( marginBuffer )
167164 . setMarginRatioOverride ( userCustomMarginRatio ) ;
168- const calc = new JsMarginCalculation ( ctx ) ;
165+ const calc = new MarginCalculation ( ctx ) ;
169166
170167 // SPOT POSITIONS
171168 // TODO: include open orders in the worst-case simulation in the same way on both spot and perp positions
@@ -2222,41 +2219,90 @@ export class User {
22222219 return netAssetValue . mul ( TEN_THOUSAND ) . div ( totalLiabilityValue ) ;
22232220 }
22242221
2225- public canBeLiquidated ( perpMarketIndex ?: number ) : {
2222+ public canBeLiquidated ( ) : {
22262223 canBeLiquidated : boolean ;
22272224 marginRequirement : BN ;
22282225 totalCollateral : BN ;
22292226 } {
2230- const liquidationBuffer = this . getLiquidationBuffer ( ) ;
2227+ // Deprecated signature retained for backward compatibility in type only
2228+ // but implementation now delegates to the new Map-based API and returns cross margin status.
2229+ const map = this . getLiquidationStatuses ( ) ;
2230+ const cross = map . get ( 'cross' ) ;
2231+ return cross ?? { canBeLiquidated : false , marginRequirement : ZERO , totalCollateral : ZERO } ;
2232+ }
22312233
2232- const totalCollateral = this . getTotalCollateral (
2233- 'Maintenance' ,
2234- undefined ,
2235- undefined ,
2236- liquidationBuffer
2237- ) ;
2234+ /**
2235+ * New API: Returns liquidation status for cross and each isolated perp position.
2236+ * Map keys:
2237+ * - 'cross' for cross margin
2238+ * - marketIndex (number) for each isolated perp position
2239+ */
2240+ public getLiquidationStatuses ( marginCalc ?: MarginCalculation ) : Map < 'cross' | number , { canBeLiquidated : boolean ; marginRequirement : BN ; totalCollateral : BN } > {
2241+ // If not provided, use buffer-aware calc for canBeLiquidated checks
2242+ if ( ! marginCalc ) {
2243+ const liquidationBuffer = this . getLiquidationBuffer ( ) ;
2244+ marginCalc = this . getMarginCalculation ( 'Maintenance' , { liquidationBuffer } ) ;
2245+ }
22382246
2239- const marginRequirement = this . getMaintenanceMarginRequirement (
2240- liquidationBuffer ,
2241- perpMarketIndex
2242- ) ;
2243- const canBeLiquidated = totalCollateral . lt ( marginRequirement ) ;
2247+ const result = new Map < 'cross' | number , {
2248+ canBeLiquidated : boolean ;
2249+ marginRequirement : BN ;
2250+ totalCollateral : BN ;
2251+ } > ( ) ;
2252+
2253+ // Cross margin status
2254+ const crossTotalCollateral = marginCalc . totalCollateral ;
2255+ const crossMarginRequirement = marginCalc . marginRequirement ;
2256+ result . set ( 'cross' , {
2257+ canBeLiquidated : crossTotalCollateral . lt ( crossMarginRequirement ) ,
2258+ marginRequirement : crossMarginRequirement ,
2259+ totalCollateral : crossTotalCollateral ,
2260+ } ) ;
22442261
2245- return {
2246- canBeLiquidated,
2247- marginRequirement,
2248- totalCollateral,
2249- } ;
2262+ // Isolated positions status
2263+ for ( const [ marketIndex , isoCalc ] of marginCalc . isolatedMarginCalculations ) {
2264+ const isoTotalCollateral = isoCalc . totalCollateral ;
2265+ const isoMarginRequirement = isoCalc . marginRequirement ;
2266+ result . set ( marketIndex , {
2267+ canBeLiquidated : isoTotalCollateral . lt ( isoMarginRequirement ) ,
2268+ marginRequirement : isoMarginRequirement ,
2269+ totalCollateral : isoTotalCollateral ,
2270+ } ) ;
2271+ }
2272+
2273+ return result ;
22502274 }
22512275
2252- public isBeingLiquidated ( ) : boolean {
2253- return (
2276+ public isBeingLiquidated ( marginCalc ?: MarginCalculation ) : boolean {
2277+ // Consider on-chain flags OR computed margin status (cross or any isolated)
2278+ const hasOnChainFlag =
22542279 ( this . getUserAccount ( ) . status &
2255- ( UserStatus . BEING_LIQUIDATED | UserStatus . BANKRUPT ) ) >
2256- 0
2280+ ( UserStatus . BEING_LIQUIDATED | UserStatus . BANKRUPT ) ) > 0 ;
2281+ const calc = marginCalc ?? this . getMarginCalculation ( 'Maintenance' ) ;
2282+ return (
2283+ hasOnChainFlag ||
2284+ this . isCrossMarginBeingLiquidated ( calc ) ||
2285+ this . isIsolatedMarginBeingLiquidated ( calc )
22572286 ) ;
22582287 }
22592288
2289+ /** Returns true if cross margin is currently below maintenance requirement (no buffer). */
2290+ public isCrossMarginBeingLiquidated ( marginCalc ?: MarginCalculation ) : boolean {
2291+ const calc = marginCalc ?? this . getMarginCalculation ( 'Maintenance' ) ;
2292+ return calc . totalCollateral . lt ( calc . marginRequirement ) ;
2293+ }
2294+
2295+ /** Returns true if any isolated perp position is currently below its maintenance requirement (no buffer). */
2296+ public isIsolatedMarginBeingLiquidated ( marginCalc ?: MarginCalculation ) : boolean {
2297+ const calc = marginCalc ?? this . getMarginCalculation ( 'Maintenance' ) ;
2298+ for ( const [ , isoCalc ] of calc . isolatedMarginCalculations ) {
2299+ if ( isoCalc . totalCollateral . lt ( isoCalc . marginRequirement ) ) {
2300+ return true ;
2301+ }
2302+ }
2303+ return false ;
2304+ }
2305+
22602306 public hasStatus ( status : UserStatus ) : boolean {
22612307 return ( this . getUserAccount ( ) . status & status ) > 0 ;
22622308 }
0 commit comments