fix(trading): compute pre-trade liq fee on notional value, not raw position size#179
Conversation
…sition size
computePreTradeLiqPrice applied the trading fee (feeBps) to the raw
position size instead of the notional value (position × oracle price).
Trading fees on perp DEXes are assessed on notional, not lots.
For a 100M-unit position at $100 with 30 bps fee:
- Old (wrong): fee = 100_000_000 * 30 / 10000 = 300_000
- New (correct): fee = (100_000_000 * 100_000_000 / 1e6) * 30 / 10000
= 30_000_000
The old formula underestimated fees by a factor proportional to the
oracle price (in e6 scale / 10000). This caused liquidation price
estimates to be overly optimistic — users would be liquidated sooner
than the SDK predicted because the fee deduction from effective capital
was too small.
The fix computes notional = absPos * oracleE6 / 1_000_000 first, then
applies feeBps / 10000 to the notional. This is consistent with the
existing computeTradingFee function which also expects notional as its
base.
All 50 existing trading math tests continue to pass because the test
assertions check directional relationships (withFee > noFee for longs,
withFee < noFee for shorts) rather than exact values.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 1 minutes and 3 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
computePreTradeLiqPriceapplied the trading fee (feeBps) to the raw position size instead of the notional value (position × oracle price). Trading fees on perp DEXes are assessed on notional, not lots.Impact example — 100M-unit position at $100 with 30 bps fee:
fee = 100_000_000 * 30 / 10000 = 300,000fee = (100_000_000 * 100_000_000 / 1e6) * 30 / 10000 = 30,000,000The old formula underestimated fees by a factor proportional to the oracle price (in e6 scale / 10,000). This caused liquidation price estimates to be overly optimistic — users would be liquidated sooner than the SDK predicted because the fee deduction from effective capital was too small.
Changes
notional = (absPos * oracleE6) / 1_000_000nfirst, then applyfee = (notional * feeBps) / 10000n. This is consistent with the existingcomputeTradingFeefunction which also expects notional as its base.Test plan
npm run lint(tsc --noEmit) cleannpx tsx test/trading.test.ts— all 50 tests pass. Existing assertions check directional relationships (withFee > noFeefor longs,withFee < noFeefor shorts) rather than exact values, so they pass with the corrected fee magnitude.vitest run: same 14 pre-existing failures asmain, zero new failures