Skip to content

Commit a8a4011

Browse files
0xbigzlowkeynicc
andauthored
sdk: add-max-size-for-target-liability-weight (#1961)
* sdk: add-max-size-for-target-liability-weight * cleanup * cleanup --------- Co-authored-by: Nick Caradonna <[email protected]>
1 parent 7d63753 commit a8a4011

File tree

1 file changed

+70
-1
lines changed

1 file changed

+70
-1
lines changed

sdk/src/math/orders.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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';
1319
import { BN } from '@coral-xyz/anchor';
1420
import { MMOraclePriceData, OraclePriceData } from '../oracles/types';
1521
import {
@@ -22,6 +28,7 @@ import {
2228
calculateMaxBaseAssetAmountToTrade,
2329
calculateUpdatedAMM,
2430
} from './amm';
31+
import { calculateSizePremiumLiabilityWeight } from './margin';
2532

2633
export 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

Comments
 (0)