@@ -9,7 +9,13 @@ import {
99 ProtectedMakerParams ,
1010 MarketTypeStr ,
1111} from '../types' ;
12- import { ZERO , TWO , ONE } from '../constants/numericConstants' ;
12+ import {
13+ ZERO ,
14+ TWO ,
15+ ONE ,
16+ SPOT_MARKET_IMF_PRECISION ,
17+ MARGIN_PRECISION ,
18+ } from '../constants/numericConstants' ;
1319import { BN } from '@coral-xyz/anchor' ;
1420import { MMOraclePriceData , OraclePriceData } from '../oracles/types' ;
1521import {
@@ -22,6 +28,7 @@ import {
2228 calculateMaxBaseAssetAmountToTrade ,
2329 calculateUpdatedAMM ,
2430} from './amm' ;
31+ import { calculateSizePremiumLiabilityWeight } from './margin' ;
2532
2633export function isOrderRiskIncreasing ( user : User , order : Order ) : boolean {
2734 if ( ! isVariant ( order . status , 'open' ) ) {
@@ -411,3 +418,65 @@ export function calculateOrderBaseAssetAmount(
411418 return BN . min ( BN . max ( existingBaseAssetAmount , ZERO ) , order . baseAssetAmount ) ;
412419 }
413420}
421+
422+ // ---------- inverse ----------
423+ /**
424+ * Invert the size-premium liability weight: given a target margin ratio (liability weight),
425+ * return the max `size` (AMM_RESERVE_PRECISION units) that still yields <= target.
426+ *
427+ * Returns:
428+ * - BN size (>=0) if bounded
429+ * - null if impossible (target < liabilityWeight) OR imfFactor == 0 (unbounded)
430+ */
431+ export function maxSizeForTargetLiabilityWeightBN (
432+ target : BN ,
433+ imfFactor : BN ,
434+ liabilityWeight : BN
435+ ) : BN | null {
436+ if ( target . lt ( liabilityWeight ) ) return null ;
437+ if ( imfFactor . isZero ( ) ) return null ;
438+
439+ const base = liabilityWeight . muln ( 4 ) . divn ( 5 ) ;
440+
441+ const denom = new BN ( 100_000 )
442+ . mul ( SPOT_MARKET_IMF_PRECISION )
443+ . div ( MARGIN_PRECISION ) ;
444+ if ( denom . isZero ( ) )
445+ throw new Error ( 'denom=0: bad precision/spotImfPrecision' ) ;
446+
447+ const allowedInc = target . gt ( base ) ? target . sub ( base ) : ZERO ;
448+
449+ const maxSqrt = allowedInc . mul ( denom ) . div ( imfFactor ) ;
450+
451+ if ( maxSqrt . lte ( ZERO ) ) {
452+ const fitsZero = calculateSizePremiumLiabilityWeight (
453+ ZERO ,
454+ imfFactor ,
455+ liabilityWeight ,
456+ MARGIN_PRECISION
457+ ) . lte ( target ) ;
458+ return fitsZero ? ZERO : null ;
459+ }
460+
461+ let hi = maxSqrt . mul ( maxSqrt ) . sub ( ONE ) . divn ( 10 ) ;
462+ if ( hi . isNeg ( ) ) hi = ZERO ;
463+
464+ let lo = ZERO ;
465+ while ( lo . lt ( hi ) ) {
466+ const mid = lo . add ( hi ) . add ( ONE ) . divn ( 2 ) ; // upper mid to prevent infinite loop
467+ if (
468+ calculateSizePremiumLiabilityWeight (
469+ mid ,
470+ imfFactor ,
471+ liabilityWeight ,
472+ MARGIN_PRECISION
473+ ) . lte ( target )
474+ ) {
475+ lo = mid ;
476+ } else {
477+ hi = mid . sub ( ONE ) ;
478+ }
479+ }
480+
481+ return lo ;
482+ }
0 commit comments