@zofai/zo-sdk 0.1.92 → 0.1.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/consts/deployments-slp-mainnet.json +1 -1
  2. package/dist/consts/deployments-usdz-mainnet.json +1 -1
  3. package/dist/consts/deployments-zlp-mainnet.json +1 -1
  4. package/dist/implementations/SLPDataAPI.cjs +227 -51
  5. package/dist/implementations/SLPDataAPI.cjs.map +1 -1
  6. package/dist/implementations/SLPDataAPI.d.cts +8 -1
  7. package/dist/implementations/SLPDataAPI.d.cts.map +1 -1
  8. package/dist/implementations/SLPDataAPI.d.mts +8 -1
  9. package/dist/implementations/SLPDataAPI.d.mts.map +1 -1
  10. package/dist/implementations/SLPDataAPI.mjs +227 -51
  11. package/dist/implementations/SLPDataAPI.mjs.map +1 -1
  12. package/dist/implementations/USDZDataAPI.cjs +208 -48
  13. package/dist/implementations/USDZDataAPI.cjs.map +1 -1
  14. package/dist/implementations/USDZDataAPI.d.cts +8 -1
  15. package/dist/implementations/USDZDataAPI.d.cts.map +1 -1
  16. package/dist/implementations/USDZDataAPI.d.mts +8 -1
  17. package/dist/implementations/USDZDataAPI.d.mts.map +1 -1
  18. package/dist/implementations/USDZDataAPI.mjs +208 -48
  19. package/dist/implementations/USDZDataAPI.mjs.map +1 -1
  20. package/dist/implementations/ZLPDataAPI.cjs +211 -50
  21. package/dist/implementations/ZLPDataAPI.cjs.map +1 -1
  22. package/dist/implementations/ZLPDataAPI.d.cts +8 -1
  23. package/dist/implementations/ZLPDataAPI.d.cts.map +1 -1
  24. package/dist/implementations/ZLPDataAPI.d.mts +8 -1
  25. package/dist/implementations/ZLPDataAPI.d.mts.map +1 -1
  26. package/dist/implementations/ZLPDataAPI.mjs +211 -50
  27. package/dist/implementations/ZLPDataAPI.mjs.map +1 -1
  28. package/dist/interfaces/base.d.cts +22 -0
  29. package/dist/interfaces/base.d.cts.map +1 -1
  30. package/dist/interfaces/base.d.mts +22 -0
  31. package/dist/interfaces/base.d.mts.map +1 -1
  32. package/dist/interfaces/slp.d.cts +8 -1
  33. package/dist/interfaces/slp.d.cts.map +1 -1
  34. package/dist/interfaces/slp.d.mts +8 -1
  35. package/dist/interfaces/slp.d.mts.map +1 -1
  36. package/dist/interfaces/usdz.d.cts +8 -1
  37. package/dist/interfaces/usdz.d.cts.map +1 -1
  38. package/dist/interfaces/usdz.d.mts +8 -1
  39. package/dist/interfaces/usdz.d.mts.map +1 -1
  40. package/dist/interfaces/zlp.d.cts +8 -1
  41. package/dist/interfaces/zlp.d.cts.map +1 -1
  42. package/dist/interfaces/zlp.d.mts +8 -1
  43. package/dist/interfaces/zlp.d.mts.map +1 -1
  44. package/package.json +4 -1
  45. package/src/consts/deployments-slp-mainnet.json +1 -1
  46. package/src/consts/deployments-usdz-mainnet.json +1 -1
  47. package/src/consts/deployments-zlp-mainnet.json +1 -1
  48. package/src/implementations/SLPDataAPI.ts +253 -23
  49. package/src/implementations/USDZDataAPI.ts +232 -20
  50. package/src/implementations/ZLPDataAPI.ts +233 -21
  51. package/src/interfaces/base.ts +26 -0
  52. package/src/interfaces/slp.ts +10 -1
  53. package/src/interfaces/usdz.ts +10 -1
  54. package/src/interfaces/zlp.ts +10 -1
@@ -15,6 +15,7 @@ import type {
15
15
  IBaseHistoryResponse,
16
16
  IBaseOrderType,
17
17
  IBaseStaked,
18
+ ISwapFeeBreakdown,
18
19
  IZLPCredential,
19
20
  IZLPDataAPI,
20
21
  IZLPFundingFeeModel,
@@ -37,6 +38,20 @@ import type {
37
38
  } from '../interfaces'
38
39
  import { joinSymbol, parseSymbolKey, parseValue, suiSymbolToSymbol } from '../utils'
39
40
 
41
+ interface SwapImpactConfig {
42
+ id: string
43
+ enabled: boolean
44
+ impactMultiplier: number
45
+ maxImpactRate: number
46
+ }
47
+
48
+ interface EmaVolatilityFeeConfig {
49
+ id: string
50
+ enabled: boolean
51
+ multiplier: number
52
+ maxFeeRate: number
53
+ }
54
+
40
55
  export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
41
56
  constructor(
42
57
  network: Network,
@@ -197,11 +212,17 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
197
212
  let zlpPrice = 0
198
213
  let value = 0
199
214
 
200
- const vaultPromises = Object.keys(this.consts.zoCore.vaults).map(async (vault) => {
215
+ const vaultKeys = Object.keys(this.consts.zoCore.vaults)
216
+ const vaultData = await Promise.all(vaultKeys.map(async (vault) => {
201
217
  const vaultInfo = await this.getVaultInfo(vault)
202
218
  const reservingFeeDelta = ZLPDataAPI.calculateVaultReservingFee(vaultInfo, vaultInfo.reservingFeeModel, Date.now() / 1000)
203
- return (reservingFeeDelta + vaultInfo.liquidity + vaultInfo.reservedAmount) * (await this.getOraclePrice(vault)).getPriceUnchecked().getPriceAsNumberUnchecked() / (10 ** this.consts.coins[vault].decimals)
204
- })
219
+ const totalVaultAmount = reservingFeeDelta + vaultInfo.liquidity + vaultInfo.reservedAmount
220
+ const oraclePrice = (await this.getOraclePrice(vault)).getPriceUnchecked().getPriceAsNumberUnchecked()
221
+ const vaultValue = totalVaultAmount * oraclePrice / (10 ** this.consts.coins[vault].decimals)
222
+ return { vault, oraclePrice, vaultValue }
223
+ }))
224
+ const vaultPrices = Object.fromEntries(vaultData.map(d => [d.vault, d.oraclePrice]))
225
+ const vaultValues = vaultData.map(d => d.vaultValue)
205
226
 
206
227
  const symbolPromises = Object.keys(this.consts.zoCore.symbols).map(async (symbol) => {
207
228
  const [direction, tokenId] = parseSymbolKey(symbol)
@@ -217,13 +238,13 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
217
238
  price,
218
239
  marketInfo.lpSupplyWithDecimals,
219
240
  Date.now() / 1000,
220
- oiState && oiState.enabled ? oiState.model : undefined,
241
+ oiState && oiState.enabled ? oiState : undefined,
221
242
  pairedInfo.openingSize,
222
243
  )
223
244
  return fundingFeeDelta + deltaSize
224
245
  })
225
246
 
226
- const [vaultValues, symbolValues] = await Promise.all([Promise.all(vaultPromises), Promise.all(symbolPromises)])
247
+ const symbolValues = await Promise.all(symbolPromises)
227
248
 
228
249
  value = vaultValues.reduce((acc: number, curr: number) => acc + curr, 0)
229
250
  value += symbolValues.reduce((acc: number, curr: number) => acc + curr, 0)
@@ -235,6 +256,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
235
256
  price: zlpPrice,
236
257
  supply: marketInfo.lpSupplyWithDecimals,
237
258
  apr: Number(marketInfo.apr),
259
+ vaultPrices,
238
260
  }
239
261
  }
240
262
 
@@ -375,6 +397,165 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
375
397
  }
376
398
  }
377
399
 
400
+ public async calculateSwapFeeBreakdown(fromToken: string, toToken: string, fromAmount: number): Promise<ISwapFeeBreakdown> {
401
+ const timestamp = Date.now() / 1000
402
+
403
+ const fromDecimals = this.consts.coins[fromToken]?.decimals
404
+ const toDecimals = this.consts.coins[toToken]?.decimals
405
+ if (fromDecimals === undefined || toDecimals === undefined) {
406
+ throw new Error(`Unknown token decimals for swap: ${fromToken} -> ${toToken}`)
407
+ }
408
+
409
+ const fromFeed = await this.getOraclePrice(fromToken)
410
+ const toFeed = await this.getOraclePrice(toToken)
411
+ const fromPrice = fromFeed.getPriceUnchecked().getPriceAsNumberUnchecked()
412
+ const toPrice = toFeed.getPriceUnchecked().getPriceAsNumberUnchecked()
413
+
414
+ const swapValue = (fromAmount * fromPrice) / (10 ** fromDecimals)
415
+ const totalVaultsValue = await this.#getTotalVaultsValueUsd(timestamp)
416
+
417
+ const rebaseFeeInRate = await this.rebaseFeeRate(fromToken, true, fromAmount)
418
+ const rebaseFeeInValue = swapValue * rebaseFeeInRate
419
+
420
+ // Estimate out-amount by notional value (ignoring price impact / spread / fees).
421
+ const estimatedToAmount = toPrice !== 0
422
+ ? (swapValue * (10 ** toDecimals)) / toPrice
423
+ : 0
424
+ const rebaseFeeOutRate = await this.rebaseFeeRate(toToken, false, estimatedToAmount)
425
+ const rebaseFeeOutValue = swapValue * rebaseFeeOutRate
426
+
427
+ const swapImpactCfg = await this.#getSwapImpactConfig()
428
+ const swapImpactFeeValue = swapImpactCfg?.enabled
429
+ ? ZLPDataAPI.#computeSwapImpactFeeValue(swapValue, totalVaultsValue, swapImpactCfg.impactMultiplier, swapImpactCfg.maxImpactRate)
430
+ : 0
431
+
432
+ const emaCfg = await this.#getEmaVolatilityFeeConfig()
433
+ const emaVolatilityFeeValue = emaCfg?.enabled
434
+ ? ZLPDataAPI.#computeEmaVolatilityFeeValue(
435
+ swapValue,
436
+ ZLPDataAPI.#maxEmaDivergenceRate(fromFeed, toFeed),
437
+ emaCfg.multiplier,
438
+ emaCfg.maxFeeRate,
439
+ )
440
+ : 0
441
+
442
+ const totalFeeValue = rebaseFeeInValue + rebaseFeeOutValue + swapImpactFeeValue + emaVolatilityFeeValue
443
+ const totalFeeRate = swapValue !== 0 ? totalFeeValue / swapValue : 0
444
+
445
+ return {
446
+ swapValue,
447
+ totalVaultsValue,
448
+ rebaseFeeInRate,
449
+ rebaseFeeOutRate,
450
+ rebaseFeeInValue,
451
+ rebaseFeeOutValue,
452
+ swapImpactFeeValue,
453
+ emaVolatilityFeeValue,
454
+ totalFeeValue,
455
+ totalFeeRate,
456
+ }
457
+ }
458
+
459
+ async #getTotalVaultsValueUsd(timestamp: number): Promise<number> {
460
+ const vaultKeys = Object.keys(this.consts.zoCore.vaults)
461
+ const vaultValues = await Promise.all(vaultKeys.map(async (vault) => {
462
+ const vaultInfo = await this.getVaultInfo(vault)
463
+ const reservingFeeDelta = ZLPDataAPI.calculateVaultReservingFee(vaultInfo, vaultInfo.reservingFeeModel, timestamp)
464
+ const totalVaultAmount = reservingFeeDelta + vaultInfo.liquidity + vaultInfo.reservedAmount
465
+ const oraclePrice = (await this.getOraclePrice(vault)).getPriceUnchecked().getPriceAsNumberUnchecked()
466
+ const { decimals } = this.consts.coins[vault]
467
+ return totalVaultAmount * oraclePrice / (10 ** decimals)
468
+ }))
469
+ return vaultValues.reduce((acc, curr) => acc + curr, 0)
470
+ }
471
+
472
+ async #getSwapImpactConfig(): Promise<SwapImpactConfig | null> {
473
+ const raw = await this.#getMarketDynamicFieldObjectByKeySuffix(this.consts.zoCore.market, 'SwapImpactConfigKey')
474
+ if (!raw)
475
+ return null
476
+ return ZLPDataAPI.#parseSwapImpactConfig(raw)
477
+ }
478
+
479
+ async #getEmaVolatilityFeeConfig(): Promise<EmaVolatilityFeeConfig | null> {
480
+ const raw = await this.#getMarketDynamicFieldObjectByKeySuffix(this.consts.zoCore.market, 'EmaVolatilityFeeConfigKey')
481
+ if (!raw)
482
+ return null
483
+ return ZLPDataAPI.#parseEmaVolatilityFeeConfig(raw)
484
+ }
485
+
486
+ async #getMarketDynamicFieldObjectByKeySuffix(parentId: string, keyTypeSuffix: string): Promise<any | null> {
487
+ let cursor: string | null | undefined
488
+ let hasNextPage = true
489
+
490
+ while (hasNextPage) {
491
+ const page = await this.provider.getDynamicFields({ parentId, cursor })
492
+ for (const field of page.data) {
493
+ const type = (field.name as any)?.type
494
+ if (typeof type === 'string' && type.endsWith(`::${keyTypeSuffix}`)) {
495
+ return await this.provider.getDynamicFieldObject({
496
+ parentId,
497
+ name: field.name as any,
498
+ })
499
+ }
500
+ }
501
+ hasNextPage = page.hasNextPage
502
+ cursor = page.nextCursor
503
+ }
504
+ return null
505
+ }
506
+
507
+ static #parseSwapImpactConfig(raw: any): SwapImpactConfig {
508
+ const { fields } = raw.data.content
509
+ return {
510
+ id: fields.id.id,
511
+ enabled: fields.enabled,
512
+ impactMultiplier: parseValue(fields.impact_multiplier),
513
+ maxImpactRate: parseValue(fields.max_impact_rate),
514
+ }
515
+ }
516
+
517
+ static #parseEmaVolatilityFeeConfig(raw: any): EmaVolatilityFeeConfig {
518
+ const { fields } = raw.data.content
519
+ return {
520
+ id: fields.id.id,
521
+ enabled: fields.enabled,
522
+ multiplier: parseValue(fields.multiplier),
523
+ maxFeeRate: parseValue(fields.max_fee_rate),
524
+ }
525
+ }
526
+
527
+ static #computeSwapImpactFeeValue(swapValue: number, totalVaultsValue: number, impactMultiplier: number, maxImpactRate: number): number {
528
+ if (swapValue <= 0 || totalVaultsValue <= 0)
529
+ return 0
530
+ const utilization = swapValue / totalVaultsValue
531
+ const rawImpactRate = impactMultiplier * utilization
532
+ const impactRate = Math.min(rawImpactRate, maxImpactRate)
533
+ return swapValue * impactRate
534
+ }
535
+
536
+ static #computeEmaVolatilityFeeValue(swapValue: number, maxDiv: number, multiplier: number, maxFeeRate: number): number {
537
+ if (swapValue <= 0 || maxDiv <= 0)
538
+ return 0
539
+ const rawFeeRate = multiplier * maxDiv
540
+ const feeRate = Math.min(rawFeeRate, maxFeeRate)
541
+ return swapValue * feeRate
542
+ }
543
+
544
+ static #maxEmaDivergenceRate(sourceFeed: any, destFeed: any): number {
545
+ const sourceDiv = ZLPDataAPI.#emaDivergenceRate(sourceFeed)
546
+ const destDiv = ZLPDataAPI.#emaDivergenceRate(destFeed)
547
+ return Math.max(sourceDiv, destDiv)
548
+ }
549
+
550
+ static #emaDivergenceRate(priceFeed: any): number {
551
+ const price = priceFeed.getPriceUnchecked().getPriceAsNumberUnchecked()
552
+ const ema = priceFeed.getEmaPriceUnchecked().getPriceAsNumberUnchecked()
553
+ const denom = Math.abs(price)
554
+ if (denom === 0)
555
+ return 0
556
+ return Math.abs(price - ema) / denom
557
+ }
558
+
378
559
  public async getPositionCapInfoList(owner: string): Promise<IZLPPositionCapInfo[]> {
379
560
  const positionCapInfoList: IZLPPositionCapInfo[] = []
380
561
  let cursor: string | undefined | null
@@ -664,7 +845,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
664
845
  const longSize = longSymbol.openingSize
665
846
  const shortSize = shortSymbol.openingSize
666
847
 
667
- const deltaRate = ZLPDataAPI.calcOiFundingFeeRate(oiState.model, longSize, shortSize, elapsed)
848
+ const deltaRate = ZLPDataAPI.calcOiFundingFeeRate(oiState.model, longSize, shortSize, elapsed, oiState.maxOiLong, oiState.maxOiShort)
668
849
  return long ? deltaRate : -deltaRate
669
850
  }
670
851
 
@@ -751,13 +932,42 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
751
932
  return pnlPerRate >= 0 ? -secondsRate : secondsRate
752
933
  }
753
934
 
754
- private static calcOiFundingFeeRate(model: IZLPOiFundingModel, longSize: number, shortSize: number, elapsed: number): number {
755
- const imbalance = Math.abs(longSize - shortSize)
935
+ /**
936
+ * OI funding rate matching Move compute_oi_funding_rate_capped.
937
+ * When both maxOiLong and maxOiShort are set and > 0, uses normalized skew (oi/cap);
938
+ * otherwise falls back to (long - short) / total.
939
+ */
940
+ private static calcOiFundingFeeRate(
941
+ model: IZLPOiFundingModel,
942
+ oiLong: number,
943
+ oiShort: number,
944
+ elapsed: number,
945
+ maxOiLong?: number,
946
+ maxOiShort?: number,
947
+ ): number {
948
+ let skew: number
949
+ if (maxOiLong && maxOiShort && maxOiLong > 0 && maxOiShort > 0) {
950
+ const normLong = Math.min(oiLong / maxOiLong, 1)
951
+ const normShort = Math.min(oiShort / maxOiShort, 1)
952
+ skew = normLong - normShort
953
+ }
954
+ else {
955
+ const total = oiLong + oiShort
956
+ if (total === 0)
957
+ return 0
958
+ skew = (oiLong - oiShort) / total
959
+ }
960
+
961
+ if (skew === 0)
962
+ return 0
756
963
 
757
- // multiplier = 0.1%, exponent = 1
758
- const dailyRate = Math.min(model.multiplier * (imbalance ** model.exponent) / (longSize + shortSize > 0 ? longSize + shortSize : 1), model.max)
759
- const secondsRate = dailyRate * elapsed / SECONDS_PER_EIGHT_HOUR
760
- return longSize >= shortSize ? secondsRate : -secondsRate
964
+ const skewIsPositive = skew > 0
965
+ const skewAbs = Math.abs(skew)
966
+ const exponentInt = Math.floor(model.exponent)
967
+ const skewPow = skewAbs ** exponentInt
968
+ const dailyRate = Math.min(model.multiplier * skewPow, model.max)
969
+ const secondsRate = (dailyRate * elapsed) / SECONDS_PER_EIGHT_HOUR
970
+ return skewIsPositive ? secondsRate : -secondsRate
761
971
  }
762
972
 
763
973
  private static calcAccFundingFeeRate(
@@ -766,17 +976,17 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
766
976
  price: number,
767
977
  lpSupplyAmount: number,
768
978
  timestamp: number,
769
- oiModel?: IZLPOiFundingModel,
979
+ oiState?: IZLPOiFundingState,
770
980
  pairedOpeningSize?: number,
771
981
  ): number {
772
982
  if (symbol.lastUpdate > 0) {
773
983
  const elapsed = timestamp - symbol.lastUpdate
774
984
  if (elapsed > 0) {
775
- // Prefer OI-based delta when model and paired side are available
776
- if (oiModel && typeof pairedOpeningSize === 'number') {
985
+ // Prefer OI-based delta when state and paired side are available
986
+ if (oiState?.enabled && oiState.model && typeof pairedOpeningSize === 'number') {
777
987
  const longSize = symbol.long ? symbol.openingSize : pairedOpeningSize
778
988
  const shortSize = symbol.long ? pairedOpeningSize : symbol.openingSize
779
- const deltaRate = ZLPDataAPI.calcOiFundingFeeRate(oiModel, longSize, shortSize, elapsed)
989
+ const deltaRate = ZLPDataAPI.calcOiFundingFeeRate(oiState.model, longSize, shortSize, elapsed, oiState.maxOiLong, oiState.maxOiShort)
780
990
  const appliedRate = symbol.long ? deltaRate : -deltaRate
781
991
  return symbol.accFundingRate + appliedRate
782
992
  }
@@ -796,7 +1006,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
796
1006
  price: number,
797
1007
  lpSupplyAmount: number,
798
1008
  timestamp: number,
799
- oiModel?: IZLPOiFundingModel,
1009
+ oiState?: IZLPOiFundingState,
800
1010
  pairedOpeningSize?: number,
801
1011
  ): number {
802
1012
  const accFundingRate = ZLPDataAPI.calcAccFundingFeeRate(
@@ -805,7 +1015,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
805
1015
  price,
806
1016
  lpSupplyAmount,
807
1017
  timestamp,
808
- oiModel,
1018
+ oiState,
809
1019
  pairedOpeningSize,
810
1020
  )
811
1021
  return symbol.unrealisedFundingFeeValue + (accFundingRate - symbol.accFundingRate) * symbol.openingSize
@@ -999,7 +1209,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
999
1209
  // OI context for funding: fetch state and paired side size when enabled
1000
1210
  const oiState = await this.getSymbolOiFundingState(positionInfo.indexToken)
1001
1211
  const pairedSymbol = await this.getSymbolInfo(positionInfo.indexToken, !positionInfo.long)
1002
- positionInfo.fundingFeeValue = ZLPDataAPI.calculatePositionFundingFee(positionInfo, await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long), (await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long)).fundingFeeModel, (await this.getOraclePrice(positionInfo.indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked(), (await this.getMarketInfo()).lpSupplyWithDecimals, Date.now() / 1000, oiState && oiState.enabled ? oiState.model : undefined, pairedSymbol.openingSize)
1212
+ positionInfo.fundingFeeValue = ZLPDataAPI.calculatePositionFundingFee(positionInfo, await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long), (await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long)).fundingFeeModel, (await this.getOraclePrice(positionInfo.indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked(), (await this.getMarketInfo()).lpSupplyWithDecimals, Date.now() / 1000, oiState && oiState.enabled ? oiState : undefined, pairedSymbol.openingSize)
1003
1213
 
1004
1214
  return positionInfo
1005
1215
  }
@@ -1011,7 +1221,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
1011
1221
  price: number,
1012
1222
  lpSupplyAmount: number,
1013
1223
  timestamp: number,
1014
- oiModel?: IZLPOiFundingModel,
1224
+ oiState?: IZLPOiFundingState,
1015
1225
  pairedOpeningSize?: number,
1016
1226
  ): number {
1017
1227
  const accFundingRate = ZLPDataAPI.calcAccFundingFeeRate(
@@ -1020,7 +1230,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
1020
1230
  price,
1021
1231
  lpSupplyAmount,
1022
1232
  timestamp,
1023
- oiModel,
1233
+ oiState,
1024
1234
  pairedOpeningSize,
1025
1235
  )
1026
1236
  return position.fundingFeeValue + (accFundingRate - position.lastFundingRate) * position.positionSize
@@ -1093,6 +1303,8 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
1093
1303
  exponent: parseValue(content.model.fields.exponent),
1094
1304
  max: parseValue(content.model.fields.max),
1095
1305
  },
1306
+ maxOiLong: content.max_oi_long !== null && content.max_oi_long !== undefined ? parseValue(content.max_oi_long) : undefined,
1307
+ maxOiShort: content.max_oi_short !== null && content.max_oi_short !== undefined ? parseValue(content.max_oi_short) : undefined,
1096
1308
  }
1097
1309
  }
1098
1310
 
@@ -18,6 +18,32 @@ export interface IBaseMarketValuationInfo {
18
18
  apr?: number
19
19
  }
20
20
 
21
+ export interface ISwapFeeBreakdown {
22
+ /** Swap notional value (in USD terms using oracle prices) */
23
+ swapValue: number
24
+ /** Total value of all vaults (in USD terms using oracle prices) */
25
+ totalVaultsValue: number
26
+
27
+ /** Rebase fee rate applied to swap-in leg (source token) */
28
+ rebaseFeeInRate: number
29
+ /** Rebase fee rate applied to swap-out leg (dest token) */
30
+ rebaseFeeOutRate: number
31
+ /** Rebase fee value for swap-in leg (USD value) */
32
+ rebaseFeeInValue: number
33
+ /** Rebase fee value for swap-out leg (USD value) */
34
+ rebaseFeeOutValue: number
35
+
36
+ /** Swap impact fee value (USD value) */
37
+ swapImpactFeeValue: number
38
+ /** EMA volatility fee value (USD value) */
39
+ emaVolatilityFeeValue: number
40
+
41
+ /** Sum of all fee components (USD value) */
42
+ totalFeeValue: number
43
+ /** totalFeeValue / swapValue (0 when swapValue is 0) */
44
+ totalFeeRate: number
45
+ }
46
+
21
47
  export interface IBaseMarketInfo {
22
48
  lpSupply: string
23
49
  positionId: string
@@ -25,10 +25,14 @@ import type {
25
25
  IBaseStakePool,
26
26
  IBaseSymbolInfo,
27
27
  IBaseVaultInfo,
28
+ ISwapFeeBreakdown,
28
29
  } from './base'
29
30
 
30
31
  // SLP-specific interfaces
31
- export interface ISLPMarketValuationInfo extends IBaseMarketValuationInfo { }
32
+ export interface ISLPMarketValuationInfo extends IBaseMarketValuationInfo {
33
+ /** Oracle price per vault token at valuation time (e.g. { sui: 1.5, usdc: 1.0 }) */
34
+ vaultPrices?: Record<string, number>
35
+ }
32
36
 
33
37
  export interface ISLPVaultInfo extends IBaseVaultInfo { }
34
38
 
@@ -99,6 +103,10 @@ export interface ISLPOiFundingState {
99
103
  enabled: boolean
100
104
  last_update: number
101
105
  model: ISLPOiFundingModel
106
+ /** OI cap for long side (optional; when set with maxOiShort, uses capped skew formula) */
107
+ maxOiLong?: number
108
+ /** OI cap for short side (optional; when set with maxOiLong, uses capped skew formula) */
109
+ maxOiShort?: number
102
110
  }
103
111
 
104
112
  /**
@@ -208,6 +216,7 @@ export interface ISLPDataAPI extends IBaseDataAPI {
208
216
  getCumulativeApr: () => Promise<number>
209
217
  getSymbolConfig: (indexToken: string, long: boolean) => Promise<ISLPSymbolConfig | null>
210
218
  getPriceImpactConfig: (indexToken: string) => Promise<ISLPPriceImpactConfig | null>
219
+ calculateSwapFeeBreakdown: (fromToken: string, toToken: string, fromAmount: number) => Promise<ISwapFeeBreakdown>
211
220
  }
212
221
 
213
222
  // SLP-specific API interface
@@ -23,10 +23,14 @@ import type {
23
23
  IBaseStakePool,
24
24
  IBaseSymbolInfo,
25
25
  IBaseVaultInfo,
26
+ ISwapFeeBreakdown,
26
27
  } from './base'
27
28
 
28
29
  // USDZ-specific interfaces
29
- export interface IUSDZMarketValuationInfo extends IBaseMarketValuationInfo { }
30
+ export interface IUSDZMarketValuationInfo extends IBaseMarketValuationInfo {
31
+ /** Oracle price per vault token at valuation time (e.g. { sui: 1.5, usdc: 1.0 }) */
32
+ vaultPrices?: Record<string, number>
33
+ }
30
34
 
31
35
  export interface IUSDZVaultInfo extends IBaseVaultInfo { }
32
36
 
@@ -100,6 +104,10 @@ export interface IUSDZOiFundingState {
100
104
  enabled: boolean
101
105
  last_update: number
102
106
  model: IUSDZOiFundingModel
107
+ /** OI cap for long side (optional; when set with maxOiShort, uses capped skew formula) */
108
+ maxOiLong?: number
109
+ /** OI cap for short side (optional; when set with maxOiLong, uses capped skew formula) */
110
+ maxOiShort?: number
103
111
  }
104
112
 
105
113
  /**
@@ -130,6 +138,7 @@ export interface IUSDZPriceImpactConfig {
130
138
  export interface IUSDZDataAPI extends IBaseDataAPI {
131
139
  getSymbolConfig: (indexToken: string, long: boolean) => Promise<IUSDZSymbolConfig | null>
132
140
  getPriceImpactConfig: (indexToken: string) => Promise<IUSDZPriceImpactConfig | null>
141
+ calculateSwapFeeBreakdown: (fromToken: string, toToken: string, fromAmount: number) => Promise<ISwapFeeBreakdown>
133
142
  }
134
143
 
135
144
  // USDZ-specific API interface
@@ -23,10 +23,14 @@ import type {
23
23
  IBaseStakePool,
24
24
  IBaseSymbolInfo,
25
25
  IBaseVaultInfo,
26
+ ISwapFeeBreakdown,
26
27
  } from './base'
27
28
 
28
29
  // ZLP-specific interfaces
29
- export interface IZLPMarketValuationInfo extends IBaseMarketValuationInfo { }
30
+ export interface IZLPMarketValuationInfo extends IBaseMarketValuationInfo {
31
+ /** Oracle price per vault token at valuation time (e.g. { sui: 1.5, usdc: 1.0 }) */
32
+ vaultPrices?: Record<string, number>
33
+ }
30
34
 
31
35
  export interface IZLPVaultInfo extends IBaseVaultInfo { }
32
36
 
@@ -100,6 +104,10 @@ export interface IZLPOiFundingState {
100
104
  enabled: boolean
101
105
  last_update: number
102
106
  model: IZLPOiFundingModel
107
+ /** OI cap for long side (optional; when set with maxOiShort, uses capped skew formula) */
108
+ maxOiLong?: number
109
+ /** OI cap for short side (optional; when set with maxOiLong, uses capped skew formula) */
110
+ maxOiShort?: number
103
111
  }
104
112
 
105
113
  /**
@@ -130,6 +138,7 @@ export interface IZLPPriceImpactConfig {
130
138
  export interface IZLPDataAPI extends IBaseDataAPI {
131
139
  getSymbolConfig: (indexToken: string, long: boolean) => Promise<IZLPSymbolConfig | null>
132
140
  getPriceImpactConfig: (indexToken: string) => Promise<IZLPPriceImpactConfig | null>
141
+ calculateSwapFeeBreakdown: (fromToken: string, toToken: string, fromAmount: number) => Promise<ISwapFeeBreakdown>
133
142
  }
134
143
 
135
144
  // ZLP-specific API interface