@lifi/perps-sdk-provider-ondo 23.0.0 → 25.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.
@@ -1,5 +1,5 @@
1
1
  import { type PerpsSDKClient, type ProviderGetQuoteParams, type QuoteListener, type StorageAdapter, WsProviderBase, type WsProviderFactory } from '@lifi/perps-sdk';
2
- import type { Subscription } from '@lifi/perps-types';
2
+ import { type Subscription } from '@lifi/perps-types';
3
3
  import type { Address } from 'viem';
4
4
  interface SubState {
5
5
  /** Subscribe payload minus `op` — re-sent verbatim on every (re)open. */
@@ -98,9 +98,10 @@ export declare class OndoWsProvider extends WsProviderBase<SubState> {
98
98
  /** Wire subs for `sub`, keyed uniquely for the base's replay registry. */
99
99
  private resolveChannel;
100
100
  /**
101
- * The stored SIWE session for `address`, or {@link OndoSessionExpiredError}
102
- * when it is absent or expired. Shared by the subscribe-time guard, the
103
- * login op and the account-summary seed so all three report one message.
101
+ * The stored SIWE session for `address`, or {@link PerpsError} with
102
+ * `SetupRequired` when it is absent or expired. Shared by the subscribe-time
103
+ * guard, the login op and the account-summary seed so all three report one
104
+ * message.
104
105
  */
105
106
  private requireSession;
106
107
  /**
@@ -112,9 +113,9 @@ export declare class OndoWsProvider extends WsProviderBase<SubState> {
112
113
  private restClient;
113
114
  /**
114
115
  * Seed the account-summary figures from the REST balance so the first emit
115
- * is complete before any positions frame lands. Throws {@link
116
- * OndoSessionExpiredError} when the SIWE session is missing, matching the
117
- * other authenticated channels.
116
+ * is complete before any positions frame lands. Throws {@link PerpsError}
117
+ * with `SetupRequired` when the SIWE session is missing, matching the other
118
+ * authenticated channels.
118
119
  */
119
120
  private seedAccountSummary;
120
121
  /** Re-read the venue balance moved by the frame and re-emit the summary. */
@@ -1 +1 @@
1
- {"version":3,"file":"OndoWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/OndoWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAGlB,KAAK,cAAc,EAGnB,cAAc,EACd,KAAK,iBAAiB,EAGvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAKV,YAAY,EACb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAgEnC,UAAU,QAAQ;IAChB,yEAAyE;IACzE,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACnE,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6EAA6E;IAC7E,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED;;;;;;;GAOG;AACH,qBAAa,cAAe,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAE/B;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IAEzD;;;;OAIG;IACH,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,wBAAwB,CAAI;IAEpC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAEnC;IAED,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAoC;IACpD,yDAAyD;IACzD,OAAO,CAAC,cAAc,CAGnB;IAEH,8DAA8D;IAC9D,OAAO,CAAC,cAAc,CAAoB;IAC1C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,eAAe,CAAI;IAC3B,OAAO,CAAC,eAAe,CAAI;gBAGzB,KAAK,GAAE,MAA4B,EACnC,WAAW,SAAoB,EAC/B,OAAO,GAAE,qBAA0B,EACnC,MAAM,CAAC,EAAE,cAAc;IAqBnB,cAAc,CAClB,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;IAkBtB,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;cAuB1B,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAoHnE;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IAYnB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAa5B,4EAA4E;IAC5E,OAAO,CAAC,cAAc;IAWtB,2EAA2E;YAC7D,WAAW;IAwBzB,4EAA4E;IAC5E,OAAO,CAAC,WAAW;cAgBH,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;cAoB1C,OAAO,IAAI,IAAI;IAYlC,0EAA0E;IAC1E,OAAO,CAAC,cAAc;IA0GtB;;;;OAIG;YACW,cAAc;IAU5B;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,UAAU;IAMlB;;;;;OAKG;YACW,kBAAkB;IAgBhC,4EAA4E;YAC9D,qBAAqB;IAuBnC,OAAO,CAAC,mBAAmB;YAMb,WAAW;IAezB,uEAAuE;IACvE,OAAO,CAAC,kBAAkB;IAgB1B,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IA+C1C,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,YAAY;IAgBpB,6EAA6E;IAC7E,OAAO,CAAC,aAAa,CAGpB;IAED,OAAO,CAAC,kBAAkB,CAKzB;IAED,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,eAAe;CA0BxB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GACzB,UAAU,qBAAqB,KAC9B,iBAKA,CAAA"}
1
+ {"version":3,"file":"OndoWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/OndoWsProvider.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/perps-sdk-provider-ondo",
3
- "version": "23.0.0",
3
+ "version": "25.0.0",
4
4
  "description": "Ondo Perps provider plugin for @lifi/perps-sdk",
5
5
  "homepage": "https://github.com/lifinance/perps-sdk",
6
6
  "bugs": {
@@ -44,10 +44,10 @@
44
44
  "dependencies": {
45
45
  "big.js": "^7.0.1",
46
46
  "viem": "^2.55.18",
47
- "@lifi/perps-types": "^19.0.0"
47
+ "@lifi/perps-types": "^20.0.0"
48
48
  },
49
49
  "peerDependencies": {
50
- "@lifi/perps-sdk": "^21.0.0"
50
+ "@lifi/perps-sdk": "^22.0.0"
51
51
  },
52
52
  "publishConfig": {
53
53
  "access": "public"
@@ -162,9 +162,10 @@ export interface OndoProviderOptions {
162
162
  *
163
163
  * Per-user reads call Ondo's REST API directly — every one requires the
164
164
  * session JWT obtained through the SIWE login and stored in the token store.
165
- * Without a stored token the reads degrade gracefully (empty pages,
166
- * `loggedIn: false` config) instead of failing; `getOrder` throws because an
167
- * empty result would be indistinguishable from "order not found".
165
+ * A data read throws `PerpsErrorCode.SetupRequired` when no session is stored
166
+ * and `PerpsErrorCode.Unauthorized` when Ondo rejects the stored session. A
167
+ * status read (`getAccount`, `accountExists`, `getDepositFlow`,
168
+ * `getWithdrawFlow`) returns the logged-out state instead.
168
169
  *
169
170
  * @example
170
171
  * ```ts
@@ -272,30 +273,69 @@ export const ondoProvider = (
272
273
  config: emptyConfig,
273
274
  })
274
275
 
275
- // Runs an authenticated read against a live session. An absent local token
276
- // and a server-revoked one (surfaced mid-call as `OndoSessionExpiredError`)
277
- // both evict any stale token and fall back to `loggedOut`, so a rotated
278
- // session never soft-locks the UI behind a token that looks valid locally.
276
+ // Runs an authenticated read against a live session. `noSession` answers
277
+ // when no token is stored; `rejected` answers after the venue rejects the
278
+ // stored token mid-call (`OndoSessionExpiredError`), which is evicted first
279
+ // so a rotated session never soft-locks the UI behind a token that looks
280
+ // valid locally.
279
281
  const withSession = async <T>(
280
282
  address: Address,
281
- loggedOut: () => T,
283
+ fallback: {
284
+ noSession: () => T
285
+ rejected: (cause: OndoSessionExpiredError) => T
286
+ },
282
287
  fn: (token: OndoAuthToken) => Promise<T>
283
288
  ): Promise<T> => {
284
289
  const token = await tokenStore.get(address)
285
290
  if (token === null) {
286
- return loggedOut()
291
+ return fallback.noSession()
287
292
  }
288
293
  try {
289
294
  return await fn(token)
290
295
  } catch (err) {
291
296
  if (err instanceof OndoSessionExpiredError) {
292
297
  await tokenStore.remove(address)
293
- return loggedOut()
298
+ return fallback.rejected(err)
294
299
  }
295
300
  throw err
296
301
  }
297
302
  }
298
303
 
304
+ const sessionRequired = (read: string) => (): never => {
305
+ const error = new PerpsError(
306
+ PerpsErrorCode.SetupRequired,
307
+ `Ondo ${read} requires a session token. Run the SIWE login first.`
308
+ )
309
+ error.tool = ONDO_PROVIDER_KEY
310
+ throw error
311
+ }
312
+
313
+ const sessionRejected =
314
+ (read: string) =>
315
+ (cause: OndoSessionExpiredError): never => {
316
+ const error = new PerpsError(
317
+ PerpsErrorCode.Unauthorized,
318
+ `Ondo ${read} failed: the venue rejected the session; sign in again.`
319
+ )
320
+ error.tool = ONDO_PROVIDER_KEY
321
+ error.cause = cause
322
+ throw error
323
+ }
324
+
325
+ // A data read throws the account's state: an empty result would be
326
+ // indistinguishable from an account with no data.
327
+ const dataRead = (read: string) => ({
328
+ noSession: sessionRequired(read),
329
+ rejected: sessionRejected(read),
330
+ })
331
+
332
+ // A status read reports the logged-out state whether the session is absent
333
+ // or was rejected.
334
+ const statusRead = <T>(loggedOut: () => T) => ({
335
+ noSession: loggedOut,
336
+ rejected: loggedOut,
337
+ })
338
+
299
339
  return {
300
340
  type: ONDO_PROVIDER_KEY,
301
341
 
@@ -311,13 +351,13 @@ export const ondoProvider = (
311
351
  const apiKeyRegistered = apiKey !== null && hasOndoApiKeyScopes(apiKey)
312
352
  return withSession(
313
353
  params.address,
314
- () => {
354
+ statusRead(() => {
315
355
  const account = loggedOutAccount(params.address)
316
356
  return {
317
357
  ...account,
318
358
  config: { ...emptyConfig, apiKeyRegistered },
319
359
  }
320
- },
360
+ }),
321
361
  async (token) => {
322
362
  const client = apiClient(opts)
323
363
  const [
@@ -415,7 +455,7 @@ export const ondoProvider = (
415
455
  ): Promise<ProviderWithdrawableBalance[]> {
416
456
  return withSession(
417
457
  params.address,
418
- (): ProviderWithdrawableBalance[] => [],
458
+ dataRead('withdrawable balances read'),
419
459
  async (token) => {
420
460
  const client = apiClient(opts)
421
461
  const [{ providers }, balance, account] = await Promise.all([
@@ -452,11 +492,7 @@ export const ondoProvider = (
452
492
  }
453
493
  return withSession(
454
494
  params.address,
455
- () => {
456
- throw new OndoSessionExpiredError(
457
- `No valid Ondo session token stored for ${params.address}. Run the SIWE login first.`
458
- )
459
- },
495
+ dataRead('market settings read'),
460
496
  async (token) => {
461
497
  const leverages = await apiClient(opts).get<OndoLeverage[]>(
462
498
  '/v1/perps/leverage',
@@ -491,7 +527,7 @@ export const ondoProvider = (
491
527
  ): Promise<AvailableToTrade | undefined> {
492
528
  return withSession(
493
529
  params.address,
494
- () => undefined,
530
+ dataRead('available-to-trade read'),
495
531
  async (token) => {
496
532
  const registry = marketRegistry()
497
533
  await registry.sync()
@@ -573,7 +609,7 @@ export const ondoProvider = (
573
609
  ): Promise<boolean> {
574
610
  return withSession(
575
611
  params.address,
576
- () => false,
612
+ statusRead(() => false),
577
613
  async (token) => {
578
614
  await apiClient(opts).get('/v1/account', { authToken: token.token })
579
615
  return true
@@ -590,10 +626,12 @@ export const ondoProvider = (
590
626
  // before a route has a recipient.
591
627
  return withSession<DepositFlow>(
592
628
  params.address,
593
- () => ({
594
- kind: 'setupRequired',
595
- setup: [ActionType.SIWE_LOGIN, ActionType.CREATE_DEPOSIT_ADDRESS],
596
- }),
629
+ statusRead(
630
+ (): DepositFlow => ({
631
+ kind: 'setupRequired',
632
+ setup: [ActionType.SIWE_LOGIN, ActionType.CREATE_DEPOSIT_ADDRESS],
633
+ })
634
+ ),
597
635
  async (token) => {
598
636
  const depositAddress = await listOndoDepositAddress(
599
637
  apiClient(opts),
@@ -622,10 +660,12 @@ export const ondoProvider = (
622
660
  // offers one destination: the login address.
623
661
  return withSession<WithdrawFlow>(
624
662
  params.address,
625
- () => ({
626
- kind: 'setupRequired',
627
- setup: [ActionType.SIWE_LOGIN, ActionType.ADD_WITHDRAWAL_ADDRESS],
628
- }),
663
+ statusRead(
664
+ (): WithdrawFlow => ({
665
+ kind: 'setupRequired',
666
+ setup: [ActionType.SIWE_LOGIN, ActionType.ADD_WITHDRAWAL_ADDRESS],
667
+ })
668
+ ),
629
669
  async (token) => {
630
670
  const { addressBook } = await apiClient(
631
671
  opts
@@ -653,11 +693,7 @@ export const ondoProvider = (
653
693
  ): Promise<PositionsResponse> {
654
694
  return withSession<PositionsResponse>(
655
695
  params.address,
656
- () => ({
657
- provider: ONDO_PROVIDER_KEY,
658
- positions: [],
659
- pagination: { limit: params.limit ?? 0, hasMore: false },
660
- }),
696
+ dataRead('positions read'),
661
697
  async (token) => {
662
698
  const client = apiClient(opts)
663
699
  const [rawPositions] = await Promise.all([
@@ -693,11 +729,7 @@ export const ondoProvider = (
693
729
  ): Promise<OrdersResponse> {
694
730
  return withSession<OrdersResponse>(
695
731
  params.address,
696
- () => ({
697
- provider: ONDO_PROVIDER_KEY,
698
- orders: [],
699
- pagination: { limit: params.limit ?? 0, hasMore: false },
700
- }),
732
+ dataRead('orders read'),
701
733
  async (token) => {
702
734
  const statuses =
703
735
  params.statuses === undefined
@@ -860,12 +892,7 @@ export const ondoProvider = (
860
892
  ): Promise<Order> {
861
893
  return withSession(
862
894
  params.address,
863
- (): Order => {
864
- throw new PerpsError(
865
- PerpsErrorCode.SDKError,
866
- 'Ondo order lookup requires a session token. Run the SIWE login first.'
867
- )
868
- },
895
+ dataRead('order lookup'),
869
896
  async (token) => {
870
897
  const client = apiClient(opts)
871
898
  const [order] = await Promise.all([
@@ -899,11 +926,7 @@ export const ondoProvider = (
899
926
  ): Promise<FillsResponse> {
900
927
  return withSession<FillsResponse>(
901
928
  params.address,
902
- () => ({
903
- provider: ONDO_PROVIDER_KEY,
904
- items: [],
905
- pagination: { limit: params.limit ?? 0, hasMore: false },
906
- }),
929
+ dataRead('fills read'),
907
930
  async (token) => {
908
931
  const client = apiClient(opts)
909
932
  const queryParams: ApiParams = {}
@@ -946,11 +969,7 @@ export const ondoProvider = (
946
969
  ): Promise<ActivitiesResponse> {
947
970
  return withSession<ActivitiesResponse>(
948
971
  params.address,
949
- () => ({
950
- provider: ONDO_PROVIDER_KEY,
951
- items: [],
952
- pagination: { limit: params.limit ?? 0, hasMore: false },
953
- }),
972
+ dataRead('activity read'),
954
973
  async (token) => {
955
974
  const inputCursor = decodeActivityCursor(params.cursor)
956
975
  const client = apiClient(opts)
@@ -1090,7 +1109,7 @@ export const ondoProvider = (
1090
1109
  ): Promise<PortfolioHistoryResponse> {
1091
1110
  return withSession<PortfolioHistoryResponse>(
1092
1111
  params.address,
1093
- () => ({ range: params.range, points: [] }),
1112
+ dataRead('portfolio history read'),
1094
1113
  async (token) => {
1095
1114
  const client = apiClient(opts)
1096
1115
  const [graph, summary] = await Promise.all([
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import {
10
- estimateLiquidationPrice as estimateIsolatedLiquidationPrice,
10
+ estimateLiquidationPrice as estimateLiquidationPriceAtRate,
11
11
  type LiquidationEstimateParams,
12
12
  } from '@lifi/perps-sdk'
13
13
  import type { PerpsMarket } from '@lifi/perps-types'
@@ -28,7 +28,7 @@ export function estimateLiquidationPrice(
28
28
  if (market.maintenanceMarginRate === undefined) {
29
29
  return undefined
30
30
  }
31
- return estimateIsolatedLiquidationPrice({
31
+ return estimateLiquidationPriceAtRate({
32
32
  entryPrice: params.entryPrice,
33
33
  leverage: params.leverage,
34
34
  isLong: params.isLong,
@@ -3,6 +3,8 @@ import {
3
3
  getMarketRegistry,
4
4
  localStorageAdapter,
5
5
  type MarketRegistry,
6
+ numberToDecimalString,
7
+ PerpsError,
6
8
  type PerpsSDKClient,
7
9
  type ProviderGetQuoteParams,
8
10
  type QuoteListener,
@@ -16,12 +18,13 @@ import {
16
18
  type WsProviderFactoryParams,
17
19
  wsLog,
18
20
  } from '@lifi/perps-sdk'
19
- import type {
20
- MarketContext,
21
- MarketDisplay,
22
- OndoAccountBalance,
23
- PerpsMarketDisplay,
24
- Subscription,
21
+ import {
22
+ type MarketContext,
23
+ type MarketDisplay,
24
+ type OndoAccountBalance,
25
+ PerpsErrorCode,
26
+ type PerpsMarketDisplay,
27
+ type Subscription,
25
28
  } from '@lifi/perps-types'
26
29
  import type { Address } from 'viem'
27
30
  import { OndoTokenStore } from '../auth/OndoTokenStore.js'
@@ -44,7 +47,6 @@ import type {
44
47
  OndoWsMessage,
45
48
  OndoWsTrade,
46
49
  } from '../types/index.js'
47
- import { OndoSessionExpiredError } from '../utils/apiClient.js'
48
50
  import {
49
51
  mapFill,
50
52
  mapOrderUpdates,
@@ -65,7 +67,7 @@ import { intervalFromBarSpan, mapInterval } from '../utils/ohlcvInterval.js'
65
67
  // connection, sent before the first private subscribe; the venue rejects a
66
68
  // second login on the same connection. The JWT comes from the SIWE session in
67
69
  // the token store — absent or expired reads back as null and surfaces as
68
- // `OndoSessionExpiredError` so callers re-run the SIWE login. A dropped
70
+ // `PerpsError` with `SetupRequired` so callers run the SIWE login. A dropped
69
71
  // socket forgets the login, so the guard resets on every close.
70
72
 
71
73
  const ONDO_AUTH_CHANNEL = {
@@ -580,14 +582,16 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
580
582
  }
581
583
 
582
584
  /**
583
- * The stored SIWE session for `address`, or {@link OndoSessionExpiredError}
584
- * when it is absent or expired. Shared by the subscribe-time guard, the
585
- * login op and the account-summary seed so all three report one message.
585
+ * The stored SIWE session for `address`, or {@link PerpsError} with
586
+ * `SetupRequired` when it is absent or expired. Shared by the subscribe-time
587
+ * guard, the login op and the account-summary seed so all three report one
588
+ * message.
586
589
  */
587
590
  private async requireSession(address: Address): Promise<OndoAuthToken> {
588
591
  const token = await this.tokenStore.get(address)
589
592
  if (token === null) {
590
- throw new OndoSessionExpiredError(
593
+ throw new PerpsError(
594
+ PerpsErrorCode.SetupRequired,
591
595
  `No Ondo session for ${address}. Run the SIWE login before subscribing to account channels.`
592
596
  )
593
597
  }
@@ -628,9 +632,9 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
628
632
 
629
633
  /**
630
634
  * Seed the account-summary figures from the REST balance so the first emit
631
- * is complete before any positions frame lands. Throws {@link
632
- * OndoSessionExpiredError} when the SIWE session is missing, matching the
633
- * other authenticated channels.
635
+ * is complete before any positions frame lands. Throws {@link PerpsError}
636
+ * with `SetupRequired` when the SIWE session is missing, matching the other
637
+ * authenticated channels.
634
638
  */
635
639
  private async seedAccountSummary(
636
640
  address: Address,
@@ -812,11 +816,11 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
812
816
  channel: 'candle',
813
817
  data: {
814
818
  t: kline.s * 1000,
815
- o: String(kline.o),
816
- h: String(kline.h),
817
- l: String(kline.l),
818
- c: String(kline.c),
819
- v: String(kline.v),
819
+ o: numberToDecimalString(kline.o),
820
+ h: numberToDecimalString(kline.h),
821
+ l: numberToDecimalString(kline.l),
822
+ c: numberToDecimalString(kline.c),
823
+ v: numberToDecimalString(kline.v),
820
824
  },
821
825
  })
822
826
  }