@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.
- package/dist/abstract/BaseAPI.cjs +3 -0
- package/dist/abstract/BaseAPI.cjs.map +1 -1
- package/dist/abstract/BaseAPI.d.cts +3 -2
- package/dist/abstract/BaseAPI.d.cts.map +1 -1
- package/dist/abstract/BaseAPI.d.mts +3 -2
- package/dist/abstract/BaseAPI.d.mts.map +1 -1
- package/dist/abstract/BaseAPI.mjs +3 -0
- package/dist/abstract/BaseAPI.mjs.map +1 -1
- package/dist/abstract/BaseDataAPI.cjs +48 -2
- package/dist/abstract/BaseDataAPI.cjs.map +1 -1
- package/dist/abstract/BaseDataAPI.d.cts +15 -2
- package/dist/abstract/BaseDataAPI.d.cts.map +1 -1
- package/dist/abstract/BaseDataAPI.d.mts +15 -2
- package/dist/abstract/BaseDataAPI.d.mts.map +1 -1
- package/dist/abstract/BaseDataAPI.mjs +48 -2
- package/dist/abstract/BaseDataAPI.mjs.map +1 -1
- package/dist/consts/deployments-zlp-mainnet.json +1 -1
- package/dist/consts/deployments-zo-oracle-mainnet.json +18 -1
- package/dist/data.cjs +19 -7
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.cts.map +1 -1
- package/dist/data.d.mts.map +1 -1
- package/dist/data.mjs +19 -7
- package/dist/data.mjs.map +1 -1
- package/dist/implementations/SLPDataAPI.cjs +26 -8
- package/dist/implementations/SLPDataAPI.cjs.map +1 -1
- package/dist/implementations/SLPDataAPI.d.cts.map +1 -1
- package/dist/implementations/SLPDataAPI.d.mts.map +1 -1
- package/dist/implementations/SLPDataAPI.mjs +26 -8
- package/dist/implementations/SLPDataAPI.mjs.map +1 -1
- package/dist/implementations/USDZDataAPI.cjs +26 -8
- package/dist/implementations/USDZDataAPI.cjs.map +1 -1
- package/dist/implementations/USDZDataAPI.d.cts.map +1 -1
- package/dist/implementations/USDZDataAPI.d.mts.map +1 -1
- package/dist/implementations/USDZDataAPI.mjs +26 -8
- package/dist/implementations/USDZDataAPI.mjs.map +1 -1
- package/dist/implementations/ZBTCVCDataAPI.cjs +19 -7
- package/dist/implementations/ZBTCVCDataAPI.cjs.map +1 -1
- package/dist/implementations/ZBTCVCDataAPI.d.cts.map +1 -1
- package/dist/implementations/ZBTCVCDataAPI.d.mts.map +1 -1
- package/dist/implementations/ZBTCVCDataAPI.mjs +19 -7
- package/dist/implementations/ZBTCVCDataAPI.mjs.map +1 -1
- package/dist/implementations/ZLPAPI.cjs +456 -123
- package/dist/implementations/ZLPAPI.cjs.map +1 -1
- package/dist/implementations/ZLPAPI.d.cts +46 -1
- package/dist/implementations/ZLPAPI.d.cts.map +1 -1
- package/dist/implementations/ZLPAPI.d.mts +46 -1
- package/dist/implementations/ZLPAPI.d.mts.map +1 -1
- package/dist/implementations/ZLPAPI.mjs +457 -124
- package/dist/implementations/ZLPAPI.mjs.map +1 -1
- package/dist/implementations/ZLPDataAPI.cjs +64 -8
- package/dist/implementations/ZLPDataAPI.cjs.map +1 -1
- package/dist/implementations/ZLPDataAPI.d.cts +16 -0
- package/dist/implementations/ZLPDataAPI.d.cts.map +1 -1
- package/dist/implementations/ZLPDataAPI.d.mts +16 -0
- package/dist/implementations/ZLPDataAPI.d.mts.map +1 -1
- package/dist/implementations/ZLPDataAPI.mjs +64 -8
- package/dist/implementations/ZLPDataAPI.mjs.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/interfaces/base.d.cts +14 -1
- package/dist/interfaces/base.d.cts.map +1 -1
- package/dist/interfaces/base.d.mts +14 -1
- package/dist/interfaces/base.d.mts.map +1 -1
- package/dist/interfaces/zlp.d.cts +19 -0
- package/dist/interfaces/zlp.d.cts.map +1 -1
- package/dist/interfaces/zlp.d.mts +19 -0
- package/dist/interfaces/zlp.d.mts.map +1 -1
- package/dist/traderPositions.cjs +130 -0
- package/dist/traderPositions.cjs.map +1 -0
- package/dist/traderPositions.d.cts +72 -0
- package/dist/traderPositions.d.cts.map +1 -0
- package/dist/traderPositions.d.mts +72 -0
- package/dist/traderPositions.d.mts.map +1 -0
- package/dist/traderPositions.mjs +124 -0
- package/dist/traderPositions.mjs.map +1 -0
- package/docs/api-reference.md +45 -0
- package/docs/architecture.md +21 -3
- package/docs/common-operations.md +56 -8
- package/docs/getting-started.md +8 -3
- package/docs/lp-specific-features.md +89 -12
- package/docs/swap-integration.md +52 -20
- package/package.json +1 -1
- package/src/abstract/BaseAPI.ts +6 -2
- package/src/abstract/BaseDataAPI.ts +67 -3
- package/src/consts/deployments-zlp-mainnet.json +1 -1
- package/src/consts/deployments-zo-oracle-mainnet.json +18 -1
- package/src/data.ts +19 -7
- package/src/implementations/SLPDataAPI.ts +34 -16
- package/src/implementations/USDZDataAPI.ts +32 -14
- package/src/implementations/ZBTCVCDataAPI.ts +23 -11
- package/src/implementations/ZLPAPI.ts +760 -151
- package/src/implementations/ZLPDataAPI.ts +79 -14
- package/src/index.ts +2 -0
- package/src/interfaces/base.ts +15 -1
- package/src/interfaces/zlp.ts +170 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1214
|
-
|
|
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
|
package/src/interfaces/base.ts
CHANGED
|
@@ -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
|
|
package/src/interfaces/zlp.ts
CHANGED
|
@@ -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
|
+
}
|