@pear-protocol/hyperliquid-sdk 0.0.10 → 0.0.11
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/hooks/index.d.ts +2 -0
- package/dist/hooks/useTokenSelection.d.ts +33 -0
- package/dist/index.d.ts +111 -2
- package/dist/index.esm.js +472 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +473 -1
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +15 -1
- package/dist/types.d.ts +31 -0
- package/dist/utils/conflict-detector.d.ts +14 -0
- package/dist/utils/token-metadata-extractor.d.ts +29 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2881,6 +2881,23 @@ const useHyperliquidNativeWebSocket = ({ address }) => {
|
|
|
2881
2881
|
};
|
|
2882
2882
|
};
|
|
2883
2883
|
|
|
2884
|
+
const DEFAULT_TOKEN_SELECTION_STATE = {
|
|
2885
|
+
longTokens: [
|
|
2886
|
+
{ symbol: 'HYPE', weight: 25 },
|
|
2887
|
+
{ symbol: 'BTC', weight: 25 }
|
|
2888
|
+
],
|
|
2889
|
+
shortTokens: [
|
|
2890
|
+
{ symbol: 'AVAX', weight: 10 },
|
|
2891
|
+
{ symbol: 'SEI', weight: 10 },
|
|
2892
|
+
{ symbol: 'ADA', weight: 10 },
|
|
2893
|
+
{ symbol: 'TRUMP', weight: 10 },
|
|
2894
|
+
{ symbol: 'SUI', weight: 10 }
|
|
2895
|
+
],
|
|
2896
|
+
openTokenSelector: false,
|
|
2897
|
+
selectorConfig: null,
|
|
2898
|
+
openConflictModal: false,
|
|
2899
|
+
conflicts: [],
|
|
2900
|
+
};
|
|
2884
2901
|
const PearHyperliquidContext = require$$0.createContext(undefined);
|
|
2885
2902
|
/**
|
|
2886
2903
|
* React Provider for PearHyperliquidClient
|
|
@@ -2890,6 +2907,8 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
|
|
|
2890
2907
|
const migrationSDK = require$$0.useMemo(() => new PearMigrationSDK(client), [client]);
|
|
2891
2908
|
// Address state
|
|
2892
2909
|
const [address, setAddress] = require$$0.useState(null);
|
|
2910
|
+
// Token selection state
|
|
2911
|
+
const [tokenSelection, setTokenSelection] = require$$0.useState(DEFAULT_TOKEN_SELECTION_STATE);
|
|
2893
2912
|
// WebSocket connection and data (Pear API)
|
|
2894
2913
|
const { data, connectionStatus, isConnected, lastError } = useHyperliquidWebSocket({
|
|
2895
2914
|
wsUrl,
|
|
@@ -2919,7 +2938,10 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
|
|
|
2919
2938
|
// HyperLiquid native WebSocket data
|
|
2920
2939
|
webData2,
|
|
2921
2940
|
allMids,
|
|
2922
|
-
|
|
2941
|
+
// Token selection state
|
|
2942
|
+
tokenSelection,
|
|
2943
|
+
setTokenSelection,
|
|
2944
|
+
}), [client, migrationSDK, address, connectionStatus, isConnected, data, lastError, nativeConnectionStatus, nativeIsConnected, nativeLastError, webData2, allMids, tokenSelection, setTokenSelection]);
|
|
2923
2945
|
return (jsxRuntimeExports.jsx(PearHyperliquidContext.Provider, { value: contextValue, children: children }));
|
|
2924
2946
|
};
|
|
2925
2947
|
/**
|
|
@@ -3439,10 +3461,459 @@ const useAccountSummary = () => {
|
|
|
3439
3461
|
};
|
|
3440
3462
|
};
|
|
3441
3463
|
|
|
3464
|
+
/**
|
|
3465
|
+
* Extracts token metadata from WebData2 and AllMids data
|
|
3466
|
+
*/
|
|
3467
|
+
class TokenMetadataExtractor {
|
|
3468
|
+
/**
|
|
3469
|
+
* Extracts comprehensive token metadata
|
|
3470
|
+
* @param symbol - Token symbol
|
|
3471
|
+
* @param webData2 - WebData2 response containing asset context and universe data
|
|
3472
|
+
* @param allMids - AllMids data containing current prices
|
|
3473
|
+
* @returns TokenMetadata or null if token not found
|
|
3474
|
+
*/
|
|
3475
|
+
static extractTokenMetadata(symbol, webData2, allMids) {
|
|
3476
|
+
if (!webData2 || !allMids) {
|
|
3477
|
+
return null;
|
|
3478
|
+
}
|
|
3479
|
+
// Find token index in universe
|
|
3480
|
+
const universeIndex = webData2.meta.universe.findIndex(asset => asset.name === symbol);
|
|
3481
|
+
if (universeIndex === -1) {
|
|
3482
|
+
return null;
|
|
3483
|
+
}
|
|
3484
|
+
const universeAsset = webData2.meta.universe[universeIndex];
|
|
3485
|
+
const assetCtx = webData2.assetCtxs[universeIndex];
|
|
3486
|
+
if (!assetCtx) {
|
|
3487
|
+
return null;
|
|
3488
|
+
}
|
|
3489
|
+
// Get current price from allMids
|
|
3490
|
+
const currentPriceStr = allMids.mids[symbol];
|
|
3491
|
+
const currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
3492
|
+
// Get previous day price
|
|
3493
|
+
const prevDayPrice = parseFloat(assetCtx.prevDayPx);
|
|
3494
|
+
// Calculate 24h price change
|
|
3495
|
+
const priceChange24h = currentPrice - prevDayPrice;
|
|
3496
|
+
const priceChange24hPercent = prevDayPrice !== 0 ? (priceChange24h / prevDayPrice) * 100 : 0;
|
|
3497
|
+
// Parse other metadata
|
|
3498
|
+
const netFunding = parseFloat(assetCtx.funding);
|
|
3499
|
+
const markPrice = parseFloat(assetCtx.markPx);
|
|
3500
|
+
const oraclePrice = parseFloat(assetCtx.oraclePx);
|
|
3501
|
+
return {
|
|
3502
|
+
currentPrice,
|
|
3503
|
+
prevDayPrice,
|
|
3504
|
+
priceChange24h,
|
|
3505
|
+
priceChange24hPercent,
|
|
3506
|
+
netFunding,
|
|
3507
|
+
maxLeverage: universeAsset.maxLeverage,
|
|
3508
|
+
markPrice,
|
|
3509
|
+
oraclePrice,
|
|
3510
|
+
openInterest: assetCtx.openInterest,
|
|
3511
|
+
dayVolume: assetCtx.dayNtlVlm,
|
|
3512
|
+
};
|
|
3513
|
+
}
|
|
3514
|
+
/**
|
|
3515
|
+
* Extracts metadata for multiple tokens
|
|
3516
|
+
* @param symbols - Array of token symbols
|
|
3517
|
+
* @param webData2 - WebData2 response
|
|
3518
|
+
* @param allMids - AllMids data
|
|
3519
|
+
* @returns Record of symbol to TokenMetadata
|
|
3520
|
+
*/
|
|
3521
|
+
static extractMultipleTokensMetadata(symbols, webData2, allMids) {
|
|
3522
|
+
const result = {};
|
|
3523
|
+
for (const symbol of symbols) {
|
|
3524
|
+
result[symbol] = this.extractTokenMetadata(symbol, webData2, allMids);
|
|
3525
|
+
}
|
|
3526
|
+
return result;
|
|
3527
|
+
}
|
|
3528
|
+
/**
|
|
3529
|
+
* Checks if token data is available in WebData2
|
|
3530
|
+
* @param symbol - Token symbol
|
|
3531
|
+
* @param webData2 - WebData2 response
|
|
3532
|
+
* @returns boolean indicating if token exists in universe
|
|
3533
|
+
*/
|
|
3534
|
+
static isTokenAvailable(symbol, webData2) {
|
|
3535
|
+
if (!webData2)
|
|
3536
|
+
return false;
|
|
3537
|
+
return webData2.meta.universe.some(asset => asset.name === symbol);
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
|
|
3541
|
+
/**
|
|
3542
|
+
* Hook to access token selection state using provider's WebSocket data
|
|
3543
|
+
*/
|
|
3544
|
+
const useTokenSelection = () => {
|
|
3545
|
+
var _a;
|
|
3546
|
+
const context = require$$0.useContext(PearHyperliquidContext);
|
|
3547
|
+
if (!context) {
|
|
3548
|
+
throw new Error('useTokenSelection must be used within PearHyperliquidProvider');
|
|
3549
|
+
}
|
|
3550
|
+
const { webData2, allMids, tokenSelection, setTokenSelection } = context;
|
|
3551
|
+
// Loading states
|
|
3552
|
+
const isPriceDataReady = require$$0.useMemo(() => {
|
|
3553
|
+
return !!(webData2 && allMids);
|
|
3554
|
+
}, [webData2, allMids]);
|
|
3555
|
+
const isLoading = require$$0.useMemo(() => {
|
|
3556
|
+
// Check if any tokens have missing metadata when price data is available
|
|
3557
|
+
if (!isPriceDataReady)
|
|
3558
|
+
return true;
|
|
3559
|
+
const allTokens = [...tokenSelection.longTokens, ...tokenSelection.shortTokens];
|
|
3560
|
+
if (allTokens.length === 0)
|
|
3561
|
+
return false;
|
|
3562
|
+
// Loading if any token is missing metadata
|
|
3563
|
+
return allTokens.some(token => !token.metadata);
|
|
3564
|
+
}, [isPriceDataReady, tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3565
|
+
// Auto-update token metadata when WebSocket data changes
|
|
3566
|
+
require$$0.useEffect(() => {
|
|
3567
|
+
if (!webData2 || !allMids)
|
|
3568
|
+
return;
|
|
3569
|
+
const allTokenSymbols = [...tokenSelection.longTokens, ...tokenSelection.shortTokens].map(t => t.symbol);
|
|
3570
|
+
if (allTokenSymbols.length === 0)
|
|
3571
|
+
return;
|
|
3572
|
+
const metadataMap = TokenMetadataExtractor.extractMultipleTokensMetadata(allTokenSymbols, webData2, allMids);
|
|
3573
|
+
setTokenSelection(prev => ({
|
|
3574
|
+
...prev,
|
|
3575
|
+
longTokens: prev.longTokens.map(token => ({
|
|
3576
|
+
...token,
|
|
3577
|
+
metadata: metadataMap[token.symbol] || undefined
|
|
3578
|
+
})),
|
|
3579
|
+
shortTokens: prev.shortTokens.map(token => ({
|
|
3580
|
+
...token,
|
|
3581
|
+
metadata: metadataMap[token.symbol] || undefined
|
|
3582
|
+
}))
|
|
3583
|
+
}));
|
|
3584
|
+
}, [webData2, allMids, setTokenSelection]);
|
|
3585
|
+
// Calculate weighted ratio: LONG^WEIGHT * SHORT^-WEIGHT
|
|
3586
|
+
const weightedRatio = require$$0.useMemo(() => {
|
|
3587
|
+
let longProduct = 1;
|
|
3588
|
+
let shortProduct = 1;
|
|
3589
|
+
// Calculate long side product: PRICE^(WEIGHT/100)
|
|
3590
|
+
tokenSelection.longTokens.forEach(token => {
|
|
3591
|
+
var _a;
|
|
3592
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.currentPrice) && token.weight > 0) {
|
|
3593
|
+
const weightFactor = token.weight / 100;
|
|
3594
|
+
longProduct *= Math.pow(token.metadata.currentPrice, weightFactor);
|
|
3595
|
+
}
|
|
3596
|
+
});
|
|
3597
|
+
// Calculate short side product: PRICE^-(WEIGHT/100)
|
|
3598
|
+
tokenSelection.shortTokens.forEach(token => {
|
|
3599
|
+
var _a;
|
|
3600
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.currentPrice) && token.weight > 0) {
|
|
3601
|
+
const weightFactor = token.weight / 100;
|
|
3602
|
+
shortProduct *= Math.pow(token.metadata.currentPrice, -weightFactor);
|
|
3603
|
+
}
|
|
3604
|
+
});
|
|
3605
|
+
return longProduct * shortProduct;
|
|
3606
|
+
}, [tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3607
|
+
// Calculate 24h weighted ratio using previous day prices
|
|
3608
|
+
const weightedRatio24h = require$$0.useMemo(() => {
|
|
3609
|
+
let longProduct = 1;
|
|
3610
|
+
let shortProduct = 1;
|
|
3611
|
+
// Calculate long side product: PREV_PRICE^(WEIGHT/100)
|
|
3612
|
+
tokenSelection.longTokens.forEach(token => {
|
|
3613
|
+
var _a;
|
|
3614
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.prevDayPrice) && token.weight > 0) {
|
|
3615
|
+
const weightFactor = token.weight / 100;
|
|
3616
|
+
longProduct *= Math.pow(token.metadata.prevDayPrice, weightFactor);
|
|
3617
|
+
}
|
|
3618
|
+
});
|
|
3619
|
+
// Calculate short side product: PREV_PRICE^-(WEIGHT/100)
|
|
3620
|
+
tokenSelection.shortTokens.forEach(token => {
|
|
3621
|
+
var _a;
|
|
3622
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.prevDayPrice) && token.weight > 0) {
|
|
3623
|
+
const weightFactor = token.weight / 100;
|
|
3624
|
+
shortProduct *= Math.pow(token.metadata.prevDayPrice, -weightFactor);
|
|
3625
|
+
}
|
|
3626
|
+
});
|
|
3627
|
+
return longProduct * shortProduct;
|
|
3628
|
+
}, [tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3629
|
+
// Calculate sum of weighted net funding
|
|
3630
|
+
const sumNetFunding = require$$0.useMemo(() => {
|
|
3631
|
+
let totalFunding = 0;
|
|
3632
|
+
// Add long funding weighted by allocation
|
|
3633
|
+
tokenSelection.longTokens.forEach(token => {
|
|
3634
|
+
var _a;
|
|
3635
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.netFunding) && token.weight > 0) {
|
|
3636
|
+
const weightFactor = token.weight / 100;
|
|
3637
|
+
totalFunding += token.metadata.netFunding * weightFactor;
|
|
3638
|
+
}
|
|
3639
|
+
});
|
|
3640
|
+
// Subtract short funding weighted by allocation (since we're short)
|
|
3641
|
+
tokenSelection.shortTokens.forEach(token => {
|
|
3642
|
+
var _a;
|
|
3643
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.netFunding) && token.weight > 0) {
|
|
3644
|
+
const weightFactor = token.weight / 100;
|
|
3645
|
+
totalFunding -= token.metadata.netFunding * weightFactor;
|
|
3646
|
+
}
|
|
3647
|
+
});
|
|
3648
|
+
return totalFunding;
|
|
3649
|
+
}, [tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3650
|
+
// Calculate max leverage (minimum of all token maxLeverages)
|
|
3651
|
+
const maxLeverage = require$$0.useMemo(() => {
|
|
3652
|
+
var _a;
|
|
3653
|
+
if (!((_a = webData2 === null || webData2 === void 0 ? void 0 : webData2.meta) === null || _a === void 0 ? void 0 : _a.universe))
|
|
3654
|
+
return 0;
|
|
3655
|
+
const allTokenSymbols = [...tokenSelection.longTokens, ...tokenSelection.shortTokens].map(t => t.symbol);
|
|
3656
|
+
if (allTokenSymbols.length === 0)
|
|
3657
|
+
return 0;
|
|
3658
|
+
let minLeverage = Infinity;
|
|
3659
|
+
allTokenSymbols.forEach(symbol => {
|
|
3660
|
+
const tokenUniverse = webData2.meta.universe.find(u => u.name === symbol);
|
|
3661
|
+
if (tokenUniverse === null || tokenUniverse === void 0 ? void 0 : tokenUniverse.maxLeverage) {
|
|
3662
|
+
minLeverage = Math.min(minLeverage, tokenUniverse.maxLeverage);
|
|
3663
|
+
}
|
|
3664
|
+
});
|
|
3665
|
+
return minLeverage === Infinity ? 0 : minLeverage;
|
|
3666
|
+
}, [(_a = webData2 === null || webData2 === void 0 ? void 0 : webData2.meta) === null || _a === void 0 ? void 0 : _a.universe, tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3667
|
+
// Calculate minimum margin (10 * total number of tokens)
|
|
3668
|
+
const minMargin = require$$0.useMemo(() => {
|
|
3669
|
+
const totalTokenCount = tokenSelection.longTokens.length + tokenSelection.shortTokens.length;
|
|
3670
|
+
return 10 * totalTokenCount;
|
|
3671
|
+
}, [tokenSelection.longTokens.length, tokenSelection.shortTokens.length]);
|
|
3672
|
+
// Actions
|
|
3673
|
+
const setLongTokens = require$$0.useCallback((tokens) => {
|
|
3674
|
+
setTokenSelection(prev => ({ ...prev, longTokens: tokens }));
|
|
3675
|
+
}, [setTokenSelection]);
|
|
3676
|
+
const setShortTokens = require$$0.useCallback((tokens) => {
|
|
3677
|
+
setTokenSelection(prev => ({ ...prev, shortTokens: tokens }));
|
|
3678
|
+
}, [setTokenSelection]);
|
|
3679
|
+
const updateTokenWeight = require$$0.useCallback((isLong, index, newWeight) => {
|
|
3680
|
+
const clampedWeight = Math.max(1, Math.min(100, newWeight));
|
|
3681
|
+
setTokenSelection(prev => {
|
|
3682
|
+
var _a, _b;
|
|
3683
|
+
const currentLongTotal = prev.longTokens.reduce((sum, token) => sum + token.weight, 0);
|
|
3684
|
+
const currentShortTotal = prev.shortTokens.reduce((sum, token) => sum + token.weight, 0);
|
|
3685
|
+
if (isLong) {
|
|
3686
|
+
const oldWeight = ((_a = prev.longTokens[index]) === null || _a === void 0 ? void 0 : _a.weight) || 0;
|
|
3687
|
+
const weightDiff = clampedWeight - oldWeight;
|
|
3688
|
+
const newLongTotal = currentLongTotal + weightDiff;
|
|
3689
|
+
if (newLongTotal + currentShortTotal > 100) {
|
|
3690
|
+
const maxAllowedWeight = Math.max(1, 100 - currentShortTotal - (currentLongTotal - oldWeight));
|
|
3691
|
+
const updated = [...prev.longTokens];
|
|
3692
|
+
updated[index] = { ...updated[index], weight: maxAllowedWeight };
|
|
3693
|
+
return { ...prev, longTokens: updated };
|
|
3694
|
+
}
|
|
3695
|
+
else {
|
|
3696
|
+
const updated = [...prev.longTokens];
|
|
3697
|
+
updated[index] = { ...updated[index], weight: clampedWeight };
|
|
3698
|
+
return { ...prev, longTokens: updated };
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
else {
|
|
3702
|
+
const oldWeight = ((_b = prev.shortTokens[index]) === null || _b === void 0 ? void 0 : _b.weight) || 0;
|
|
3703
|
+
const weightDiff = clampedWeight - oldWeight;
|
|
3704
|
+
const newShortTotal = currentShortTotal + weightDiff;
|
|
3705
|
+
if (currentLongTotal + newShortTotal > 100) {
|
|
3706
|
+
const maxAllowedWeight = Math.max(1, 100 - currentLongTotal - (currentShortTotal - oldWeight));
|
|
3707
|
+
const updated = [...prev.shortTokens];
|
|
3708
|
+
updated[index] = { ...updated[index], weight: maxAllowedWeight };
|
|
3709
|
+
return { ...prev, shortTokens: updated };
|
|
3710
|
+
}
|
|
3711
|
+
else {
|
|
3712
|
+
const updated = [...prev.shortTokens];
|
|
3713
|
+
updated[index] = { ...updated[index], weight: clampedWeight };
|
|
3714
|
+
return { ...prev, shortTokens: updated };
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
});
|
|
3718
|
+
}, [setTokenSelection]);
|
|
3719
|
+
const addToken = require$$0.useCallback((isLong) => {
|
|
3720
|
+
const currentTokens = isLong ? tokenSelection.longTokens : tokenSelection.shortTokens;
|
|
3721
|
+
const newIndex = currentTokens.length;
|
|
3722
|
+
setTokenSelection(prev => ({
|
|
3723
|
+
...prev,
|
|
3724
|
+
selectorConfig: { isLong, index: newIndex },
|
|
3725
|
+
openTokenSelector: true,
|
|
3726
|
+
}));
|
|
3727
|
+
}, [tokenSelection.longTokens, tokenSelection.shortTokens, setTokenSelection]);
|
|
3728
|
+
const removeToken = require$$0.useCallback((isLong, index) => {
|
|
3729
|
+
setTokenSelection(prev => {
|
|
3730
|
+
if (isLong) {
|
|
3731
|
+
const updated = prev.longTokens.filter((_, i) => i !== index);
|
|
3732
|
+
return { ...prev, longTokens: updated };
|
|
3733
|
+
}
|
|
3734
|
+
else {
|
|
3735
|
+
const updated = prev.shortTokens.filter((_, i) => i !== index);
|
|
3736
|
+
return { ...prev, shortTokens: updated };
|
|
3737
|
+
}
|
|
3738
|
+
});
|
|
3739
|
+
}, [setTokenSelection]);
|
|
3740
|
+
const setOpenTokenSelector = require$$0.useCallback((open) => {
|
|
3741
|
+
setTokenSelection(prev => ({ ...prev, openTokenSelector: open }));
|
|
3742
|
+
}, [setTokenSelection]);
|
|
3743
|
+
const setSelectorConfig = require$$0.useCallback((config) => {
|
|
3744
|
+
setTokenSelection(prev => ({ ...prev, selectorConfig: config }));
|
|
3745
|
+
}, [setTokenSelection]);
|
|
3746
|
+
const setOpenConflictModal = require$$0.useCallback((open) => {
|
|
3747
|
+
setTokenSelection(prev => ({ ...prev, openConflictModal: open }));
|
|
3748
|
+
}, [setTokenSelection]);
|
|
3749
|
+
const setConflicts = require$$0.useCallback((conflicts) => {
|
|
3750
|
+
setTokenSelection(prev => ({ ...prev, conflicts }));
|
|
3751
|
+
}, [setTokenSelection]);
|
|
3752
|
+
const resetToDefaults = require$$0.useCallback(() => {
|
|
3753
|
+
setTokenSelection(prev => ({
|
|
3754
|
+
...prev,
|
|
3755
|
+
longTokens: [
|
|
3756
|
+
{ symbol: 'HYPE', weight: 25 },
|
|
3757
|
+
{ symbol: 'BTC', weight: 25 }
|
|
3758
|
+
],
|
|
3759
|
+
shortTokens: [
|
|
3760
|
+
{ symbol: 'AVAX', weight: 10 },
|
|
3761
|
+
{ symbol: 'SEI', weight: 10 },
|
|
3762
|
+
{ symbol: 'ADA', weight: 10 },
|
|
3763
|
+
{ symbol: 'TRUMP', weight: 10 },
|
|
3764
|
+
{ symbol: 'SUI', weight: 10 }
|
|
3765
|
+
],
|
|
3766
|
+
openTokenSelector: false,
|
|
3767
|
+
selectorConfig: null,
|
|
3768
|
+
openConflictModal: false,
|
|
3769
|
+
}));
|
|
3770
|
+
}, [setTokenSelection]);
|
|
3771
|
+
const handleTokenSelect = require$$0.useCallback((selectedToken) => {
|
|
3772
|
+
if (!tokenSelection.selectorConfig)
|
|
3773
|
+
return;
|
|
3774
|
+
const { isLong, index } = tokenSelection.selectorConfig;
|
|
3775
|
+
const existingTokens = isLong ? tokenSelection.longTokens : tokenSelection.shortTokens;
|
|
3776
|
+
// Check if token already exists
|
|
3777
|
+
if (existingTokens.some(t => t.symbol === selectedToken))
|
|
3778
|
+
return;
|
|
3779
|
+
// Get metadata for new token
|
|
3780
|
+
const metadata = TokenMetadataExtractor.extractTokenMetadata(selectedToken, webData2, allMids);
|
|
3781
|
+
setTokenSelection(prev => {
|
|
3782
|
+
if (index >= existingTokens.length) {
|
|
3783
|
+
// Adding new token - calculate safe weight
|
|
3784
|
+
const currentLongTotal = prev.longTokens.reduce((sum, token) => sum + token.weight, 0);
|
|
3785
|
+
const currentShortTotal = prev.shortTokens.reduce((sum, token) => sum + token.weight, 0);
|
|
3786
|
+
const currentTotal = currentLongTotal + currentShortTotal;
|
|
3787
|
+
const maxAvailableWeight = Math.max(1, 100 - currentTotal);
|
|
3788
|
+
const safeWeight = Math.min(20, maxAvailableWeight);
|
|
3789
|
+
const newToken = {
|
|
3790
|
+
symbol: selectedToken,
|
|
3791
|
+
weight: safeWeight,
|
|
3792
|
+
metadata: metadata || undefined
|
|
3793
|
+
};
|
|
3794
|
+
if (isLong) {
|
|
3795
|
+
return { ...prev, longTokens: [...prev.longTokens, newToken] };
|
|
3796
|
+
}
|
|
3797
|
+
else {
|
|
3798
|
+
return { ...prev, shortTokens: [...prev.shortTokens, newToken] };
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
else {
|
|
3802
|
+
// Replacing existing token
|
|
3803
|
+
if (isLong) {
|
|
3804
|
+
const updated = [...prev.longTokens];
|
|
3805
|
+
updated[index] = {
|
|
3806
|
+
...updated[index],
|
|
3807
|
+
symbol: selectedToken,
|
|
3808
|
+
metadata: metadata || undefined
|
|
3809
|
+
};
|
|
3810
|
+
return { ...prev, longTokens: updated };
|
|
3811
|
+
}
|
|
3812
|
+
else {
|
|
3813
|
+
const updated = [...prev.shortTokens];
|
|
3814
|
+
updated[index] = {
|
|
3815
|
+
...updated[index],
|
|
3816
|
+
symbol: selectedToken,
|
|
3817
|
+
metadata: metadata || undefined
|
|
3818
|
+
};
|
|
3819
|
+
return { ...prev, shortTokens: updated };
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
});
|
|
3823
|
+
}, [tokenSelection.selectorConfig, tokenSelection.longTokens, tokenSelection.shortTokens, webData2, allMids, setTokenSelection]);
|
|
3824
|
+
// updateTokenMetadata is now handled automatically by the useEffect above
|
|
3825
|
+
return {
|
|
3826
|
+
// State
|
|
3827
|
+
longTokens: tokenSelection.longTokens,
|
|
3828
|
+
shortTokens: tokenSelection.shortTokens,
|
|
3829
|
+
openTokenSelector: tokenSelection.openTokenSelector,
|
|
3830
|
+
selectorConfig: tokenSelection.selectorConfig,
|
|
3831
|
+
openConflictModal: tokenSelection.openConflictModal,
|
|
3832
|
+
conflicts: tokenSelection.conflicts,
|
|
3833
|
+
// Loading states
|
|
3834
|
+
isLoading,
|
|
3835
|
+
isPriceDataReady,
|
|
3836
|
+
// Calculated values
|
|
3837
|
+
weightedRatio,
|
|
3838
|
+
weightedRatio24h,
|
|
3839
|
+
sumNetFunding,
|
|
3840
|
+
maxLeverage,
|
|
3841
|
+
minMargin,
|
|
3842
|
+
// Actions
|
|
3843
|
+
setLongTokens,
|
|
3844
|
+
setShortTokens,
|
|
3845
|
+
updateTokenWeight,
|
|
3846
|
+
addToken,
|
|
3847
|
+
removeToken,
|
|
3848
|
+
handleTokenSelect,
|
|
3849
|
+
setOpenTokenSelector,
|
|
3850
|
+
setSelectorConfig,
|
|
3851
|
+
setOpenConflictModal,
|
|
3852
|
+
setConflicts,
|
|
3853
|
+
resetToDefaults,
|
|
3854
|
+
};
|
|
3855
|
+
};
|
|
3856
|
+
|
|
3857
|
+
/**
|
|
3858
|
+
* Detects conflicts between selected tokens and existing positions
|
|
3859
|
+
*/
|
|
3860
|
+
class ConflictDetector {
|
|
3861
|
+
/**
|
|
3862
|
+
* Detects conflicts between token selections and open positions
|
|
3863
|
+
* @param longTokens - Selected long tokens
|
|
3864
|
+
* @param shortTokens - Selected short tokens
|
|
3865
|
+
* @param openPositions - Current open positions from API
|
|
3866
|
+
* @returns Array of detected conflicts
|
|
3867
|
+
*/
|
|
3868
|
+
static detectConflicts(longTokens, shortTokens, openPositions) {
|
|
3869
|
+
const detectedConflicts = [];
|
|
3870
|
+
if (!openPositions) {
|
|
3871
|
+
return detectedConflicts;
|
|
3872
|
+
}
|
|
3873
|
+
// Check long tokens against existing short positions
|
|
3874
|
+
longTokens.forEach((token) => {
|
|
3875
|
+
const existingShortPosition = openPositions.find((pos) => {
|
|
3876
|
+
var _a;
|
|
3877
|
+
// Check multiple possible property names and side values
|
|
3878
|
+
const symbol = pos.coin || pos.symbol || pos.asset;
|
|
3879
|
+
const side = (_a = pos.side) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
3880
|
+
return symbol === token.symbol && (side === 'short' || side === 'sell');
|
|
3881
|
+
});
|
|
3882
|
+
if (existingShortPosition) {
|
|
3883
|
+
detectedConflicts.push({
|
|
3884
|
+
symbol: token.symbol,
|
|
3885
|
+
conflictType: 'short',
|
|
3886
|
+
conflictMessage: `${token.symbol} Long conflicts with existing ${token.symbol} Short position`
|
|
3887
|
+
});
|
|
3888
|
+
}
|
|
3889
|
+
});
|
|
3890
|
+
// Check short tokens against existing long positions
|
|
3891
|
+
shortTokens.forEach((token) => {
|
|
3892
|
+
const existingLongPosition = openPositions.find((pos) => {
|
|
3893
|
+
var _a;
|
|
3894
|
+
// Check multiple possible property names and side values
|
|
3895
|
+
const symbol = pos.coin || pos.symbol || pos.asset;
|
|
3896
|
+
const side = (_a = pos.side) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
3897
|
+
return symbol === token.symbol && (side === 'long' || side === 'buy');
|
|
3898
|
+
});
|
|
3899
|
+
if (existingLongPosition) {
|
|
3900
|
+
detectedConflicts.push({
|
|
3901
|
+
symbol: token.symbol,
|
|
3902
|
+
conflictType: 'long',
|
|
3903
|
+
conflictMessage: `${token.symbol} Short conflicts with existing ${token.symbol} Long position`
|
|
3904
|
+
});
|
|
3905
|
+
}
|
|
3906
|
+
});
|
|
3907
|
+
return detectedConflicts;
|
|
3908
|
+
}
|
|
3909
|
+
}
|
|
3910
|
+
|
|
3442
3911
|
exports.AccountSummaryCalculator = AccountSummaryCalculator;
|
|
3912
|
+
exports.ConflictDetector = ConflictDetector;
|
|
3443
3913
|
exports.PearHyperliquidClient = PearHyperliquidClient;
|
|
3444
3914
|
exports.PearHyperliquidProvider = PearHyperliquidProvider;
|
|
3445
3915
|
exports.PearMigrationSDK = PearMigrationSDK;
|
|
3916
|
+
exports.TokenMetadataExtractor = TokenMetadataExtractor;
|
|
3446
3917
|
exports.default = PearHyperliquidClient;
|
|
3447
3918
|
exports.useAccountSummary = useAccountSummary;
|
|
3448
3919
|
exports.useAddress = useAddress;
|
|
@@ -3454,5 +3925,6 @@ exports.useMigrationSDK = useMigrationSDK;
|
|
|
3454
3925
|
exports.useOpenOrders = useOpenOrders;
|
|
3455
3926
|
exports.useOpenPositions = useOpenPositions;
|
|
3456
3927
|
exports.usePearHyperliquidClient = usePearHyperliquidClient;
|
|
3928
|
+
exports.useTokenSelection = useTokenSelection;
|
|
3457
3929
|
exports.useTradeHistories = useTradeHistories;
|
|
3458
3930
|
//# sourceMappingURL=index.js.map
|