@pear-protocol/exchanges-sdk 0.8.0 → 0.9.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.
package/dist/index.d.ts CHANGED
@@ -161,6 +161,8 @@ declare class LighterWs extends BaseWs {
161
161
  protected getWsUrl(): string;
162
162
  protected getPingIntervalMs(): number;
163
163
  protected buildPingMessage(): WsMessage;
164
+ /** Subscribes to one account channel with the authentication Lighter requires. */
165
+ subscribe(channel: string, authToken: string): void;
164
166
  }
165
167
 
166
168
  declare class LighterExchangeWs extends ExchangeWs {
@@ -255,6 +257,15 @@ type ApiKey = {
255
257
  public_key: string;
256
258
  transaction_time: number;
257
259
  };
260
+ /**
261
+ * The three account tiers Lighter offers, spelled the way the venue spells them.
262
+ *
263
+ * Tier decides an account's fees, latency, and read allowance, and it is the venue's own
264
+ * vocabulary on both sides of the wire — `/accountLimits` reports it and `/changeAccountTier`
265
+ * accepts it. It lives here so the reader and the writer each import it from the venue rather
266
+ * than from each other.
267
+ */
268
+ type LighterAccountTier = 'standard' | 'plus' | 'premium';
258
269
  /** A source network Lighter currently credits through an intent address. */
259
270
  type LighterDepositNetwork = {
260
271
  name: string;
@@ -274,14 +285,30 @@ type LighterDeposit = {
274
285
  l1TxHash: string;
275
286
  };
276
287
 
288
+ /** Shares one live Lighter auth token per account without crossing rotated credentials. */
289
+
290
+ type LighterAuthCredentials = {
291
+ accountIndex: number;
292
+ apiKeyIndex: number;
293
+ apiPrivateKey: string;
294
+ };
295
+ /** Returns a live token while coalescing concurrent signing requests. */
296
+ declare function retrieveLighterAuthToken(sdk: PearSDK, credentials: LighterAuthCredentials, demo: boolean): Promise<string>;
297
+
277
298
  type WalletClientWithAccount = WalletClient<Transport, Chain | undefined, Account>;
278
299
 
279
- /** Native USDC contracts and transfer operations for Lighter's CCTP source chains. */
300
+ /** Native USDC contracts and transfer operations for Lighter's EVM deposit source chains. */
280
301
 
281
- /** Circle's native USDC token on every source chain supported by this build. */
282
- declare const LIGHTER_CCTP_USDC_ADDRESSES: Record<number, `0x${string}`>;
302
+ /**
303
+ * Circle's native USDC token on every source chain this build can transfer from.
304
+ *
305
+ * Every route that moves USDC from a connected wallet reads this map. A chain is absent until its
306
+ * native USDC contract has been verified, because transferring to a wrong contract loses the funds —
307
+ * so the Fun.xyz route accepts fewer chains for a wallet transfer than the bridge itself accepts.
308
+ */
309
+ declare const LIGHTER_NATIVE_USDC_ADDRESSES: Record<number, `0x${string}`>;
283
310
  /** USDC carries six decimals on every supported source chain. */
284
- declare const LIGHTER_CCTP_USDC_DECIMALS = 6;
311
+ declare const LIGHTER_USDC_DECIMALS = 6;
285
312
  /** The ERC-20 calls used to read and transfer native USDC. */
286
313
  declare const usdcAbi: readonly [{
287
314
  readonly inputs: readonly [{
@@ -317,15 +344,7 @@ declare const usdcAbi: readonly [{
317
344
  readonly type: "function";
318
345
  }];
319
346
  /** Names native USDC for a source chain this SDK can transfer from safely. */
320
- declare function getLighterCctpUsdcAddress(chainId: number): `0x${string}` | undefined;
321
-
322
- /** Shares one live Lighter auth token per account without crossing rotated credentials. */
323
-
324
- type LighterAuthCredentials = {
325
- accountIndex: number;
326
- apiKeyIndex: number;
327
- apiPrivateKey: string;
328
- };
347
+ declare function getLighterNativeUsdcAddress(chainId: number): `0x${string}` | undefined;
329
348
 
330
349
  declare const AssetId: {
331
350
  readonly ETH: 1;
@@ -361,37 +380,54 @@ declare function getAssetDecimals(assetId: number): number;
361
380
  type ConnectWalletParams = {
362
381
  accountIndex: number;
363
382
  };
364
- type DepositParams = {
365
- to: `0x${string}`;
366
- assetId: number;
367
- routeType: number;
368
- amount: string;
369
- nativeValue?: string;
370
- /** Optional cached `assetDetails.l1_decimals`; the helper fetches assetDetails when omitted. */
371
- l1Decimals?: number;
372
- };
373
- type CctpDepositIntentParams = {
374
- /** A `chainId` from `listDepositNetworks()`; Lighter adds networks without a release. */
375
- chainId: number;
376
- /** The L1 owner whose main Lighter account receives funds, not necessarily the sender. */
377
- ownerAddress: `0x${string}`;
378
- };
379
- type CctpDepositIntentResult = {
380
- /** Send at least `MIN_LIGHTER_CCTP_DEPOSIT_USDC` on the selected chain to this address. */
381
- intentAddress: `0x${string}`;
382
- /** Local deadline before Lighter's documented ten-minute cancellation boundary. */
383
- expiresAt: number;
383
+ /** The Lighter book a Fun.xyz deposit funds. */
384
+ type FunxyzMarket = 'perps' | 'spot';
385
+ /** What a Fun.xyz deposit is denominated in at its source. Fun.xyz converts ETH to USDC on arrival. */
386
+ type FunxyzAsset = 'USDC' | 'ETH';
387
+ /**
388
+ * The EVM chains this SDK routes a Fun.xyz deposit from, by chain id.
389
+ *
390
+ * Narrower than the bridge's own roster: a chain stays out until Circle issues native USDC on it,
391
+ * because every deposit here moves Circle's own token and a bridged variant would be lost. That
392
+ * currently excludes BNB Smart Chain and Robinhood, which the bridge accepts and this SDK does not.
393
+ *
394
+ * Ethereum mainnet sits in the same map but carries its own deposit minimum, because a mainnet
395
+ * deposit pays far more to bridge than one from an L2.
396
+ */
397
+ declare const FUNXYZ_EVM_CHAIN_NAMES: Record<number, string>;
398
+ /** Ethereum mainnet, whose Fun.xyz minimum never drops for an existing account. */
399
+ declare const FUNXYZ_ETHEREUM_MAINNET_CHAIN_ID = 1;
400
+ /** The chain families Fun.xyz mints a deposit address for, each with its own minimum. */
401
+ type FunxyzDepositSource = 'ethereum-mainnet' | 'evm' | 'solana' | 'tron' | 'bitcoin';
402
+ /** Whether the depositing wallet already owns a Lighter account. */
403
+ type FunxyzAccountState = 'new' | 'existing';
404
+ /**
405
+ * Fun.xyz deposit minimums in whole US dollars, by source and by account state.
406
+ *
407
+ * Send more than the minimum: bridge and swap operations lose some of the amount to slippage, and a
408
+ * deposit that lands under the minimum is not credited.
409
+ */
410
+ declare const FUNXYZ_DEPOSIT_MINIMUMS_USD: Record<FunxyzDepositSource, Record<FunxyzAccountState, string>>;
411
+ /** What the Fun.xyz bridge will credit once a deposit to the minted addresses lands. */
412
+ type FunxyzDepositCredit = {
413
+ account: 'existing';
414
+ accountIndex: number;
415
+ } | {
416
+ account: 'new';
417
+ ownerAddress: string;
384
418
  };
385
419
  /**
386
420
  * A step in a deposit's life after its transfer is submitted.
387
421
  *
388
- * `credited` carries the history entry, whose `amount` is the figure Lighter actually
389
- * booked — the only place that figure appears. `registered` is the terminal state of a
390
- * first deposit, which carries the account indexes instead of a history entry. `untracked`
391
- * ends a transfer this caller cannot follow, and `unsettled` ends one whose watch window
392
- * closed first, so nobody waits for an outcome that never arrives.
422
+ * `credited` carries whichever record the route can actually read. `registered` is the terminal
423
+ * state of a first deposit, which reports the account indexes the deposit created. `untracked` ends
424
+ * a transfer this caller asked nobody to follow, and `unsettled` ends one whose watch window closed
425
+ * first, so nobody waits for an outcome that never arrives.
426
+ *
427
+ * `failed` and `action-required` are reachable only on the CCTP route: Lighter's deposit history is
428
+ * the one source that names them, and the Fun.xyz bridge documents no failure state at all.
393
429
  */
394
- type CctpDepositProgress = {
430
+ type LighterDepositProgress = {
395
431
  state: 'confirming';
396
432
  txHash: string;
397
433
  } | {
@@ -400,7 +436,7 @@ type CctpDepositProgress = {
400
436
  } | {
401
437
  state: 'credited';
402
438
  txHash: string;
403
- deposit: LighterDeposit;
439
+ credit: LighterDepositCredit;
404
440
  } | {
405
441
  state: 'failed';
406
442
  txHash: string;
@@ -421,13 +457,27 @@ type CctpDepositProgress = {
421
457
  state: 'unsettled';
422
458
  txHash: string;
423
459
  };
460
+ /**
461
+ * The evidence that a deposit was credited, kept in the form its own route produces.
462
+ *
463
+ * The CCTP route reads Lighter's authenticated deposit history, which is the only place the booked
464
+ * amount appears. The Fun.xyz route reads the bridge's own transaction list, which answers before a
465
+ * first deposit has an account to authenticate with. Neither record substitutes for the other.
466
+ */
467
+ type LighterDepositCredit = {
468
+ source: 'lighter-history';
469
+ deposit: LighterDeposit;
470
+ } | {
471
+ source: 'funxyz-bridge';
472
+ transaction: HttpTypes.LighterUdaTransaction;
473
+ };
424
474
  /** Wallet transport a deposit borrows from its caller, keeping this SDK free of any wallet library. */
425
- type CctpDepositWalletAdapter = {
475
+ type LighterDepositWalletAdapter = {
426
476
  readUsdcBalance: (chainId: number, ownerAddress: `0x${string}`) => Promise<bigint>;
427
477
  retrieveWallet: (chainId: number) => Promise<WalletClientWithAccount>;
428
478
  confirmTransaction: (chainId: number, txHash: string) => Promise<void>;
429
479
  };
430
- /** Credentials that let a deposit watch read the credited main account's deposit history. */
480
+ /** Credentials that let a CCTP deposit watch read the credited main account's deposit history. */
431
481
  type CctpDepositHistorySettlement = {
432
482
  follow: 'deposit-history';
433
483
  selectedAccountIndex: number;
@@ -438,35 +488,155 @@ type CctpDepositRegistrationSettlement = {
438
488
  follow: 'account-registration';
439
489
  };
440
490
  /**
441
- * How a submitted deposit is followed to its Lighter outcome.
491
+ * How a submitted CCTP deposit is followed to its Lighter outcome.
442
492
  *
443
493
  * A first deposit cannot supply credentials — it is the deposit that creates the account — so
444
494
  * it re-runs the onboarding read instead of the authenticated deposit history.
445
495
  */
446
496
  type CctpDepositSettlement = CctpDepositHistorySettlement | CctpDepositRegistrationSettlement;
497
+ /**
498
+ * Follows a submitted Fun.xyz deposit to its Lighter outcome.
499
+ *
500
+ * Carries no follow mode on purpose: only the bridge knows which record can answer, and it says so
501
+ * when it mints the address. An account that already exists is confirmed from the bridge's own
502
+ * transaction list; the deposit that creates an account is confirmed by Lighter registering it.
503
+ * Asking a caller to predict that invites the one combination that never resolves. Omit this object
504
+ * to submit a deposit nobody waits on.
505
+ */
506
+ type FunxyzDepositSettlement = {
507
+ follow: 'outcome';
508
+ };
509
+ /** Deposits through Lighter's Ethereum gateway contract, signed by the owner's own wallet. */
510
+ type EthereumDepositParams = {
511
+ route: 'ethereum';
512
+ /** The mainnet wallet that signs the gateway call. */
513
+ walletClient: WalletClientWithAccount;
514
+ to: `0x${string}`;
515
+ assetId: number;
516
+ routeType: number;
517
+ amount: string;
518
+ nativeValue?: string;
519
+ /** Optional cached `assetDetails.l1_decimals`; the helper fetches assetDetails when omitted. */
520
+ l1Decimals?: number;
521
+ };
522
+ /** Deposits native USDC to a Lighter CCTP intent address bound to this exact amount. */
447
523
  type CctpDepositParams = {
524
+ route: 'cctp';
448
525
  /** The L1 wallet whose main Lighter account receives the deposit. */
449
526
  ownerAddress: `0x${string}`;
450
527
  /** The browser wallet allowed to use the direct-transfer path. */
451
528
  connectedAddress: `0x${string}` | undefined;
452
- /** A `chainId` from `listDepositNetworks()`; the connected wallet must already be on it. */
529
+ /** A `chainId` from `listCctpDepositNetworks()`; the connected wallet must already be on it. */
453
530
  chainId: number;
454
531
  /** Positive human-readable USDC amount with at most six fractional digits. */
455
532
  amount: string;
456
533
  /** Supplies wallet transport operations without coupling the SDK to Wagmi. */
457
- wallet: CctpDepositWalletAdapter;
534
+ wallet: LighterDepositWalletAdapter;
458
535
  /** Receives source-confirmation and Lighter-settlement state changes. */
459
- onProgress: (progress: CctpDepositProgress) => void;
536
+ onProgress: (progress: LighterDepositProgress) => void;
460
537
  /** Stops in-memory settlement polling when the owning view changes. */
461
538
  signal?: AbortSignal;
462
539
  /** Follows deposit history for a funded account, or account registration for a first deposit. */
463
540
  settlement?: CctpDepositSettlement;
541
+ /** Overrides how long the settlement watch waits before reporting `unsettled`; defaults to `SETTLEMENT_WATCH_LIMIT_MS`. */
542
+ settlementTimeoutMs?: number;
543
+ };
544
+ /**
545
+ * Deposits native USDC to the wallet's Fun.xyz universal deposit address.
546
+ *
547
+ * USDC only: the wallet adapter reads a USDC balance and nothing else, so an ETH deposit goes
548
+ * through `createDepositAddress` and the depositor's own transfer instead.
549
+ */
550
+ type FunxyzDepositParams = {
551
+ route: 'funxyz';
552
+ /** The L1 wallet whose Lighter account the bridge credits. */
553
+ ownerAddress: `0x${string}`;
554
+ /** The browser wallet allowed to use the direct-transfer path. */
555
+ connectedAddress: `0x${string}` | undefined;
556
+ /** A chain id from `FUNXYZ_EVM_CHAIN_NAMES`; the connected wallet must already be on it. */
557
+ chainId: number;
558
+ /** Positive human-readable USDC amount with at most six fractional digits. */
559
+ amount: string;
560
+ /** Which Lighter book the deposit funds. */
561
+ market: FunxyzMarket;
562
+ /** Targets a sub-account; omit to credit the owner's master account. */
563
+ accountIndex?: number;
564
+ /** Supplies wallet transport operations without coupling the SDK to Wagmi. */
565
+ wallet: LighterDepositWalletAdapter;
566
+ /** Receives source-confirmation and bridge-settlement state changes. */
567
+ onProgress: (progress: LighterDepositProgress) => void;
568
+ /** Stops in-memory settlement polling when the owning view changes. */
569
+ signal?: AbortSignal;
570
+ /** Follows the bridge, and account registration when this is the account's first deposit. */
571
+ settlement?: FunxyzDepositSettlement;
572
+ };
573
+ /** Every way this SDK can move funds into a Lighter account, selected by `route`. */
574
+ type LighterDepositParams = EthereumDepositParams | CctpDepositParams | FunxyzDepositParams;
575
+ type EthereumDepositResult = {
576
+ route: 'ethereum';
577
+ txHash: string;
464
578
  };
465
579
  type CctpDepositResult = {
580
+ route: 'cctp';
466
581
  txHash: string;
467
582
  /** The intent address the transfer credits, so a caller can link to what it funded. */
468
583
  intentAddress: `0x${string}`;
469
584
  };
585
+ type FunxyzDepositResult = {
586
+ route: 'funxyz';
587
+ txHash: string;
588
+ /** The universal deposit address the transfer credits, so a caller can link to what it funded. */
589
+ depositAddress: `0x${string}`;
590
+ /** What the bridge will credit: an existing account index, or the account this deposit creates. */
591
+ credits: FunxyzDepositCredit;
592
+ };
593
+ type LighterDepositResult = EthereumDepositResult | CctpDepositResult | FunxyzDepositResult;
594
+ /** Requests a short-lived CCTP address any wallet or exchange may send native USDC to. */
595
+ type CctpDepositAddressParams = {
596
+ route: 'cctp';
597
+ /** A `chainId` from `listCctpDepositNetworks()`; Lighter adds networks without a release. */
598
+ chainId: number;
599
+ /** The L1 owner whose main Lighter account receives funds, not necessarily the sender. */
600
+ ownerAddress: `0x${string}`;
601
+ };
602
+ /** Requests the wallet's permanent Fun.xyz addresses, one per supported chain family. */
603
+ type FunxyzDepositAddressParams = {
604
+ route: 'funxyz';
605
+ /** The L1 owner whose Lighter account receives funds, not necessarily the sender. */
606
+ ownerAddress: `0x${string}`;
607
+ /** Which Lighter book the deposit funds. */
608
+ market: FunxyzMarket;
609
+ /** What the depositor will send; Fun.xyz converts ETH to USDC on arrival. */
610
+ asset: FunxyzAsset;
611
+ /** Targets a sub-account; omit to credit the owner's master account. */
612
+ accountIndex?: number;
613
+ };
614
+ /** Every way this SDK can hand out an address that credits a Lighter account, selected by `route`. */
615
+ type LighterDepositAddressParams = CctpDepositAddressParams | FunxyzDepositAddressParams;
616
+ type CctpDepositAddressResult = {
617
+ route: 'cctp';
618
+ /** Send at least `MIN_LIGHTER_CCTP_DEPOSIT_USDC` on the selected chain to this address. */
619
+ intentAddress: `0x${string}`;
620
+ /** Local deadline before Lighter's documented ten-minute cancellation boundary. */
621
+ expiresAt: number;
622
+ };
623
+ /**
624
+ * The wallet's Fun.xyz addresses, which the bridge mints once and then reuses.
625
+ *
626
+ * Unlike a CCTP intent these never expire and are not bound to an amount, so a caller may show them
627
+ * for as long as the wallet is connected. A family the bridge cannot currently serve is absent
628
+ * rather than empty, so no caller offers an address that credits nobody.
629
+ */
630
+ type FunxyzDepositAddressResult = {
631
+ route: 'funxyz';
632
+ evmAddress: `0x${string}`;
633
+ solanaAddress?: string;
634
+ tronAddress?: string;
635
+ bitcoinSegwitAddress?: string;
636
+ /** What the bridge will credit: an existing account index, or the account a first deposit creates. */
637
+ credits: FunxyzDepositCredit;
638
+ };
639
+ type LighterDepositAddressResult = CctpDepositAddressResult | FunxyzDepositAddressResult;
470
640
  type WithdrawParams = {
471
641
  accountIndex: number;
472
642
  assetId: number;
@@ -496,15 +666,22 @@ type ApproveIntegratorParams = {
496
666
  type ApproveIntegratorResult = {
497
667
  txHash: string;
498
668
  };
669
+ type ChangeAccountTierParams = {
670
+ accountIndex: number;
671
+ apiKeyIndex: number;
672
+ apiPrivateKey: string;
673
+ /** The tier to move onto; the tier in force reads off the account tracker. */
674
+ tier: LighterAccountTier;
675
+ };
676
+ type ChangeAccountTierResult = {
677
+ tier: LighterAccountTier;
678
+ };
499
679
  type IntegratorApprovalRequirements = {
500
680
  /** Minimum perps maker-fee cap, in Lighter's integer fee-tick units. */
501
681
  minPerpsMakerFee: number;
502
682
  /** Minimum perps taker-fee cap, in Lighter's integer fee-tick units. */
503
683
  minPerpsTakerFee: number;
504
684
  };
505
- type DepositResult = {
506
- txHash: string;
507
- };
508
685
  type WithdrawResult = {
509
686
  txHash: string;
510
687
  };
@@ -529,13 +706,19 @@ type LighterOnboardingStatus = {
529
706
  interface LighterHelper {
530
707
  checkOnboarding(l1Address: string): Promise<LighterOnboardingStatus>;
531
708
  lookupAccount(l1Address: string): Promise<LighterLookupResult>;
532
- checkIntegratorApproval(accountIndex: number, integratorAccountIndex: number, requirements?: IntegratorApprovalRequirements): Promise<boolean>;
709
+ checkIntegratorApproval(accountIndex: number, integratorAccountIndex: number, requirements?: IntegratorApprovalRequirements, authToken?: string): Promise<boolean>;
533
710
  connectWallet(walletClient: WalletClientWithAccount, params: ConnectWalletParams): Promise<ConnectWalletResult>;
534
711
  approveIntegrator(walletClient: WalletClientWithAccount, params: ApproveIntegratorParams): Promise<ApproveIntegratorResult>;
535
- listDepositNetworks(): Promise<LighterDepositNetwork[]>;
536
- createExternalCctpDepositIntent(params: CctpDepositIntentParams): Promise<CctpDepositIntentResult>;
537
- depositUsdcViaCctp(params: CctpDepositParams): Promise<CctpDepositResult>;
538
- deposit(walletClient: WalletClientWithAccount, params: DepositParams): Promise<DepositResult>;
712
+ changeAccountTier(params: ChangeAccountTierParams): Promise<ChangeAccountTierResult>;
713
+ listCctpDepositNetworks(): Promise<LighterDepositNetwork[]>;
714
+ /** Runs one deposit route end to end, narrowing its result to the route the caller selected. */
715
+ deposit<TParams extends LighterDepositParams>(params: TParams): Promise<Extract<LighterDepositResult, {
716
+ route: TParams['route'];
717
+ }>>;
718
+ /** Hands out an address any sender may fund, narrowed to the route the caller selected. */
719
+ createDepositAddress<TParams extends LighterDepositAddressParams>(params: TParams): Promise<Extract<LighterDepositAddressResult, {
720
+ route: TParams['route'];
721
+ }>>;
539
722
  fastWithdraw(walletClient: WalletClientWithAccount, params: FastWithdrawParams): Promise<FastWithdrawResult>;
540
723
  withdraw(walletClient: WalletClientWithAccount, params: WithdrawParams): Promise<WithdrawResult>;
541
724
  }
@@ -544,6 +727,33 @@ type LighterLookupResult = {
544
727
  subAccountIndexes: number[];
545
728
  };
546
729
 
730
+ /**
731
+ * Functional Lighter deposit operations that route through the Fun.xyz bridge.
732
+ *
733
+ * The bridge mints a universal deposit address (UDA) per wallet and credits anything sent to it,
734
+ * creating the Lighter account when the first deposit lands. That is what lets one operation serve a
735
+ * wallet Lighter has never seen and one that already holds an account.
736
+ *
737
+ * Every bridge call goes through Core, which holds the builder API key. The key authenticates a
738
+ * builder rather than a user, so it must never reach a browser bundle.
739
+ */
740
+
741
+ /** Names the Fun.xyz minimum, in whole US dollars, for one source and account state. */
742
+ declare function readFunxyzMinimumUsd(source: FunxyzDepositSource, account: FunxyzAccountState): string;
743
+ /**
744
+ * Lists the EVM chains a connected wallet can deposit from through `deposit({ route: 'funxyz' })`.
745
+ *
746
+ * Narrower than what the bridge accepts: this SDK submits the ERC-20 transfer itself, so it offers a
747
+ * chain only once that chain's native USDC contract is verified. A caller wanting the rest of the
748
+ * bridge's roster hands out an address from `createDepositAddress` instead.
749
+ */
750
+ declare function listFunxyzTransferableChains(): Array<{
751
+ chainId: number;
752
+ name: string;
753
+ }>;
754
+ /** Names which minimum an EVM chain falls under, since mainnet never gets the reduced one. */
755
+ declare function readFunxyzChainSource(chainId: number): FunxyzDepositSource;
756
+
547
757
  declare const MIN_USER_API_KEY_INDEX = 4;
548
758
  declare const MAX_API_KEY_INDEX = 254;
549
759
  declare function findAvailableApiKeyIndex(apiKeys: ReadonlyArray<Pick<ApiKey, 'api_key_index'>>): number;
@@ -1950,11 +2160,18 @@ declare const LighterUnifiedBalance: z.ZodObject<{
1950
2160
  type LighterUnifiedBalance = z.infer<typeof LighterUnifiedBalance>;
1951
2161
 
1952
2162
  type LighterAccountTrackerConfig = AccountTrackerConfig & {
2163
+ /** Null leaves the tier unread: `/accountLimits` is authenticated and only Core mints a token. */
2164
+ sdk: PearSDK | null;
1953
2165
  account: TradeAccount;
1954
2166
  credentials: SupportedCredentials;
1955
2167
  };
2168
+ /** Told the account's tier, or told there is no answer yet. */
2169
+ type AccountTierCallback = (tier: LighterAccountTier | null) => void;
1956
2170
  declare class LighterAccountTracker extends BaseAccountTracker {
2171
+ private readonly sdk;
1957
2172
  private readonly accountIdentifier;
2173
+ private readonly apiKeyIndex;
2174
+ private readonly apiPrivateKey;
1958
2175
  private ws;
1959
2176
  private messageListenerId;
1960
2177
  private openListenerId;
@@ -1962,8 +2179,10 @@ declare class LighterAccountTracker extends BaseAccountTracker {
1962
2179
  private positionPollInFlight;
1963
2180
  private marketRefreshTimer;
1964
2181
  private marketRefreshInFlight;
2182
+ private subscribeRetryTimer;
1965
2183
  private startInFlight;
1966
2184
  private lifecycleVersion;
2185
+ private wsConnectionVersion;
1967
2186
  private stateVersion;
1968
2187
  private assetsByAssetId;
1969
2188
  private wsPositionsByMarketId;
@@ -1971,9 +2190,30 @@ declare class LighterAccountTracker extends BaseAccountTracker {
1971
2190
  private marketsBySymbol;
1972
2191
  private spotPriceBySymbol;
1973
2192
  private stats;
2193
+ private accountTier;
2194
+ private accountTierListeners;
2195
+ private accountTierInFlight;
1974
2196
  private hasAssets;
1975
2197
  constructor(config: LighterAccountTrackerConfig);
1976
- /** Stateless one-shot account read — public endpoints only, and no websocket. */
2198
+ /**
2199
+ * The tier Lighter has the account on, and every later change to it.
2200
+ *
2201
+ * A separate channel from the balance on purpose: tier is account configuration, so it neither
2202
+ * moves with the account's figures nor belongs to a trading mode. No websocket channel carries
2203
+ * it — `/accountLimits` is the only source — so this reports what the last read said, and
2204
+ * `refreshAccountTier` is what asks again.
2205
+ */
2206
+ trackAccountTier(callback: AccountTierCallback): () => void;
2207
+ /** The tier as the last read left it, without asking the venue again. */
2208
+ getAccountTier(): LighterAccountTier | null;
2209
+ /**
2210
+ * Re-reads the tier and tells every subscriber what changed.
2211
+ *
2212
+ * Called after something moves the tier — a change this account submitted — because nothing on
2213
+ * the socket announces one. Repeated callers share one in-flight read.
2214
+ */
2215
+ refreshAccountTier(): Promise<void>;
2216
+ /** Stateless one-shot account read — authenticated for connected accounts, and no websocket. */
1977
2217
  snapshot(): Promise<AccountSnapshot>;
1978
2218
  /**
1979
2219
  * Stateless one-shot per-asset settings read, keyed by market id (the same identifier the live
@@ -1995,7 +2235,21 @@ declare class LighterAccountTracker extends BaseAccountTracker {
1995
2235
  protected releaseAsset(_coin: string): void;
1996
2236
  /** Starts a clean account-data epoch before subscribing on each websocket connection. */
1997
2237
  private handleWsOpen;
1998
- private sendStaticSubs;
2238
+ /**
2239
+ * Subscribes this socket epoch's account channels, and keeps trying until one attempt lands.
2240
+ *
2241
+ * This is the sole subscriber of `account_all` and `user_stats`, and the live balance is built
2242
+ * from those two channels alone — see `buildBalance`. A mint that failed once and was never
2243
+ * retried therefore left the tracker connected but permanently unsubscribed: the 2s REST poll
2244
+ * kept positions moving while the balance silently froze until some incidental reconnect.
2245
+ *
2246
+ * The wait doubles up to a ceiling, and only a new connection epoch or teardown ends it.
2247
+ */
2248
+ private subscribeAccountChannels;
2249
+ /** Mints a live token for this socket epoch and authenticates every account subscription. */
2250
+ private sendAccountSubscriptions;
2251
+ /** Drops a pending subscription retry, so nothing outlives the connection that scheduled it. */
2252
+ private clearSubscribeRetry;
1999
2253
  private routeRaw;
2000
2254
  private handle;
2001
2255
  private onAccountAll;
@@ -2018,7 +2272,14 @@ declare class LighterAccountTracker extends BaseAccountTracker {
2018
2272
  private marketContext;
2019
2273
  /** The account's current per-market settings as the base tracker already holds them. */
2020
2274
  private liveAccountSettings;
2275
+ /** Reads the account with credentials when present, or explicitly uses the read-only verifier path. */
2021
2276
  private fetchPrimaryAccount;
2277
+ /** Reads market context under the same account identity as the snapshot that consumes it. */
2278
+ private fetchMarkets;
2279
+ /** Returns this account's cached auth token, or no token for the explicit empty-key verifier. */
2280
+ private retrieveAuthToken;
2281
+ /** Requires credentials for private WebSocket channels even when REST is in verifier mode. */
2282
+ private retrieveRequiredAuthToken;
2022
2283
  private pollPositions;
2023
2284
  /**
2024
2285
  * Republishes positions and per-market settings from REST.
@@ -2033,6 +2294,15 @@ declare class LighterAccountTracker extends BaseAccountTracker {
2033
2294
  * partly REST-derived without any reader being able to tell.
2034
2295
  */
2035
2296
  private performPositionPoll;
2297
+ /**
2298
+ * Reads the tier Lighter currently has the account on, and publishes it when it moved.
2299
+ *
2300
+ * `/accountLimits` is authenticated, so a tracker with no SDK to mint a token through — and demo,
2301
+ * where no such account exists — reports no tier rather than a wrong one. A failed read does the
2302
+ * same and leaves the last known tier standing: the endpoint failing is not the account losing
2303
+ * its tier, and blanking it would announce a change nobody made.
2304
+ */
2305
+ private performAccountTierRead;
2036
2306
  /** Shares one in-flight market read, so a slow response cannot stack requests behind the WAF. */
2037
2307
  private refreshMarkets;
2038
2308
  /**
@@ -2248,6 +2518,8 @@ declare class OkxAccountTracker extends BaseAccountTracker {
2248
2518
  }
2249
2519
 
2250
2520
  type CreateAccountTrackerConfig = AccountTrackerConfig & {
2521
+ /** Lighter only: null there leaves the account's tier unread. */
2522
+ sdk: PearSDK | null;
2251
2523
  account: TradeAccount;
2252
2524
  credentials: SupportedCredentials;
2253
2525
  };
@@ -2278,4 +2550,4 @@ declare class ExchangesSDK {
2278
2550
  private fetchCredentials;
2279
2551
  }
2280
2552
 
2281
- export { ACCOUNT_MODE_LABELS, ASSET_DECIMALS, AccountBalance, AccountBalanceCore, type AccountHealthStatus, AccountMode, type AccountPosition, type AccountSnapshot, type AccountStatus, type AccountSyncer, type AccountSyncerConfig, type AccountTracker, type AccountTrackerConfig, type AccountWarningReason, type ApiKey, type ApproveIntegratorParams, type ApproveIntegratorResult, AssetId, type AssetSnapshotMap, type BalanceCallback, BaseAccountSyncer, BaseAccountTracker, BaseWs, BasketLeg, BinanceAccountSyncer, BinanceAccountTracker, type BinanceAccountTrackerConfig, BinanceExchangeWs, BinanceMultiAssetBalance, BinanceSingleAssetBalance, BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig, BybitAccountSyncer, BybitAccountTracker, type BybitAccountTrackerConfig, BybitExchangeWs, BybitIsolatedMarginBalance, BybitPortfolioMarginBalance, BybitRegularMarginBalance, BybitWs, type BybitWsConfig, type CappedBasketLeg, type CctpDepositHistorySettlement, type CctpDepositIntentParams, type CctpDepositIntentResult, type CctpDepositParams, type CctpDepositProgress, type CctpDepositRegistrationSettlement, type CctpDepositResult, type CctpDepositSettlement, type CctpDepositWalletAdapter, type CheckApiWalletParams, CollateralBalance, type ConnectOptions, type ConnectWalletParams, type ConnectWalletResult, type CreateAccountTrackerConfig, type CreateExchangeWsConfig, DecimalString, type DepositParams, type DepositResult, type ExchangeConnection, type ExchangeHelperExchange, type ExchangeHelperMap, type ExchangeState, ExchangeWs, type ExchangeWsByConnector, ExchangesSDK, type ExchangesSDKConfig, type FastWithdrawParams, type FastWithdrawResult, type FillSyncOutcome, type FundingSyncOutcome, HyperliquidAccountSyncer, HyperliquidAccountTracker, type HyperliquidAccountTrackerConfig, HyperliquidDexState, HyperliquidExchangeWs, type HyperliquidHelper, HyperliquidPortfolioMarginBalance, HyperliquidPortfolioMarginCollateral, HyperliquidStandardBalance, HyperliquidUnifiedBalance, HyperliquidWs, type IntegratorApprovalRequirements, L2_ASSET_DECIMALS, LIGHTER_CCTP_USDC_ADDRESSES, LIGHTER_CCTP_USDC_DECIMALS, LighterAccountSyncer, LighterAccountTracker, type LighterAccountTrackerConfig, LighterClassicBalance, type LighterDeposit, type LighterDepositNetwork, LighterExchangeWs, type LighterHelper, type LighterLookupResult, type LighterOnboardingStatus, LighterUnifiedBalance, LighterWs, type ListExternalFillsParams, type ListExternalFundingParams, type ListExternalPositionsParams, MAX_API_KEY_INDEX, MIN_LIGHTER_CCTP_DEPOSIT_USDC, MIN_LIGHTER_FAST_WITHDRAW_USDC, MIN_USER_API_KEY_INDEX, MarginMode, type MaxBasketSizeCalculation, MaxBasketSizeInput, MaxBasketSizeResult, type MessageListener, OkxAccountSyncer, OkxAccountTracker, type OkxAccountTrackerConfig, OkxExchangeWs, OkxFuturesBalance, OkxMultiCurrencyMarginBalance, OkxPortfolioMarginBalance, OkxSpotBalance, OkxWs, type OkxWsConfig, type OpenListener, type PositionsCallback, RouteType, Side, SignedDecimalString, type StateUpdate, type SupportedCredentials, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, computeMaxBasketSize, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, findAvailableApiKeyIndex, getAssetDecimals, getLighterCctpUsdcAddress, usdcAbi };
2553
+ export { ACCOUNT_MODE_LABELS, ASSET_DECIMALS, AccountBalance, AccountBalanceCore, type AccountHealthStatus, AccountMode, type AccountPosition, type AccountSnapshot, type AccountStatus, type AccountSyncer, type AccountSyncerConfig, type AccountTierCallback, type AccountTracker, type AccountTrackerConfig, type AccountWarningReason, type ApiKey, type ApproveIntegratorParams, type ApproveIntegratorResult, AssetId, type AssetSnapshotMap, type BalanceCallback, BaseAccountSyncer, BaseAccountTracker, BaseWs, BasketLeg, BinanceAccountSyncer, BinanceAccountTracker, type BinanceAccountTrackerConfig, BinanceExchangeWs, BinanceMultiAssetBalance, BinanceSingleAssetBalance, BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig, BybitAccountSyncer, BybitAccountTracker, type BybitAccountTrackerConfig, BybitExchangeWs, BybitIsolatedMarginBalance, BybitPortfolioMarginBalance, BybitRegularMarginBalance, BybitWs, type BybitWsConfig, type CappedBasketLeg, type CctpDepositAddressParams, type CctpDepositAddressResult, type CctpDepositHistorySettlement, type CctpDepositParams, type CctpDepositRegistrationSettlement, type CctpDepositResult, type CctpDepositSettlement, type ChangeAccountTierParams, type ChangeAccountTierResult, type CheckApiWalletParams, CollateralBalance, type ConnectOptions, type ConnectWalletParams, type ConnectWalletResult, type CreateAccountTrackerConfig, type CreateExchangeWsConfig, DecimalString, type EthereumDepositParams, type EthereumDepositResult, type ExchangeConnection, type ExchangeHelperExchange, type ExchangeHelperMap, type ExchangeState, ExchangeWs, type ExchangeWsByConnector, ExchangesSDK, type ExchangesSDKConfig, FUNXYZ_DEPOSIT_MINIMUMS_USD, FUNXYZ_ETHEREUM_MAINNET_CHAIN_ID, FUNXYZ_EVM_CHAIN_NAMES, type FastWithdrawParams, type FastWithdrawResult, type FillSyncOutcome, type FundingSyncOutcome, type FunxyzAccountState, type FunxyzAsset, type FunxyzDepositAddressParams, type FunxyzDepositAddressResult, type FunxyzDepositCredit, type FunxyzDepositParams, type FunxyzDepositResult, type FunxyzDepositSettlement, type FunxyzDepositSource, type FunxyzMarket, HyperliquidAccountSyncer, HyperliquidAccountTracker, type HyperliquidAccountTrackerConfig, HyperliquidDexState, HyperliquidExchangeWs, type HyperliquidHelper, HyperliquidPortfolioMarginBalance, HyperliquidPortfolioMarginCollateral, HyperliquidStandardBalance, HyperliquidUnifiedBalance, HyperliquidWs, type IntegratorApprovalRequirements, L2_ASSET_DECIMALS, LIGHTER_NATIVE_USDC_ADDRESSES, LIGHTER_USDC_DECIMALS, LighterAccountSyncer, type LighterAccountTier, LighterAccountTracker, type LighterAccountTrackerConfig, type LighterAuthCredentials, LighterClassicBalance, type LighterDeposit, type LighterDepositAddressParams, type LighterDepositAddressResult, type LighterDepositCredit, type LighterDepositNetwork, type LighterDepositParams, type LighterDepositProgress, type LighterDepositResult, type LighterDepositWalletAdapter, LighterExchangeWs, type LighterHelper, type LighterLookupResult, type LighterOnboardingStatus, LighterUnifiedBalance, LighterWs, type ListExternalFillsParams, type ListExternalFundingParams, type ListExternalPositionsParams, MAX_API_KEY_INDEX, MIN_LIGHTER_CCTP_DEPOSIT_USDC, MIN_LIGHTER_FAST_WITHDRAW_USDC, MIN_USER_API_KEY_INDEX, MarginMode, type MaxBasketSizeCalculation, MaxBasketSizeInput, MaxBasketSizeResult, type MessageListener, OkxAccountSyncer, OkxAccountTracker, type OkxAccountTrackerConfig, OkxExchangeWs, OkxFuturesBalance, OkxMultiCurrencyMarginBalance, OkxPortfolioMarginBalance, OkxSpotBalance, OkxWs, type OkxWsConfig, type OpenListener, type PositionsCallback, RouteType, Side, SignedDecimalString, type StateUpdate, type SupportedCredentials, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, computeMaxBasketSize, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, findAvailableApiKeyIndex, getAssetDecimals, getLighterNativeUsdcAddress, listFunxyzTransferableChains, readFunxyzChainSource, readFunxyzMinimumUsd, retrieveLighterAuthToken, usdcAbi };
package/dist/sdk.js CHANGED
@@ -80,6 +80,8 @@ class ExchangesSDK {
80
80
  }
81
81
  buildTracker(connection) {
82
82
  return createAccountTracker(connection.connector, {
83
+ // Lighter's tier read is authenticated, and Core is what mints the token for it.
84
+ sdk: this.sdk,
83
85
  demo: this.demo,
84
86
  account: connection.account,
85
87
  credentials: connection.credentials
@@ -32,6 +32,11 @@ async function checkLighterAccountStatus(config) {
32
32
  }
33
33
  if (integratorAccountIndex !== void 0 && integratorMinPerpsMakerFee !== void 0 && integratorMinPerpsTakerFee !== void 0) {
34
34
  try {
35
+ const token = await retrieveLighterAuthToken(config.sdk, {
36
+ accountIndex,
37
+ apiKeyIndex: credentials.api_key_index,
38
+ apiPrivateKey: credentials.api_private_key
39
+ }, config.demo);
35
40
  const helper = createExchangeHelper({
36
41
  exchange: "lighter",
37
42
  sdk: config.sdk,
@@ -40,7 +45,7 @@ async function checkLighterAccountStatus(config) {
40
45
  const approved = await helper.checkIntegratorApproval(accountIndex, integratorAccountIndex, {
41
46
  minPerpsMakerFee: integratorMinPerpsMakerFee,
42
47
  minPerpsTakerFee: integratorMinPerpsTakerFee
43
- });
48
+ }, token);
44
49
  if (!approved) reasons.push("lighter_integrator_not_approved");
45
50
  } catch {
46
51
  reasons.push("lighter_integrator_not_approved");
@@ -30,11 +30,13 @@ class LighterAccountSyncer extends BaseAccountSyncer {
30
30
  }, this.demo);
31
31
  }
32
32
  async listExternalPositions({ instruments }) {
33
+ this.assertAuthenticatedSyncAvailable();
33
34
  const contractSizeByInstrumentId = new Map(instruments.map((instrument) => [
34
35
  instrument.id,
35
36
  instrument.precision.quantity.contractSize
36
37
  ]));
37
- const response = await fetchAccount(this.accountIndex, this.demo);
38
+ const token = await this.retrieveAuthToken();
39
+ const response = await fetchAccount(this.accountIndex, token, this.demo);
38
40
  const rawPositions = response.accounts?.[0]?.positions ?? [];
39
41
  return rawPositions.reduce((positions, rawPosition) => {
40
42
  const instrumentId = rawPosition.market_id.toString();
@@ -50,6 +50,7 @@ function createAccountTracker(exchange, config) {
50
50
  });
51
51
  case "lighter":
52
52
  return new LighterAccountTracker({
53
+ sdk: config.sdk,
53
54
  demo: config.demo,
54
55
  onError: config.onError,
55
56
  account: config.account,