zo-sdk 0.1.43 → 0.1.45
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.
- package/dist/consts/deployments-slp-mainnet.json +1 -1
- package/dist/consts/deployments-zlp-mainnet.json +1 -1
- package/dist/consts/deployments-zlp-testnet.json +1 -1
- package/dist/implementations/SLPDataAPI.cjs +80 -62
- package/dist/implementations/SLPDataAPI.cjs.map +1 -1
- package/dist/implementations/SLPDataAPI.d.cts +8 -2
- package/dist/implementations/SLPDataAPI.d.cts.map +1 -1
- package/dist/implementations/SLPDataAPI.d.mts +8 -2
- package/dist/implementations/SLPDataAPI.d.mts.map +1 -1
- package/dist/implementations/SLPDataAPI.mjs +81 -63
- package/dist/implementations/SLPDataAPI.mjs.map +1 -1
- package/dist/interfaces/slp.d.cts +12 -0
- package/dist/interfaces/slp.d.cts.map +1 -1
- package/dist/interfaces/slp.d.mts +12 -0
- package/dist/interfaces/slp.d.mts.map +1 -1
- package/package.json +1 -1
- package/src/consts/deployments-slp-mainnet.json +1 -1
- package/src/consts/deployments-zlp-mainnet.json +1 -1
- package/src/consts/deployments-zlp-testnet.json +1 -1
- package/src/implementations/SLPDataAPI.ts +128 -65
- package/src/interfaces/slp.ts +14 -0
|
@@ -11,7 +11,7 @@ import { Transaction } from '@mysten/sui/transactions'
|
|
|
11
11
|
import { SUI_CLOCK_OBJECT_ID } from '@mysten/sui/utils'
|
|
12
12
|
|
|
13
13
|
import { BaseDataAPI } from '../abstract'
|
|
14
|
-
import { Rate,
|
|
14
|
+
import { Rate, SymbolsValuation, VaultsValuation } from '../bcs'
|
|
15
15
|
import type { Network } from '../consts'
|
|
16
16
|
import { LPToken, SLP_TOKEN_DECIMALS } from '../consts'
|
|
17
17
|
import type {
|
|
@@ -21,6 +21,8 @@ import type {
|
|
|
21
21
|
ISLPFundingFeeModel,
|
|
22
22
|
ISLPMarketInfo,
|
|
23
23
|
ISLPMarketValuationInfo,
|
|
24
|
+
ISLPOiFundingModel,
|
|
25
|
+
ISLPOiFundingState,
|
|
24
26
|
ISLPOrderCapInfo,
|
|
25
27
|
ISLPOrderInfo,
|
|
26
28
|
ISLPPositionCapInfo,
|
|
@@ -346,6 +348,28 @@ export class SLPDataAPI extends BaseDataAPI implements ISLPDataAPI {
|
|
|
346
348
|
}
|
|
347
349
|
}
|
|
348
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Gets SLP symbol OI funding state (global per symbol)
|
|
353
|
+
*/
|
|
354
|
+
public async getSymbolOiFundingState(indexToken: string): Promise<ISLPOiFundingState | null> {
|
|
355
|
+
this.validateCache()
|
|
356
|
+
try {
|
|
357
|
+
const rawData = await this.provider.getDynamicFieldObject({
|
|
358
|
+
parentId: this.consts.sudoCore.market,
|
|
359
|
+
name: {
|
|
360
|
+
type: `${this.consts.sudoCore.upgradedPackage}::funding::FundingStateKey<${this.consts.coins[indexToken].module}>`,
|
|
361
|
+
value: { dummy_field: false },
|
|
362
|
+
},
|
|
363
|
+
})
|
|
364
|
+
return SLPDataAPI.parseOiFundingState(rawData)
|
|
365
|
+
}
|
|
366
|
+
catch (e: any) {
|
|
367
|
+
// If the dynamic field doesn't exist, return null
|
|
368
|
+
console.error('Error Fetching SLP Symbol OI Funding State:', e)
|
|
369
|
+
return null
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
349
373
|
public async getPositionInfoList(
|
|
350
374
|
positionCapInfoList: ISLPPositionCapInfo[],
|
|
351
375
|
owner: string,
|
|
@@ -562,70 +586,38 @@ export class SLPDataAPI extends BaseDataAPI implements ISLPDataAPI {
|
|
|
562
586
|
}
|
|
563
587
|
}
|
|
564
588
|
|
|
565
|
-
public async fundingFeeRate(indexToken: string, long: boolean
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
const symbol_ = joinSymbol(long ? 'long' : 'short', indexToken)
|
|
571
|
-
const currentTimestamp = Number.parseInt((Date.now() / 1000).toFixed(0), 10)
|
|
572
|
-
const symbol = tx.moveCall({
|
|
573
|
-
target: `${this.consts.sudoCore.upgradedPackage}::market::symbol`,
|
|
574
|
-
typeArguments: [
|
|
575
|
-
`${this.consts.sudoCore.package}::slp::SLP`,
|
|
576
|
-
this.consts.coins[indexToken].module,
|
|
577
|
-
`${this.consts.sudoCore.package}::market::${long ? 'LONG' : 'SHORT'}`,
|
|
578
|
-
],
|
|
579
|
-
arguments: [tx.object(this.consts.sudoCore.market)],
|
|
580
|
-
})
|
|
581
|
-
const aggPriceConfig = tx.moveCall({
|
|
582
|
-
target: `${this.consts.sudoCore.package}::pool::symbol_price_config`,
|
|
583
|
-
typeArguments: [],
|
|
584
|
-
arguments: [symbol],
|
|
585
|
-
})
|
|
586
|
-
const aggPrice = tx.moveCall({
|
|
587
|
-
target: `${this.consts.sudoCore.package}::agg_price::parse_pyth_feeder_v1_1`,
|
|
588
|
-
typeArguments: [],
|
|
589
|
-
arguments: [
|
|
590
|
-
aggPriceConfig,
|
|
591
|
-
tx.object(this.consts.pythFeeder.feeder[indexToken]),
|
|
592
|
-
tx.pure.u64(currentTimestamp),
|
|
593
|
-
],
|
|
594
|
-
})
|
|
595
|
-
const deltaSize = tx.moveCall({
|
|
596
|
-
target: `${this.consts.sudoCore.package}::pool::symbol_delta_size`,
|
|
597
|
-
typeArguments: [],
|
|
598
|
-
arguments: [symbol, aggPrice, tx.pure.bool(long)],
|
|
599
|
-
})
|
|
600
|
-
const LpSupplyAmount = tx.moveCall({
|
|
601
|
-
target: `${this.consts.sudoCore.upgradedPackage}::market::lp_supply_amount`,
|
|
602
|
-
typeArguments: [`${this.consts.sudoCore.package}::slp::SLP`],
|
|
603
|
-
arguments: [tx.object(this.consts.sudoCore.market)],
|
|
604
|
-
})
|
|
605
|
-
const PnlPerLp = tx.moveCall({
|
|
606
|
-
target: `${this.consts.sudoCore.package}::pool::symbol_pnl_per_lp`,
|
|
607
|
-
typeArguments: [],
|
|
608
|
-
arguments: [symbol, deltaSize, LpSupplyAmount],
|
|
609
|
-
})
|
|
610
|
-
tx.moveCall({
|
|
611
|
-
target: `${this.consts.sudoCore.package}::model::compute_funding_fee_rate`,
|
|
612
|
-
arguments: [
|
|
613
|
-
tx.object(this.consts.sudoCore.symbols[symbol_].fundingFeeModel),
|
|
614
|
-
PnlPerLp,
|
|
615
|
-
tx.pure.u64(8 * 3600),
|
|
616
|
-
],
|
|
617
|
-
})
|
|
589
|
+
public async fundingFeeRate(indexToken: string, long: boolean): Promise<number> {
|
|
590
|
+
const oiState = await this.getSymbolOiFundingState(indexToken)
|
|
591
|
+
if (oiState && oiState.enabled) {
|
|
592
|
+
const longSymbol = await this.getSymbolInfo(indexToken, true)
|
|
593
|
+
const shortSymbol = await this.getSymbolInfo(indexToken, false)
|
|
618
594
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
})
|
|
595
|
+
if (longSymbol.lastUpdate <= 0 && shortSymbol.lastUpdate <= 0) {
|
|
596
|
+
return 0
|
|
597
|
+
}
|
|
623
598
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
599
|
+
const elapsed = SECONDS_PER_EIGHT_HOUR
|
|
600
|
+
const deltaRate = SLPDataAPI.calcOiFundingFeeRate(
|
|
601
|
+
oiState.model,
|
|
602
|
+
longSymbol.openingSize,
|
|
603
|
+
shortSymbol.openingSize,
|
|
604
|
+
elapsed,
|
|
605
|
+
)
|
|
606
|
+
return long ? deltaRate : -deltaRate
|
|
607
|
+
}
|
|
627
608
|
|
|
628
|
-
|
|
609
|
+
const symbol = await this.getSymbolInfo(indexToken, long)
|
|
610
|
+
if (symbol.lastUpdate <= 0) {
|
|
611
|
+
return 0
|
|
612
|
+
}
|
|
613
|
+
const price = (await this.getOraclePrice(indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked()
|
|
614
|
+
const lpSupplyAmount = (await this.getMarketInfo()).lpSupplyWithDecimals
|
|
615
|
+
const model = symbol.fundingFeeModel
|
|
616
|
+
const elapsed = SECONDS_PER_EIGHT_HOUR
|
|
617
|
+
|
|
618
|
+
const deltaSize = SLPDataAPI.calcDeltaSize(symbol, price, symbol.long)
|
|
619
|
+
const pnlPerLp = (symbol.realisedPnl + symbol.unrealisedFundingFeeValue + deltaSize) / lpSupplyAmount
|
|
620
|
+
return SLPDataAPI.calcFundingFeeRate(model, pnlPerLp, elapsed)
|
|
629
621
|
}
|
|
630
622
|
|
|
631
623
|
public async rebaseFeeRate(collateralToken: string, increase: boolean, amount: number, sender?: string): Promise<number> {
|
|
@@ -1000,15 +992,52 @@ export class SLPDataAPI extends BaseDataAPI implements ISLPDataAPI {
|
|
|
1000
992
|
}
|
|
1001
993
|
|
|
1002
994
|
// Private helper methods
|
|
1003
|
-
private static calculatePositionFundingFee(
|
|
1004
|
-
|
|
995
|
+
private static calculatePositionFundingFee(
|
|
996
|
+
position: ISLPPositionInfo,
|
|
997
|
+
symbol: ISLPSymbolInfo,
|
|
998
|
+
model: ISLPFundingFeeModel,
|
|
999
|
+
price: number,
|
|
1000
|
+
lpSupplyAmount: number,
|
|
1001
|
+
timestamp: number,
|
|
1002
|
+
oiModel?: ISLPOiFundingModel,
|
|
1003
|
+
pairedOpeningSize?: number,
|
|
1004
|
+
): number {
|
|
1005
|
+
const accFundingRate = this.calcAccFundingFeeRate(
|
|
1006
|
+
symbol,
|
|
1007
|
+
model,
|
|
1008
|
+
price,
|
|
1009
|
+
lpSupplyAmount,
|
|
1010
|
+
timestamp,
|
|
1011
|
+
position.long,
|
|
1012
|
+
oiModel,
|
|
1013
|
+
pairedOpeningSize,
|
|
1014
|
+
)
|
|
1005
1015
|
return position.fundingFeeValue + (accFundingRate - position.lastFundingRate) * position.positionSize
|
|
1006
1016
|
}
|
|
1007
1017
|
|
|
1008
|
-
private static calcAccFundingFeeRate(
|
|
1018
|
+
private static calcAccFundingFeeRate(
|
|
1019
|
+
symbol: ISLPSymbolInfo,
|
|
1020
|
+
model: ISLPFundingFeeModel,
|
|
1021
|
+
price: number,
|
|
1022
|
+
lpSupplyAmount: number,
|
|
1023
|
+
timestamp: number,
|
|
1024
|
+
isLong: boolean,
|
|
1025
|
+
oiModel?: ISLPOiFundingModel,
|
|
1026
|
+
pairedOpeningSize?: number,
|
|
1027
|
+
): number {
|
|
1009
1028
|
if (symbol.lastUpdate > 0) {
|
|
1010
1029
|
const elapsed = timestamp - symbol.lastUpdate
|
|
1011
1030
|
if (elapsed > 0) {
|
|
1031
|
+
// Prefer OI-based delta when OI model and paired side are available
|
|
1032
|
+
if (oiModel && typeof pairedOpeningSize === 'number') {
|
|
1033
|
+
const longSize = isLong ? symbol.openingSize : pairedOpeningSize
|
|
1034
|
+
const shortSize = isLong ? pairedOpeningSize : symbol.openingSize
|
|
1035
|
+
const deltaRate = SLPDataAPI.calcOiFundingFeeRate(oiModel, longSize, shortSize, elapsed)
|
|
1036
|
+
const appliedRate = isLong ? deltaRate : -deltaRate
|
|
1037
|
+
return symbol.accFundingRate + appliedRate
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// Fallback to PnL-based funding delta
|
|
1012
1041
|
const deltaSize = this.calcDeltaSize(symbol, price, isLong)
|
|
1013
1042
|
const pnlPerLp = (symbol.realisedPnl + symbol.unrealisedFundingFeeValue + deltaSize) / lpSupplyAmount
|
|
1014
1043
|
return symbol.accFundingRate + SLPDataAPI.calcFundingFeeRate(model, pnlPerLp, elapsed)
|
|
@@ -1028,6 +1057,18 @@ export class SLPDataAPI extends BaseDataAPI implements ISLPDataAPI {
|
|
|
1028
1057
|
return pnlPerRate >= 0 ? -secondsRate : secondsRate
|
|
1029
1058
|
}
|
|
1030
1059
|
|
|
1060
|
+
private static calcOiFundingFeeRate(model: ISLPOiFundingModel, longSize: number, shortSize: number, elapsed: number): number {
|
|
1061
|
+
const imbalance = Math.abs(longSize - shortSize)
|
|
1062
|
+
const denom = longSize + shortSize > 0 ? longSize + shortSize : 1
|
|
1063
|
+
|
|
1064
|
+
const dailyRate = Math.min(
|
|
1065
|
+
(model.multiplier * (imbalance ** model.exponent)) / denom,
|
|
1066
|
+
model.max,
|
|
1067
|
+
)
|
|
1068
|
+
const secondsRate = dailyRate * elapsed / SECONDS_PER_EIGHT_HOUR
|
|
1069
|
+
return longSize >= shortSize ? secondsRate : -secondsRate
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1031
1072
|
private static calculatePositionReserveFee(position: ISLPPositionInfo, vault: ISLPVaultInfo, model: ISLPReservingFeeModel, timestamp: number): number {
|
|
1032
1073
|
const accReservingRate = SLPDataAPI.calcAccReservingFeeRate(vault, model, timestamp)
|
|
1033
1074
|
return position.reservingFeeAmount + (accReservingRate - position.lastReservingRate) * position.collateralAmount
|
|
@@ -1112,6 +1153,21 @@ export class SLPDataAPI extends BaseDataAPI implements ISLPDataAPI {
|
|
|
1112
1153
|
}
|
|
1113
1154
|
}
|
|
1114
1155
|
|
|
1156
|
+
private static parseOiFundingState(raw: any): ISLPOiFundingState {
|
|
1157
|
+
const content = raw.data.content.fields
|
|
1158
|
+
return {
|
|
1159
|
+
id: content.id.id,
|
|
1160
|
+
enabled: content.enabled,
|
|
1161
|
+
last_update: parseValue(content.last_update),
|
|
1162
|
+
model: {
|
|
1163
|
+
id: content.model.fields.id.id,
|
|
1164
|
+
multiplier: parseValue(content.model.fields.multiplier),
|
|
1165
|
+
exponent: parseValue(content.model.fields.exponent),
|
|
1166
|
+
max: parseValue(content.model.fields.max),
|
|
1167
|
+
},
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1115
1171
|
private static parseMarketInfo(raw: any): ISLPMarketInfo {
|
|
1116
1172
|
const content = raw.data.content.fields
|
|
1117
1173
|
|
|
@@ -1236,6 +1292,11 @@ export class SLPDataAPI extends BaseDataAPI implements ISLPDataAPI {
|
|
|
1236
1292
|
(await this.getVaultInfo(positionInfo.collateralToken)).reservingFeeModel,
|
|
1237
1293
|
Date.now() / 1000,
|
|
1238
1294
|
)
|
|
1295
|
+
|
|
1296
|
+
// OI context for funding: fetch state and paired side size when enabled
|
|
1297
|
+
const oiState = await this.getSymbolOiFundingState(positionInfo.indexToken)
|
|
1298
|
+
const pairedSymbol = await this.getSymbolInfo(positionInfo.indexToken, !positionInfo.long)
|
|
1299
|
+
|
|
1239
1300
|
positionInfo.fundingFeeValue = SLPDataAPI.calculatePositionFundingFee(
|
|
1240
1301
|
positionInfo,
|
|
1241
1302
|
await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long),
|
|
@@ -1243,6 +1304,8 @@ export class SLPDataAPI extends BaseDataAPI implements ISLPDataAPI {
|
|
|
1243
1304
|
(await this.getOraclePrice(positionInfo.indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked(),
|
|
1244
1305
|
(await this.getMarketInfo()).lpSupplyWithDecimals,
|
|
1245
1306
|
Date.now() / 1000,
|
|
1307
|
+
oiState && oiState.enabled ? oiState.model : undefined,
|
|
1308
|
+
pairedSymbol.openingSize,
|
|
1246
1309
|
)
|
|
1247
1310
|
}
|
|
1248
1311
|
catch (e) {
|
package/src/interfaces/slp.ts
CHANGED
|
@@ -87,6 +87,20 @@ export interface ISLPSymbolConfig {
|
|
|
87
87
|
instant_exit_fee_config: ISLPPositionInstantExitFeeConfig
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
export interface ISLPOiFundingModel {
|
|
91
|
+
id: string
|
|
92
|
+
multiplier: number
|
|
93
|
+
exponent: number
|
|
94
|
+
max: number
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface ISLPOiFundingState {
|
|
98
|
+
id: string
|
|
99
|
+
enabled: boolean
|
|
100
|
+
last_update: number
|
|
101
|
+
model: ISLPOiFundingModel
|
|
102
|
+
}
|
|
103
|
+
|
|
90
104
|
// Sudo SDK specific data structures
|
|
91
105
|
export interface ISudoMarket {
|
|
92
106
|
lpSupply: bigint
|