@zofai/zo-sdk 0.2.29 → 0.2.31

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 (103) hide show
  1. package/dist/abstract/BaseAPI.cjs +3 -0
  2. package/dist/abstract/BaseAPI.cjs.map +1 -1
  3. package/dist/abstract/BaseAPI.d.cts +3 -2
  4. package/dist/abstract/BaseAPI.d.cts.map +1 -1
  5. package/dist/abstract/BaseAPI.d.mts +3 -2
  6. package/dist/abstract/BaseAPI.d.mts.map +1 -1
  7. package/dist/abstract/BaseAPI.mjs +3 -0
  8. package/dist/abstract/BaseAPI.mjs.map +1 -1
  9. package/dist/abstract/BaseDataAPI.cjs +48 -2
  10. package/dist/abstract/BaseDataAPI.cjs.map +1 -1
  11. package/dist/abstract/BaseDataAPI.d.cts +15 -2
  12. package/dist/abstract/BaseDataAPI.d.cts.map +1 -1
  13. package/dist/abstract/BaseDataAPI.d.mts +15 -2
  14. package/dist/abstract/BaseDataAPI.d.mts.map +1 -1
  15. package/dist/abstract/BaseDataAPI.mjs +48 -2
  16. package/dist/abstract/BaseDataAPI.mjs.map +1 -1
  17. package/dist/consts/deployments-zlp-mainnet.json +1 -1
  18. package/dist/consts/deployments-zo-oracle-mainnet.json +18 -1
  19. package/dist/data.cjs +19 -7
  20. package/dist/data.cjs.map +1 -1
  21. package/dist/data.d.cts.map +1 -1
  22. package/dist/data.d.mts.map +1 -1
  23. package/dist/data.mjs +19 -7
  24. package/dist/data.mjs.map +1 -1
  25. package/dist/implementations/SLPDataAPI.cjs +26 -8
  26. package/dist/implementations/SLPDataAPI.cjs.map +1 -1
  27. package/dist/implementations/SLPDataAPI.d.cts.map +1 -1
  28. package/dist/implementations/SLPDataAPI.d.mts.map +1 -1
  29. package/dist/implementations/SLPDataAPI.mjs +26 -8
  30. package/dist/implementations/SLPDataAPI.mjs.map +1 -1
  31. package/dist/implementations/USDZDataAPI.cjs +26 -8
  32. package/dist/implementations/USDZDataAPI.cjs.map +1 -1
  33. package/dist/implementations/USDZDataAPI.d.cts.map +1 -1
  34. package/dist/implementations/USDZDataAPI.d.mts.map +1 -1
  35. package/dist/implementations/USDZDataAPI.mjs +26 -8
  36. package/dist/implementations/USDZDataAPI.mjs.map +1 -1
  37. package/dist/implementations/ZBTCVCDataAPI.cjs +19 -7
  38. package/dist/implementations/ZBTCVCDataAPI.cjs.map +1 -1
  39. package/dist/implementations/ZBTCVCDataAPI.d.cts.map +1 -1
  40. package/dist/implementations/ZBTCVCDataAPI.d.mts.map +1 -1
  41. package/dist/implementations/ZBTCVCDataAPI.mjs +19 -7
  42. package/dist/implementations/ZBTCVCDataAPI.mjs.map +1 -1
  43. package/dist/implementations/ZLPAPI.cjs +456 -123
  44. package/dist/implementations/ZLPAPI.cjs.map +1 -1
  45. package/dist/implementations/ZLPAPI.d.cts +46 -1
  46. package/dist/implementations/ZLPAPI.d.cts.map +1 -1
  47. package/dist/implementations/ZLPAPI.d.mts +46 -1
  48. package/dist/implementations/ZLPAPI.d.mts.map +1 -1
  49. package/dist/implementations/ZLPAPI.mjs +457 -124
  50. package/dist/implementations/ZLPAPI.mjs.map +1 -1
  51. package/dist/implementations/ZLPDataAPI.cjs +64 -8
  52. package/dist/implementations/ZLPDataAPI.cjs.map +1 -1
  53. package/dist/implementations/ZLPDataAPI.d.cts +16 -0
  54. package/dist/implementations/ZLPDataAPI.d.cts.map +1 -1
  55. package/dist/implementations/ZLPDataAPI.d.mts +16 -0
  56. package/dist/implementations/ZLPDataAPI.d.mts.map +1 -1
  57. package/dist/implementations/ZLPDataAPI.mjs +64 -8
  58. package/dist/implementations/ZLPDataAPI.mjs.map +1 -1
  59. package/dist/index.cjs +1 -0
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.d.cts +2 -0
  62. package/dist/index.d.cts.map +1 -1
  63. package/dist/index.d.mts +2 -0
  64. package/dist/index.d.mts.map +1 -1
  65. package/dist/index.mjs +1 -0
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/interfaces/base.d.cts +14 -1
  68. package/dist/interfaces/base.d.cts.map +1 -1
  69. package/dist/interfaces/base.d.mts +14 -1
  70. package/dist/interfaces/base.d.mts.map +1 -1
  71. package/dist/interfaces/zlp.d.cts +19 -0
  72. package/dist/interfaces/zlp.d.cts.map +1 -1
  73. package/dist/interfaces/zlp.d.mts +19 -0
  74. package/dist/interfaces/zlp.d.mts.map +1 -1
  75. package/dist/traderPositions.cjs +130 -0
  76. package/dist/traderPositions.cjs.map +1 -0
  77. package/dist/traderPositions.d.cts +72 -0
  78. package/dist/traderPositions.d.cts.map +1 -0
  79. package/dist/traderPositions.d.mts +72 -0
  80. package/dist/traderPositions.d.mts.map +1 -0
  81. package/dist/traderPositions.mjs +124 -0
  82. package/dist/traderPositions.mjs.map +1 -0
  83. package/docs/api-reference.md +45 -0
  84. package/docs/architecture.md +21 -3
  85. package/docs/common-operations.md +56 -8
  86. package/docs/getting-started.md +8 -3
  87. package/docs/lp-specific-features.md +89 -12
  88. package/docs/swap-integration.md +52 -20
  89. package/package.json +1 -1
  90. package/src/abstract/BaseAPI.ts +6 -2
  91. package/src/abstract/BaseDataAPI.ts +67 -3
  92. package/src/consts/deployments-zlp-mainnet.json +1 -1
  93. package/src/consts/deployments-zo-oracle-mainnet.json +18 -1
  94. package/src/data.ts +19 -7
  95. package/src/implementations/SLPDataAPI.ts +34 -16
  96. package/src/implementations/USDZDataAPI.ts +32 -14
  97. package/src/implementations/ZBTCVCDataAPI.ts +23 -11
  98. package/src/implementations/ZLPAPI.ts +760 -151
  99. package/src/implementations/ZLPDataAPI.ts +79 -14
  100. package/src/index.ts +2 -0
  101. package/src/interfaces/base.ts +15 -1
  102. package/src/interfaces/zlp.ts +170 -0
  103. package/src/traderPositions.ts +218 -0
@@ -35,6 +35,8 @@ import type {
35
35
  IZLPSymbolInfo,
36
36
  IZLPVaultInfo,
37
37
  } from '../interfaces'
38
+ import type { OracleInputs } from '../oraclePro'
39
+ import { valuateSymbolsV2, valuateVaultsV2 } from '../oraclePro'
38
40
  import type { DynamicFieldInfo, SuiClient } from '../suiClient'
39
41
  import { joinSymbol, parseSymbolKey, parseValue, suiSymbolToSymbol } from '../utils'
40
42
 
@@ -204,6 +206,46 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
204
206
  return { vaultsValuation, symbolsValuation }
205
207
  }
206
208
 
209
+ /**
210
+ * Creates vaults valuation using valuate_vault_v2 (Pyth Pro + Stork).
211
+ */
212
+ public valuateVaultsV2(tx: Transaction, oracle: OracleInputs) {
213
+ return valuateVaultsV2({
214
+ tx,
215
+ upgradedPackage: this.consts.zoCore.upgradedPackage,
216
+ lpType: `${this.consts.zoCore.package}::zlp::ZLP`,
217
+ market: this.consts.zoCore.market,
218
+ vaults: this.consts.zoCore.vaults,
219
+ coinModules: this.consts.coins,
220
+ oracle,
221
+ })
222
+ }
223
+
224
+ /**
225
+ * Creates symbols valuation using valuate_symbol_v2 (Pyth Pro + Stork).
226
+ */
227
+ public valuateSymbolsV2(tx: Transaction, oracle: OracleInputs) {
228
+ return valuateSymbolsV2({
229
+ tx,
230
+ upgradedPackage: this.consts.zoCore.upgradedPackage,
231
+ marketPackage: this.consts.zoCore.package,
232
+ lpType: `${this.consts.zoCore.package}::zlp::ZLP`,
233
+ market: this.consts.zoCore.market,
234
+ symbols: this.consts.zoCore.symbols,
235
+ coinModules: this.consts.coins,
236
+ oracle,
237
+ })
238
+ }
239
+
240
+ /**
241
+ * Creates both vaults and symbols valuation (Pyth Pro + Stork).
242
+ */
243
+ public valuateV2(tx: Transaction, oracle: OracleInputs) {
244
+ const vaultsValuation = this.valuateVaultsV2(tx, oracle)
245
+ const symbolsValuation = this.valuateSymbolsV2(tx, oracle)
246
+ return { vaultsValuation, symbolsValuation }
247
+ }
248
+
207
249
  /**
208
250
  * Valuates the ZLP market
209
251
  */
@@ -265,7 +307,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
265
307
  public async getMarketInfo(): Promise<IZLPMarketInfo> {
266
308
  this.validateCache()
267
309
  if (this.marketInfoCache) {
268
- return this.marketInfoCache
310
+ return this.marketInfoCache as IZLPMarketInfo
269
311
  }
270
312
  const rawData = await this.provider.getObject({
271
313
  id: this.consts.zoCore.market,
@@ -273,7 +315,9 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
273
315
  showContent: true,
274
316
  },
275
317
  })
276
- return ZLPDataAPI.parseMarketInfo(rawData)
318
+ const info = ZLPDataAPI.parseMarketInfo(rawData)
319
+ this.marketInfoCache = info
320
+ return info
277
321
  }
278
322
 
279
323
  /**
@@ -282,7 +326,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
282
326
  public async getVaultInfo(vaultToken: string): Promise<IZLPVaultInfo> {
283
327
  this.validateCache()
284
328
  if (this.vaultInfoCache[vaultToken]) {
285
- return this.vaultInfoCache[vaultToken]
329
+ return this.vaultInfoCache[vaultToken] as IZLPVaultInfo
286
330
  }
287
331
 
288
332
  const rawData = await this.provider.getDynamicFieldObject({
@@ -292,7 +336,9 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
292
336
  value: { dummy_field: false },
293
337
  },
294
338
  })
295
- return await this.parseVaultInfo(rawData)
339
+ const info = await this.parseVaultInfo(rawData)
340
+ this.vaultInfoCache[vaultToken] = info
341
+ return info
296
342
  }
297
343
 
298
344
  /**
@@ -302,7 +348,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
302
348
  this.validateCache()
303
349
  const symbol = joinSymbol(long ? 'long' : 'short', indexToken)
304
350
  if (this.symbolInfoCache[symbol]) {
305
- return this.symbolInfoCache[symbol]
351
+ return this.symbolInfoCache[symbol] as IZLPSymbolInfo
306
352
  }
307
353
  const rawData = await this.provider.getDynamicFieldObject({
308
354
  parentId: this.consts.zoCore.symbolsParent,
@@ -311,14 +357,16 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
311
357
  value: { dummy_field: false },
312
358
  },
313
359
  })
314
- return await this.parseSymbolInfo(rawData, long)
360
+ const info = await this.parseSymbolInfo(rawData, long)
361
+ this.symbolInfoCache[symbol] = info
362
+ return info
315
363
  }
316
364
 
317
365
  public async getPositionConfig(indexToken: string, long: boolean): Promise<IZLPPositionConfig> {
318
366
  this.validateCache()
319
367
  const symbol = joinSymbol(long ? 'long' : 'short', indexToken)
320
368
  if (this.positionConfigCache[symbol]) {
321
- return this.positionConfigCache[symbol]
369
+ return this.positionConfigCache[symbol] as IZLPPositionConfig
322
370
  }
323
371
  const rawData = await this.provider.getObject({
324
372
  id: this.consts.zoCore.symbols[symbol].positionConfig,
@@ -326,7 +374,9 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
326
374
  showContent: true,
327
375
  },
328
376
  })
329
- return ZLPDataAPI.parsePositionConfig(rawData)
377
+ const info = ZLPDataAPI.parsePositionConfig(rawData)
378
+ this.positionConfigCache[symbol] = info
379
+ return info
330
380
  }
331
381
 
332
382
  /**
@@ -356,6 +406,9 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
356
406
  */
357
407
  public async getSymbolOiFundingState(indexToken: string): Promise<IZLPOiFundingState | null> {
358
408
  this.validateCache()
409
+ if (Object.prototype.hasOwnProperty.call(this.oiFundingStateCache, indexToken)) {
410
+ return this.oiFundingStateCache[indexToken] as IZLPOiFundingState | null
411
+ }
359
412
  try {
360
413
  const rawData = await this.provider.getDynamicFieldObject({
361
414
  parentId: this.consts.zoCore.market,
@@ -364,11 +417,14 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
364
417
  value: { dummy_field: false },
365
418
  },
366
419
  })
367
- return ZLPDataAPI.parseOiFundingState(rawData)
420
+ const info = ZLPDataAPI.parseOiFundingState(rawData)
421
+ this.oiFundingStateCache[indexToken] = info
422
+ return info
368
423
  }
369
424
  catch (e: any) {
370
425
  // If the dynamic field doesn't exist, return null
371
426
  console.error('Error Fetching Symbol OI Funding State:', e)
427
+ this.oiFundingStateCache[indexToken] = null
372
428
  return null
373
429
  }
374
430
  }
@@ -797,7 +853,7 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
797
853
  public async getRebaseFeeModel(): Promise<IZLPRebaseFeeModel> {
798
854
  this.validateCache()
799
855
  if (this.rebaseFeeModelCache) {
800
- return this.rebaseFeeModelCache
856
+ return this.rebaseFeeModelCache as IZLPRebaseFeeModel
801
857
  }
802
858
  const rawData = await this.provider.getObject({
803
859
  id: this.consts.zoCore.rebaseFeeModel,
@@ -811,7 +867,9 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
811
867
  this.consts.zoCore.rebaseFeeModel,
812
868
  this.consts.zoCore.upgradedPackage,
813
869
  )
814
- return { ...model, exponent }
870
+ const info = { ...model, exponent }
871
+ this.rebaseFeeModelCache = info
872
+ return info
815
873
  }
816
874
 
817
875
  public async fundingFeeRate(indexToken: string, long: boolean): Promise<number> {
@@ -1204,14 +1262,21 @@ export class ZLPDataAPI extends BaseDataAPI implements IZLPDataAPI {
1204
1262
  openTimestamp: parseValue(positionFields.open_timestamp),
1205
1263
  }
1206
1264
 
1207
- positionInfo.reservingFeeAmount = ZLPDataAPI.calculatePositionReserveFee(positionInfo, await this.getVaultInfo(positionInfo.collateralToken), (await this.getVaultInfo(positionInfo.collateralToken)).reservingFeeModel, Date.now() / 1000)
1265
+ const vaultInfo = await this.getVaultInfo(positionInfo.collateralToken)
1266
+ positionInfo.reservingFeeAmount = ZLPDataAPI.calculatePositionReserveFee(
1267
+ positionInfo,
1268
+ vaultInfo,
1269
+ vaultInfo.reservingFeeModel,
1270
+ Date.now() / 1000,
1271
+ )
1208
1272
  // OI context for funding: fetch state and paired side size when enabled
1209
1273
  const oiState = await this.getSymbolOiFundingState(positionInfo.indexToken)
1210
1274
  const pairedSymbol = await this.getSymbolInfo(positionInfo.indexToken, !positionInfo.long)
1275
+ const symbolInfo = await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long)
1211
1276
  const computedFundingFeeValue = ZLPDataAPI.calculatePositionFundingFee(
1212
1277
  positionInfo,
1213
- await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long),
1214
- (await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long)).fundingFeeModel,
1278
+ symbolInfo,
1279
+ symbolInfo.fundingFeeModel,
1215
1280
  (await this.getOraclePrice(positionInfo.indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked(),
1216
1281
  (await this.getMarketInfo()).lpSupplyWithDecimals,
1217
1282
  Date.now() / 1000,
package/src/index.ts CHANGED
@@ -30,8 +30,10 @@ export * from './consts'
30
30
  export * from './data'
31
31
  export * from './oracle'
32
32
  export * from './oraclePro'
33
+ export type { PythProChannel } from './pythProClient'
33
34
  export * from './storkClient'
34
35
  export * from './storkOracle'
36
+ export * from './traderPositions'
35
37
  export * from './utils'
36
38
 
37
39
  // Re-export commonly used types from Sui SDK
@@ -196,6 +196,15 @@ export interface IBasePositionCapInfo {
196
196
  long: boolean
197
197
  }
198
198
 
199
+ export interface IGetTraderOpenPositionsOptions {
200
+ indexToken?: string
201
+ collateralToken?: string
202
+ /** RPC batch size for getPositionInfoList (default 10). */
203
+ batchSize?: number
204
+ /** Max OPEN rows to load from the API (default: all pages). */
205
+ limit?: number
206
+ }
207
+
199
208
  export interface IBaseOrderCapInfo {
200
209
  orderCapId: string
201
210
  symbol0: string
@@ -291,6 +300,11 @@ export interface IBaseDataAPI {
291
300
  // User data methods
292
301
  getPositionCapInfoList: (owner: string) => Promise<IBasePositionCapInfo[]>
293
302
  getPositionInfoList: (positionCapInfoList: IBasePositionCapInfo[], owner: string, batchSize?: number) => Promise<IBasePositionInfo[]>
303
+ /**
304
+ * Fetch OPEN positions from zo API `/trader-positions`, then hydrate live details via RPC.
305
+ * Skips on-chain PositionCap discovery; uses indexed position ids + symbol metadata.
306
+ */
307
+ getTraderOpenPositionInfoList: (owner: string, options?: IGetTraderOpenPositionsOptions) => Promise<IBasePositionInfo[]>
294
308
  getOrderCapInfoList: (owner: string) => Promise<IBaseOrderCapInfo[]>
295
309
  getOrderInfoList: (orderCapInfoList: IBaseOrderCapInfo[], owner: string, batchSize?: number) => Promise<IBaseOrderInfo[]>
296
310
  getHistory: (trader: string, page: number, limit: number, orderType?: string, symbol?: string) => Promise<IBaseHistoryResponse>
@@ -330,7 +344,7 @@ export interface IBaseDataAPI {
330
344
 
331
345
  resolveStorkAssetsForTokens: (tokens: string[]) => string[]
332
346
 
333
- fetchStorkUpdateDataForTokens: (tokens: string[]) => Promise<import('../storkClient').IStorkUpdateData[]>
347
+ fetchStorkUpdateDataForTokens: (tokens: string[]) => Promise<Array<import('../storkClient').IStorkUpdateData>>
334
348
 
335
349
  estimateStorkUpdateFeeForTokens: (tokens: string[]) => bigint
336
350
 
@@ -5,6 +5,7 @@
5
5
 
6
6
  import type { Transaction, TransactionObjectArgument } from '@mysten/sui/transactions'
7
7
 
8
+ import type { OracleInputs } from '../oraclePro'
8
9
  import type {
9
10
  IBaseAPI,
10
11
  IBaseCredential,
@@ -139,6 +140,9 @@ export interface IZLPDataAPI extends IBaseDataAPI {
139
140
  getSymbolConfig: (indexToken: string, long: boolean) => Promise<IZLPSymbolConfig | null>
140
141
  getPriceImpactConfig: (indexToken: string) => Promise<IZLPPriceImpactConfig | null>
141
142
  calculateSwapFeeBreakdown: (fromToken: string, toToken: string, fromAmount: number) => Promise<ISwapFeeBreakdown>
143
+ valuateVaultsV2: (tx: Transaction, oracle: OracleInputs) => TransactionObjectArgument
144
+ valuateSymbolsV2: (tx: Transaction, oracle: OracleInputs) => TransactionObjectArgument
145
+ valuateV2: (tx: Transaction, oracle: OracleInputs) => { vaultsValuation: TransactionObjectArgument, symbolsValuation: TransactionObjectArgument }
142
146
  }
143
147
 
144
148
  // ZLP-specific API interface
@@ -262,4 +266,170 @@ export interface IZLPAPI extends IBaseAPI {
262
266
  minAmountOut?: number,
263
267
  tx?: Transaction,
264
268
  ) => Promise<TransactionObjectArgument>
269
+
270
+ /** Pyth Pro + Stork swap (transfers output). */
271
+ swapV3: (
272
+ fromToken: string,
273
+ toToken: string,
274
+ fromAmount: bigint,
275
+ fromCoinObjects: string[],
276
+ pythProUpdateBytes: Uint8Array | number[],
277
+ minAmountOut?: number,
278
+ tx?: Transaction,
279
+ ) => Promise<Transaction>
280
+
281
+ /** Pyth Pro + Stork swap PTB (returns output coin). */
282
+ swapV3Ptb: (
283
+ fromToken: string,
284
+ toToken: string,
285
+ fromAmount: bigint,
286
+ fromCoinObjects: string[],
287
+ pythProUpdateBytes: Uint8Array | number[],
288
+ minAmountOut?: number,
289
+ tx?: Transaction,
290
+ ) => Promise<TransactionObjectArgument>
291
+
292
+ openPositionV3: (
293
+ collateralToken: string,
294
+ indexToken: string,
295
+ size: bigint,
296
+ collateralAmount: bigint,
297
+ coinObjects: string[],
298
+ long: boolean,
299
+ reserveAmount: bigint,
300
+ indexPrice: number,
301
+ collateralPrice: number,
302
+ pythProUpdateBytes: Uint8Array | number[],
303
+ isLimitOrder?: boolean,
304
+ isIocOrder?: boolean,
305
+ pricesSlippage?: number,
306
+ collateralSlippage?: number,
307
+ relayerFee?: bigint,
308
+ referralAddress?: string,
309
+ sender?: string,
310
+ sponsoredTx?: boolean,
311
+ ) => Promise<Transaction>
312
+
313
+ openPositionWithSCardV3: (
314
+ collateralToken: string,
315
+ indexToken: string,
316
+ size: bigint,
317
+ collateralAmount: bigint,
318
+ coinObjects: string[],
319
+ long: boolean,
320
+ reserveAmount: bigint,
321
+ indexPrice: number,
322
+ collateralPrice: number,
323
+ kioskClient: import('@mysten/kiosk').KioskClient,
324
+ kioskCap: import('@mysten/kiosk').KioskOwnerCap,
325
+ scard: string,
326
+ pythProUpdateBytes: Uint8Array | number[],
327
+ isLimitOrder?: boolean,
328
+ isIocOrder?: boolean,
329
+ pricesSlippage?: number,
330
+ collateralSlippage?: number,
331
+ relayerFee?: bigint,
332
+ referralAddress?: string,
333
+ sender?: string,
334
+ sponsoredTx?: boolean,
335
+ ) => Promise<Transaction>
336
+
337
+ openPositionWithCoinV3: (
338
+ collateralToken: string,
339
+ indexToken: string,
340
+ size: bigint,
341
+ coinObj: TransactionObjectArgument,
342
+ long: boolean,
343
+ reserveAmount: bigint,
344
+ indexPrice: number,
345
+ collateralPrice: number,
346
+ pythProUpdateBytes: Uint8Array | number[],
347
+ isLimitOrder?: boolean,
348
+ isIocOrder?: boolean,
349
+ pricesSlippage?: number,
350
+ collateralSlippage?: number,
351
+ relayerFee?: bigint,
352
+ referralAddress?: string,
353
+ sender?: string,
354
+ tx?: Transaction,
355
+ sponsoredTx?: boolean,
356
+ ) => Promise<Transaction>
357
+
358
+ openPositionWithCoinAndSCardV3: (
359
+ collateralToken: string,
360
+ indexToken: string,
361
+ size: bigint,
362
+ coinObj: TransactionObjectArgument,
363
+ long: boolean,
364
+ reserveAmount: bigint,
365
+ indexPrice: number,
366
+ collateralPrice: number,
367
+ kioskClient: import('@mysten/kiosk').KioskClient,
368
+ kioskCap: import('@mysten/kiosk').KioskOwnerCap,
369
+ scard: string,
370
+ pythProUpdateBytes: Uint8Array | number[],
371
+ isLimitOrder?: boolean,
372
+ isIocOrder?: boolean,
373
+ pricesSlippage?: number,
374
+ collateralSlippage?: number,
375
+ relayerFee?: bigint,
376
+ referralAddress?: string,
377
+ sender?: string,
378
+ tx?: Transaction,
379
+ sponsoredTx?: boolean,
380
+ ) => Promise<Transaction>
381
+
382
+ decreasePositionV3: (
383
+ pcpId: string,
384
+ collateralToken: string,
385
+ indexToken: string,
386
+ amount: bigint,
387
+ long: boolean,
388
+ indexPrice: number,
389
+ collateralPrice: number,
390
+ pythProUpdateBytes: Uint8Array | number[],
391
+ isTriggerOrder?: boolean,
392
+ isTakeProfitOrder?: boolean,
393
+ isIocOrder?: boolean,
394
+ pricesSlippage?: number,
395
+ collateralSlippage?: number,
396
+ relayerFee?: bigint,
397
+ coinObjects?: string[],
398
+ sponsoredTx?: boolean,
399
+ sender?: string,
400
+ ) => Promise<Transaction>
401
+
402
+ decreasePositionWithSCardV3: (
403
+ pcpId: string,
404
+ collateralToken: string,
405
+ indexToken: string,
406
+ amount: bigint,
407
+ long: boolean,
408
+ indexPrice: number,
409
+ collateralPrice: number,
410
+ kioskClient: import('@mysten/kiosk').KioskClient,
411
+ kioskCap: import('@mysten/kiosk').KioskOwnerCap,
412
+ scard: string,
413
+ pythProUpdateBytes: Uint8Array | number[],
414
+ isTriggerOrder?: boolean,
415
+ isTakeProfitOrder?: boolean,
416
+ isIocOrder?: boolean,
417
+ pricesSlippage?: number,
418
+ collateralSlippage?: number,
419
+ relayerFee?: bigint,
420
+ coinObjects?: string[],
421
+ sponsoredTx?: boolean,
422
+ sender?: string,
423
+ ) => Promise<Transaction>
424
+
425
+ /** Pyth Pro path (not legacy feeder v2). */
426
+ redeemFromPositionV2: (
427
+ pcpId: string,
428
+ collateralToken: string,
429
+ indexToken: string,
430
+ amount: number,
431
+ long: boolean,
432
+ pythProUpdateBytes: Uint8Array | number[],
433
+ tx?: Transaction,
434
+ ) => Promise<Transaction>
265
435
  }
@@ -0,0 +1,218 @@
1
+ import type { IConsts } from './consts'
2
+ import type { IBasePositionCapInfo } from './interfaces'
3
+
4
+ export type TraderPositionStatus = 'OPEN' | 'CLOSED' | 'LIQUIDATED' | 'UNKNOWN'
5
+
6
+ /** Row shape from GET /trader-positions (zo API). */
7
+ export interface ITraderPositionRecord {
8
+ positionId: string
9
+ owner: string
10
+ address: string
11
+ chain?: string
12
+ pool?: string | null
13
+ collateralToken?: string | null
14
+ indexToken?: string | null
15
+ direction?: string | null
16
+ status: TraderPositionStatus
17
+ closed?: boolean | null
18
+ openedAt?: string | null
19
+ closedAt?: string | null
20
+ updatedAt?: string
21
+ lastOrderId?: string | null
22
+ lastEventName?: string | null
23
+ lastTxDigest?: string | null
24
+ lastEventSeq?: string | null
25
+ positionNameType?: string | null
26
+ openAmount?: string | null
27
+ decreaseAmount?: string | null
28
+ collateralAmount?: string | null
29
+ reserveAmount?: string | null
30
+ positionSize?: string | null
31
+ settledAmount?: string | null
32
+ collateralPrice?: number | null
33
+ indexPrice?: number | null
34
+ pnl?: number | null
35
+ }
36
+
37
+ export interface ITraderPositionsPagination {
38
+ total: number
39
+ limit: number
40
+ offset: number
41
+ }
42
+
43
+ export interface ITraderPositionsQuery {
44
+ owner: string
45
+ status?: TraderPositionStatus
46
+ indexToken?: string
47
+ collateralToken?: string
48
+ limit?: number
49
+ offset?: number
50
+ }
51
+
52
+ export interface ITraderPositionsApiResponse {
53
+ success: boolean
54
+ data?: {
55
+ positions: ITraderPositionRecord[]
56
+ pagination: ITraderPositionsPagination
57
+ }
58
+ error?: string
59
+ message?: string
60
+ }
61
+
62
+ const DEFAULT_PAGE_LIMIT = 200
63
+
64
+ /**
65
+ * Parse `PositionName<collateral, index, LONG|SHORT>` from a Move type string.
66
+ */
67
+ export function parsePositionNameType(positionNameType: string): {
68
+ symbol0: string
69
+ symbol1: string
70
+ long: boolean
71
+ } | null {
72
+ const marker = 'PositionName<'
73
+ const start = positionNameType.indexOf(marker)
74
+ if (start < 0) {
75
+ return null
76
+ }
77
+ const inner = positionNameType.slice(start + marker.length).split('>')[0]
78
+ if (!inner) {
79
+ return null
80
+ }
81
+ const parts = inner.split(',').map(part => part.trim())
82
+ if (parts.length < 3) {
83
+ return null
84
+ }
85
+ return {
86
+ symbol0: parts[0],
87
+ symbol1: parts[1],
88
+ long: parts[2].includes('LONG'),
89
+ }
90
+ }
91
+
92
+ function tokenKeyToMoveType(tokenKey: string, consts: IConsts): string | null {
93
+ const key = tokenKey.toLowerCase()
94
+ if (key === 'sui') {
95
+ return '0x2::sui::SUI'
96
+ }
97
+ const coin = consts.coins[key]
98
+ return coin?.module ?? null
99
+ }
100
+
101
+ /** Map an indexed trader position row to PositionCap lookup fields for on-chain hydration. */
102
+ export function traderPositionToCapInfo(
103
+ record: ITraderPositionRecord,
104
+ consts: IConsts,
105
+ ): IBasePositionCapInfo | null {
106
+ if (!record.positionId) {
107
+ return null
108
+ }
109
+
110
+ const fromType = record.positionNameType
111
+ ? parsePositionNameType(record.positionNameType)
112
+ : null
113
+ if (fromType) {
114
+ return {
115
+ positionCapId: record.positionId,
116
+ symbol0: fromType.symbol0,
117
+ symbol1: fromType.symbol1,
118
+ long: fromType.long,
119
+ }
120
+ }
121
+
122
+ const collateral = record.collateralToken?.trim().toLowerCase()
123
+ const index = record.indexToken?.trim().toLowerCase()
124
+ if (!collateral || !index) {
125
+ return null
126
+ }
127
+
128
+ const symbol0 = tokenKeyToMoveType(collateral, consts)
129
+ const symbol1 = tokenKeyToMoveType(index, consts)
130
+ if (!symbol0 || !symbol1) {
131
+ return null
132
+ }
133
+
134
+ return {
135
+ positionCapId: record.positionId,
136
+ symbol0,
137
+ symbol1,
138
+ long: (record.direction?.toUpperCase() ?? 'LONG') === 'LONG',
139
+ }
140
+ }
141
+
142
+ export async function fetchTraderPositionsPage(
143
+ apiEndpoint: string,
144
+ query: ITraderPositionsQuery,
145
+ ): Promise<{ positions: ITraderPositionRecord[], pagination: ITraderPositionsPagination }> {
146
+ if (!apiEndpoint) {
147
+ throw new Error('apiEndpoint is required to fetch trader positions')
148
+ }
149
+
150
+ const params = new URLSearchParams({
151
+ owner: query.owner.trim().toLowerCase(),
152
+ })
153
+ if (query.status) {
154
+ params.set('status', query.status)
155
+ }
156
+ if (query.indexToken) {
157
+ params.set('indexToken', query.indexToken.trim().toLowerCase())
158
+ }
159
+ if (query.collateralToken) {
160
+ params.set('collateralToken', query.collateralToken.trim().toLowerCase())
161
+ }
162
+ if (query.limit != null) {
163
+ params.set('limit', String(query.limit))
164
+ }
165
+ if (query.offset != null) {
166
+ params.set('offset', String(query.offset))
167
+ }
168
+
169
+ const url = `${apiEndpoint.replace(/\/$/, '')}/trader-positions?${params}`
170
+ const res = await fetch(url, {
171
+ method: 'GET',
172
+ headers: { 'Content-Type': 'application/json' },
173
+ })
174
+
175
+ const body = await res.json() as ITraderPositionsApiResponse
176
+ if (!res.ok || !body.success || !body.data) {
177
+ throw new Error(
178
+ body.error || body.message || `Failed to fetch trader positions (${res.status})`,
179
+ )
180
+ }
181
+
182
+ return body.data
183
+ }
184
+
185
+ /** Fetch all pages matching the query (respects optional total `limit`). */
186
+ export async function fetchAllTraderPositions(
187
+ apiEndpoint: string,
188
+ query: Omit<ITraderPositionsQuery, 'limit' | 'offset'>,
189
+ maxRows?: number,
190
+ ): Promise<ITraderPositionRecord[]> {
191
+ const rows: ITraderPositionRecord[] = []
192
+ let offset = 0
193
+ let total = Number.POSITIVE_INFINITY
194
+
195
+ while (offset < total) {
196
+ const remaining = maxRows != null ? maxRows - rows.length : DEFAULT_PAGE_LIMIT
197
+ if (remaining <= 0) {
198
+ break
199
+ }
200
+
201
+ const pageLimit = Math.min(DEFAULT_PAGE_LIMIT, remaining)
202
+ const { positions, pagination } = await fetchTraderPositionsPage(apiEndpoint, {
203
+ ...query,
204
+ limit: pageLimit,
205
+ offset,
206
+ })
207
+
208
+ rows.push(...positions)
209
+ total = pagination.total
210
+ offset += positions.length
211
+
212
+ if (positions.length === 0 || offset >= total) {
213
+ break
214
+ }
215
+ }
216
+
217
+ return maxRows != null ? rows.slice(0, maxRows) : rows
218
+ }