@pear-protocol/exchanges-sdk 0.12.1 → 0.13.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.
@@ -6,6 +6,16 @@ const HL_INFO_URLS = {
6
6
  mainnet: "https://api.hyperliquid.xyz/info",
7
7
  testnet: "https://api.hyperliquid-testnet.xyz/info"
8
8
  };
9
+ class HyperliquidInfoRequestError extends Error {
10
+ static {
11
+ __name(this, "HyperliquidInfoRequestError");
12
+ }
13
+ status;
14
+ constructor(status) {
15
+ super(`Hyperliquid info request failed: ${status}`);
16
+ this.status = status;
17
+ }
18
+ }
9
19
  async function fetchInfo(body, demo = false) {
10
20
  const url = demo ? HL_INFO_URLS.testnet : HL_INFO_URLS.mainnet;
11
21
  const res = await proxyFetch(url, {
@@ -16,7 +26,7 @@ async function fetchInfo(body, demo = false) {
16
26
  body: JSON.stringify(body)
17
27
  });
18
28
  if (!res.ok) {
19
- throw new Error(`Hyperliquid info request failed: ${res.status}`);
29
+ throw new HyperliquidInfoRequestError(res.status);
20
30
  }
21
31
  return res.json();
22
32
  }
@@ -85,4 +95,4 @@ async function fetchActiveAssetData(user, coin, demo = false) {
85
95
  }
86
96
  __name(fetchActiveAssetData, "fetchActiveAssetData");
87
97
 
88
- export { fetchActiveAssetData, fetchAllMids, fetchClearinghouseState, fetchDelegatorSummary, fetchInfo, fetchPerpDexs, fetchSpotClearinghouseState, fetchUserAbstraction, fetchUserRole, fetchUserVaultEquities };
98
+ export { HyperliquidInfoRequestError, fetchActiveAssetData, fetchAllMids, fetchClearinghouseState, fetchDelegatorSummary, fetchInfo, fetchPerpDexs, fetchSpotClearinghouseState, fetchUserAbstraction, fetchUserRole, fetchUserVaultEquities };
@@ -3,6 +3,17 @@ import { getLighterBaseUrl } from './constants';
3
3
 
4
4
  var __defProp = Object.defineProperty;
5
5
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ class LighterRequestError extends Error {
7
+ static {
8
+ __name(this, "LighterRequestError");
9
+ }
10
+ status;
11
+ constructor(message, status) {
12
+ super(message);
13
+ this.name = "LighterRequestError";
14
+ this.status = status;
15
+ }
16
+ }
6
17
  const INTENT_REQUEST_ATTEMPTS = 3;
7
18
  const INTENT_RETRY_BASE_DELAY_MS = 500;
8
19
  const RETRYABLE_INTENT_STATUSES = /* @__PURE__ */ new Set([
@@ -176,9 +187,11 @@ async function fetchAccountsByL1Address(l1Address, demo = false) {
176
187
  };
177
188
  }
178
189
  __name(fetchAccountsByL1Address, "fetchAccountsByL1Address");
179
- async function fetchAccount(accountIndex, authToken, demo = false) {
180
- const response = await authenticatedLighterFetch(`${getLighterBaseUrl(demo)}/api/v1/account?by=index&value=${accountIndex}`, authToken);
181
- return readLighterResponse(response, "/account");
190
+ async function fetchAccount(accountIndex, authToken, demo = false, throttle) {
191
+ return gatedLighterRead(throttle, "account", async () => {
192
+ const response = await authenticatedLighterFetch(`${getLighterBaseUrl(demo)}/api/v1/account?by=index&value=${accountIndex}`, authToken);
193
+ return readLighterResponse(response, "/account");
194
+ }, () => 0);
182
195
  }
183
196
  __name(fetchAccount, "fetchAccount");
184
197
  async function fetchPublicAccount(accountIndex, demo = false) {
@@ -232,7 +245,7 @@ async function fetchAssetDetails(demo) {
232
245
  return data.asset_details;
233
246
  }
234
247
  __name(fetchAssetDetails, "fetchAssetDetails");
235
- async function fetchTradesSince(accountIndex, authToken, since, demo = false) {
248
+ async function fetchTradesSince(accountIndex, authToken, since, demo = false, throttle) {
236
249
  const results = [];
237
250
  const seenCursors = /* @__PURE__ */ new Set();
238
251
  let cursor;
@@ -251,8 +264,10 @@ async function fetchTradesSince(accountIndex, authToken, since, demo = false) {
251
264
  cursor
252
265
  } : {}
253
266
  });
254
- const response = await authenticatedLighterFetch(`${getLighterBaseUrl(demo)}/api/v1/trades?${params.toString()}`, authToken);
255
- const data = await readLighterResponse(response, "/trades");
267
+ const data = await gatedLighterRead(throttle, "trades", async () => {
268
+ const response = await authenticatedLighterFetch(`${getLighterBaseUrl(demo)}/api/v1/trades?${params.toString()}`, authToken);
269
+ return readLighterResponse(response, "/trades");
270
+ }, (page2) => (page2.trades ?? []).length);
256
271
  const page = data.trades ?? [];
257
272
  results.push(...page.filter((trade) => trade.timestamp >= since.getTime()));
258
273
  const reachedSince = page.some((trade) => trade.timestamp < since.getTime());
@@ -269,7 +284,7 @@ async function fetchTradesSince(accountIndex, authToken, since, demo = false) {
269
284
  return Array.from(byId.values());
270
285
  }
271
286
  __name(fetchTradesSince, "fetchTradesSince");
272
- async function fetchPositionFundingSince(accountIndex, authToken, since, demo = false) {
287
+ async function fetchPositionFundingSince(accountIndex, authToken, since, demo = false, throttle) {
273
288
  const results = /* @__PURE__ */ new Map();
274
289
  const seenCursors = /* @__PURE__ */ new Set();
275
290
  let cursor;
@@ -284,8 +299,10 @@ async function fetchPositionFundingSince(accountIndex, authToken, since, demo =
284
299
  cursor
285
300
  } : {}
286
301
  });
287
- const response = await authenticatedLighterFetch(`${getLighterBaseUrl(demo)}/api/v1/positionFunding?${params.toString()}`, authToken);
288
- const data = await readLighterResponse(response, "/positionFunding");
302
+ const data = await gatedLighterRead(throttle, "positionFunding", async () => {
303
+ const response = await authenticatedLighterFetch(`${getLighterBaseUrl(demo)}/api/v1/positionFunding?${params.toString()}`, authToken);
304
+ return readLighterResponse(response, "/positionFunding");
305
+ }, (page) => (page.position_fundings ?? []).length);
289
306
  for (const funding of data.position_fundings ?? []) {
290
307
  if (funding.timestamp >= sinceSeconds) {
291
308
  results.set(`${funding.market_id}:${funding.funding_id}`, funding);
@@ -374,6 +391,21 @@ async function fetchUserReferrals(params, demo = false) {
374
391
  };
375
392
  }
376
393
  __name(fetchUserReferrals, "fetchUserReferrals");
394
+ async function gatedLighterRead(throttle, requestType, run, countItems) {
395
+ if (!throttle) {
396
+ return run();
397
+ }
398
+ await throttle.beforeRequest(requestType);
399
+ try {
400
+ const result = await run();
401
+ throttle.afterRequest(requestType, countItems(result));
402
+ return result;
403
+ } catch (error) {
404
+ throttle.afterRequestError(requestType, error);
405
+ throw error;
406
+ }
407
+ }
408
+ __name(gatedLighterRead, "gatedLighterRead");
377
409
  async function authenticatedLighterFetch(url, authToken, init) {
378
410
  const headers = new Headers(init?.headers);
379
411
  headers.set("authorization", authToken);
@@ -440,10 +472,10 @@ async function readLighterResponse(response, endpoint, acceptedCodes = [
440
472
  data = void 0;
441
473
  }
442
474
  if (!data) {
443
- throw new Error(`Lighter ${endpoint} returned ${response.status}`);
475
+ throw new LighterRequestError(`Lighter ${endpoint} returned ${response.status}`, response.status);
444
476
  }
445
477
  if (!acceptedCodes.includes(data.code)) {
446
- throw new Error(`Lighter ${endpoint} returned ${data.code}: ${data.message ?? `HTTP ${response.status}`}`);
478
+ throw new LighterRequestError(`Lighter ${endpoint} returned ${data.code}: ${data.message ?? `HTTP ${response.status}`}`, response.status);
447
479
  }
448
480
  return data;
449
481
  }
@@ -493,4 +525,4 @@ function readReferralAmount(value) {
493
525
  }
494
526
  __name(readReferralAmount, "readReferralAmount");
495
527
 
496
- export { createCctpDepositIntentAddress, fetchAccount, fetchAccountLimits, fetchAccountMetadata, fetchAccountsByL1Address, fetchApiKeys, fetchAssetDetails, fetchDepositHistory, fetchDepositNetworks, fetchOrderBookDetails, fetchPositionFundingSince, fetchPublicAccount, fetchPublicOrderBookDetails, fetchTradesSince, fetchUserReferrals, fetchWithdrawHistory, submitReferralCode };
528
+ export { LighterRequestError, createCctpDepositIntentAddress, fetchAccount, fetchAccountLimits, fetchAccountMetadata, fetchAccountsByL1Address, fetchApiKeys, fetchAssetDetails, fetchDepositHistory, fetchDepositNetworks, fetchOrderBookDetails, fetchPositionFundingSince, fetchPublicAccount, fetchPublicOrderBookDetails, fetchTradesSince, fetchUserReferrals, fetchWithdrawHistory, submitReferralCode };
package/dist/index.d.ts CHANGED
@@ -6,9 +6,30 @@ import { WalletClient, Transport, Chain, Account } from 'viem';
6
6
  import { z } from 'zod';
7
7
 
8
8
  type SupportedCredentials = HttpTypes.ExchangeCredentialsResponse['credentials'];
9
+ /**
10
+ * Optional pacing seam around the syncer's exchange info requests. The SDK stays
11
+ * rate-limit-agnostic: it only exposes when a request starts, what it returned,
12
+ * and when it failed — the caller owns all budget math and waiting.
13
+ */
14
+ type SyncerThrottle = {
15
+ /** Awaited before the request fires; the caller blocks here until its budget allows the call. */
16
+ beforeRequest(requestType: string): Promise<void>;
17
+ /** Called after a successful response; `itemCount` is the response array length (0 for object responses). */
18
+ afterRequest(requestType: string, itemCount: number): void;
19
+ /** Called when the request threw, before the error propagates; lets the caller inspect rate-limit rejections. */
20
+ afterRequestError(requestType: string, error: unknown): void;
21
+ };
9
22
  type ExchangesSDKConfig = {
10
23
  sdk: PearSDK;
11
24
  demo?: boolean;
25
+ /** Optional pacing seam around the syncer's exchange info requests; absent = unthrottled (current behavior). */
26
+ throttle?: SyncerThrottle;
27
+ /**
28
+ * Optional pre-fetched Hyperliquid perp-dex names ('' = the main dex). The list is
29
+ * global (identical for every account), so a batch caller fetches it once per run and
30
+ * passes it here; absent = the syncer fetches it per sync (current behavior).
31
+ */
32
+ hyperliquidPerpDexNames?: string[];
12
33
  /**
13
34
  * Optional forward-proxy for the exchange REST calls. When enabled, requests are re-pointed at
14
35
  * `proxy.url` with the original venue host in `X-Proxy-Target`. Injected here because the SDK
@@ -918,6 +939,10 @@ interface AccountSyncerConfig {
918
939
  account: TradeAccount;
919
940
  credentials: SupportedCredentials;
920
941
  demo: boolean;
942
+ /** Optional pacing seam around the exchange info requests; absent = unthrottled (current behavior). */
943
+ throttle?: SyncerThrottle;
944
+ /** Optional pre-fetched Hyperliquid perp-dex names ('' = the main dex); absent = fetched per sync. */
945
+ hyperliquidPerpDexNames?: string[];
921
946
  }
922
947
  /**
923
948
  * Outcome of one fill sync cycle, so batch/cron callers can tell a completed
@@ -959,6 +984,7 @@ declare abstract class BaseAccountSyncer<ExternalFill> implements AccountSyncer
959
984
  protected account: TradeAccount;
960
985
  protected credentials: SupportedCredentials;
961
986
  protected demo: boolean;
987
+ protected throttle: SyncerThrottle | undefined;
962
988
  constructor(config: AccountSyncerConfig);
963
989
  /**
964
990
  * Fetch the account's currently-open positions from the exchange, normalized
@@ -1125,11 +1151,19 @@ type UserFillsByTimeResponse = {
1125
1151
  type HyperliquidRawFill = UserFillsByTimeResponse;
1126
1152
  declare class HyperliquidAccountSyncer extends BaseAccountSyncer<HyperliquidRawFill> {
1127
1153
  private readonly address;
1154
+ private readonly perpDexNames;
1128
1155
  constructor(config: AccountSyncerConfig);
1129
1156
  protected listExternalPositions({ instruments, }: ListExternalPositionsParams): Promise<HttpTypes.ExternalPosition[]>;
1130
1157
  protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
1131
1158
  protected listExternalFunding({ since, instruments, }: ListExternalFundingParams): Promise<HttpTypes.FundingPaymentEntry[]>;
1132
1159
  protected isReduceOnly(rawFill: HyperliquidRawFill): boolean;
1160
+ /** Fetch the perp-dex descriptors and reduce them to unique dex names ('' = the main dex). */
1161
+ private fetchPerpDexNames;
1162
+ /**
1163
+ * Route one info request through the optional throttle seam: gate before the
1164
+ * call, report the response size after, surface a failure before it propagates.
1165
+ */
1166
+ private fetchInfoGated;
1133
1167
  }
1134
1168
 
1135
1169
  type RawFill$1 = LighterRawTrade;
@@ -2531,6 +2565,8 @@ declare function createAccountTracker(exchange: Connector, config: CreateAccount
2531
2565
  declare class ExchangesSDK {
2532
2566
  private sdk;
2533
2567
  private demo;
2568
+ private throttle;
2569
+ private hyperliquidPerpDexNames;
2534
2570
  constructor(config: ExchangesSDKConfig);
2535
2571
  connect(tradeAccountId: string): Promise<ExchangeConnection>;
2536
2572
  /**
@@ -2548,4 +2584,4 @@ declare class ExchangesSDK {
2548
2584
  private fetchCredentials;
2549
2585
  }
2550
2586
 
2551
- 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, 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 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 LighterApplyReferralCodeParams, type LighterAuthCredentials, LighterClassicBalance, type LighterDeposit, type LighterDepositAddressParams, type LighterDepositAddressResult, type LighterDepositCredit, type LighterDepositHistoryParams, type LighterDepositNetwork, type LighterDepositPage, type LighterDepositParams, type LighterDepositProgress, type LighterDepositResult, type LighterDepositStatus, type LighterDepositWalletAdapter, LighterExchangeWs, type LighterHelper, type LighterLookupResult, type LighterOnboardingStatus, type LighterReferral, type LighterReferralTotals, type LighterReferralTradeStats, LighterUnifiedBalance, type LighterUserReferrals, type LighterUserReferralsParams, type LighterWithdraw, type LighterWithdrawHistoryParams, type LighterWithdrawPage, type LighterWithdrawStatus, type LighterWithdrawType, 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 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, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, findAvailableApiKeyIndex, getAssetDecimals, getLighterNativeUsdcAddress, listFunxyzTransferableChains, readFunxyzChainSource, readFunxyzMinimumUsd, retrieveLighterAuthToken, usdcAbi };
2587
+ 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, 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 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 LighterApplyReferralCodeParams, type LighterAuthCredentials, LighterClassicBalance, type LighterDeposit, type LighterDepositAddressParams, type LighterDepositAddressResult, type LighterDepositCredit, type LighterDepositHistoryParams, type LighterDepositNetwork, type LighterDepositPage, type LighterDepositParams, type LighterDepositProgress, type LighterDepositResult, type LighterDepositStatus, type LighterDepositWalletAdapter, LighterExchangeWs, type LighterHelper, type LighterLookupResult, type LighterOnboardingStatus, type LighterReferral, type LighterReferralTotals, type LighterReferralTradeStats, LighterUnifiedBalance, type LighterUserReferrals, type LighterUserReferralsParams, type LighterWithdraw, type LighterWithdrawHistoryParams, type LighterWithdrawPage, type LighterWithdrawStatus, type LighterWithdrawType, 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 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 SyncerThrottle, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, findAvailableApiKeyIndex, getAssetDecimals, getLighterNativeUsdcAddress, listFunxyzTransferableChains, readFunxyzChainSource, readFunxyzMinimumUsd, retrieveLighterAuthToken, usdcAbi };
package/dist/sdk.js CHANGED
@@ -12,9 +12,13 @@ class ExchangesSDK {
12
12
  }
13
13
  sdk;
14
14
  demo;
15
+ throttle;
16
+ hyperliquidPerpDexNames;
15
17
  constructor(config) {
16
18
  this.sdk = config.sdk;
17
19
  this.demo = config.demo ?? false;
20
+ this.throttle = config.throttle;
21
+ this.hyperliquidPerpDexNames = config.hyperliquidPerpDexNames;
18
22
  if (config.proxy) configureProxy(config.proxy);
19
23
  }
20
24
  async connect(tradeAccountId) {
@@ -67,7 +71,9 @@ class ExchangesSDK {
67
71
  connector: connection.connector,
68
72
  account: connection.account,
69
73
  credentials: connection.credentials,
70
- demo: this.demo
74
+ demo: this.demo,
75
+ throttle: this.throttle,
76
+ hyperliquidPerpDexNames: this.hyperliquidPerpDexNames
71
77
  });
72
78
  }
73
79
  buildTracker(connection) {
@@ -12,12 +12,14 @@ class BaseAccountSyncer {
12
12
  account;
13
13
  credentials;
14
14
  demo;
15
+ throttle;
15
16
  constructor(config) {
16
17
  this.sdk = config.sdk;
17
18
  this.connector = config.connector;
18
19
  this.account = config.account;
19
20
  this.credentials = config.credentials;
20
21
  this.demo = config.demo;
22
+ this.throttle = config.throttle;
21
23
  }
22
24
  // Phase A: Load current Pear state (positions, fills, instruments, watermark).
23
25
  async loadPearState() {
@@ -11,9 +11,11 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
11
11
  __name(this, "HyperliquidAccountSyncer");
12
12
  }
13
13
  address;
14
+ perpDexNames;
14
15
  constructor(config) {
15
16
  super(config);
16
17
  this.address = config.account.exchangeIdentifier;
18
+ this.perpDexNames = config.hyperliquidPerpDexNames;
17
19
  }
18
20
  async listExternalPositions({ instruments }) {
19
21
  const instrumentByBase = new Map(instruments.map((instrument) => [
@@ -23,17 +25,12 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
23
25
  contractSize: instrument.precision.quantity.contractSize
24
26
  }
25
27
  ]));
26
- const perpDexs = await fetchInfo({
27
- type: "perpDexs"
28
- }, this.demo);
29
- const dexNames = [
30
- ...new Set(perpDexs.map((perpDex) => perpDex?.name ?? ""))
31
- ];
32
- const states = await Promise.all(dexNames.map((dex) => fetchInfo({
28
+ const dexNames = this.perpDexNames ?? await this.fetchPerpDexNames();
29
+ const states = await Promise.all(dexNames.map((dex) => this.fetchInfoGated({
33
30
  type: "clearinghouseState",
34
31
  user: this.address,
35
32
  dex
36
- }, this.demo)));
33
+ })));
37
34
  const assetPositions = states.flatMap((state) => state.assetPositions);
38
35
  return assetPositions.reduce((positions, { position: rawPosition }) => {
39
36
  const szi = new BigNumber(rawPosition.szi);
@@ -72,12 +69,12 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
72
69
  let cursor = since.getTime();
73
70
  let batchSize;
74
71
  do {
75
- const batch = await fetchInfo({
72
+ const batch = await this.fetchInfoGated({
76
73
  type: "userFillsByTime",
77
74
  user: this.address,
78
75
  startTime: cursor,
79
76
  aggregateByTime: true
80
- }, this.demo);
77
+ });
81
78
  batchSize = batch.length;
82
79
  for (const rawFill of batch) {
83
80
  addFill(rawFill);
@@ -93,12 +90,12 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
93
90
  } while (batchSize === HYPERLIQUID_FILL_PAGE_LIMIT);
94
91
  cursor = since.getTime();
95
92
  do {
96
- const twapBatch = await fetchInfo({
93
+ const twapBatch = await this.fetchInfoGated({
97
94
  type: "userTwapSliceFillsByTime",
98
95
  user: this.address,
99
96
  startTime: cursor,
100
97
  aggregateByTime: true
101
- }, this.demo);
98
+ });
102
99
  batchSize = twapBatch.length;
103
100
  for (const item of twapBatch) {
104
101
  addFill(item.fill);
@@ -149,11 +146,11 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
149
146
  let cursor = since.getTime();
150
147
  let batchSize;
151
148
  do {
152
- const batch = await fetchInfo({
149
+ const batch = await this.fetchInfoGated({
153
150
  type: "userFunding",
154
151
  user: this.address,
155
152
  startTime: cursor
156
- }, this.demo);
153
+ });
157
154
  batchSize = batch.length;
158
155
  for (const event of batch) {
159
156
  allEvents.set(`${event.time}:${event.delta.coin}:${event.hash}`, event);
@@ -174,6 +171,33 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
174
171
  isReduceOnly(rawFill) {
175
172
  return rawFill.dir.includes("Close");
176
173
  }
174
+ /** Fetch the perp-dex descriptors and reduce them to unique dex names ('' = the main dex). */
175
+ async fetchPerpDexNames() {
176
+ const perpDexs = await this.fetchInfoGated({
177
+ type: "perpDexs"
178
+ });
179
+ return [
180
+ ...new Set(perpDexs.map((perpDex) => perpDex?.name ?? ""))
181
+ ];
182
+ }
183
+ /**
184
+ * Route one info request through the optional throttle seam: gate before the
185
+ * call, report the response size after, surface a failure before it propagates.
186
+ */
187
+ async fetchInfoGated(body) {
188
+ if (!this.throttle) {
189
+ return fetchInfo(body, this.demo);
190
+ }
191
+ await this.throttle.beforeRequest(body.type);
192
+ try {
193
+ const response = await fetchInfo(body, this.demo);
194
+ this.throttle.afterRequest(body.type, Array.isArray(response) ? response.length : 0);
195
+ return response;
196
+ } catch (error) {
197
+ this.throttle.afterRequestError(body.type, error);
198
+ throw error;
199
+ }
200
+ }
177
201
  }
178
202
  function warnStalledPagination(stream, cursor) {
179
203
  console.warn(`Hyperliquid ${stream} pagination stalled at timestamp ${cursor}; returned history may be incomplete.`);
@@ -36,7 +36,7 @@ class LighterAccountSyncer extends BaseAccountSyncer {
36
36
  instrument.precision.quantity.contractSize
37
37
  ]));
38
38
  const token = await this.retrieveAuthToken();
39
- const response = await fetchAccount(this.accountIndex, token, this.demo);
39
+ const response = await fetchAccount(this.accountIndex, token, this.demo, this.throttle);
40
40
  const rawPositions = response.accounts?.[0]?.positions ?? [];
41
41
  return rawPositions.reduce((positions, rawPosition) => {
42
42
  const instrumentId = rawPosition.market_id.toString();
@@ -59,7 +59,7 @@ class LighterAccountSyncer extends BaseAccountSyncer {
59
59
  async listExternalFills({ since, instruments }) {
60
60
  this.assertAuthenticatedSyncAvailable();
61
61
  const token = await this.retrieveAuthToken();
62
- const trades = await fetchTradesSince(this.accountIndex, token, since, this.demo);
62
+ const trades = await fetchTradesSince(this.accountIndex, token, since, this.demo, this.throttle);
63
63
  const instrumentIds = new Set(instruments.map((instrument) => instrument.id));
64
64
  return trades.toSorted((a, b) => a.timestamp - b.timestamp).reduce((fills, rawFill) => {
65
65
  const instrumentId = rawFill.market_id.toString();
@@ -92,7 +92,7 @@ class LighterAccountSyncer extends BaseAccountSyncer {
92
92
  async listExternalFunding({ since, instruments }) {
93
93
  this.assertAuthenticatedSyncAvailable();
94
94
  const token = await this.retrieveAuthToken();
95
- const fundingEvents = await fetchPositionFundingSince(this.accountIndex, token, since, this.demo);
95
+ const fundingEvents = await fetchPositionFundingSince(this.accountIndex, token, since, this.demo, this.throttle);
96
96
  const instrumentIds = new Set(instruments.map((instrument) => instrument.id));
97
97
  return toFundingPaymentEntries(fundingEvents, instrumentIds);
98
98
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/exchanges-sdk",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "Pear Protocol Exchanges SDK",
5
5
  "private": false,
6
6
  "type": "module",
@@ -27,9 +27,9 @@
27
27
  "test:watch": "vitest"
28
28
  },
29
29
  "dependencies": {
30
- "@pear-protocol/core-sdk": "^1.19.2",
31
- "@pear-protocol/types": "^1.30.1",
32
- "@pear-protocol/utils": "^0.7.0",
30
+ "@pear-protocol/core-sdk": "^1.20.0",
31
+ "@pear-protocol/types": "^1.32.0",
32
+ "@pear-protocol/utils": "^0.8.1",
33
33
  "bignumber.js": "^11.1.1",
34
34
  "partysocket": "^1.0.3",
35
35
  "viem": "^2.48.8",