@pear-protocol/exchanges-sdk 0.10.0 → 0.12.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/client/lighter/rest.js +119 -1
- package/dist/helper/lighter/helper.js +13 -0
- package/dist/helper/lighter/referral.helper.js +33 -0
- package/dist/index.d.ts +95 -150
- package/dist/sdk.js +0 -8
- package/dist/tracker/binance/tracker.js +0 -21
- package/dist/tracker/bybit/tracker.js +0 -21
- package/dist/tracker/hyperliquid/collateral.js +15 -2
- package/dist/tracker/hyperliquid/tracker.js +1 -69
- package/dist/tracker/index.js +0 -1
- package/dist/tracker/lighter/tracker.js +0 -50
- package/dist/tracker/okx/tracker.js +0 -22
- package/package.json +4 -4
- package/dist/tracker/basket-size.js +0 -194
- package/dist/tracker/hyperliquid/basket-size.js +0 -93
- package/dist/tracker/lighter/basket-size.js +0 -74
|
@@ -300,6 +300,80 @@ async function fetchPositionFundingSince(accountIndex, authToken, since, demo =
|
|
|
300
300
|
return Array.from(results.values());
|
|
301
301
|
}
|
|
302
302
|
__name(fetchPositionFundingSince, "fetchPositionFundingSince");
|
|
303
|
+
async function submitReferralCode(params, demo = false) {
|
|
304
|
+
const body = new URLSearchParams({
|
|
305
|
+
l1_address: params.l1Address,
|
|
306
|
+
referral_code: params.referralCode
|
|
307
|
+
});
|
|
308
|
+
if (params.discord) {
|
|
309
|
+
body.set("discord", params.discord);
|
|
310
|
+
}
|
|
311
|
+
if (params.telegram) {
|
|
312
|
+
body.set("telegram", params.telegram);
|
|
313
|
+
}
|
|
314
|
+
if (params.x) {
|
|
315
|
+
body.set("x", params.x);
|
|
316
|
+
}
|
|
317
|
+
if (params.signature) {
|
|
318
|
+
body.set("signature", params.signature);
|
|
319
|
+
}
|
|
320
|
+
const response = await authenticatedLighterFetch(`${getLighterBaseUrl(demo)}/api/v1/referral/use`, params.authToken, {
|
|
321
|
+
method: "POST",
|
|
322
|
+
headers: {
|
|
323
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
324
|
+
},
|
|
325
|
+
body
|
|
326
|
+
});
|
|
327
|
+
await readLighterResponse(response, "/referral/use");
|
|
328
|
+
}
|
|
329
|
+
__name(submitReferralCode, "submitReferralCode");
|
|
330
|
+
async function fetchUserReferrals(params, demo = false) {
|
|
331
|
+
const query = new URLSearchParams({
|
|
332
|
+
l1_address: params.l1Address
|
|
333
|
+
});
|
|
334
|
+
if (params.cursor) {
|
|
335
|
+
query.set("cursor", params.cursor);
|
|
336
|
+
}
|
|
337
|
+
if (params.statsStartTimestamp !== void 0) {
|
|
338
|
+
query.set("stats_start_timestamp", params.statsStartTimestamp.toString());
|
|
339
|
+
}
|
|
340
|
+
if (params.statsEndTimestamp !== void 0) {
|
|
341
|
+
query.set("stats_end_timestamp", params.statsEndTimestamp.toString());
|
|
342
|
+
}
|
|
343
|
+
if (params.limit !== void 0) {
|
|
344
|
+
query.set("limit", params.limit.toString());
|
|
345
|
+
}
|
|
346
|
+
if (params.eligibleOnly) {
|
|
347
|
+
query.set("is_eligible", "true");
|
|
348
|
+
}
|
|
349
|
+
const response = await authenticatedLighterFetch(`${getLighterBaseUrl(demo)}/api/v1/referral/userReferrals?${query.toString()}`, params.authToken);
|
|
350
|
+
const data = await readLighterResponse(response, "/referral/userReferrals");
|
|
351
|
+
const referrals = [];
|
|
352
|
+
for (const referral of data.referrals ?? []) {
|
|
353
|
+
if (typeof referral !== "object" || referral === null) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (typeof referral.l1_address !== "string") {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
referrals.push({
|
|
360
|
+
l1Address: referral.l1_address,
|
|
361
|
+
referralCode: typeof referral.referral_code === "string" ? referral.referral_code : "",
|
|
362
|
+
usedAt: readReferralCount(referral.used_at),
|
|
363
|
+
tier: typeof referral.tier === "string" ? referral.tier : "",
|
|
364
|
+
tradeStats: readReferralTradeStats(referral.trade_stats)
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
usedCode: typeof data.used_code === "string" && data.used_code.length > 0 ? data.used_code : null,
|
|
369
|
+
referrals,
|
|
370
|
+
totals: readReferralTotals(data.totals),
|
|
371
|
+
// Reuse the funding-history reading: it treats an unparseable cursor as live, so the worst an
|
|
372
|
+
// encoding mismatch costs here is one extra empty page rather than a dropped one.
|
|
373
|
+
nextCursor: readHistoryCursor(data.cursor)
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
__name(fetchUserReferrals, "fetchUserReferrals");
|
|
303
377
|
async function authenticatedLighterFetch(url, authToken, init) {
|
|
304
378
|
const headers = new Headers(init?.headers);
|
|
305
379
|
headers.set("authorization", authToken);
|
|
@@ -374,5 +448,49 @@ async function readLighterResponse(response, endpoint, acceptedCodes = [
|
|
|
374
448
|
return data;
|
|
375
449
|
}
|
|
376
450
|
__name(readLighterResponse, "readLighterResponse");
|
|
451
|
+
function readReferralTradeStats(stats) {
|
|
452
|
+
const raw = typeof stats === "object" && stats !== null ? stats : {};
|
|
453
|
+
return {
|
|
454
|
+
count: readReferralCount(raw.count),
|
|
455
|
+
volume: readReferralAmount(raw.volume),
|
|
456
|
+
webCount: readReferralCount(raw.web_count),
|
|
457
|
+
webVolume: readReferralAmount(raw.web_volume),
|
|
458
|
+
mobileAppCount: readReferralCount(raw.mobile_app_count),
|
|
459
|
+
mobileAppVolume: readReferralAmount(raw.mobile_app_volume),
|
|
460
|
+
mobileBrowserCount: readReferralCount(raw.mobile_browser_count),
|
|
461
|
+
mobileBrowserVolume: readReferralAmount(raw.mobile_browser_volume),
|
|
462
|
+
freeMakerVolume: readReferralAmount(raw.free_maker_volume),
|
|
463
|
+
freeTakerVolume: readReferralAmount(raw.free_taker_volume),
|
|
464
|
+
nonFreeMakerVolume: readReferralAmount(raw.non_free_maker_volume),
|
|
465
|
+
nonFreeTakerVolume: readReferralAmount(raw.non_free_taker_volume),
|
|
466
|
+
makerFeesPaid: readReferralAmount(raw.maker_fees_paid),
|
|
467
|
+
takerFeesPaid: readReferralAmount(raw.taker_fees_paid)
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
__name(readReferralTradeStats, "readReferralTradeStats");
|
|
471
|
+
function readReferralTotals(totals) {
|
|
472
|
+
const raw = typeof totals === "object" && totals !== null ? totals : {};
|
|
473
|
+
return {
|
|
474
|
+
count: readReferralCount(raw.count),
|
|
475
|
+
volume: readReferralAmount(raw.volume),
|
|
476
|
+
freeMakerVolume: readReferralAmount(raw.free_maker_volume),
|
|
477
|
+
freeTakerVolume: readReferralAmount(raw.free_taker_volume),
|
|
478
|
+
nonFreeMakerVolume: readReferralAmount(raw.non_free_maker_volume),
|
|
479
|
+
nonFreeTakerVolume: readReferralAmount(raw.non_free_taker_volume),
|
|
480
|
+
makerFeesPaid: readReferralAmount(raw.maker_fees_paid),
|
|
481
|
+
takerFeesPaid: readReferralAmount(raw.taker_fees_paid),
|
|
482
|
+
totalReferrals: readReferralCount(raw.total_referrals),
|
|
483
|
+
totalPremiumReferrals: readReferralCount(raw.total_premium_referrals)
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
__name(readReferralTotals, "readReferralTotals");
|
|
487
|
+
function readReferralCount(value) {
|
|
488
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
489
|
+
}
|
|
490
|
+
__name(readReferralCount, "readReferralCount");
|
|
491
|
+
function readReferralAmount(value) {
|
|
492
|
+
return typeof value === "string" && value.length > 0 ? value : "0";
|
|
493
|
+
}
|
|
494
|
+
__name(readReferralAmount, "readReferralAmount");
|
|
377
495
|
|
|
378
|
-
export { createCctpDepositIntentAddress, fetchAccount, fetchAccountLimits, fetchAccountMetadata, fetchAccountsByL1Address, fetchApiKeys, fetchAssetDetails, fetchDepositHistory, fetchDepositNetworks, fetchOrderBookDetails, fetchPositionFundingSince, fetchPublicAccount, fetchPublicOrderBookDetails, fetchTradesSince, fetchWithdrawHistory };
|
|
496
|
+
export { createCctpDepositIntentAddress, fetchAccount, fetchAccountLimits, fetchAccountMetadata, fetchAccountsByL1Address, fetchApiKeys, fetchAssetDetails, fetchDepositHistory, fetchDepositNetworks, fetchOrderBookDetails, fetchPositionFundingSince, fetchPublicAccount, fetchPublicOrderBookDetails, fetchTradesSince, fetchUserReferrals, fetchWithdrawHistory, submitReferralCode };
|
|
@@ -7,6 +7,7 @@ import { createDepositAddressForRoute, depositThroughRoute } from './deposit.hel
|
|
|
7
7
|
import { writeWithdraw } from './ethereum';
|
|
8
8
|
import { readWithdrawHistory, readDepositHistory } from './history.helper';
|
|
9
9
|
import { LIGHTER_ACCOUNT_NOT_REGISTERED_CODE, readOnboardingStatus } from './onboarding.helper';
|
|
10
|
+
import { readUserReferrals, applyReferralCode } from './referral.helper';
|
|
10
11
|
import { MIN_LIGHTER_FAST_WITHDRAW_USDC } from './types';
|
|
11
12
|
|
|
12
13
|
var __defProp = Object.defineProperty;
|
|
@@ -198,6 +199,18 @@ function createLighterHelper(sdk, demo = false) {
|
|
|
198
199
|
/** Reads one page of the account's withdrawal history, newest first. */
|
|
199
200
|
async getWithdrawHistory(params) {
|
|
200
201
|
return readWithdrawHistory(sdk, params, demo);
|
|
202
|
+
},
|
|
203
|
+
/** Reads the Fun.xyz bridge deposits Lighter has seen for a wallet. */
|
|
204
|
+
async listUdaDeposits(walletAddress) {
|
|
205
|
+
return sdk.core.misc.lighter.listUdaDeposits(walletAddress);
|
|
206
|
+
},
|
|
207
|
+
/** Applies a referrer's code to the owner. Lighter accepts this at most once per owner. */
|
|
208
|
+
async applyReferralCode(params) {
|
|
209
|
+
return applyReferralCode(sdk, params, demo);
|
|
210
|
+
},
|
|
211
|
+
/** Reads one page of the owner's referral record, including the code that referred them. */
|
|
212
|
+
async getUserReferrals(params) {
|
|
213
|
+
return readUserReferrals(sdk, params, demo);
|
|
201
214
|
}
|
|
202
215
|
};
|
|
203
216
|
return helper;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { submitReferralCode, fetchUserReferrals } from '../../client/lighter/rest';
|
|
2
|
+
import { retrieveLighterAuthToken } from './auth-token.helper';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
async function applyReferralCode(sdk, params, demo) {
|
|
7
|
+
const authToken = await retrieveLighterAuthToken(sdk, params.credentials, demo);
|
|
8
|
+
await submitReferralCode({
|
|
9
|
+
l1Address: params.l1Address,
|
|
10
|
+
referralCode: params.referralCode,
|
|
11
|
+
authToken,
|
|
12
|
+
discord: params.discord,
|
|
13
|
+
telegram: params.telegram,
|
|
14
|
+
x: params.x,
|
|
15
|
+
signature: params.signature
|
|
16
|
+
}, demo);
|
|
17
|
+
}
|
|
18
|
+
__name(applyReferralCode, "applyReferralCode");
|
|
19
|
+
async function readUserReferrals(sdk, params, demo) {
|
|
20
|
+
const authToken = await retrieveLighterAuthToken(sdk, params.credentials, demo);
|
|
21
|
+
return fetchUserReferrals({
|
|
22
|
+
l1Address: params.l1Address,
|
|
23
|
+
authToken,
|
|
24
|
+
cursor: params.cursor,
|
|
25
|
+
statsStartTimestamp: params.statsStartTimestamp,
|
|
26
|
+
statsEndTimestamp: params.statsEndTimestamp,
|
|
27
|
+
limit: params.limit,
|
|
28
|
+
eligibleOnly: params.eligibleOnly
|
|
29
|
+
}, demo);
|
|
30
|
+
}
|
|
31
|
+
__name(readUserReferrals, "readUserReferrals");
|
|
32
|
+
|
|
33
|
+
export { applyReferralCode, readUserReferrals };
|
package/dist/index.d.ts
CHANGED
|
@@ -319,6 +319,62 @@ type LighterWithdrawPage = {
|
|
|
319
319
|
/** Null once Lighter holds no older page. */
|
|
320
320
|
nextCursor: string | null;
|
|
321
321
|
};
|
|
322
|
+
/** What one referred trader has traded, over whatever window the request asked Lighter for. */
|
|
323
|
+
type LighterReferralTradeStats = {
|
|
324
|
+
count: number;
|
|
325
|
+
volume: string;
|
|
326
|
+
webCount: number;
|
|
327
|
+
webVolume: string;
|
|
328
|
+
mobileAppCount: number;
|
|
329
|
+
mobileAppVolume: string;
|
|
330
|
+
mobileBrowserCount: number;
|
|
331
|
+
mobileBrowserVolume: string;
|
|
332
|
+
freeMakerVolume: string;
|
|
333
|
+
freeTakerVolume: string;
|
|
334
|
+
nonFreeMakerVolume: string;
|
|
335
|
+
nonFreeTakerVolume: string;
|
|
336
|
+
makerFeesPaid: string;
|
|
337
|
+
takerFeesPaid: string;
|
|
338
|
+
};
|
|
339
|
+
/** One trader who signed up under the owner's code. */
|
|
340
|
+
type LighterReferral = {
|
|
341
|
+
l1Address: string;
|
|
342
|
+
/** The code that trader used, which is the owner's own code. */
|
|
343
|
+
referralCode: string;
|
|
344
|
+
/** When the code was used. Lighter states no unit; its funding histories send milliseconds. */
|
|
345
|
+
usedAt: number;
|
|
346
|
+
/** Lighter's tier wording for that trader; a kickback accrues only above `standard`. */
|
|
347
|
+
tier: string;
|
|
348
|
+
tradeStats: LighterReferralTradeStats;
|
|
349
|
+
};
|
|
350
|
+
/** The owner's running referral totals, which count every referral rather than only this page. */
|
|
351
|
+
type LighterReferralTotals = {
|
|
352
|
+
count: number;
|
|
353
|
+
volume: string;
|
|
354
|
+
freeMakerVolume: string;
|
|
355
|
+
freeTakerVolume: string;
|
|
356
|
+
nonFreeMakerVolume: string;
|
|
357
|
+
nonFreeTakerVolume: string;
|
|
358
|
+
makerFeesPaid: string;
|
|
359
|
+
takerFeesPaid: string;
|
|
360
|
+
totalReferrals: number;
|
|
361
|
+
/** How many referrals hold a paid tier, which is the only kind that earns a kickback. */
|
|
362
|
+
totalPremiumReferrals: number;
|
|
363
|
+
};
|
|
364
|
+
/**
|
|
365
|
+
* One page of an owner's referral record.
|
|
366
|
+
*
|
|
367
|
+
* `usedCode` is the only place Lighter reports who referred the owner, and it reports the code
|
|
368
|
+
* rather than the referrer. Lighter publishes no endpoint that resolves a code back to its owner.
|
|
369
|
+
*/
|
|
370
|
+
type LighterUserReferrals = {
|
|
371
|
+
/** The code the owner signed up under, or null when nobody referred them. */
|
|
372
|
+
usedCode: string | null;
|
|
373
|
+
referrals: LighterReferral[];
|
|
374
|
+
totals: LighterReferralTotals;
|
|
375
|
+
/** Null once Lighter holds no further page. */
|
|
376
|
+
nextCursor: string | null;
|
|
377
|
+
};
|
|
322
378
|
|
|
323
379
|
/** Shares one live Lighter auth token per account without crossing rotated credentials. */
|
|
324
380
|
|
|
@@ -752,6 +808,38 @@ type LighterOnboardingStatus = {
|
|
|
752
808
|
mainAccountIndex: number;
|
|
753
809
|
subAccountIndexes: number[];
|
|
754
810
|
};
|
|
811
|
+
type LighterApplyReferralCodeParams = {
|
|
812
|
+
/** Signs the write; the account it names must belong to the address below. */
|
|
813
|
+
credentials: LighterAuthCredentials;
|
|
814
|
+
/** The owner address the referral binds to; Lighter keys its referral record by address. */
|
|
815
|
+
l1Address: string;
|
|
816
|
+
/** The referrer's code, spelled the way Lighter prints it. */
|
|
817
|
+
referralCode: string;
|
|
818
|
+
/** Lighter accepts a Discord handle beside the code but documents no format for it. */
|
|
819
|
+
discord?: string;
|
|
820
|
+
/** Lighter accepts a Telegram handle beside the code but documents no format for it. */
|
|
821
|
+
telegram?: string;
|
|
822
|
+
/** Lighter accepts an X handle beside the code but documents no format for it. */
|
|
823
|
+
x?: string;
|
|
824
|
+
/** Lighter accepts a signature beside the code but documents neither its payload nor its scheme. */
|
|
825
|
+
signature?: string;
|
|
826
|
+
};
|
|
827
|
+
type LighterUserReferralsParams = {
|
|
828
|
+
/** Signs the read; the account it names must belong to the address below. */
|
|
829
|
+
credentials: LighterAuthCredentials;
|
|
830
|
+
/** The owner address whose referral record comes back. */
|
|
831
|
+
l1Address: string;
|
|
832
|
+
/** The `nextCursor` of the page just read; omit to read the first page. */
|
|
833
|
+
cursor?: string;
|
|
834
|
+
/** Opens the `tradeStats` window. Lighter states no unit for it, so pass what its own client passes. */
|
|
835
|
+
statsStartTimestamp?: number;
|
|
836
|
+
/** Closes the `tradeStats` window. Lighter states no unit for it, so pass what its own client passes. */
|
|
837
|
+
statsEndTimestamp?: number;
|
|
838
|
+
/** Rows per page, between 1 and 300; omit to take Lighter's own page size. */
|
|
839
|
+
limit?: number;
|
|
840
|
+
/** Narrows the page to the referrals Lighter counts toward a kickback tier. */
|
|
841
|
+
eligibleOnly?: boolean;
|
|
842
|
+
};
|
|
755
843
|
interface LighterHelper {
|
|
756
844
|
checkOnboarding(l1Address: string): Promise<LighterOnboardingStatus>;
|
|
757
845
|
lookupAccount(l1Address: string): Promise<LighterLookupResult>;
|
|
@@ -774,6 +862,12 @@ interface LighterHelper {
|
|
|
774
862
|
getDepositHistory(params: LighterDepositHistoryParams): Promise<LighterDepositPage>;
|
|
775
863
|
/** Reads one page of the account's withdrawal history, newest first. */
|
|
776
864
|
getWithdrawHistory(params: LighterWithdrawHistoryParams): Promise<LighterWithdrawPage>;
|
|
865
|
+
/** Reads the Fun.xyz bridge deposits Lighter has seen for a wallet. */
|
|
866
|
+
listUdaDeposits(walletAddress: string): Promise<HttpTypes.ListLighterUdaDepositsResult>;
|
|
867
|
+
/** Applies a referrer's code to the owner. Lighter accepts this at most once per owner. */
|
|
868
|
+
applyReferralCode(params: LighterApplyReferralCodeParams): Promise<void>;
|
|
869
|
+
/** Reads one page of the owner's referral record, including the code that referred them. */
|
|
870
|
+
getUserReferrals(params: LighterUserReferralsParams): Promise<LighterUserReferrals>;
|
|
777
871
|
}
|
|
778
872
|
type LighterLookupResult = {
|
|
779
873
|
mainAccountIndex: number;
|
|
@@ -1432,98 +1526,6 @@ declare const AccountBalanceCore: z.ZodObject<{
|
|
|
1432
1526
|
/** Human-readable name for each mode, as the venue's own account page labels it. */
|
|
1433
1527
|
declare const ACCOUNT_MODE_LABELS: Record<AccountMode, string>;
|
|
1434
1528
|
|
|
1435
|
-
/**
|
|
1436
|
-
* Mirrors the shipped basket model (`BasketItem` in the frontend): unsigned `weight`
|
|
1437
|
-
* with `side` alongside, weights summing to 100. Sizing ignores `side` — margin
|
|
1438
|
-
* requirement does not depend on direction — and normalises by Σweight.
|
|
1439
|
-
*/
|
|
1440
|
-
declare const BasketLeg: z.ZodObject<{
|
|
1441
|
-
asset: z.ZodString;
|
|
1442
|
-
marginMode: z.ZodEnum<{
|
|
1443
|
-
isolated: "isolated";
|
|
1444
|
-
cross: "cross";
|
|
1445
|
-
}>;
|
|
1446
|
-
leverage: z.ZodString;
|
|
1447
|
-
side: z.ZodEnum<{
|
|
1448
|
-
BUY: "BUY";
|
|
1449
|
-
SELL: "SELL";
|
|
1450
|
-
}>;
|
|
1451
|
-
weight: z.ZodNumber;
|
|
1452
|
-
}, z.core.$strip>;
|
|
1453
|
-
type BasketLeg = z.infer<typeof BasketLeg>;
|
|
1454
|
-
declare const MaxBasketSizeInput: z.ZodObject<{
|
|
1455
|
-
legs: z.ZodArray<z.ZodObject<{
|
|
1456
|
-
asset: z.ZodString;
|
|
1457
|
-
marginMode: z.ZodEnum<{
|
|
1458
|
-
isolated: "isolated";
|
|
1459
|
-
cross: "cross";
|
|
1460
|
-
}>;
|
|
1461
|
-
leverage: z.ZodString;
|
|
1462
|
-
side: z.ZodEnum<{
|
|
1463
|
-
BUY: "BUY";
|
|
1464
|
-
SELL: "SELL";
|
|
1465
|
-
}>;
|
|
1466
|
-
weight: z.ZodNumber;
|
|
1467
|
-
}, z.core.$strip>>;
|
|
1468
|
-
}, z.core.$strip>;
|
|
1469
|
-
type MaxBasketSizeInput = z.infer<typeof MaxBasketSizeInput>;
|
|
1470
|
-
declare const MaxBasketSizeResult: z.ZodObject<{
|
|
1471
|
-
maxNotional: z.ZodNullable<z.ZodString>;
|
|
1472
|
-
legs: z.ZodArray<z.ZodObject<{
|
|
1473
|
-
asset: z.ZodString;
|
|
1474
|
-
notional: z.ZodString;
|
|
1475
|
-
marginRequired: z.ZodString;
|
|
1476
|
-
}, z.core.$strip>>;
|
|
1477
|
-
bindingConstraint: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
1478
|
-
kind: z.ZodLiteral<"cross-pool">;
|
|
1479
|
-
pool: z.ZodString;
|
|
1480
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
1481
|
-
kind: z.ZodLiteral<"isolated-leg">;
|
|
1482
|
-
asset: z.ZodString;
|
|
1483
|
-
}, z.core.$strip>], "kind">>;
|
|
1484
|
-
}, z.core.$strip>;
|
|
1485
|
-
type MaxBasketSizeResult = z.infer<typeof MaxBasketSizeResult>;
|
|
1486
|
-
/**
|
|
1487
|
-
* One basket leg with its leverage already capped by the venue adapter.
|
|
1488
|
-
*
|
|
1489
|
-
* `marginMode` does not enter the maths: an isolated leg gets dedicated margin, but that margin is
|
|
1490
|
-
* still transferred out of the same free balance, so it draws on the same budget as a cross leg.
|
|
1491
|
-
* It is carried so the caller passes its basket through unchanged.
|
|
1492
|
-
*/
|
|
1493
|
-
type CappedBasketLeg = {
|
|
1494
|
-
asset: string;
|
|
1495
|
-
/**
|
|
1496
|
-
* The collateral pool this leg's margin comes out of, as the venue adapter resolves it — a CEX
|
|
1497
|
-
* from the symbol's settlement currency, Hyperliquid from the dex's collateral token. Legs in
|
|
1498
|
-
* different pools cannot fund each other.
|
|
1499
|
-
*/
|
|
1500
|
-
pool: string;
|
|
1501
|
-
/** Unsigned, in the caller's own scale — `computeMaxBasketSize` normalises by Σweight. */
|
|
1502
|
-
weight: number;
|
|
1503
|
-
effectiveLeverage: string;
|
|
1504
|
-
marginMode: MarginMode;
|
|
1505
|
-
/** This leg's own venue ceiling in USD notional; `null` when the venue names no cap. */
|
|
1506
|
-
maxNotional: string | null;
|
|
1507
|
-
};
|
|
1508
|
-
/** The margin budget behind each collateral pool, plus the legs those pools must fund at once. */
|
|
1509
|
-
type MaxBasketSizeCalculation = {
|
|
1510
|
-
/**
|
|
1511
|
-
* Pool id to that pool's USD-equivalent budget. A pool whose collateral is not ~1 USD supplies no
|
|
1512
|
-
* entry until someone adds a price source, and a leg drawing on a missing entry voids the answer.
|
|
1513
|
-
*/
|
|
1514
|
-
budgets: Record<string, string>;
|
|
1515
|
-
legs: CappedBasketLeg[];
|
|
1516
|
-
};
|
|
1517
|
-
/**
|
|
1518
|
-
* The largest gross notional this basket can reach while every leg stays funded at its weight.
|
|
1519
|
-
*
|
|
1520
|
-
* Returns a null size when a pool behind the basket cannot be valued — never a zero, which a
|
|
1521
|
-
* consumer would read as "no collateral" rather than "not known". A basket whose own figures cannot
|
|
1522
|
-
* be sized (see `isSizeableInput`) gets the same null, so this call never throws and never returns a
|
|
1523
|
-
* result that fails `MaxBasketSizeResult`.
|
|
1524
|
-
*/
|
|
1525
|
-
declare function computeMaxBasketSize(input: MaxBasketSizeCalculation): MaxBasketSizeResult;
|
|
1526
|
-
|
|
1527
1529
|
interface AccountPosition {
|
|
1528
1530
|
symbol: string;
|
|
1529
1531
|
side: 'long' | 'short' | 'both';
|
|
@@ -1580,16 +1582,12 @@ interface AccountTracker {
|
|
|
1580
1582
|
disconnect(): Promise<void>;
|
|
1581
1583
|
snapshot(): Promise<AccountSnapshot>;
|
|
1582
1584
|
snapshotAssets(coins: string[]): Promise<AssetSnapshotMap>;
|
|
1583
|
-
/** Sizes a basket over REST alone, so it stays usable without a running socket. */
|
|
1584
|
-
snapshotMaxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
1585
1585
|
readonly isConnected: boolean;
|
|
1586
1586
|
readonly isInitialized: boolean;
|
|
1587
1587
|
readonly hasListeners: boolean;
|
|
1588
1588
|
trackBalance(cb: BalanceCallback): () => void;
|
|
1589
1589
|
trackPosition(cb: PositionsCallback): () => void;
|
|
1590
1590
|
trackAsset(asset: string, cb: TrackedAssetCallback): () => void;
|
|
1591
|
-
/** Async: a basket may name assets this tracker has not subscribed to yet. */
|
|
1592
|
-
maxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
1593
1591
|
getBalance(): AccountBalance | null;
|
|
1594
1592
|
getPositions(): AccountPosition[];
|
|
1595
1593
|
getTrackedAsset(coin: string): TrackedAssetInfo | null;
|
|
@@ -1630,9 +1628,6 @@ declare abstract class BaseAccountTracker implements AccountTracker {
|
|
|
1630
1628
|
private broadcast;
|
|
1631
1629
|
abstract start(): Promise<void>;
|
|
1632
1630
|
abstract snapshot(): Promise<AccountSnapshot>;
|
|
1633
|
-
/** Every venue implements both sizing paths — the live one and the REST one. */
|
|
1634
|
-
abstract maxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
1635
|
-
abstract snapshotMaxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
1636
1631
|
protected abstract fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
|
|
1637
1632
|
abstract get isConnected(): boolean;
|
|
1638
1633
|
protected abstract ensureAssetTracked(asset: string): void;
|
|
@@ -1705,15 +1700,6 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
|
|
|
1705
1700
|
private trackedAssetInfos;
|
|
1706
1701
|
constructor(config: BinanceAccountTrackerConfig);
|
|
1707
1702
|
snapshot(): Promise<AccountSnapshot>;
|
|
1708
|
-
/**
|
|
1709
|
-
* Binance sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
|
|
1710
|
-
* `availableMargin` alone would ship a number no venue field backs. The missing input is
|
|
1711
|
-
* `/fapi/v2/positionRisk` → `maxNotionalValue` (the account's own per-symbol ceiling), with
|
|
1712
|
-
* `/fapi/v1/leverageBracket` behind it for the tier a larger size would fall into.
|
|
1713
|
-
*/
|
|
1714
|
-
maxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
1715
|
-
/** The REST path answers the same way — there is no size either way, not a slower one. */
|
|
1716
|
-
snapshotMaxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
1717
1703
|
/**
|
|
1718
1704
|
* Stateless one-shot per-asset settings read: `positionRisk` with no symbol returns leverage +
|
|
1719
1705
|
* margin type for every symbol (positioned or not), so any number of assets costs one call.
|
|
@@ -1812,15 +1798,6 @@ declare class BybitAccountTracker extends BaseAccountTracker {
|
|
|
1812
1798
|
private trackedAssetInfos;
|
|
1813
1799
|
constructor(config: BybitAccountTrackerConfig);
|
|
1814
1800
|
snapshot(): Promise<AccountSnapshot>;
|
|
1815
|
-
/**
|
|
1816
|
-
* Bybit sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
|
|
1817
|
-
* `availableMargin` alone would ship a number no venue field backs. The missing input is
|
|
1818
|
-
* `/v5/position/list` → `leverage` (the account's own per-symbol setting), with
|
|
1819
|
-
* `/v5/market/risk-limit` → `maxLeverage` behind it for the tier a larger size would fall into.
|
|
1820
|
-
*/
|
|
1821
|
-
maxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
1822
|
-
/** The REST path answers the same way — there is no size either way, not a slower one. */
|
|
1823
|
-
snapshotMaxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
1824
1801
|
/**
|
|
1825
1802
|
* Stateless one-shot per-asset settings read. Bybit has no batch leverage endpoint, but
|
|
1826
1803
|
* `position/list` by settleCoin returns every open position (with leverage) in one call, so
|
|
@@ -2093,13 +2070,6 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
|
|
|
2093
2070
|
* per-asset headroom without opening a socket.
|
|
2094
2071
|
*/
|
|
2095
2072
|
snapshot(): Promise<AccountSnapshot>;
|
|
2096
|
-
/** Sizes a basket over REST alone, so the call stays usable without a running socket. */
|
|
2097
|
-
snapshotMaxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
2098
|
-
/**
|
|
2099
|
-
* Sizes a basket against live state, fetching per-asset data for any leg the socket has not
|
|
2100
|
-
* subscribed to — which is exactly why the call is asynchronous on both paths.
|
|
2101
|
-
*/
|
|
2102
|
-
maxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
2103
2073
|
/**
|
|
2104
2074
|
* Stateless one-shot per-asset settings read via the `activeAssetData` info request (the REST
|
|
2105
2075
|
* twin of the live WS subscription), one request per coin fired in parallel — the info endpoint
|
|
@@ -2123,10 +2093,6 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
|
|
|
2123
2093
|
private routeRaw;
|
|
2124
2094
|
private handle;
|
|
2125
2095
|
private loadPerpMetas;
|
|
2126
|
-
/** Loads the dex metadata a sizing call needs, reusing whatever `start()` already cached. */
|
|
2127
|
-
private loadPerpMetasOnce;
|
|
2128
|
-
/** Loads the token names a pool id is spelled with, reusing whatever `start()` already cached. */
|
|
2129
|
-
private loadCollateralTokenNamesOnce;
|
|
2130
2096
|
/** Reads `activeAssetData` for each coin in parallel, dropping the coins the venue refuses. */
|
|
2131
2097
|
private fetchActiveAssetEvents;
|
|
2132
2098
|
/** The asset set `availableMargin` is the floor over: the locked coins plus every tracked one. */
|
|
@@ -2275,10 +2241,6 @@ declare class LighterAccountTracker extends BaseAccountTracker {
|
|
|
2275
2241
|
* supplies the exchange default for markets absent from the account payload.
|
|
2276
2242
|
*/
|
|
2277
2243
|
protected fetchAssetSnapshots(marketIds: string[]): Promise<AssetSnapshotMap>;
|
|
2278
|
-
/** Sizes a basket against the live account state, falling back to REST before the socket is up. */
|
|
2279
|
-
maxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
2280
|
-
/** Sizes a basket over REST alone, so the answer needs no running socket. */
|
|
2281
|
-
snapshotMaxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
2282
2244
|
start(): Promise<void>;
|
|
2283
2245
|
/** Creates one tracker lifecycle while repeated callers share the same pending start. */
|
|
2284
2246
|
private performStart;
|
|
@@ -2323,8 +2285,6 @@ declare class LighterAccountTracker extends BaseAccountTracker {
|
|
|
2323
2285
|
private buildBalance;
|
|
2324
2286
|
/** The market data both read paths join account state against, as the latest read left it. */
|
|
2325
2287
|
private marketContext;
|
|
2326
|
-
/** The account's current per-market settings as the base tracker already holds them. */
|
|
2327
|
-
private liveAccountSettings;
|
|
2328
2288
|
/** Reads the account with credentials when present, or explicitly uses the read-only verifier path. */
|
|
2329
2289
|
private fetchPrimaryAccount;
|
|
2330
2290
|
/** Reads market context under the same account identity as the snapshot that consumes it. */
|
|
@@ -2484,16 +2444,6 @@ declare class OkxAccountTracker extends BaseAccountTracker {
|
|
|
2484
2444
|
private trackedAssetInfos;
|
|
2485
2445
|
constructor(config: OkxAccountTrackerConfig);
|
|
2486
2446
|
snapshot(): Promise<AccountSnapshot>;
|
|
2487
|
-
/**
|
|
2488
|
-
* OKX sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
|
|
2489
|
-
* `availableMargin` alone would ship a number no venue field backs. The missing input is
|
|
2490
|
-
* `GET /api/v5/public/position-tiers` → `maxLever`/`imr` per tier, which the client does not
|
|
2491
|
-
* call — and it is NOT `GET /api/v5/account/position-tiers`, a different endpoint carrying no
|
|
2492
|
-
* margin or leverage data at all.
|
|
2493
|
-
*/
|
|
2494
|
-
maxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
2495
|
-
/** The REST path answers the same way — there is no size either way, not a slower one. */
|
|
2496
|
-
snapshotMaxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
2497
2447
|
/**
|
|
2498
2448
|
* Stateless one-shot per-asset leverage read via `leverage-info`, which accepts up to 20 instIds
|
|
2499
2449
|
* per request (chunked in the client), so N assets cost ceil(N/20) calls. Cross margin only,
|
|
@@ -2591,11 +2541,6 @@ declare class ExchangesSDK {
|
|
|
2591
2541
|
status(connection: ExchangeConnection, options?: ConnectOptions): Promise<AccountStatus>;
|
|
2592
2542
|
createTracker(connection: ExchangeConnection): AccountTracker;
|
|
2593
2543
|
snapshot(tradeAccountId: string): Promise<AccountSnapshot>;
|
|
2594
|
-
/**
|
|
2595
|
-
* Sizes a basket in one shot. Routed to the tracker's REST path on purpose: this entry point
|
|
2596
|
-
* builds a throwaway tracker per call, so it must open no socket.
|
|
2597
|
-
*/
|
|
2598
|
-
maxBasketSize(tradeAccountId: string, input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
|
|
2599
2544
|
snapshotAssets(tradeAccountId: string, coins: string[]): Promise<AssetSnapshotMap>;
|
|
2600
2545
|
createHelper<E extends ExchangeHelperExchange>(exchange: E): ExchangeHelperMap[E];
|
|
2601
2546
|
createSyncer(connection: ExchangeConnection): AccountSyncer;
|
|
@@ -2603,4 +2548,4 @@ declare class ExchangesSDK {
|
|
|
2603
2548
|
private fetchCredentials;
|
|
2604
2549
|
}
|
|
2605
2550
|
|
|
2606
|
-
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,
|
|
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 };
|
package/dist/sdk.js
CHANGED
|
@@ -42,14 +42,6 @@ class ExchangesSDK {
|
|
|
42
42
|
const connection = await this.fetchCredentials(tradeAccountId);
|
|
43
43
|
return this.buildTracker(connection).snapshot();
|
|
44
44
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Sizes a basket in one shot. Routed to the tracker's REST path on purpose: this entry point
|
|
47
|
-
* builds a throwaway tracker per call, so it must open no socket.
|
|
48
|
-
*/
|
|
49
|
-
async maxBasketSize(tradeAccountId, input) {
|
|
50
|
-
const connection = await this.fetchCredentials(tradeAccountId);
|
|
51
|
-
return this.buildTracker(connection).snapshotMaxBasketSize(input);
|
|
52
|
-
}
|
|
53
45
|
async snapshotAssets(tradeAccountId, coins) {
|
|
54
46
|
const connection = await this.fetchCredentials(tradeAccountId);
|
|
55
47
|
return this.buildTracker(connection).snapshotAssets(coins);
|
|
@@ -38,19 +38,6 @@ class BinanceAccountTracker extends BaseAccountTracker {
|
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* Binance sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
|
|
42
|
-
* `availableMargin` alone would ship a number no venue field backs. The missing input is
|
|
43
|
-
* `/fapi/v2/positionRisk` → `maxNotionalValue` (the account's own per-symbol ceiling), with
|
|
44
|
-
* `/fapi/v1/leverageBracket` behind it for the tier a larger size would fall into.
|
|
45
|
-
*/
|
|
46
|
-
async maxBasketSize(_input) {
|
|
47
|
-
return unsizedBasket();
|
|
48
|
-
}
|
|
49
|
-
/** The REST path answers the same way — there is no size either way, not a slower one. */
|
|
50
|
-
async snapshotMaxBasketSize(_input) {
|
|
51
|
-
return unsizedBasket();
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
41
|
* Stateless one-shot per-asset settings read: `positionRisk` with no symbol returns leverage +
|
|
55
42
|
* margin type for every symbol (positioned or not), so any number of assets costs one call.
|
|
56
43
|
*/
|
|
@@ -254,13 +241,5 @@ function toTrackedAssetInfo(coin, risk) {
|
|
|
254
241
|
};
|
|
255
242
|
}
|
|
256
243
|
__name(toTrackedAssetInfo, "toTrackedAssetInfo");
|
|
257
|
-
function unsizedBasket() {
|
|
258
|
-
return {
|
|
259
|
-
maxNotional: null,
|
|
260
|
-
legs: [],
|
|
261
|
-
bindingConstraint: null
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
__name(unsizedBasket, "unsizedBasket");
|
|
265
244
|
|
|
266
245
|
export { BinanceAccountTracker };
|
|
@@ -37,19 +37,6 @@ class BybitAccountTracker extends BaseAccountTracker {
|
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
|
-
* Bybit sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
|
|
41
|
-
* `availableMargin` alone would ship a number no venue field backs. The missing input is
|
|
42
|
-
* `/v5/position/list` → `leverage` (the account's own per-symbol setting), with
|
|
43
|
-
* `/v5/market/risk-limit` → `maxLeverage` behind it for the tier a larger size would fall into.
|
|
44
|
-
*/
|
|
45
|
-
async maxBasketSize(_input) {
|
|
46
|
-
return unsizedBasket();
|
|
47
|
-
}
|
|
48
|
-
/** The REST path answers the same way — there is no size either way, not a slower one. */
|
|
49
|
-
async snapshotMaxBasketSize(_input) {
|
|
50
|
-
return unsizedBasket();
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
40
|
* Stateless one-shot per-asset settings read. Bybit has no batch leverage endpoint, but
|
|
54
41
|
* `position/list` by settleCoin returns every open position (with leverage) in one call, so
|
|
55
42
|
* only requested symbols without an open position need a per-symbol fill-in read (`?symbol=`
|
|
@@ -426,14 +413,6 @@ function sameWithdrawable(left, right) {
|
|
|
426
413
|
return true;
|
|
427
414
|
}
|
|
428
415
|
__name(sameWithdrawable, "sameWithdrawable");
|
|
429
|
-
function unsizedBasket() {
|
|
430
|
-
return {
|
|
431
|
-
maxNotional: null,
|
|
432
|
-
legs: [],
|
|
433
|
-
bindingConstraint: null
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
__name(unsizedBasket, "unsizedBasket");
|
|
437
416
|
function toTrackedAssetInfo(coin, pos) {
|
|
438
417
|
return {
|
|
439
418
|
coin,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { minimumAvailableToTrade } from './basket-size';
|
|
2
1
|
import { splitDexCoin } from './coin-name';
|
|
2
|
+
import { toDecimal } from './decimal';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
@@ -44,5 +44,18 @@ function collateralTokenByDex(perDexState) {
|
|
|
44
44
|
return tokenByDex;
|
|
45
45
|
}
|
|
46
46
|
__name(collateralTokenByDex, "collateralTokenByDex");
|
|
47
|
+
function minimumAvailableToTrade(assetData) {
|
|
48
|
+
let floor = null;
|
|
49
|
+
for (const data of assetData) {
|
|
50
|
+
for (const available of data.availableToTrade ?? []) {
|
|
51
|
+
const value = toDecimal(available);
|
|
52
|
+
if (floor === null || value.isLessThan(floor)) {
|
|
53
|
+
floor = value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return floor === null ? null : floor.toFixed();
|
|
58
|
+
}
|
|
59
|
+
__name(minimumAvailableToTrade, "minimumAvailableToTrade");
|
|
47
60
|
|
|
48
|
-
export { buildAvailableMarginByToken, buildCollateralTokenNames };
|
|
61
|
+
export { buildAvailableMarginByToken, buildCollateralTokenNames, minimumAvailableToTrade };
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { createExchangeWs } from '../../client';
|
|
2
2
|
import { fetchPerpDexs, fetchInfo, fetchAllMids, fetchUserAbstraction, fetchSpotClearinghouseState, fetchDelegatorSummary, fetchUserVaultEquities, fetchClearinghouseState, fetchActiveAssetData } from '../../client/hyperliquid/rest';
|
|
3
3
|
import { BaseAccountTracker } from '../base';
|
|
4
|
-
import { computeMaxBasketSize } from '../basket-size';
|
|
5
4
|
import { resolveHyperliquidAccountType } from './account-mode';
|
|
6
|
-
import {
|
|
7
|
-
import { buildAvailableMarginByToken, buildCollateralTokenNames } from './collateral';
|
|
5
|
+
import { buildAvailableMarginByToken, buildCollateralTokenNames, minimumAvailableToTrade } from './collateral';
|
|
8
6
|
import { LOCKED_TRACKED_COINS } from './const';
|
|
9
7
|
import { toDecimal, ZERO } from './decimal';
|
|
10
8
|
import { emptyClearinghouseSummary, aggregateClearinghouseStates, mapBalance, mapPositions } from './mapper';
|
|
@@ -96,35 +94,6 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
|
|
|
96
94
|
positions
|
|
97
95
|
};
|
|
98
96
|
}
|
|
99
|
-
/** Sizes a basket over REST alone, so the call stays usable without a running socket. */
|
|
100
|
-
async snapshotMaxBasketSize(input) {
|
|
101
|
-
const [dexToMeta, tokenNames] = await Promise.all([
|
|
102
|
-
this.loadPerpMetasOnce(),
|
|
103
|
-
this.loadCollateralTokenNamesOnce()
|
|
104
|
-
]);
|
|
105
|
-
const assetData = await this.fetchActiveAssetEvents(input.legs.map((leg) => leg.asset));
|
|
106
|
-
return sizeBasket(input, dexToMeta, tokenNames, assetData);
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Sizes a basket against live state, fetching per-asset data for any leg the socket has not
|
|
110
|
-
* subscribed to — which is exactly why the call is asynchronous on both paths.
|
|
111
|
-
*/
|
|
112
|
-
async maxBasketSize(input) {
|
|
113
|
-
const [dexToMeta, tokenNames] = await Promise.all([
|
|
114
|
-
this.loadPerpMetasOnce(),
|
|
115
|
-
this.loadCollateralTokenNamesOnce()
|
|
116
|
-
]);
|
|
117
|
-
const missingCoins = input.legs.map((leg) => leg.asset).filter((asset) => !this.trackedAssetData.has(asset));
|
|
118
|
-
const fetched = await this.fetchActiveAssetEvents(missingCoins);
|
|
119
|
-
const assetData = new Map(fetched);
|
|
120
|
-
for (const leg of input.legs) {
|
|
121
|
-
const cached = this.trackedAssetData.get(leg.asset);
|
|
122
|
-
if (cached) {
|
|
123
|
-
assetData.set(leg.asset, cached);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return sizeBasket(input, dexToMeta, tokenNames, assetData);
|
|
127
|
-
}
|
|
128
97
|
/**
|
|
129
98
|
* Stateless one-shot per-asset settings read via the `activeAssetData` info request (the REST
|
|
130
99
|
* twin of the live WS subscription), one request per coin fired in parallel — the info endpoint
|
|
@@ -363,31 +332,6 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
|
|
|
363
332
|
this.dexToMeta.set(dex, dexMeta);
|
|
364
333
|
});
|
|
365
334
|
}
|
|
366
|
-
/** Loads the dex metadata a sizing call needs, reusing whatever `start()` already cached. */
|
|
367
|
-
async loadPerpMetasOnce() {
|
|
368
|
-
if (this.dexToMeta.size > 0) {
|
|
369
|
-
return this.dexToMeta;
|
|
370
|
-
}
|
|
371
|
-
const [allMetas, perpDexs] = await Promise.all([
|
|
372
|
-
fetchInfo({
|
|
373
|
-
type: "allPerpMetas"
|
|
374
|
-
}, this.demo),
|
|
375
|
-
fetchPerpDexs(this.demo)
|
|
376
|
-
]);
|
|
377
|
-
this.loadPerpMetas(allMetas, perpDexs);
|
|
378
|
-
return this.dexToMeta;
|
|
379
|
-
}
|
|
380
|
-
/** Loads the token names a pool id is spelled with, reusing whatever `start()` already cached. */
|
|
381
|
-
async loadCollateralTokenNamesOnce() {
|
|
382
|
-
if (this.collateralTokenNames.size > 0) {
|
|
383
|
-
return this.collateralTokenNames;
|
|
384
|
-
}
|
|
385
|
-
const spotMeta = await fetchInfo({
|
|
386
|
-
type: "spotMeta"
|
|
387
|
-
}, this.demo);
|
|
388
|
-
this.collateralTokenNames = buildCollateralTokenNames(spotMeta);
|
|
389
|
-
return this.collateralTokenNames;
|
|
390
|
-
}
|
|
391
335
|
/** Reads `activeAssetData` for each coin in parallel, dropping the coins the venue refuses. */
|
|
392
336
|
async fetchActiveAssetEvents(coins) {
|
|
393
337
|
const unique = [
|
|
@@ -558,18 +502,6 @@ class HyperliquidAccountTracker extends BaseAccountTracker {
|
|
|
558
502
|
return result;
|
|
559
503
|
}
|
|
560
504
|
}
|
|
561
|
-
function sizeBasket(input, dexToMeta, tokenNames, assetData) {
|
|
562
|
-
const markets = new Map(input.legs.map((leg) => [
|
|
563
|
-
leg.asset,
|
|
564
|
-
findLegMarket(dexToMeta, tokenNames, leg.asset, assetData.get(leg.asset)?.leverage.value ?? null)
|
|
565
|
-
]));
|
|
566
|
-
const budgets = buildPoolBudgets(input.legs, markets, assetData);
|
|
567
|
-
return computeMaxBasketSize({
|
|
568
|
-
budgets,
|
|
569
|
-
legs: buildCappedLegs(input.legs, markets)
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
__name(sizeBasket, "sizeBasket");
|
|
573
505
|
function buildTrackedAssetInfo(data) {
|
|
574
506
|
return {
|
|
575
507
|
coin: data.coin,
|
package/dist/tracker/index.js
CHANGED
|
@@ -11,7 +11,6 @@ export { OkxAccountTracker } from './okx/tracker';
|
|
|
11
11
|
export { AccountBalance } from './balance';
|
|
12
12
|
export { ACCOUNT_MODE_LABELS, AccountBalanceCore, AccountMode, CollateralBalance, DecimalString, MarginMode, Side, SignedDecimalString } from './balance-core';
|
|
13
13
|
export { BaseAccountTracker } from './base';
|
|
14
|
-
export { BasketLeg, MaxBasketSizeInput, MaxBasketSizeResult, computeMaxBasketSize } from './basket-size';
|
|
15
14
|
export { BinanceMultiAssetBalance, BinanceSingleAssetBalance } from './binance/balance';
|
|
16
15
|
export { BybitIsolatedMarginBalance, BybitPortfolioMarginBalance, BybitRegularMarginBalance } from './bybit/balance';
|
|
17
16
|
export { HyperliquidDexState, HyperliquidPortfolioMarginBalance, HyperliquidPortfolioMarginCollateral, HyperliquidStandardBalance, HyperliquidUnifiedBalance } from './hyperliquid/balance';
|
|
@@ -3,8 +3,6 @@ import { createExchangeWs } from '../../client';
|
|
|
3
3
|
import { fetchAccount, fetchPublicAccount, fetchOrderBookDetails, fetchPublicOrderBookDetails, fetchAccountLimits } from '../../client/lighter/rest';
|
|
4
4
|
import { retrieveLighterAuthToken } from '../../helper/lighter/auth-token.helper';
|
|
5
5
|
import { BaseAccountTracker } from '../base';
|
|
6
|
-
import { computeMaxBasketSize } from '../basket-size';
|
|
7
|
-
import { toLighterBasketCalculation } from './basket-size';
|
|
8
6
|
import { buildSpotPriceIndex, mapPositions, mapRestBalance, mapMarketDefaultAssetInfo, toLighterAccountType, mapLiveBalance, toLighterAccountTier } from './mapper';
|
|
9
7
|
|
|
10
8
|
var __defProp = Object.defineProperty;
|
|
@@ -141,36 +139,6 @@ class LighterAccountTracker extends BaseAccountTracker {
|
|
|
141
139
|
}
|
|
142
140
|
return result;
|
|
143
141
|
}
|
|
144
|
-
/** Sizes a basket against the live account state, falling back to REST before the socket is up. */
|
|
145
|
-
async maxBasketSize(input) {
|
|
146
|
-
if (!this.stats || this.marketsBySymbol.size === 0) {
|
|
147
|
-
return this.snapshotMaxBasketSize(input);
|
|
148
|
-
}
|
|
149
|
-
return computeMaxBasketSize(toLighterBasketCalculation(input.legs, {
|
|
150
|
-
availableBalance: this.stats.total.available_balance,
|
|
151
|
-
perpBySymbol: this.marketsBySymbol,
|
|
152
|
-
settingsByMarketId: this.liveAccountSettings()
|
|
153
|
-
}));
|
|
154
|
-
}
|
|
155
|
-
/** Sizes a basket over REST alone, so the answer needs no running socket. */
|
|
156
|
-
async snapshotMaxBasketSize(input) {
|
|
157
|
-
const [account, markets] = await Promise.all([
|
|
158
|
-
this.fetchPrimaryAccount(),
|
|
159
|
-
this.fetchMarkets()
|
|
160
|
-
]);
|
|
161
|
-
if (!account) {
|
|
162
|
-
return computeMaxBasketSize({
|
|
163
|
-
budgets: {},
|
|
164
|
-
legs: []
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
const context = {
|
|
168
|
-
availableBalance: account.available_balance,
|
|
169
|
-
perpBySymbol: toMarketsBySymbol(markets.perp),
|
|
170
|
-
settingsByMarketId: toAccountSettings(markets.perp, account.positions ?? [])
|
|
171
|
-
};
|
|
172
|
-
return computeMaxBasketSize(toLighterBasketCalculation(input.legs, context));
|
|
173
|
-
}
|
|
174
142
|
start() {
|
|
175
143
|
if (this.startInFlight) {
|
|
176
144
|
return this.startInFlight;
|
|
@@ -414,17 +382,6 @@ class LighterAccountTracker extends BaseAccountTracker {
|
|
|
414
382
|
spotPriceBySymbol: this.spotPriceBySymbol
|
|
415
383
|
};
|
|
416
384
|
}
|
|
417
|
-
/** The account's current per-market settings as the base tracker already holds them. */
|
|
418
|
-
liveAccountSettings() {
|
|
419
|
-
const settings = /* @__PURE__ */ new Map();
|
|
420
|
-
for (const marketId of this.marketsByMarketId.keys()) {
|
|
421
|
-
const info = this.getTrackedAsset(String(marketId));
|
|
422
|
-
if (info) {
|
|
423
|
-
settings.set(String(marketId), info);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
return settings;
|
|
427
|
-
}
|
|
428
385
|
/** Reads the account with credentials when present, or explicitly uses the read-only verifier path. */
|
|
429
386
|
async fetchPrimaryAccount() {
|
|
430
387
|
const authToken = await this.retrieveAuthToken();
|
|
@@ -604,13 +561,6 @@ function toMarketContext(perpMarkets, spotMarkets) {
|
|
|
604
561
|
};
|
|
605
562
|
}
|
|
606
563
|
__name(toMarketContext, "toMarketContext");
|
|
607
|
-
function toMarketsBySymbol(perpMarkets) {
|
|
608
|
-
return new Map(perpMarkets.map((market) => [
|
|
609
|
-
market.symbol,
|
|
610
|
-
market
|
|
611
|
-
]));
|
|
612
|
-
}
|
|
613
|
-
__name(toMarketsBySymbol, "toMarketsBySymbol");
|
|
614
564
|
function toAccountSettings(perpMarkets, positions) {
|
|
615
565
|
const settings = /* @__PURE__ */ new Map();
|
|
616
566
|
for (const market of perpMarkets) {
|
|
@@ -36,20 +36,6 @@ class OkxAccountTracker extends BaseAccountTracker {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* OKX sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
|
|
40
|
-
* `availableMargin` alone would ship a number no venue field backs. The missing input is
|
|
41
|
-
* `GET /api/v5/public/position-tiers` → `maxLever`/`imr` per tier, which the client does not
|
|
42
|
-
* call — and it is NOT `GET /api/v5/account/position-tiers`, a different endpoint carrying no
|
|
43
|
-
* margin or leverage data at all.
|
|
44
|
-
*/
|
|
45
|
-
async maxBasketSize(_input) {
|
|
46
|
-
return unsizedBasket();
|
|
47
|
-
}
|
|
48
|
-
/** The REST path answers the same way — there is no size either way, not a slower one. */
|
|
49
|
-
async snapshotMaxBasketSize(_input) {
|
|
50
|
-
return unsizedBasket();
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
39
|
* Stateless one-shot per-asset leverage read via `leverage-info`, which accepts up to 20 instIds
|
|
54
40
|
* per request (chunked in the client), so N assets cost ceil(N/20) calls. Cross margin only,
|
|
55
41
|
* matching the account-level assumption used everywhere else in this connector.
|
|
@@ -406,13 +392,5 @@ function sameWithdrawable(left, right) {
|
|
|
406
392
|
return true;
|
|
407
393
|
}
|
|
408
394
|
__name(sameWithdrawable, "sameWithdrawable");
|
|
409
|
-
function unsizedBasket() {
|
|
410
|
-
return {
|
|
411
|
-
maxNotional: null,
|
|
412
|
-
legs: [],
|
|
413
|
-
bindingConstraint: null
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
__name(unsizedBasket, "unsizedBasket");
|
|
417
395
|
|
|
418
396
|
export { OkxAccountTracker };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pear-protocol/exchanges-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.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.
|
|
31
|
-
"@pear-protocol/types": "^1.30.
|
|
32
|
-
"@pear-protocol/utils": "^0.
|
|
30
|
+
"@pear-protocol/core-sdk": "^1.19.1",
|
|
31
|
+
"@pear-protocol/types": "^1.30.1",
|
|
32
|
+
"@pear-protocol/utils": "^0.6.0",
|
|
33
33
|
"bignumber.js": "^11.1.1",
|
|
34
34
|
"partysocket": "^1.0.3",
|
|
35
35
|
"viem": "^2.48.8",
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import BigNumber from 'bignumber.js';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { Side, DecimalString, MarginMode } from './balance-core';
|
|
4
|
-
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
-
const BasketLeg = z.object({
|
|
8
|
-
asset: z.string(),
|
|
9
|
-
marginMode: MarginMode,
|
|
10
|
-
leverage: DecimalString,
|
|
11
|
-
side: Side,
|
|
12
|
-
/** Unsigned percentage. The set sums to 100. */
|
|
13
|
-
weight: z.number().positive()
|
|
14
|
-
});
|
|
15
|
-
const MaxBasketSizeInput = z.object({
|
|
16
|
-
legs: z.array(BasketLeg).min(1)
|
|
17
|
-
});
|
|
18
|
-
const MaxBasketSizeResult = z.object({
|
|
19
|
-
/**
|
|
20
|
-
* The whole basket's max GROSS notional in USD — Σ leg notional, not per-side and not per-asset.
|
|
21
|
-
* The basket is atomic, so this is one ceiling for the entire structure.
|
|
22
|
-
* Null when the venue cannot supply a per-asset max leverage (all three CEXs in v1), and null
|
|
23
|
-
* when any leg draws on a pool the caller could not value.
|
|
24
|
-
*/
|
|
25
|
-
maxNotional: DecimalString.nullable(),
|
|
26
|
-
/** Derived from maxNotional — each leg's notional at that basket size. NOT a per-leg maximum. */
|
|
27
|
-
legs: z.array(z.object({
|
|
28
|
-
asset: z.string(),
|
|
29
|
-
notional: DecimalString,
|
|
30
|
-
marginRequired: DecimalString
|
|
31
|
-
})),
|
|
32
|
-
/** Which pool or leg ran out first. */
|
|
33
|
-
bindingConstraint: z.discriminatedUnion("kind", [
|
|
34
|
-
z.object({
|
|
35
|
-
kind: z.literal("cross-pool"),
|
|
36
|
-
pool: z.string()
|
|
37
|
-
}),
|
|
38
|
-
z.object({
|
|
39
|
-
kind: z.literal("isolated-leg"),
|
|
40
|
-
asset: z.string()
|
|
41
|
-
})
|
|
42
|
-
]).nullable()
|
|
43
|
-
});
|
|
44
|
-
function computeMaxBasketSize(input) {
|
|
45
|
-
if (!isSizeableInput(input)) {
|
|
46
|
-
return unsizedResult();
|
|
47
|
-
}
|
|
48
|
-
const budgets = new Map(Object.entries(input.budgets));
|
|
49
|
-
const weightSum = sumWeights(input.legs);
|
|
50
|
-
if (weightSum.isZero()) {
|
|
51
|
-
return unsizedResult();
|
|
52
|
-
}
|
|
53
|
-
const shares = input.legs.map((leg) => toLegShare(leg, weightSum));
|
|
54
|
-
const demandByPool = marginPerUnitNotionalByPool(shares);
|
|
55
|
-
const tightestPool = tightestPoolCeiling(demandByPool, budgets);
|
|
56
|
-
if (tightestPool === null) {
|
|
57
|
-
return unsizedResult();
|
|
58
|
-
}
|
|
59
|
-
const tightestCap = tightestLegCap(shares);
|
|
60
|
-
if (tightestCap === null || tightestPool.size.isLessThanOrEqualTo(tightestCap.size)) {
|
|
61
|
-
return buildResult(tightestPool.size, shares, {
|
|
62
|
-
kind: "cross-pool",
|
|
63
|
-
pool: tightestPool.pool
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
return buildResult(tightestCap.size, shares, {
|
|
67
|
-
kind: "isolated-leg",
|
|
68
|
-
asset: tightestCap.asset
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
__name(computeMaxBasketSize, "computeMaxBasketSize");
|
|
72
|
-
function isSizeableInput(input) {
|
|
73
|
-
for (const budget of Object.values(input.budgets)) {
|
|
74
|
-
if (!isUnsignedDecimal(budget)) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
for (const leg of input.legs) {
|
|
79
|
-
if (!isPositiveFinite(leg.weight)) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
if (!isUsableLeverage(leg.effectiveLeverage)) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
if (leg.maxNotional !== null && !isUnsignedDecimal(leg.maxNotional)) {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
__name(isSizeableInput, "isSizeableInput");
|
|
92
|
-
function isUnsignedDecimal(value) {
|
|
93
|
-
return DecimalString.safeParse(value).success;
|
|
94
|
-
}
|
|
95
|
-
__name(isUnsignedDecimal, "isUnsignedDecimal");
|
|
96
|
-
function isPositiveFinite(weight) {
|
|
97
|
-
return Number.isFinite(weight) && weight > 0;
|
|
98
|
-
}
|
|
99
|
-
__name(isPositiveFinite, "isPositiveFinite");
|
|
100
|
-
function isUsableLeverage(effectiveLeverage) {
|
|
101
|
-
if (!isUnsignedDecimal(effectiveLeverage)) {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
return !new BigNumber(effectiveLeverage).isZero();
|
|
105
|
-
}
|
|
106
|
-
__name(isUsableLeverage, "isUsableLeverage");
|
|
107
|
-
function sumWeights(legs) {
|
|
108
|
-
let total = new BigNumber(0);
|
|
109
|
-
for (const leg of legs) {
|
|
110
|
-
total = total.plus(String(leg.weight));
|
|
111
|
-
}
|
|
112
|
-
return total;
|
|
113
|
-
}
|
|
114
|
-
__name(sumWeights, "sumWeights");
|
|
115
|
-
function unsizedResult() {
|
|
116
|
-
return {
|
|
117
|
-
maxNotional: null,
|
|
118
|
-
legs: [],
|
|
119
|
-
bindingConstraint: null
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
__name(unsizedResult, "unsizedResult");
|
|
123
|
-
function toLegShare(leg, weightSum) {
|
|
124
|
-
return {
|
|
125
|
-
asset: leg.asset,
|
|
126
|
-
pool: leg.pool,
|
|
127
|
-
share: new BigNumber(String(leg.weight)).div(weightSum),
|
|
128
|
-
imr: new BigNumber(1).div(leg.effectiveLeverage),
|
|
129
|
-
maxNotional: leg.maxNotional === null ? null : new BigNumber(leg.maxNotional)
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
__name(toLegShare, "toLegShare");
|
|
133
|
-
function marginPerUnitNotionalByPool(shares) {
|
|
134
|
-
const demandByPool = /* @__PURE__ */ new Map();
|
|
135
|
-
for (const leg of shares) {
|
|
136
|
-
const running = demandByPool.get(leg.pool) ?? new BigNumber(0);
|
|
137
|
-
demandByPool.set(leg.pool, running.plus(leg.share.times(leg.imr)));
|
|
138
|
-
}
|
|
139
|
-
return demandByPool;
|
|
140
|
-
}
|
|
141
|
-
__name(marginPerUnitNotionalByPool, "marginPerUnitNotionalByPool");
|
|
142
|
-
function tightestPoolCeiling(demandByPool, budgets) {
|
|
143
|
-
let tightest = null;
|
|
144
|
-
for (const [pool, marginPerUnitNotional] of demandByPool) {
|
|
145
|
-
const budget = budgets.get(pool);
|
|
146
|
-
if (budget === void 0) {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
const size = new BigNumber(budget).div(marginPerUnitNotional);
|
|
150
|
-
if (tightest === null || size.isLessThan(tightest.size)) {
|
|
151
|
-
tightest = {
|
|
152
|
-
pool,
|
|
153
|
-
size
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return tightest;
|
|
158
|
-
}
|
|
159
|
-
__name(tightestPoolCeiling, "tightestPoolCeiling");
|
|
160
|
-
function tightestLegCap(shares) {
|
|
161
|
-
let tightest = null;
|
|
162
|
-
for (const leg of shares) {
|
|
163
|
-
if (leg.maxNotional === null) {
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
const size = leg.maxNotional.div(leg.share);
|
|
167
|
-
if (tightest === null || size.isLessThan(tightest.size)) {
|
|
168
|
-
tightest = {
|
|
169
|
-
asset: leg.asset,
|
|
170
|
-
size
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return tightest;
|
|
175
|
-
}
|
|
176
|
-
__name(tightestLegCap, "tightestLegCap");
|
|
177
|
-
function buildResult(size, shares, bindingConstraint) {
|
|
178
|
-
const legs = shares.map((leg) => {
|
|
179
|
-
const notional = size.times(leg.share);
|
|
180
|
-
return {
|
|
181
|
-
asset: leg.asset,
|
|
182
|
-
notional: notional.toFixed(),
|
|
183
|
-
marginRequired: notional.times(leg.imr).toFixed()
|
|
184
|
-
};
|
|
185
|
-
});
|
|
186
|
-
return {
|
|
187
|
-
maxNotional: size.toFixed(),
|
|
188
|
-
legs,
|
|
189
|
-
bindingConstraint
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
__name(buildResult, "buildResult");
|
|
193
|
-
|
|
194
|
-
export { BasketLeg, MaxBasketSizeInput, MaxBasketSizeResult, computeMaxBasketSize };
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import BigNumber from 'bignumber.js';
|
|
2
|
-
import { splitDexCoin } from './coin-name';
|
|
3
|
-
import { toDecimal } from './decimal';
|
|
4
|
-
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
-
const UNRESOLVED_POOL = "";
|
|
8
|
-
function buildCappedLegs(legs, markets) {
|
|
9
|
-
return legs.map((leg) => {
|
|
10
|
-
const market = markets.get(leg.asset) ?? null;
|
|
11
|
-
const leverage = effectiveLeverage(leg.leverage, market);
|
|
12
|
-
return {
|
|
13
|
-
asset: leg.asset,
|
|
14
|
-
pool: market?.pool ?? UNRESOLVED_POOL,
|
|
15
|
-
weight: leg.weight,
|
|
16
|
-
effectiveLeverage: leverage,
|
|
17
|
-
marginMode: leg.marginMode,
|
|
18
|
-
maxNotional: tierBoundaryNotional(market?.marginTiers ?? null, leverage)
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
__name(buildCappedLegs, "buildCappedLegs");
|
|
23
|
-
function buildPoolBudgets(legs, markets, assetData) {
|
|
24
|
-
const dataByPool = /* @__PURE__ */ new Map();
|
|
25
|
-
for (const leg of legs) {
|
|
26
|
-
const pool = markets.get(leg.asset)?.pool ?? null;
|
|
27
|
-
const data = assetData.get(leg.asset);
|
|
28
|
-
if (pool === null || data === void 0) {
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
const bucket = dataByPool.get(pool) ?? [];
|
|
32
|
-
bucket.push(data);
|
|
33
|
-
dataByPool.set(pool, bucket);
|
|
34
|
-
}
|
|
35
|
-
const budgets = {};
|
|
36
|
-
for (const [pool, data] of dataByPool) {
|
|
37
|
-
const floor = minimumAvailableToTrade(data);
|
|
38
|
-
if (floor !== null) {
|
|
39
|
-
budgets[pool] = floor;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return budgets;
|
|
43
|
-
}
|
|
44
|
-
__name(buildPoolBudgets, "buildPoolBudgets");
|
|
45
|
-
function effectiveLeverage(requestedLeverage, market) {
|
|
46
|
-
let leverage = toDecimal(requestedLeverage);
|
|
47
|
-
if (market?.venueMaxLeverage !== null && market?.venueMaxLeverage !== void 0) {
|
|
48
|
-
leverage = BigNumber.min(leverage, market.venueMaxLeverage);
|
|
49
|
-
}
|
|
50
|
-
if (market?.accountLeverage !== null && market?.accountLeverage !== void 0) {
|
|
51
|
-
leverage = BigNumber.min(leverage, market.accountLeverage);
|
|
52
|
-
}
|
|
53
|
-
return BigNumber.max(leverage, 1).toFixed();
|
|
54
|
-
}
|
|
55
|
-
__name(effectiveLeverage, "effectiveLeverage");
|
|
56
|
-
function tierBoundaryNotional(marginTiers, effectiveLeverage2) {
|
|
57
|
-
if (!marginTiers) {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
const leverage = toDecimal(effectiveLeverage2);
|
|
61
|
-
const boundary = marginTiers.find((tier) => leverage.isGreaterThan(tier.maxLeverage));
|
|
62
|
-
return boundary ? boundary.lowerBound : null;
|
|
63
|
-
}
|
|
64
|
-
__name(tierBoundaryNotional, "tierBoundaryNotional");
|
|
65
|
-
function minimumAvailableToTrade(assetData) {
|
|
66
|
-
let floor = null;
|
|
67
|
-
for (const data of assetData) {
|
|
68
|
-
for (const available of data.availableToTrade ?? []) {
|
|
69
|
-
const value = toDecimal(available);
|
|
70
|
-
if (floor === null || value.isLessThan(floor)) {
|
|
71
|
-
floor = value;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return floor === null ? null : floor.toFixed();
|
|
76
|
-
}
|
|
77
|
-
__name(minimumAvailableToTrade, "minimumAvailableToTrade");
|
|
78
|
-
function findLegMarket(dexToMeta, tokenNames, coin, accountLeverage) {
|
|
79
|
-
const { dex, bareCoin } = splitDexCoin(coin);
|
|
80
|
-
const meta = dexToMeta.get(dex);
|
|
81
|
-
const asset = meta?.universe.find((candidate) => candidate.name === coin || candidate.name === bareCoin);
|
|
82
|
-
const marginTiers = meta?.marginTables.find(([id]) => id === asset?.marginTableId)?.[1].marginTiers;
|
|
83
|
-
const collateralToken = meta?.collateralToken;
|
|
84
|
-
return {
|
|
85
|
-
pool: collateralToken === void 0 ? null : tokenNames.get(collateralToken) ?? null,
|
|
86
|
-
venueMaxLeverage: asset?.maxLeverage ?? null,
|
|
87
|
-
accountLeverage,
|
|
88
|
-
marginTiers: marginTiers?.length ? marginTiers : null
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
__name(findLegMarket, "findLegMarket");
|
|
92
|
-
|
|
93
|
-
export { buildCappedLegs, buildPoolBudgets, effectiveLeverage, findLegMarket, minimumAvailableToTrade, tierBoundaryNotional };
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import BigNumber from 'bignumber.js';
|
|
2
|
-
import { QUOTE_ASSET } from './const';
|
|
3
|
-
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
-
const MARGIN_FRACTION_SCALE = 1e4;
|
|
7
|
-
const CROSS_POOL = QUOTE_ASSET;
|
|
8
|
-
const DECIMAL_PATTERN = /^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;
|
|
9
|
-
function toLighterBasketCalculation(legs, context) {
|
|
10
|
-
const capped = [];
|
|
11
|
-
for (const leg of legs) {
|
|
12
|
-
const market = context.perpBySymbol.get(leg.asset);
|
|
13
|
-
if (!market) {
|
|
14
|
-
return {
|
|
15
|
-
budgets: {},
|
|
16
|
-
legs: []
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
capped.push(toCappedLeg(leg, market, context.settingsByMarketId.get(String(market.market_id))));
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
// Every leg draws on the same pool, so one entry carries the whole basket's budget.
|
|
23
|
-
budgets: {
|
|
24
|
-
[CROSS_POOL]: context.availableBalance
|
|
25
|
-
},
|
|
26
|
-
legs: capped
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
__name(toLighterBasketCalculation, "toLighterBasketCalculation");
|
|
30
|
-
function toCappedLeg(leg, market, currentSetting) {
|
|
31
|
-
return {
|
|
32
|
-
asset: leg.asset,
|
|
33
|
-
pool: CROSS_POOL,
|
|
34
|
-
weight: leg.weight,
|
|
35
|
-
effectiveLeverage: effectiveLeverage(leg.leverage, market, currentSetting),
|
|
36
|
-
marginMode: leg.marginMode,
|
|
37
|
-
maxNotional: null
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
__name(toCappedLeg, "toCappedLeg");
|
|
41
|
-
function effectiveLeverage(requested, market, currentSetting) {
|
|
42
|
-
const accountLeverage = currentSetting === void 0 ? defaultAccountLeverage(market) : toDecimal(currentSetting.leverage);
|
|
43
|
-
const granted = BigNumber.min(toDecimal(requested), venueMaxLeverage(market), accountLeverage);
|
|
44
|
-
return granted.isFinite() && granted.isGreaterThan(0) ? granted.toFixed() : "1";
|
|
45
|
-
}
|
|
46
|
-
__name(effectiveLeverage, "effectiveLeverage");
|
|
47
|
-
function venueMaxLeverage(market) {
|
|
48
|
-
return leverageFromMarginFraction(market.min_initial_margin_fraction);
|
|
49
|
-
}
|
|
50
|
-
__name(venueMaxLeverage, "venueMaxLeverage");
|
|
51
|
-
function defaultAccountLeverage(market) {
|
|
52
|
-
return leverageFromMarginFraction(market.default_initial_margin_fraction).integerValue(BigNumber.ROUND_FLOOR);
|
|
53
|
-
}
|
|
54
|
-
__name(defaultAccountLeverage, "defaultAccountLeverage");
|
|
55
|
-
function leverageFromMarginFraction(marginFraction) {
|
|
56
|
-
const fraction = toDecimal(marginFraction);
|
|
57
|
-
if (!fraction.isGreaterThan(0)) {
|
|
58
|
-
return new BigNumber(1);
|
|
59
|
-
}
|
|
60
|
-
return new BigNumber(MARGIN_FRACTION_SCALE).div(fraction);
|
|
61
|
-
}
|
|
62
|
-
__name(leverageFromMarginFraction, "leverageFromMarginFraction");
|
|
63
|
-
function toDecimal(value) {
|
|
64
|
-
if (typeof value === "number") {
|
|
65
|
-
return Number.isFinite(value) ? new BigNumber(value) : new BigNumber(0);
|
|
66
|
-
}
|
|
67
|
-
if (typeof value !== "string" || !DECIMAL_PATTERN.test(value)) {
|
|
68
|
-
return new BigNumber(0);
|
|
69
|
-
}
|
|
70
|
-
return new BigNumber(value);
|
|
71
|
-
}
|
|
72
|
-
__name(toDecimal, "toDecimal");
|
|
73
|
-
|
|
74
|
-
export { toLighterBasketCalculation, venueMaxLeverage };
|