diff --git a/src/apps/perps/hooks/useHyperliquid.ts b/src/apps/perps/hooks/useHyperliquid.ts
index 9793add8..0b9acabe 100644
--- a/src/apps/perps/hooks/useHyperliquid.ts
+++ b/src/apps/perps/hooks/useHyperliquid.ts
@@ -77,18 +77,23 @@ export function useHyperliquid() {
});
isImported = true;
} else {
- // 2. Fallback to Connected Wallet
- const walletProvider = kit.getEtherspotProvider();
- const eoa = (await walletProvider.getSdk()).getEOAAddress() || null;
- console.log('DEBUG: Wallet Provider EOA:', eoa);
- if (eoa && clientTransport) {
- targetAddress = eoa;
- client = createWalletClient({
- account: eoa as `0x${string}`,
- chain: arbitrum,
- transport: clientTransport,
- });
+ // 2. Fallback to Connected Wallet
+ try {
+ const walletProvider = kit.getEtherspotProvider();
+ const eoa = (await walletProvider.getSdk()).getEOAAddress() || null;
+ console.log('DEBUG: Wallet Provider EOA:', eoa);
+
+ if (eoa && clientTransport) {
+ targetAddress = eoa;
+ client = createWalletClient({
+ account: eoa as `0x${string}`,
+ chain: arbitrum,
+ transport: clientTransport,
+ });
+ }
+ } catch (err) {
+ console.warn('Failed to get Etherspot provider or EOA (expected in delegatedEoa mode without imported account):', err);
}
}
diff --git a/src/apps/pillarx-app/components/TokenMarketDataRow/tests/__snapshots__/LeftColumnTokenMarketDataRow.test.tsx.snap b/src/apps/pillarx-app/components/TokenMarketDataRow/tests/__snapshots__/LeftColumnTokenMarketDataRow.test.tsx.snap
index fab28c42..8bae6cfc 100644
--- a/src/apps/pillarx-app/components/TokenMarketDataRow/tests/__snapshots__/LeftColumnTokenMarketDataRow.test.tsx.snap
+++ b/src/apps/pillarx-app/components/TokenMarketDataRow/tests/__snapshots__/LeftColumnTokenMarketDataRow.test.tsx.snap
@@ -41,7 +41,7 @@ exports[` - ETH token row > renders and matches
- 9mo ago
+ 10mo ago
- ETH token row > renders and matches
- 9mo ago
+ 10mo ago
> renders and matches snapshot 1`] = `
- 9mo ago
+ 10mo ago
> renders and matches snapshot 1`] = `
- 9mo ago
+ 10mo ago
> renders and matches snapshot 1`] = `
- 9mo ago
+ 10mo ago
> renders and matches snapshot 1`] = `
- 9mo ago
+ 10mo ago
> renders and matches snapshot 1`] = `
- 9mo ago
+ 10mo ago
> renders and matches snapshot 1`] = `
- 9mo ago
+ 10mo ago
> renders and matches snapshot 1`] = `
- 9mo ago
+ 10mo ago
> renders and matches snapshot 1`] = `
- 9mo ago
+ 10mo ago
{
+ const { signals, loading } = useTradingSignals({ enabled: true });
+
+ const stats = useMemo(() => {
+ if (loading || signals.length === 0) return null;
+
+ // Helper to calculate PnL for a set of signals
+ const calculatePnL = (filterFn: (s: InsightSignal) => boolean) => {
+ return signals
+ .filter(filterFn)
+ .reduce((sum, s) => sum + (s.realized_pnl_percent || 0), 0);
+ };
+
+ const now = Date.now();
+ const oneMonthAgo = now - 30 * 24 * 60 * 60 * 1000;
+ const threeMonthsAgo = now - 90 * 24 * 60 * 60 * 1000;
+ const sixMonthsAgo = now - 180 * 24 * 60 * 60 * 1000;
+
+ // PnL metrics
+ const pnl1m = calculatePnL((s) => {
+ const closedAt = s.closed_at ? new Date(s.closed_at).getTime() : 0;
+ return closedAt > oneMonthAgo;
+ });
+
+ const pnl3m = calculatePnL((s) => {
+ const closedAt = s.closed_at ? new Date(s.closed_at).getTime() : 0;
+ return closedAt > threeMonthsAgo;
+ });
+
+ const pnl6m = calculatePnL((s) => {
+ const closedAt = s.closed_at ? new Date(s.closed_at).getTime() : 0;
+ return closedAt > sixMonthsAgo;
+ });
+
+ // PnL Status (Winning/Losing/Neutral)
+ const closedSignals = signals.filter(
+ (s) =>
+ s.status === 'closed' ||
+ s.status === 'completed' ||
+ s.status === 'stopped'
+ );
+ const totalClosed = closedSignals.length;
+
+ let winning = 0;
+ let losing = 0;
+ let neutral = 0;
+
+ if (totalClosed > 0) {
+ winning =
+ (closedSignals.filter((s) => (s.realized_pnl_percent || 0) > 0).length /
+ totalClosed) *
+ 100;
+ losing =
+ (closedSignals.filter((s) => (s.realized_pnl_percent || 0) < 0).length /
+ totalClosed) *
+ 100;
+ neutral =
+ (closedSignals.filter((s) => (s.realized_pnl_percent || 0) === 0)
+ .length /
+ totalClosed) *
+ 100;
+ }
+
+ // Cumulative PnL History Generation
+ const generateHistory = (cutoffTime: number) => {
+ // Sort signals by close time
+ const relevantSignals = signals
+ .filter(
+ (s) => s.closed_at && new Date(s.closed_at).getTime() > cutoffTime
+ )
+ .sort(
+ (a, b) =>
+ new Date(a.closed_at!).getTime() - new Date(b.closed_at!).getTime()
+ );
+
+ let runningPnL = 0;
+ const history = relevantSignals.map((s) => {
+ runningPnL += s.realized_pnl_percent || 0;
+ return {
+ timestamp: new Date(s.closed_at!).getTime() / 1000,
+ value: runningPnL,
+ };
+ });
+
+ // Ensure we have a starting point? Or just the trade history.
+ // If history is empty, return empty array
+ return history;
+ };
+
+ // For cumulative values in the object, we use the specific period totals calculated above
+ // but the history needs to be generated point-by-point.
+
+ return {
+ pnl1m: Number(pnl1m.toFixed(2)),
+ pnl3m: Number(pnl3m.toFixed(2)),
+ pnl6m: Number(pnl6m.toFixed(2)),
+ riskLevel: 'Low Risk', // Placeholder logic
+ pnlStatus: {
+ winning: Number(winning.toFixed(1)),
+ losing: Number(losing.toFixed(1)),
+ neutral: Number(neutral.toFixed(1)),
+ },
+ cumulativePnl: {
+ '1w': {
+ value: Number(
+ calculatePnL((s) =>
+ s.closed_at
+ ? new Date(s.closed_at).getTime() >
+ now - 7 * 24 * 60 * 60 * 1000
+ : false
+ ).toFixed(2)
+ ),
+ history: generateHistory(now - 7 * 24 * 60 * 60 * 1000),
+ },
+ '1m': {
+ value: Number(pnl1m.toFixed(2)),
+ history: generateHistory(oneMonthAgo),
+ },
+ '3m': {
+ value: Number(pnl3m.toFixed(2)),
+ history: generateHistory(threeMonthsAgo),
+ },
+ '6m': {
+ value: Number(pnl6m.toFixed(2)),
+ history: generateHistory(sixMonthsAgo),
+ },
+ },
+ };
+ }, [signals, loading]);
+
+ return { stats, loading };
+};