zo-sdk 0.1.39 → 0.1.41

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.
@@ -19,6 +19,8 @@ import type {
19
19
  IZLPFundingFeeModel,
20
20
  IZLPMarketInfo,
21
21
  IZLPMarketValuationInfo,
22
+ IZLPOiFundingModel,
23
+ IZLPOiFundingState,
22
24
  IZLPOrderCapInfo,
23
25
  IZLPOrderInfo,
24
26
  IZLPPositionCapInfo,
@@ -204,8 +206,20 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
204
206
  const symbolPromises = Object.keys(this.consts.zoCore.symbols).map(async (symbol) => {
205
207
  const [direction, tokenId] = parseSymbolKey(symbol)
206
208
  const symbolInfo = await this.getSymbolInfo(tokenId, direction === 'long')
207
- const deltaSize = ZLPDataAPI.calcDeltaSize(symbolInfo, (await this.getOraclePrice(tokenId)).getPriceUnchecked().getPriceAsNumberUnchecked())
208
- const fundingFeeDelta = ZLPDataAPI.calculateSymbolFundingFee(symbolInfo, symbolInfo.fundingFeeModel, (await this.getOraclePrice(tokenId)).getPriceUnchecked().getPriceAsNumberUnchecked(), marketInfo.lpSupplyWithDecimals, Date.now() / 1000)
209
+ const price = (await this.getOraclePrice(tokenId)).getPriceUnchecked().getPriceAsNumberUnchecked()
210
+ const deltaSize = ZLPDataAPI.calcDeltaSize(symbolInfo, price)
211
+
212
+ const oiState = await this.getSymbolOiFundingState(tokenId)
213
+ const pairedInfo = await this.getSymbolInfo(tokenId, direction !== 'long')
214
+ const fundingFeeDelta = ZLPDataAPI.calculateSymbolFundingFee(
215
+ symbolInfo,
216
+ symbolInfo.fundingFeeModel,
217
+ price,
218
+ marketInfo.lpSupplyWithDecimals,
219
+ Date.now() / 1000,
220
+ oiState && oiState.enabled ? oiState.model : undefined,
221
+ pairedInfo.openingSize,
222
+ )
209
223
  return fundingFeeDelta + deltaSize
210
224
  })
211
225
 
@@ -309,9 +323,31 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
309
323
  })
310
324
  return ZLPDataAPI.parseSymbolConfig(rawData)
311
325
  }
312
- catch {
326
+ catch (e: any) {
327
+ // If the dynamic field doesn't exist, return null
328
+ console.error('Error Fetching Symbol Config:', e)
329
+ return null
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Gets ZLP symbol OI funding model
335
+ */
336
+ public async getSymbolOiFundingState(indexToken: string): Promise<IZLPOiFundingState | null> {
337
+ this.validateCache()
338
+ try {
339
+ const rawData = await this.provider.getDynamicFieldObject({
340
+ parentId: this.consts.zoCore.market,
341
+ name: {
342
+ type: `${this.consts.zoCore.upgradedPackage}::funding::FundingStateKey<${this.consts.coins[indexToken].module}>`,
343
+ value: { dummy_field: false },
344
+ },
345
+ })
346
+ return ZLPDataAPI.parseOiFundingState(rawData)
347
+ }
348
+ catch (e: any) {
313
349
  // If the dynamic field doesn't exist, return null
314
- console.error('Symbol Config Not Found')
350
+ console.error('Error Fetching Symbol OI Funding State:', e)
315
351
  return null
316
352
  }
317
353
  }
@@ -570,18 +606,38 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
570
606
  }
571
607
 
572
608
  public async fundingFeeRate(indexToken: string, long: boolean): Promise<number> {
573
- const symbol = await this.getSymbolInfo(indexToken, long)
574
- if (symbol.lastUpdate <= 0) {
609
+ const oiState = await this.getSymbolOiFundingState(indexToken)
610
+
611
+ if (!oiState || !oiState.enabled) {
612
+ const symbol = await this.getSymbolInfo(indexToken, long)
613
+ if (symbol.lastUpdate <= 0) {
614
+ return 0
615
+ }
616
+ const price = (await this.getOraclePrice(indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked()
617
+ const lpSupplyAmount = (await this.getMarketInfo()).lpSupplyWithDecimals
618
+ const model = symbol.fundingFeeModel
619
+ const elapsed = SECONDS_PER_EIGHT_HOUR
620
+
621
+ const deltaSize = ZLPDataAPI.calcDeltaSize(symbol, price)
622
+ const pnlPerLp = (symbol.realisedPnl + symbol.unrealisedFundingFeeValue + deltaSize) / lpSupplyAmount
623
+ return ZLPDataAPI.calcFundingFeeRate(model, pnlPerLp, elapsed)
624
+ }
625
+
626
+ const longSymbol = await this.getSymbolInfo(indexToken, true)
627
+ const shortSymbol = await this.getSymbolInfo(indexToken, false)
628
+
629
+ if (longSymbol.lastUpdate <= 0 && shortSymbol.lastUpdate <= 0) {
575
630
  return 0
576
631
  }
577
- const price = (await this.getOraclePrice(indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked()
578
- const lpSupplyAmount = (await this.getMarketInfo()).lpSupplyWithDecimals
579
- const model = symbol.fundingFeeModel
632
+
580
633
  const elapsed = SECONDS_PER_EIGHT_HOUR
581
634
 
582
- const deltaSize = ZLPDataAPI.calcDeltaSize(symbol, price)
583
- const pnlPerLp = (symbol.realisedPnl + symbol.unrealisedFundingFeeValue + deltaSize) / lpSupplyAmount
584
- return ZLPDataAPI.calcFundingFeeRate(model, pnlPerLp, elapsed)
635
+ const longSize = longSymbol.openingSize
636
+ const shortSize = shortSymbol.openingSize
637
+
638
+ const deltaRate = ZLPDataAPI.calcOiFundingFeeRate(oiState.model, longSize, shortSize, elapsed)
639
+ console.log('deltaRate is:', deltaRate)
640
+ return long ? deltaRate : -deltaRate
585
641
  }
586
642
 
587
643
  public async rebaseFeeRate(collateralToken: string, increase: boolean, amount: number): Promise<number> {
@@ -667,10 +723,37 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
667
723
  return pnlPerRate >= 0 ? -secondsRate : secondsRate
668
724
  }
669
725
 
670
- private static calcAccFundingFeeRate(symbol: IZLPSymbolInfo, model: IZLPFundingFeeModel, price: number, lpSupplyAmount: number, timestamp: number): number {
726
+ private static calcOiFundingFeeRate(model: IZLPOiFundingModel, longSize: number, shortSize: number, elapsed: number): number {
727
+ const imbalance = Math.abs(longSize - shortSize)
728
+
729
+ // multiplier = 0.1%, exponent = 1
730
+ const dailyRate = Math.min(model.multiplier * (imbalance ** model.exponent) / (longSize + shortSize > 0 ? longSize + shortSize : 1), model.max)
731
+ const secondsRate = dailyRate * elapsed / SECONDS_PER_EIGHT_HOUR
732
+ return longSize >= shortSize ? secondsRate : -secondsRate
733
+ }
734
+
735
+ private static calcAccFundingFeeRate(
736
+ symbol: IZLPSymbolInfo,
737
+ model: IZLPFundingFeeModel,
738
+ price: number,
739
+ lpSupplyAmount: number,
740
+ timestamp: number,
741
+ oiModel?: IZLPOiFundingModel,
742
+ pairedOpeningSize?: number,
743
+ ): number {
671
744
  if (symbol.lastUpdate > 0) {
672
745
  const elapsed = timestamp - symbol.lastUpdate
673
746
  if (elapsed > 0) {
747
+ // Prefer OI-based delta when model and paired side are available
748
+ if (oiModel && typeof pairedOpeningSize === 'number') {
749
+ const longSize = symbol.long ? symbol.openingSize : pairedOpeningSize
750
+ const shortSize = symbol.long ? pairedOpeningSize : symbol.openingSize
751
+ const deltaRate = ZLPDataAPI.calcOiFundingFeeRate(oiModel, longSize, shortSize, elapsed)
752
+ const appliedRate = symbol.long ? deltaRate : -deltaRate
753
+ return symbol.accFundingRate + appliedRate
754
+ }
755
+
756
+ // Fallback to PnL-based funding delta
674
757
  const deltaSize = ZLPDataAPI.calcDeltaSize(symbol, price)
675
758
  const pnlPerLp = (symbol.realisedPnl + symbol.unrealisedFundingFeeValue + deltaSize) / lpSupplyAmount
676
759
  return symbol.accFundingRate + ZLPDataAPI.calcFundingFeeRate(model, pnlPerLp, elapsed)
@@ -679,8 +762,24 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
679
762
  return symbol.accFundingRate
680
763
  }
681
764
 
682
- private static calculateSymbolFundingFee(symbol: IZLPSymbolInfo, model: IZLPFundingFeeModel, price: number, lpSupplyAmount: number, timestamp: number): number {
683
- const accFundingRate = ZLPDataAPI.calcAccFundingFeeRate(symbol, model, price, lpSupplyAmount, timestamp)
765
+ private static calculateSymbolFundingFee(
766
+ symbol: IZLPSymbolInfo,
767
+ model: IZLPFundingFeeModel,
768
+ price: number,
769
+ lpSupplyAmount: number,
770
+ timestamp: number,
771
+ oiModel?: IZLPOiFundingModel,
772
+ pairedOpeningSize?: number,
773
+ ): number {
774
+ const accFundingRate = ZLPDataAPI.calcAccFundingFeeRate(
775
+ symbol,
776
+ model,
777
+ price,
778
+ lpSupplyAmount,
779
+ timestamp,
780
+ oiModel,
781
+ pairedOpeningSize,
782
+ )
684
783
  return symbol.unrealisedFundingFeeValue + (accFundingRate - symbol.accFundingRate) * symbol.openingSize
685
784
  }
686
785
 
@@ -868,13 +967,33 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
868
967
  }
869
968
 
870
969
  positionInfo.reservingFeeAmount = ZLPDataAPI.calculatePositionReserveFee(positionInfo, await this.getVaultInfo(positionInfo.collateralToken), (await this.getVaultInfo(positionInfo.collateralToken)).reservingFeeModel, Date.now() / 1000)
871
- 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)
970
+ // OI context for funding: fetch state and paired side size when enabled
971
+ const oiState = await this.getSymbolOiFundingState(positionInfo.indexToken)
972
+ const pairedSymbol = await this.getSymbolInfo(positionInfo.indexToken, !positionInfo.long)
973
+ 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)
872
974
 
873
975
  return positionInfo
874
976
  }
875
977
 
876
- private static calculatePositionFundingFee(position: IZLPPositionInfo, symbol: IZLPSymbolInfo, model: IZLPFundingFeeModel, price: number, lpSupplyAmount: number, timestamp: number): number {
877
- const accFundingRate = ZLPDataAPI.calcAccFundingFeeRate(symbol, model, price, lpSupplyAmount, timestamp)
978
+ private static calculatePositionFundingFee(
979
+ position: IZLPPositionInfo,
980
+ symbol: IZLPSymbolInfo,
981
+ model: IZLPFundingFeeModel,
982
+ price: number,
983
+ lpSupplyAmount: number,
984
+ timestamp: number,
985
+ oiModel?: IZLPOiFundingModel,
986
+ pairedOpeningSize?: number,
987
+ ): number {
988
+ const accFundingRate = ZLPDataAPI.calcAccFundingFeeRate(
989
+ symbol,
990
+ model,
991
+ price,
992
+ lpSupplyAmount,
993
+ timestamp,
994
+ oiModel,
995
+ pairedOpeningSize,
996
+ )
878
997
  return position.fundingFeeValue + (accFundingRate - position.lastFundingRate) * position.positionSize
879
998
  }
880
999
 
@@ -902,6 +1021,23 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
902
1021
  }
903
1022
  }
904
1023
 
1024
+ private static parseOiFundingState(raw: any): IZLPOiFundingState {
1025
+ console.log('checking oi funding state raw:', raw)
1026
+ const content = raw.data.content.fields
1027
+ console.log('oi funding state raw:', content)
1028
+ return {
1029
+ id: content.id.id,
1030
+ enabled: content.enabled,
1031
+ last_update: parseValue(content.last_update),
1032
+ model: {
1033
+ id: content.model.fields.id.id,
1034
+ multiplier: parseValue(content.model.fields.multiplier),
1035
+ exponent: parseValue(content.model.fields.exponent),
1036
+ max: parseValue(content.model.fields.max),
1037
+ },
1038
+ }
1039
+ }
1040
+
905
1041
  private parseOrderInfo(raw: any, capId: string): IZLPOrderInfo {
906
1042
  const { content } = raw.data
907
1043
  const { fields } = content.fields.value
@@ -89,6 +89,19 @@ export interface IZLPSymbolConfig {
89
89
  instant_exit_fee_config: IZLPPositionInstantExitFeeConfig
90
90
  }
91
91
 
92
+ export interface IZLPOiFundingModel {
93
+ id: string
94
+ multiplier: number
95
+ exponent: number
96
+ max: number
97
+ }
98
+ export interface IZLPOiFundingState {
99
+ id: string
100
+ enabled: boolean
101
+ last_update: number
102
+ model: IZLPOiFundingModel
103
+ }
104
+
92
105
  // ZLP-specific data API interface
93
106
  export interface IZLPDataAPI extends IBaseDataAPI {
94
107
  getSymbolConfig: (indexToken: string, long: boolean) => Promise<IZLPSymbolConfig | null>