@lifi/perps-sdk 13.0.0 → 14.0.0

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 (115) hide show
  1. package/README.md +7 -5
  2. package/dist/cjs/client/PerpsClient.d.ts +5 -1
  3. package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
  4. package/dist/cjs/client/PerpsClient.js +8 -0
  5. package/dist/cjs/client/PerpsClient.js.map +1 -1
  6. package/dist/cjs/index.d.ts +4 -3
  7. package/dist/cjs/index.d.ts.map +1 -1
  8. package/dist/cjs/index.js +10 -3
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/registry/assetRegistry.d.ts +2 -0
  11. package/dist/cjs/registry/assetRegistry.d.ts.map +1 -1
  12. package/dist/cjs/registry/assetRegistry.js +18 -1
  13. package/dist/cjs/registry/assetRegistry.js.map +1 -1
  14. package/dist/cjs/registry/referenceDataRegistry.d.ts +5 -2
  15. package/dist/cjs/registry/referenceDataRegistry.d.ts.map +1 -1
  16. package/dist/cjs/registry/referenceDataRegistry.js +37 -7
  17. package/dist/cjs/registry/referenceDataRegistry.js.map +1 -1
  18. package/dist/cjs/services/getOrders.d.ts +2 -1
  19. package/dist/cjs/services/getOrders.d.ts.map +1 -1
  20. package/dist/cjs/services/getOrders.js +2 -0
  21. package/dist/cjs/services/getOrders.js.map +1 -1
  22. package/dist/cjs/transport/fetchWithRetry.d.ts.map +1 -1
  23. package/dist/cjs/transport/fetchWithRetry.js.map +1 -1
  24. package/dist/cjs/types/provider.d.ts +2 -6
  25. package/dist/cjs/types/provider.d.ts.map +1 -1
  26. package/dist/cjs/utils/orderClassification.d.ts +9 -5
  27. package/dist/cjs/utils/orderClassification.d.ts.map +1 -1
  28. package/dist/cjs/utils/orderClassification.js +19 -0
  29. package/dist/cjs/utils/orderClassification.js.map +1 -1
  30. package/dist/cjs/utils/orderMath.d.ts +2 -2
  31. package/dist/cjs/utils/orderMath.d.ts.map +1 -1
  32. package/dist/cjs/utils/orderMath.js +15 -4
  33. package/dist/cjs/utils/orderMath.js.map +1 -1
  34. package/dist/cjs/utils/warnOnce.d.ts +2 -0
  35. package/dist/cjs/utils/warnOnce.d.ts.map +1 -0
  36. package/dist/cjs/utils/warnOnce.js +22 -0
  37. package/dist/cjs/utils/warnOnce.js.map +1 -0
  38. package/dist/cjs/version.d.ts +1 -1
  39. package/dist/cjs/version.js +1 -1
  40. package/dist/esm/client/PerpsClient.d.ts +7 -1
  41. package/dist/esm/client/PerpsClient.d.ts.map +1 -1
  42. package/dist/esm/client/PerpsClient.js +10 -0
  43. package/dist/esm/client/PerpsClient.js.map +1 -1
  44. package/dist/esm/index.d.ts +4 -3
  45. package/dist/esm/index.d.ts.map +1 -1
  46. package/dist/esm/index.js +3 -2
  47. package/dist/esm/index.js.map +1 -1
  48. package/dist/esm/registry/assetRegistry.d.ts +5 -8
  49. package/dist/esm/registry/assetRegistry.d.ts.map +1 -1
  50. package/dist/esm/registry/assetRegistry.js +21 -9
  51. package/dist/esm/registry/assetRegistry.js.map +1 -1
  52. package/dist/esm/registry/referenceDataRegistry.d.ts +6 -14
  53. package/dist/esm/registry/referenceDataRegistry.d.ts.map +1 -1
  54. package/dist/esm/registry/referenceDataRegistry.js +38 -19
  55. package/dist/esm/registry/referenceDataRegistry.js.map +1 -1
  56. package/dist/esm/services/getOrders.d.ts +3 -17
  57. package/dist/esm/services/getOrders.d.ts.map +1 -1
  58. package/dist/esm/services/getOrders.js +3 -16
  59. package/dist/esm/services/getOrders.js.map +1 -1
  60. package/dist/esm/transport/fetchWithRetry.d.ts +3 -2
  61. package/dist/esm/transport/fetchWithRetry.d.ts.map +1 -1
  62. package/dist/esm/transport/fetchWithRetry.js +3 -2
  63. package/dist/esm/transport/fetchWithRetry.js.map +1 -1
  64. package/dist/esm/types/api.d.ts +2 -2
  65. package/dist/esm/types/provider.d.ts +2 -16
  66. package/dist/esm/types/provider.d.ts.map +1 -1
  67. package/dist/esm/utils/orderClassification.d.ts +14 -19
  68. package/dist/esm/utils/orderClassification.d.ts.map +1 -1
  69. package/dist/esm/utils/orderClassification.js +21 -15
  70. package/dist/esm/utils/orderClassification.js.map +1 -1
  71. package/dist/esm/utils/orderMath.d.ts +3 -13
  72. package/dist/esm/utils/orderMath.d.ts.map +1 -1
  73. package/dist/esm/utils/orderMath.js +17 -16
  74. package/dist/esm/utils/orderMath.js.map +1 -1
  75. package/dist/esm/utils/warnOnce.d.ts +9 -0
  76. package/dist/esm/utils/warnOnce.d.ts.map +1 -0
  77. package/dist/esm/utils/warnOnce.js +29 -0
  78. package/dist/esm/utils/warnOnce.js.map +1 -0
  79. package/dist/esm/version.d.ts +1 -1
  80. package/dist/esm/version.js +1 -1
  81. package/dist/types/client/PerpsClient.d.ts +7 -1
  82. package/dist/types/client/PerpsClient.d.ts.map +1 -1
  83. package/dist/types/index.d.ts +4 -3
  84. package/dist/types/index.d.ts.map +1 -1
  85. package/dist/types/registry/assetRegistry.d.ts +5 -8
  86. package/dist/types/registry/assetRegistry.d.ts.map +1 -1
  87. package/dist/types/registry/referenceDataRegistry.d.ts +6 -14
  88. package/dist/types/registry/referenceDataRegistry.d.ts.map +1 -1
  89. package/dist/types/services/getOrders.d.ts +3 -17
  90. package/dist/types/services/getOrders.d.ts.map +1 -1
  91. package/dist/types/transport/fetchWithRetry.d.ts +3 -2
  92. package/dist/types/transport/fetchWithRetry.d.ts.map +1 -1
  93. package/dist/types/types/api.d.ts +2 -2
  94. package/dist/types/types/provider.d.ts +2 -16
  95. package/dist/types/types/provider.d.ts.map +1 -1
  96. package/dist/types/utils/orderClassification.d.ts +14 -19
  97. package/dist/types/utils/orderClassification.d.ts.map +1 -1
  98. package/dist/types/utils/orderMath.d.ts +3 -13
  99. package/dist/types/utils/orderMath.d.ts.map +1 -1
  100. package/dist/types/utils/warnOnce.d.ts +9 -0
  101. package/dist/types/utils/warnOnce.d.ts.map +1 -0
  102. package/dist/types/version.d.ts +1 -1
  103. package/package.json +2 -2
  104. package/src/client/PerpsClient.ts +26 -0
  105. package/src/index.ts +6 -2
  106. package/src/registry/assetRegistry.ts +29 -9
  107. package/src/registry/referenceDataRegistry.ts +46 -19
  108. package/src/services/getOrders.ts +5 -17
  109. package/src/transport/fetchWithRetry.ts +3 -2
  110. package/src/types/api.ts +2 -2
  111. package/src/types/provider.ts +2 -21
  112. package/src/utils/orderClassification.ts +37 -19
  113. package/src/utils/orderMath.ts +25 -17
  114. package/src/utils/warnOnce.ts +29 -0
  115. package/src/version.ts +1 -1
@@ -9,5 +9,5 @@ export declare const name = "@lifi/perps-sdk";
9
9
  *
10
10
  * @public
11
11
  */
12
- export declare const version = "13.0.0";
12
+ export declare const version = "14.0.0";
13
13
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/perps-sdk",
3
- "version": "13.0.0",
3
+ "version": "14.0.0",
4
4
  "description": "LI.FI Perps SDK for perpetuals trading",
5
5
  "homepage": "https://github.com/lifinance/perps-sdk",
6
6
  "bugs": {
@@ -46,7 +46,7 @@
46
46
  "big.js": "^7.0.1",
47
47
  "partysocket": "^1.1.19",
48
48
  "viem": "^2.55.18",
49
- "@lifi/perps-types": "^12.3.0"
49
+ "@lifi/perps-types": "^13.0.0"
50
50
  },
51
51
  "publishConfig": {
52
52
  "access": "public"
@@ -9,6 +9,8 @@ import type {
9
9
  MarketRef,
10
10
  MarketSettings,
11
11
  MetaActionType,
12
+ Order,
13
+ OrdersResponse,
12
14
  PortfolioHistoryResponse,
13
15
  Position,
14
16
  PositionMarginConstraints,
@@ -30,6 +32,14 @@ import { getAssetRegistry } from '../registry/assetRegistry.js'
30
32
  import { createAction } from '../services/createAction.js'
31
33
  import { executeAction } from '../services/executeAction.js'
32
34
  import { getAccount as fetchAccount } from '../services/getAccount.js'
35
+ import {
36
+ getOrder as fetchOrder,
37
+ type GetOrderParams,
38
+ } from '../services/getOrder.js'
39
+ import {
40
+ getOrders as fetchOrders,
41
+ type GetOrdersParams,
42
+ } from '../services/getOrders.js'
33
43
  import { getProviders } from '../services/getProviders.js'
34
44
  import type {
35
45
  BuildProviderSetupParams,
@@ -190,6 +200,22 @@ export class PerpsClient {
190
200
  return resolveProvider(this.sdkClient, provider)
191
201
  }
192
202
 
203
+ /** Read active or historical orders from the selected venue. */
204
+ async getOrders(
205
+ params: GetOrdersParams,
206
+ options?: SDKRequestOptions
207
+ ): Promise<OrdersResponse> {
208
+ return fetchOrders(this.sdkClient, params, options)
209
+ }
210
+
211
+ /** Read one venue order through the provider's unified mapper. */
212
+ async getOrder(
213
+ params: GetOrderParams,
214
+ options?: SDKRequestOptions
215
+ ): Promise<Order> {
216
+ return fetchOrder(this.sdkClient, params, options)
217
+ }
218
+
193
219
  /**
194
220
  * Ask the provider plugin for the signer-bearing wire fields of `action` —
195
221
  * the on-wire `signerAddress` and any signer-derived params (e.g.
package/src/index.ts CHANGED
@@ -87,7 +87,7 @@ export { createMemoryStorage } from './storage/storage.js'
87
87
  export type { StorageAdapter } from './storage/types.js'
88
88
  export { errorCodeFromStatus } from './transport/errorCodeFromStatus.js'
89
89
  export type { FetchWithRetryOptions } from './transport/fetchWithRetry.js'
90
- export { fetchWithRetry } from './transport/fetchWithRetry.js'
90
+ export { fetchWithRetry, isAbortError } from './transport/fetchWithRetry.js'
91
91
  export type {
92
92
  ProviderRetryConfig,
93
93
  ResolvedRetryPolicy,
@@ -160,7 +160,6 @@ export type {
160
160
  ProviderGetPortfolioHistoryParams,
161
161
  ProviderGetPositionsParams,
162
162
  ProviderGetQuoteParams,
163
- ProviderGetRunningTwapsParams,
164
163
  ProviderGetWithdrawableBalancesParams,
165
164
  QuoteListener,
166
165
  SignActionProgress,
@@ -222,9 +221,13 @@ export {
222
221
  classifyFill,
223
222
  FillClassification,
224
223
  isActiveOrderStatus,
224
+ isRegularOrder,
225
225
  isStopLossOrder,
226
226
  isTakeProfitOrder,
227
227
  isTpSlOrder,
228
+ isTriggerOrder,
229
+ isTwapOrder,
230
+ triggerConditionFor,
228
231
  } from './utils/orderClassification.js'
229
232
  export {
230
233
  expectedRealizedPnlForOpenOrder,
@@ -252,6 +255,7 @@ export type { RemovableIsolatedMarginParams } from './utils/transferMargin.js'
252
255
  export { removableIsolatedMargin } from './utils/transferMargin.js'
253
256
  export { fromBaseUnits, fromBaseUnitsNumber } from './utils/units.js'
254
257
  export { validateMargin } from './utils/validation.js'
258
+ export { createWarnOnce } from './utils/warnOnce.js'
255
259
  // Version
256
260
  export { name, version } from './version.js'
257
261
  export { cachePromise } from './websocket/cachePromise.js'
@@ -1,19 +1,39 @@
1
1
  import type { Asset, AssetsResponse } from '@lifi/perps-types'
2
+ import { PerpsErrorCode } from '@lifi/perps-types'
3
+ import { PerpsError } from '../errors/PerpsError.js'
2
4
  import { buildUrl, request } from '../transport/request.js'
3
5
  import type { PerpsSDKClient } from '../types/provider.js'
4
6
  import { ReferenceDataRegistry } from './referenceDataRegistry.js'
5
7
 
6
- /**
7
- * Per-provider index over the backend's `/assets` token registry, keyed by
8
- * `Asset.id` — the provider-native asset id (Lighter: the stringified
9
- * `asset_id`, Hyperliquid spot: the venue token index). Obtain via
10
- * {@link getAssetRegistry}.
11
- *
12
- * @public
13
- */
8
+ const addressKey = (address: string): string =>
9
+ /^0x[0-9a-f]{40}$/i.test(address) ? address.toLowerCase() : address
10
+
11
+ /** Provider `/assets` index by native `id` and by L1 contract address. @public */
14
12
  export class AssetRegistry extends ReferenceDataRegistry<Asset> {
15
13
  constructor(client: PerpsSDKClient, provider: string) {
16
- super(client, provider, 'asset')
14
+ super(client, provider, 'asset', {
15
+ l1Address: (asset) =>
16
+ asset.l1Address === undefined ? undefined : addressKey(asset.l1Address),
17
+ })
18
+ }
19
+
20
+ /** Lookup by provider identity; hexadecimal L1 addresses are case-insensitive. */
21
+ override get(id: string, key: 'id' | 'l1Address' = 'id'): Asset | undefined {
22
+ return key === 'id' ? super.get(id) : this.getByIndex(addressKey(id), key)
23
+ }
24
+
25
+ /** Resolve registry membership or report a stale or mis-keyed asset registry. */
26
+ require(id: string, key: 'id' | 'l1Address' = 'id'): Asset {
27
+ const asset = this.get(id, key)
28
+ if (asset === undefined) {
29
+ const error = new PerpsError(
30
+ PerpsErrorCode.ValidationError,
31
+ `[${this.provider}] stale or mis-keyed asset registry: unknown ${key} '${id}'`
32
+ )
33
+ error.tool = this.provider
34
+ throw error
35
+ }
36
+ return asset
17
37
  }
18
38
 
19
39
  /**
@@ -1,27 +1,23 @@
1
+ import { PerpsErrorCode } from '@lifi/perps-types'
2
+ import { PerpsError } from '../errors/PerpsError.js'
1
3
  import type { PerpsSDKClient } from '../types/provider.js'
4
+ import { createWarnOnce } from '../utils/warnOnce.js'
2
5
 
3
- /**
4
- * Per-provider hash index over one of the provider's reference-data lists
5
- * (`/markets`, `/assets`), keyed by the list's own primary key.
6
- *
7
- * NOT a cache: it holds no freshness policy of its own. Every {@link sync}
8
- * refetches through the HTTP layer, whose `cache-control` headers decide
9
- * whether the response comes from disk or the network. A lookup miss warns
10
- * once per id and returns `undefined`; subsequent syncs reconcile the index
11
- * without replaying the warning for an id that remains absent.
12
- *
13
- * @internal
14
- */
6
+ /** Atomic provider reference indexes; HTTP cache headers govern freshness. @internal */
15
7
  export abstract class ReferenceDataRegistry<T> {
16
8
  private index = new Map<string, T>()
9
+ private secondaryIndexes = new Map<string, Map<string, T>>()
17
10
  private current: readonly T[] = []
18
11
  private inflight: Promise<readonly T[]> | undefined
19
- private warnedIds = new Set<string>()
12
+ private readonly warnOnce = createWarnOnce()
20
13
 
21
14
  protected constructor(
22
15
  protected readonly client: PerpsSDKClient,
23
16
  readonly provider: string,
24
- private readonly kind: string
17
+ private readonly kind: string,
18
+ private readonly secondaryKeys: Readonly<
19
+ Record<string, (item: T) => string | undefined>
20
+ > = {}
25
21
  ) {}
26
22
 
27
23
  /** Fetch the provider's full list through the HTTP layer. */
@@ -55,16 +51,47 @@ export abstract class ReferenceDataRegistry<T> {
55
51
  if (item !== undefined) {
56
52
  return item
57
53
  }
58
- if (!this.warnedIds.has(id)) {
59
- this.warnedIds.add(id)
60
- console.warn(`[${this.provider}] unknown ${this.kind} id '${id}'`)
61
- }
54
+ this.warnOnce(id, `[${this.provider}] unknown ${this.kind} id '${id}'`)
62
55
  return undefined
63
56
  }
64
57
 
58
+ protected getByIndex(id: string, key: string): T | undefined {
59
+ return this.secondaryIndexes.get(key)?.get(id)
60
+ }
61
+
65
62
  private async load(): Promise<readonly T[]> {
66
63
  const items = await this.fetchItems()
67
- this.index = new Map(items.map((item) => [this.keyOf(item), item]))
64
+ const index = new Map<string, T>()
65
+ for (const item of items) {
66
+ const key = this.keyOf(item)
67
+ if (index.has(key)) {
68
+ throw new PerpsError(
69
+ PerpsErrorCode.ValidationError,
70
+ `[${this.provider}] stale or mis-keyed ${this.kind} registry: duplicate id '${key}'`
71
+ )
72
+ }
73
+ index.set(key, item)
74
+ }
75
+ const secondaryIndexes = new Map<string, Map<string, T>>()
76
+ for (const [name, keyOf] of Object.entries(this.secondaryKeys)) {
77
+ const secondary = new Map<string, T>()
78
+ for (const item of items) {
79
+ const key = keyOf(item)
80
+ if (key === undefined) {
81
+ continue
82
+ }
83
+ if (secondary.has(key)) {
84
+ throw new PerpsError(
85
+ PerpsErrorCode.ValidationError,
86
+ `[${this.provider}] stale or mis-keyed ${this.kind} registry: duplicate ${name} '${key}'`
87
+ )
88
+ }
89
+ secondary.set(key, item)
90
+ }
91
+ secondaryIndexes.set(name, secondary)
92
+ }
93
+ this.index = index
94
+ this.secondaryIndexes = secondaryIndexes
68
95
  this.current = items
69
96
  return items
70
97
  }
@@ -1,8 +1,9 @@
1
- import type { OrdersResponse } from '@lifi/perps-types'
1
+ import type { OrderStatus, OrdersResponse } from '@lifi/perps-types'
2
2
  import type { Address } from 'viem'
3
3
  import { requireProvider } from '../client/requireProvider.js'
4
4
  import type { SDKRequestOptions } from '../types/config.js'
5
5
  import type { PerpsSDKClient } from '../types/provider.js'
6
+ import { ACTIVE_ORDER_STATUSES } from '../utils/orderClassification.js'
6
7
 
7
8
  /**
8
9
  * Parameters for {@link getOrders}.
@@ -12,6 +13,7 @@ import type { PerpsSDKClient } from '../types/provider.js'
12
13
  export interface GetOrdersParams {
13
14
  provider: string
14
15
  address: Address
16
+ statuses?: OrderStatus[]
15
17
  /** Optional opaque `Market.id` filter, not a display symbol. */
16
18
  marketId?: string
17
19
  /** Maximum items returned; provider defaults and caps apply. */
@@ -20,22 +22,7 @@ export interface GetOrdersParams {
20
22
  cursor?: string
21
23
  }
22
24
 
23
- /**
24
- * Get open orders and trigger orders for an account. Delegates to the
25
- * registered venue plugin (direct-to-venue); requires the provider plugin to be
26
- * registered on the client.
27
- *
28
- * @throws {PerpsError} When the provider plugin is not registered, or on
29
- * backend / network / parsing errors.
30
- * @example
31
- * ```ts
32
- * const { openOrders, triggerOrders } = await getOrders(client, {
33
- * provider: 'hyperliquid',
34
- * address: '0x1234...',
35
- * })
36
- * ```
37
- * @public
38
- */
25
+ /** Read account orders with active lifecycle statuses as the default filter. */
39
26
  export async function getOrders(
40
27
  client: PerpsSDKClient,
41
28
  params: GetOrdersParams,
@@ -44,6 +31,7 @@ export async function getOrders(
44
31
  return requireProvider(client, params.provider).getOrders(
45
32
  {
46
33
  address: params.address,
34
+ statuses: params.statuses ?? [...ACTIVE_ORDER_STATUSES],
47
35
  marketId: params.marketId,
48
36
  limit: params.limit,
49
37
  cursor: params.cursor,
@@ -18,9 +18,10 @@ export interface FetchWithRetryOptions {
18
18
  /**
19
19
  * True when `error` is an `AbortSignal` cancellation (the native `fetch` abort
20
20
  * rejection) rather than a genuine network failure. An abort is a deliberate
21
- * caller action, so it is rethrown untouched instead of being retried.
21
+ * caller action, so every transport rethrows it untouched instead of retrying
22
+ * it or wrapping it in a provider error.
22
23
  *
23
- * @internal
24
+ * @public
24
25
  */
25
26
  export function isAbortError(error: unknown): boolean {
26
27
  return error instanceof Error && error.name === 'AbortError'
package/src/types/api.ts CHANGED
@@ -176,8 +176,8 @@ export interface PlaceOrderParams {
176
176
  }
177
177
 
178
178
  /**
179
- * Parameters for placing trigger-only orders (TP/SL on existing positions).
180
- * Sends a TRIGGER_ONLY order that skips the main order wire.
179
+ * Sends `ActionType.PLACE_TRIGGER_ORDER` with
180
+ * `{ market, side, takeProfit?, stopLoss? }`.
181
181
  *
182
182
  * @public
183
183
  */
@@ -13,6 +13,7 @@ import type {
13
13
  MarketRef,
14
14
  MarketSettings,
15
15
  Order,
16
+ OrderStatus,
16
17
  OrdersResponse,
17
18
  PerpsMarket,
18
19
  PerpsSigner,
@@ -27,7 +28,6 @@ import type {
27
28
  SignedActionStep,
28
29
  SigningMethod,
29
30
  TradeType,
30
- TwapOrder,
31
31
  } from '@lifi/perps-types'
32
32
  import type { Address } from 'viem'
33
33
  import type {
@@ -223,6 +223,7 @@ export interface ProviderGetMarketSettingsParams {
223
223
  */
224
224
  export interface ProviderGetOrdersParams {
225
225
  address: Address
226
+ statuses?: OrderStatus[]
226
227
  /** Optional opaque `Market.id` filter (not a display symbol). */
227
228
  marketId?: string
228
229
  /** Maximum items returned; provider defaults and caps apply. */
@@ -231,17 +232,6 @@ export interface ProviderGetOrdersParams {
231
232
  cursor?: string
232
233
  }
233
234
 
234
- /**
235
- * Read params for {@link PerpsProvider.getRunningTwaps}.
236
- *
237
- * @public
238
- */
239
- export interface ProviderGetRunningTwapsParams {
240
- address: Address
241
- /** Optional opaque `Market.id` filter (not a display symbol). */
242
- marketId?: string
243
- }
244
-
245
235
  /**
246
236
  * Read params for {@link PerpsProvider.getOrder}.
247
237
  *
@@ -457,15 +447,6 @@ export interface PerpsProviderPlugin {
457
447
  options?: SDKRequestOptions
458
448
  ): Promise<OrdersResponse>
459
449
 
460
- /**
461
- * Fetch the account's currently running TWAP parent orders directly from the
462
- * venue. Child slice orders are excluded.
463
- */
464
- getRunningTwaps?(
465
- params: ProviderGetRunningTwapsParams,
466
- options?: SDKRequestOptions
467
- ): Promise<TwapOrder[]>
468
-
469
450
  getOrder(
470
451
  params: ProviderGetOrderParams,
471
452
  options?: SDKRequestOptions
@@ -1,17 +1,15 @@
1
- /**
2
- * Order classification utilities.
3
- *
4
- * Type guards and classifiers that operate on SDK types to determine
5
- * order categories (TP/SL, open/close). These use the OrderType enum
6
- * for classification — no string matching.
7
- */
8
-
9
- import type { OpenOrder } from '@lifi/perps-types'
1
+ import type {
2
+ Order,
3
+ RegularOrder,
4
+ TriggerOrder,
5
+ TwapOrder,
6
+ } from '@lifi/perps-types'
10
7
  import {
11
8
  FillClassification,
12
9
  OrderSide,
13
10
  OrderStatus,
14
11
  OrderType,
12
+ TriggerCondition,
15
13
  } from '@lifi/perps-types'
16
14
  import { stringToFloat } from './parse.js'
17
15
 
@@ -36,7 +34,7 @@ const SL_TYPES = new Set<OrderType>([
36
34
  * Check if an open order is a Take Profit trigger order.
37
35
  * @public
38
36
  */
39
- export function isTakeProfitOrder(order: Pick<OpenOrder, 'type'>): boolean {
37
+ export function isTakeProfitOrder(order: Pick<Order, 'type'>): boolean {
40
38
  return TP_TYPES.has(order.type)
41
39
  }
42
40
 
@@ -44,7 +42,7 @@ export function isTakeProfitOrder(order: Pick<OpenOrder, 'type'>): boolean {
44
42
  * Check if an open order is a Stop Loss trigger order.
45
43
  * @public
46
44
  */
47
- export function isStopLossOrder(order: Pick<OpenOrder, 'type'>): boolean {
45
+ export function isStopLossOrder(order: Pick<Order, 'type'>): boolean {
48
46
  return SL_TYPES.has(order.type)
49
47
  }
50
48
 
@@ -52,17 +50,37 @@ export function isStopLossOrder(order: Pick<OpenOrder, 'type'>): boolean {
52
50
  * Check if an open order is a TP or SL trigger order.
53
51
  * @public
54
52
  */
55
- export function isTpSlOrder(order: Pick<OpenOrder, 'type'>): boolean {
53
+ export function isTpSlOrder(order: Pick<Order, 'type'>): boolean {
56
54
  return TP_TYPES.has(order.type) || SL_TYPES.has(order.type)
57
55
  }
58
56
 
59
- /**
60
- * Order statuses representing an order still resting on the book (visible
61
- * in `openOrders` / `triggerOrders`). Anything not in this set is terminal —
62
- * filled, cancelled, rejected, expired — and should be evicted from the
63
- * cached orders list when seen in a WS update.
64
- * @public
65
- */
57
+ /** Narrow an order to a price-activated order. */
58
+ export function isTriggerOrder(order: Order): order is TriggerOrder {
59
+ return isTpSlOrder(order)
60
+ }
61
+
62
+ /** Narrow an order to a market or limit order. */
63
+ export function isRegularOrder(order: Order): order is RegularOrder {
64
+ return order.type === OrderType.MARKET || order.type === OrderType.LIMIT
65
+ }
66
+
67
+ /** Narrow an order to a time-weighted execution parent. */
68
+ export function isTwapOrder(order: Order): order is TwapOrder {
69
+ return order.type === OrderType.TWAP
70
+ }
71
+
72
+ /** Derive the trigger price relation from the trigger type and execution side. */
73
+ export function triggerConditionFor(
74
+ type: TriggerOrder['type'],
75
+ side: OrderSide
76
+ ): TriggerCondition {
77
+ const takeProfit = TP_TYPES.has(type)
78
+ return takeProfit === (side === OrderSide.SELL)
79
+ ? TriggerCondition.ABOVE
80
+ : TriggerCondition.BELOW
81
+ }
82
+
83
+ /** Lifecycle statuses included in order reads by default. */
66
84
  export const ACTIVE_ORDER_STATUSES: ReadonlySet<OrderStatus> = new Set([
67
85
  OrderStatus.OPEN,
68
86
  OrderStatus.PENDING,
@@ -1,10 +1,12 @@
1
1
  import {
2
- type OpenOrder,
3
2
  OrderSide,
3
+ OrderStatus,
4
4
  type Position,
5
5
  PositionSide,
6
+ type RegularOrder,
6
7
  type TriggerOrder,
7
8
  } from '@lifi/perps-types'
9
+ import { isActiveOrderStatus } from './orderClassification.js'
8
10
  import { realizedPnlOnClose } from './positionMath.js'
9
11
 
10
12
  /**
@@ -55,10 +57,10 @@ export function resolveCloseSize(
55
57
  * @public
56
58
  */
57
59
  export function expectedRealizedPnlForOpenOrder(
58
- order: OpenOrder,
60
+ order: RegularOrder,
59
61
  position: Position | undefined
60
62
  ): number | null {
61
- if (!position) {
63
+ if (!position || !isActiveOrderStatus(order.status)) {
62
64
  return null
63
65
  }
64
66
 
@@ -70,7 +72,7 @@ export function expectedRealizedPnlForOpenOrder(
70
72
  return null
71
73
  }
72
74
 
73
- const limitPrice = Number.parseFloat(order.price)
75
+ const limitPrice = Number.parseFloat(order.price ?? '')
74
76
  const entryPrice = Number.parseFloat(position.entryPrice)
75
77
  const orderSize = Math.abs(Number.parseFloat(order.remainingSize))
76
78
  const positionSize = Math.abs(Number.parseFloat(position.size))
@@ -100,29 +102,29 @@ export function expectedRealizedPnlForOpenOrder(
100
102
  })
101
103
  }
102
104
 
103
- /**
104
- * Expected rPnL for a TP/SL trigger order against a matching position.
105
- *
106
- * A trigger order is by construction a closing leg — its direction is the
107
- * opposite of the position's. With no matching position there is nothing to
108
- * close, so rPnL is `null`. The trigger price (always present on the SDK
109
- * `TriggerOrder` shape) is used as the rPnL price; the optional `limitPrice`
110
- * for STOP_LIMIT / TAKE_PROFIT_LIMIT is the post-trigger limit, not the rPnL
111
- * price.
112
- * @public
113
- */
105
+ /** Project the unfilled closing quantity of an active trigger at its trigger price. */
114
106
  export function expectedRealizedPnlForTriggerOrder(
115
107
  order: TriggerOrder,
116
108
  position: Position | undefined
117
109
  ): number | null {
118
- if (!position) {
110
+ if (
111
+ !position ||
112
+ !isActiveOrderStatus(order.status) ||
113
+ order.status === OrderStatus.PENDING
114
+ ) {
119
115
  return null
120
116
  }
121
117
 
122
118
  const isLong = position.side === PositionSide.LONG
119
+ if (
120
+ (isLong && order.side !== OrderSide.SELL) ||
121
+ (!isLong && order.side !== OrderSide.BUY)
122
+ ) {
123
+ return null
124
+ }
123
125
  const triggerPrice = Number.parseFloat(order.triggerPrice)
124
126
  const entryPrice = Number.parseFloat(position.entryPrice)
125
- const orderSize = Math.abs(Number.parseFloat(order.size))
127
+ const orderSize = Math.abs(Number.parseFloat(order.remainingSize))
126
128
  const positionSize = Math.abs(Number.parseFloat(position.size))
127
129
  if (
128
130
  !Number.isFinite(triggerPrice) ||
@@ -133,6 +135,12 @@ export function expectedRealizedPnlForTriggerOrder(
133
135
  ) {
134
136
  return null
135
137
  }
138
+ if (
139
+ orderSize === 0 &&
140
+ (Number.parseFloat(order.originalSize) !== 0 || !order.reduceOnly)
141
+ ) {
142
+ return null
143
+ }
136
144
 
137
145
  const closeSize = resolveCloseSize(orderSize, positionSize)
138
146
  return realizedPnlOnClose({
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The number of keys one warner remembers. Venue wire data supplies the keys,
3
+ * so the memory must not grow for as long as the process runs.
4
+ */
5
+ const KEY_MEMORY_LIMIT = 256
6
+
7
+ /**
8
+ * Build a warner that writes each distinct key once. The warner forgets the
9
+ * oldest key when its memory is full, so a key it saw long ago can warn a
10
+ * second time.
11
+ *
12
+ * @internal
13
+ */
14
+ export const createWarnOnce = (): ((key: string, message: string) => void) => {
15
+ const seen = new Set<string>()
16
+ return (key, message) => {
17
+ if (seen.has(key)) {
18
+ return
19
+ }
20
+ if (seen.size >= KEY_MEMORY_LIMIT) {
21
+ const oldest = seen.values().next().value
22
+ if (oldest !== undefined) {
23
+ seen.delete(oldest)
24
+ }
25
+ }
26
+ seen.add(key)
27
+ console.warn(message)
28
+ }
29
+ }
package/src/version.ts CHANGED
@@ -10,4 +10,4 @@ export const name = '@lifi/perps-sdk'
10
10
  *
11
11
  * @public
12
12
  */
13
- export const version = '13.0.0'
13
+ export const version = '14.0.0'