@0xmonaco/react 0.7.6 → 0.7.7
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/package.json +3 -3
- package/dist/hooks/index.d.ts +0 -15
- package/dist/hooks/index.js +0 -15
- package/dist/hooks/useAuth/index.d.ts +0 -2
- package/dist/hooks/useAuth/index.js +0 -1
- package/dist/hooks/useAuth/types.d.ts +0 -30
- package/dist/hooks/useAuth/types.js +0 -0
- package/dist/hooks/useAuth/useAuth.d.ts +0 -2
- package/dist/hooks/useAuth/useAuth.js +0 -145
- package/dist/hooks/useFees/index.d.ts +0 -2
- package/dist/hooks/useFees/index.js +0 -1
- package/dist/hooks/useFees/types.d.ts +0 -5
- package/dist/hooks/useFees/types.js +0 -0
- package/dist/hooks/useFees/useFees.d.ts +0 -2
- package/dist/hooks/useFees/useFees.js +0 -14
- package/dist/hooks/useMarket/index.d.ts +0 -2
- package/dist/hooks/useMarket/index.js +0 -1
- package/dist/hooks/useMarket/types.d.ts +0 -30
- package/dist/hooks/useMarket/types.js +0 -0
- package/dist/hooks/useMarket/useMarket.d.ts +0 -2
- package/dist/hooks/useMarket/useMarket.js +0 -92
- package/dist/hooks/useMonaco/index.d.ts +0 -2
- package/dist/hooks/useMonaco/index.js +0 -1
- package/dist/hooks/useMonaco/types.d.ts +0 -13
- package/dist/hooks/useMonaco/types.js +0 -0
- package/dist/hooks/useMonaco/useMonaco.d.ts +0 -2
- package/dist/hooks/useMonaco/useMonaco.js +0 -13
- package/dist/hooks/useOHLCV/index.d.ts +0 -2
- package/dist/hooks/useOHLCV/index.js +0 -2
- package/dist/hooks/useOHLCV/types.d.ts +0 -29
- package/dist/hooks/useOHLCV/types.js +0 -0
- package/dist/hooks/useOHLCV/useOHLCV.d.ts +0 -11
- package/dist/hooks/useOHLCV/useOHLCV.js +0 -76
- package/dist/hooks/useOrderbook/index.d.ts +0 -2
- package/dist/hooks/useOrderbook/index.js +0 -1
- package/dist/hooks/useOrderbook/types.d.ts +0 -27
- package/dist/hooks/useOrderbook/types.js +0 -0
- package/dist/hooks/useOrderbook/useOrderbook.d.ts +0 -3
- package/dist/hooks/useOrderbook/useOrderbook.js +0 -31
- package/dist/hooks/usePositions/index.d.ts +0 -2
- package/dist/hooks/usePositions/index.js +0 -1
- package/dist/hooks/usePositions/types.d.ts +0 -11
- package/dist/hooks/usePositions/types.js +0 -0
- package/dist/hooks/usePositions/usePositions.d.ts +0 -2
- package/dist/hooks/usePositions/usePositions.js +0 -65
- package/dist/hooks/useProfile/index.d.ts +0 -2
- package/dist/hooks/useProfile/index.js +0 -1
- package/dist/hooks/useProfile/types.d.ts +0 -23
- package/dist/hooks/useProfile/types.js +0 -0
- package/dist/hooks/useProfile/useProfile.d.ts +0 -2
- package/dist/hooks/useProfile/useProfile.js +0 -128
- package/dist/hooks/useTokenLifecycle/index.d.ts +0 -2
- package/dist/hooks/useTokenLifecycle/index.js +0 -1
- package/dist/hooks/useTokenLifecycle/types.d.ts +0 -23
- package/dist/hooks/useTokenLifecycle/types.js +0 -0
- package/dist/hooks/useTokenLifecycle/useTokenLifecycle.d.ts +0 -20
- package/dist/hooks/useTokenLifecycle/useTokenLifecycle.js +0 -125
- package/dist/hooks/useTokenLifecycle/utils.d.ts +0 -7
- package/dist/hooks/useTokenLifecycle/utils.js +0 -15
- package/dist/hooks/useTrade/index.d.ts +0 -2
- package/dist/hooks/useTrade/index.js +0 -1
- package/dist/hooks/useTrade/types.d.ts +0 -49
- package/dist/hooks/useTrade/types.js +0 -0
- package/dist/hooks/useTrade/useTrade.d.ts +0 -2
- package/dist/hooks/useTrade/useTrade.js +0 -132
- package/dist/hooks/useTradeFeed/index.d.ts +0 -2
- package/dist/hooks/useTradeFeed/index.js +0 -2
- package/dist/hooks/useTradeFeed/types.d.ts +0 -14
- package/dist/hooks/useTradeFeed/types.js +0 -0
- package/dist/hooks/useTradeFeed/useTradeFeed.d.ts +0 -12
- package/dist/hooks/useTradeFeed/useTradeFeed.js +0 -32
- package/dist/hooks/useUserBalances/index.d.ts +0 -2
- package/dist/hooks/useUserBalances/index.js +0 -2
- package/dist/hooks/useUserBalances/types.d.ts +0 -18
- package/dist/hooks/useUserBalances/types.js +0 -0
- package/dist/hooks/useUserBalances/useUserBalances.d.ts +0 -9
- package/dist/hooks/useUserBalances/useUserBalances.js +0 -171
- package/dist/hooks/useUserMovements/index.d.ts +0 -2
- package/dist/hooks/useUserMovements/index.js +0 -2
- package/dist/hooks/useUserMovements/types.d.ts +0 -23
- package/dist/hooks/useUserMovements/types.js +0 -0
- package/dist/hooks/useUserMovements/useUserMovements.d.ts +0 -18
- package/dist/hooks/useUserMovements/useUserMovements.js +0 -122
- package/dist/hooks/useUserOrders/index.d.ts +0 -2
- package/dist/hooks/useUserOrders/index.js +0 -2
- package/dist/hooks/useUserOrders/types.d.ts +0 -18
- package/dist/hooks/useUserOrders/types.js +0 -0
- package/dist/hooks/useUserOrders/useUserOrders.d.ts +0 -11
- package/dist/hooks/useUserOrders/useUserOrders.js +0 -191
- package/dist/hooks/useVault/index.d.ts +0 -2
- package/dist/hooks/useVault/index.js +0 -1
- package/dist/hooks/useVault/types.d.ts +0 -15
- package/dist/hooks/useVault/types.js +0 -0
- package/dist/hooks/useVault/useVault.d.ts +0 -2
- package/dist/hooks/useVault/useVault.js +0 -66
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/provider/MonacoProvider.d.ts +0 -3
- package/dist/provider/MonacoProvider.js +0 -142
- package/dist/provider/TradeFeedProvider.d.ts +0 -22
- package/dist/provider/TradeFeedProvider.js +0 -143
- package/dist/provider/index.d.ts +0 -3
- package/dist/provider/index.js +0 -3
- package/dist/provider/types.d.ts +0 -49
- package/dist/provider/types.js +0 -9
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/tokenStorage.d.ts +0 -38
- package/dist/utils/tokenStorage.js +0 -102
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { useCallback } from "react";
|
|
2
|
-
import { useMonacoSDK } from "../useMonaco";
|
|
3
|
-
export const useTrade = () => {
|
|
4
|
-
const { sdk } = useMonacoSDK();
|
|
5
|
-
const placeLimitOrder = useCallback(async (tradingPairId, side, quantity, price, options) => {
|
|
6
|
-
if (!sdk)
|
|
7
|
-
throw new Error("SDK not available");
|
|
8
|
-
if (!tradingPairId?.trim())
|
|
9
|
-
throw new Error("Trading pair ID is required and cannot be empty");
|
|
10
|
-
if (!side)
|
|
11
|
-
throw new Error("Order side is required");
|
|
12
|
-
if (!quantity?.trim())
|
|
13
|
-
throw new Error("Quantity is required and cannot be empty");
|
|
14
|
-
if (!price?.trim())
|
|
15
|
-
throw new Error("Price is required and cannot be empty");
|
|
16
|
-
if (Number(quantity) <= 0)
|
|
17
|
-
throw new Error("Quantity must be greater than 0");
|
|
18
|
-
if (Number(price) <= 0)
|
|
19
|
-
throw new Error("Price must be greater than 0");
|
|
20
|
-
return await sdk.trading.placeLimitOrder(tradingPairId, side, quantity, price, options);
|
|
21
|
-
}, [sdk]);
|
|
22
|
-
const placeMarketOrder = useCallback(async (tradingPairId, side, quantity, options) => {
|
|
23
|
-
if (!sdk)
|
|
24
|
-
throw new Error("SDK not available");
|
|
25
|
-
if (!tradingPairId?.trim())
|
|
26
|
-
throw new Error("Trading pair ID is required and cannot be empty");
|
|
27
|
-
if (!side)
|
|
28
|
-
throw new Error("Order side is required");
|
|
29
|
-
if (!quantity?.trim())
|
|
30
|
-
throw new Error("Quantity is required and cannot be empty");
|
|
31
|
-
if (Number(quantity) <= 0)
|
|
32
|
-
throw new Error("Quantity must be greater than 0");
|
|
33
|
-
return await sdk.trading.placeMarketOrder(tradingPairId, side, quantity, options);
|
|
34
|
-
}, [sdk]);
|
|
35
|
-
const cancelOrder = useCallback(async (orderId) => {
|
|
36
|
-
if (!sdk)
|
|
37
|
-
throw new Error("SDK not available");
|
|
38
|
-
if (!orderId?.trim())
|
|
39
|
-
throw new Error("Order ID is required and cannot be empty");
|
|
40
|
-
return await sdk.trading.cancelOrder(orderId);
|
|
41
|
-
}, [sdk]);
|
|
42
|
-
const createConditionalOrder = useCallback(async (params) => {
|
|
43
|
-
if (!sdk)
|
|
44
|
-
throw new Error("SDK not available");
|
|
45
|
-
return await sdk.trading.createConditionalOrder(params);
|
|
46
|
-
}, [sdk]);
|
|
47
|
-
const cancelConditionalOrder = useCallback(async (conditionalOrderId) => {
|
|
48
|
-
if (!sdk)
|
|
49
|
-
throw new Error("SDK not available");
|
|
50
|
-
if (!conditionalOrderId?.trim())
|
|
51
|
-
throw new Error("Conditional order ID is required and cannot be empty");
|
|
52
|
-
return await sdk.trading.cancelConditionalOrder(conditionalOrderId);
|
|
53
|
-
}, [sdk]);
|
|
54
|
-
const listConditionalOrders = useCallback(async (params) => {
|
|
55
|
-
if (!sdk)
|
|
56
|
-
throw new Error("SDK not available");
|
|
57
|
-
return await sdk.trading.listConditionalOrders(params);
|
|
58
|
-
}, [sdk]);
|
|
59
|
-
const batchCancel = useCallback(async (orderIds) => {
|
|
60
|
-
if (!sdk)
|
|
61
|
-
throw new Error("SDK not available");
|
|
62
|
-
return await sdk.trading.batchCancel(orderIds);
|
|
63
|
-
}, [sdk]);
|
|
64
|
-
const batchCancelAll = useCallback(async (tradingPairId) => {
|
|
65
|
-
if (!sdk)
|
|
66
|
-
throw new Error("SDK not available");
|
|
67
|
-
return await sdk.trading.batchCancelAll(tradingPairId);
|
|
68
|
-
}, [sdk]);
|
|
69
|
-
const replaceOrder = useCallback(async (orderId, newOrder) => {
|
|
70
|
-
if (!sdk)
|
|
71
|
-
throw new Error("SDK not available");
|
|
72
|
-
if (!orderId?.trim())
|
|
73
|
-
throw new Error("Order ID is required and cannot be empty");
|
|
74
|
-
if (!newOrder)
|
|
75
|
-
throw new Error("New order object is required");
|
|
76
|
-
// Validate quantity only if provided
|
|
77
|
-
if (newOrder.quantity !== undefined) {
|
|
78
|
-
if (!newOrder.quantity?.trim())
|
|
79
|
-
throw new Error("Quantity cannot be empty");
|
|
80
|
-
if (Number(newOrder.quantity) <= 0)
|
|
81
|
-
throw new Error("Quantity must be greater than 0");
|
|
82
|
-
}
|
|
83
|
-
// Validate price only if provided
|
|
84
|
-
if (newOrder.price !== undefined) {
|
|
85
|
-
if (!newOrder.price?.trim())
|
|
86
|
-
throw new Error("Price cannot be empty");
|
|
87
|
-
if (Number(newOrder.price) <= 0)
|
|
88
|
-
throw new Error("Price must be a valid positive number");
|
|
89
|
-
}
|
|
90
|
-
return await sdk.trading.replaceOrder(orderId, newOrder);
|
|
91
|
-
}, [sdk]);
|
|
92
|
-
const batchCreate = useCallback(async (orders) => {
|
|
93
|
-
if (!sdk)
|
|
94
|
-
throw new Error("SDK not available");
|
|
95
|
-
return await sdk.trading.batchCreate(orders);
|
|
96
|
-
}, [sdk]);
|
|
97
|
-
const batchReplace = useCallback(async (orders) => {
|
|
98
|
-
if (!sdk)
|
|
99
|
-
throw new Error("SDK not available");
|
|
100
|
-
return await sdk.trading.batchReplace(orders);
|
|
101
|
-
}, [sdk]);
|
|
102
|
-
const getPaginatedOrders = useCallback(async (params) => {
|
|
103
|
-
if (!sdk)
|
|
104
|
-
throw new Error("SDK not available");
|
|
105
|
-
return await sdk.trading.getPaginatedOrders(params);
|
|
106
|
-
}, [sdk]);
|
|
107
|
-
const getOrder = useCallback(async (orderId) => {
|
|
108
|
-
if (!sdk)
|
|
109
|
-
throw new Error("SDK not available");
|
|
110
|
-
if (!orderId?.trim())
|
|
111
|
-
throw new Error("Order ID is required and cannot be empty");
|
|
112
|
-
return await sdk.trading.getOrder(orderId);
|
|
113
|
-
}, [sdk]);
|
|
114
|
-
return {
|
|
115
|
-
// Order placement
|
|
116
|
-
placeLimitOrder,
|
|
117
|
-
placeMarketOrder,
|
|
118
|
-
// Order management
|
|
119
|
-
cancelOrder,
|
|
120
|
-
createConditionalOrder,
|
|
121
|
-
cancelConditionalOrder,
|
|
122
|
-
listConditionalOrders,
|
|
123
|
-
batchCancel,
|
|
124
|
-
batchCancelAll,
|
|
125
|
-
replaceOrder,
|
|
126
|
-
batchCreate,
|
|
127
|
-
batchReplace,
|
|
128
|
-
// Order queries
|
|
129
|
-
getPaginatedOrders,
|
|
130
|
-
getOrder,
|
|
131
|
-
};
|
|
132
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { TradeEvent } from "@0xmonaco/types";
|
|
2
|
-
/**
|
|
3
|
-
* Return type for the useTradeFeed hook
|
|
4
|
-
*/
|
|
5
|
-
export interface UseTradeFeedReturn {
|
|
6
|
-
/** Array of trade events from WebSocket and REST API */
|
|
7
|
-
trades: TradeEvent[];
|
|
8
|
-
/** Whether currently subscribed to a market. Will be false if the SDK is not yet initialized. */
|
|
9
|
-
subscribed: boolean;
|
|
10
|
-
/** Whether the initial trades are being fetched */
|
|
11
|
-
fetchingInitialState: boolean;
|
|
12
|
-
/** Any error that occurred during connection or subscription */
|
|
13
|
-
error: Error | null;
|
|
14
|
-
}
|
|
File without changes
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { UseTradeFeedReturn } from "./types";
|
|
2
|
-
/**
|
|
3
|
-
* Hook for subscribing to real-time trade events via WebSocket (public)
|
|
4
|
-
*
|
|
5
|
-
* Subscriptions are shared at the provider level - multiple components using the same
|
|
6
|
-
* tradingPairId will share both the WebSocket connection and the trade state.
|
|
7
|
-
* Initial trades are fetched only once when the first component subscribes.
|
|
8
|
-
* The last 50 trades are kept in state (this limit is fixed and not configurable).
|
|
9
|
-
*
|
|
10
|
-
* @param tradingPairId - The trading pair UUID to subscribe to
|
|
11
|
-
*/
|
|
12
|
-
export declare function useTradeFeed(tradingPairId: string): UseTradeFeedReturn;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { MAX_TRADES, useTradeFeedContext } from "../../provider";
|
|
3
|
-
import { useMonacoSDK } from "../useMonaco";
|
|
4
|
-
/**
|
|
5
|
-
* Hook for subscribing to real-time trade events via WebSocket (public)
|
|
6
|
-
*
|
|
7
|
-
* Subscriptions are shared at the provider level - multiple components using the same
|
|
8
|
-
* tradingPairId will share both the WebSocket connection and the trade state.
|
|
9
|
-
* Initial trades are fetched only once when the first component subscribes.
|
|
10
|
-
* The last 50 trades are kept in state (this limit is fixed and not configurable).
|
|
11
|
-
*
|
|
12
|
-
* @param tradingPairId - The trading pair UUID to subscribe to
|
|
13
|
-
*/
|
|
14
|
-
export function useTradeFeed(tradingPairId) {
|
|
15
|
-
const { sdk } = useMonacoSDK();
|
|
16
|
-
const { subscribe, subscriptions } = useTradeFeedContext();
|
|
17
|
-
const subscription = subscriptions.get(tradingPairId);
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
if (!sdk?.ws || !sdk?.trades || !tradingPairId) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const fetchInitialTrades = () => sdk.trades.getTrades(tradingPairId, { page_size: MAX_TRADES });
|
|
23
|
-
const subscribeToWs = (handler) => sdk.ws.trades(tradingPairId, handler);
|
|
24
|
-
return subscribe(tradingPairId, fetchInitialTrades, subscribeToWs);
|
|
25
|
-
}, [sdk?.ws, sdk?.trades, tradingPairId, subscribe]);
|
|
26
|
-
return {
|
|
27
|
-
trades: subscription?.trades ?? [],
|
|
28
|
-
subscribed: subscription?.subscribed ?? false,
|
|
29
|
-
fetchingInitialState: subscription?.fetchingInitialState ?? false,
|
|
30
|
-
error: subscription?.error ?? null,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { AccountBalance } from "@0xmonaco/types";
|
|
2
|
-
/**
|
|
3
|
-
* Return type for the useUserBalances hook
|
|
4
|
-
*/
|
|
5
|
-
export interface UseUserBalancesReturn {
|
|
6
|
-
/** Array of user balances, updated in real-time via WebSocket */
|
|
7
|
-
balances: AccountBalance[];
|
|
8
|
-
/** Whether initial data is being loaded */
|
|
9
|
-
loading: boolean;
|
|
10
|
-
/** Whether currently subscribed to balances channel */
|
|
11
|
-
subscribed: boolean;
|
|
12
|
-
/** Any error that occurred during connection or subscription */
|
|
13
|
-
error: Error | null;
|
|
14
|
-
/** Clear the current error state */
|
|
15
|
-
clearError: () => void;
|
|
16
|
-
/** Manually refresh balances from REST API */
|
|
17
|
-
refresh: () => Promise<void>;
|
|
18
|
-
}
|
|
File without changes
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { UseUserBalancesReturn } from "./types";
|
|
2
|
-
/**
|
|
3
|
-
* Hook for subscribing to real-time user balance updates via WebSocket (authenticated)
|
|
4
|
-
*
|
|
5
|
-
* Fetches initial balances from the REST API, then subscribes to real-time updates.
|
|
6
|
-
* Requires authentication - the user must be logged in with a valid JWT token.
|
|
7
|
-
* User is identified on the backend via the JWT token.
|
|
8
|
-
*/
|
|
9
|
-
export declare function useUserBalances(): UseUserBalancesReturn;
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from "react";
|
|
2
|
-
import { useMonacoSDK } from "../useMonaco";
|
|
3
|
-
/**
|
|
4
|
-
* Update an AccountBalance with data from a WebSocket balance event
|
|
5
|
-
*/
|
|
6
|
-
function updateBalanceFromEvent(balance, event) {
|
|
7
|
-
const totalBalance = totalBalanceFromEvent(balance, event);
|
|
8
|
-
return {
|
|
9
|
-
...balance,
|
|
10
|
-
available_balance: event.data.available,
|
|
11
|
-
available_balance_raw: event.data.availableRaw,
|
|
12
|
-
locked_balance: event.data.locked,
|
|
13
|
-
locked_balance_raw: event.data.lockedRaw,
|
|
14
|
-
total_balance: totalBalance,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
function parseDecimal(value) {
|
|
18
|
-
const match = value.trim().match(/^(-?)(\d+)(?:\.(\d+))?$/);
|
|
19
|
-
if (!match)
|
|
20
|
-
return null;
|
|
21
|
-
const [, sign, whole, fractional = ""] = match;
|
|
22
|
-
const digits = `${whole}${fractional}`.replace(/^0+(?=\d)/, "");
|
|
23
|
-
const parsed = BigInt(digits || "0");
|
|
24
|
-
return {
|
|
25
|
-
value: sign === "-" ? -parsed : parsed,
|
|
26
|
-
scale: fractional.length,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function pow10(exponent) {
|
|
30
|
-
return 10n ** BigInt(exponent);
|
|
31
|
-
}
|
|
32
|
-
function toScale(value, scale) {
|
|
33
|
-
return value.value * pow10(scale - value.scale);
|
|
34
|
-
}
|
|
35
|
-
function formatDecimal(value, scale) {
|
|
36
|
-
const sign = value < 0n ? "-" : "";
|
|
37
|
-
const absolute = value < 0n ? -value : value;
|
|
38
|
-
if (scale === 0)
|
|
39
|
-
return `${sign}${absolute.toString()}`;
|
|
40
|
-
const padded = absolute.toString().padStart(scale + 1, "0");
|
|
41
|
-
const whole = padded.slice(0, -scale);
|
|
42
|
-
const fractional = padded.slice(-scale).replace(/0+$/, "");
|
|
43
|
-
return fractional ? `${sign}${whole}.${fractional}` : `${sign}${whole}`;
|
|
44
|
-
}
|
|
45
|
-
function decimalSum(...values) {
|
|
46
|
-
const parsed = values.map(parseDecimal);
|
|
47
|
-
if (parsed.some((value) => value === null))
|
|
48
|
-
return null;
|
|
49
|
-
const decimals = parsed;
|
|
50
|
-
const scale = Math.max(...decimals.map((value) => value.scale));
|
|
51
|
-
const sum = decimals.reduce((total, value) => total + toScale(value, scale), 0n);
|
|
52
|
-
return formatDecimal(sum, scale);
|
|
53
|
-
}
|
|
54
|
-
function decimalDifference(left, ...right) {
|
|
55
|
-
return decimalSum(left, ...right.map((value) => (value.startsWith("-") ? value.slice(1) : `-${value}`)));
|
|
56
|
-
}
|
|
57
|
-
function decimalGreaterThanZero(value) {
|
|
58
|
-
const parsed = parseDecimal(value);
|
|
59
|
-
return parsed ? parsed.value > 0n : false;
|
|
60
|
-
}
|
|
61
|
-
function totalBalanceFromEvent(balance, event) {
|
|
62
|
-
if (event.data.reason === "margin_transfer_in" || event.data.reason === "margin_transfer_out") {
|
|
63
|
-
return event.data.total;
|
|
64
|
-
}
|
|
65
|
-
const eventExtraTotal = decimalDifference(event.data.total, event.data.available, event.data.locked);
|
|
66
|
-
if (eventExtraTotal && decimalGreaterThanZero(eventExtraTotal)) {
|
|
67
|
-
return event.data.total;
|
|
68
|
-
}
|
|
69
|
-
const previousMarginTotal = decimalDifference(balance.total_balance, balance.available_balance, balance.locked_balance);
|
|
70
|
-
if (!previousMarginTotal || !decimalGreaterThanZero(previousMarginTotal)) {
|
|
71
|
-
return event.data.total;
|
|
72
|
-
}
|
|
73
|
-
return decimalSum(event.data.total, previousMarginTotal) ?? event.data.total;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Hook for subscribing to real-time user balance updates via WebSocket (authenticated)
|
|
77
|
-
*
|
|
78
|
-
* Fetches initial balances from the REST API, then subscribes to real-time updates.
|
|
79
|
-
* Requires authentication - the user must be logged in with a valid JWT token.
|
|
80
|
-
* User is identified on the backend via the JWT token.
|
|
81
|
-
*/
|
|
82
|
-
export function useUserBalances() {
|
|
83
|
-
const { sdk } = useMonacoSDK();
|
|
84
|
-
const [balances, setBalances] = useState([]);
|
|
85
|
-
const [loading, setLoading] = useState(false);
|
|
86
|
-
const [error, setError] = useState(null);
|
|
87
|
-
const [subscribed, setSubscribed] = useState(false);
|
|
88
|
-
const clearError = useCallback(() => setError(null), []);
|
|
89
|
-
const fetchBalances = useCallback(async () => {
|
|
90
|
-
if (!sdk?.profile)
|
|
91
|
-
return;
|
|
92
|
-
setLoading(true);
|
|
93
|
-
try {
|
|
94
|
-
const response = await sdk.profile.getUserBalances();
|
|
95
|
-
setBalances(response.balances);
|
|
96
|
-
}
|
|
97
|
-
catch (err) {
|
|
98
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
99
|
-
}
|
|
100
|
-
finally {
|
|
101
|
-
setLoading(false);
|
|
102
|
-
}
|
|
103
|
-
}, [sdk?.profile]);
|
|
104
|
-
const refresh = useCallback(async () => {
|
|
105
|
-
await fetchBalances();
|
|
106
|
-
}, [fetchBalances]);
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
if (!sdk?.ws || !sdk?.profile) {
|
|
109
|
-
setSubscribed(false);
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
setBalances([]);
|
|
113
|
-
setError(null);
|
|
114
|
-
setLoading(true);
|
|
115
|
-
// Fetch initial balances via REST API, then subscribe to WebSocket updates
|
|
116
|
-
let unsubscribe;
|
|
117
|
-
let cancelled = false;
|
|
118
|
-
fetchBalances()
|
|
119
|
-
.then(() => {
|
|
120
|
-
// Bail out if effect was cleaned up before fetch resolved
|
|
121
|
-
if (cancelled)
|
|
122
|
-
return;
|
|
123
|
-
// Subscribe to WebSocket balance updates after initial data is loaded
|
|
124
|
-
try {
|
|
125
|
-
unsubscribe = sdk.ws.balances((event) => {
|
|
126
|
-
let needsRefresh = false;
|
|
127
|
-
setBalances((prev) => {
|
|
128
|
-
// Find by token address and update (case-insensitive for addresses)
|
|
129
|
-
const existingIndex = prev.findIndex((b) => b.token.toLowerCase() === event.data.tokenAddress.toLowerCase());
|
|
130
|
-
const existingBalance = prev[existingIndex];
|
|
131
|
-
if (existingIndex >= 0 && existingBalance) {
|
|
132
|
-
// Update existing balance
|
|
133
|
-
const updatedBalance = updateBalanceFromEvent(existingBalance, event);
|
|
134
|
-
const newBalances = [...prev];
|
|
135
|
-
newBalances[existingIndex] = updatedBalance;
|
|
136
|
-
return newBalances;
|
|
137
|
-
}
|
|
138
|
-
// New token - flag for refresh outside the updater
|
|
139
|
-
needsRefresh = true;
|
|
140
|
-
return prev;
|
|
141
|
-
});
|
|
142
|
-
// Refresh outside the state updater to keep it pure
|
|
143
|
-
if (needsRefresh && !cancelled) {
|
|
144
|
-
fetchBalances().catch((err) => {
|
|
145
|
-
if (!cancelled) {
|
|
146
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
setSubscribed(true);
|
|
152
|
-
}
|
|
153
|
-
catch (err) {
|
|
154
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
155
|
-
setSubscribed(false);
|
|
156
|
-
}
|
|
157
|
-
})
|
|
158
|
-
.catch((err) => {
|
|
159
|
-
if (cancelled)
|
|
160
|
-
return;
|
|
161
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
162
|
-
setLoading(false);
|
|
163
|
-
});
|
|
164
|
-
return () => {
|
|
165
|
-
cancelled = true;
|
|
166
|
-
unsubscribe?.();
|
|
167
|
-
setSubscribed(false);
|
|
168
|
-
};
|
|
169
|
-
}, [sdk?.ws, sdk?.profile, fetchBalances]);
|
|
170
|
-
return { balances, loading, subscribed, error, clearError, refresh };
|
|
171
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { GetUserMovementsParams, UserMovementEvent } from "@0xmonaco/types";
|
|
2
|
-
/**
|
|
3
|
-
* Options for the useUserMovements hook
|
|
4
|
-
*/
|
|
5
|
-
export interface UseUserMovementsOptions extends Omit<GetUserMovementsParams, "page"> {
|
|
6
|
-
/** Maximum number of movements to keep in state (default: 50) */
|
|
7
|
-
maxMovements?: number;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Return type for the useUserMovements hook
|
|
11
|
-
*/
|
|
12
|
-
export interface UseUserMovementsReturn {
|
|
13
|
-
/** Array of user movement events from WebSocket */
|
|
14
|
-
movements: UserMovementEvent[];
|
|
15
|
-
/** Whether initial data is being loaded */
|
|
16
|
-
loading: boolean;
|
|
17
|
-
/** Whether currently subscribed to movements channel */
|
|
18
|
-
subscribed: boolean;
|
|
19
|
-
/** Any error that occurred during connection or subscription */
|
|
20
|
-
error: Error | null;
|
|
21
|
-
/** Clear the current error state */
|
|
22
|
-
clearError: () => void;
|
|
23
|
-
}
|
|
File without changes
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { UseUserMovementsOptions, UseUserMovementsReturn } from "./types";
|
|
2
|
-
/**
|
|
3
|
-
* Hook for subscribing to real-time user movement events via WebSocket (authenticated)
|
|
4
|
-
*
|
|
5
|
-
* Fetches initial movements from the REST API, then subscribes to real-time updates.
|
|
6
|
-
* Requires authentication - the user must be logged in with a valid JWT token.
|
|
7
|
-
* User is identified on the backend via the JWT token.
|
|
8
|
-
*
|
|
9
|
-
* Re-fetches movements whenever filter options change.
|
|
10
|
-
*
|
|
11
|
-
* @param options - Optional filter and pagination options
|
|
12
|
-
* @param options.maxMovements - Maximum number of movements to keep in state (default: 50)
|
|
13
|
-
* @param options.page_size - Number of items per page for the API call (default: maxMovements)
|
|
14
|
-
* @param options.entry_type - Filter by entry type (CREDIT, DEBIT, LOCK, UNLOCK, FEE)
|
|
15
|
-
* @param options.transaction_type - Filter by transaction type (DEPOSIT, WITHDRAWAL, TRADE, etc.)
|
|
16
|
-
* @param options.asset_id - Filter by asset ID (UUID)
|
|
17
|
-
*/
|
|
18
|
-
export declare function useUserMovements(options?: UseUserMovementsOptions): UseUserMovementsReturn;
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from "react";
|
|
2
|
-
import { useMonacoContext } from "../../provider";
|
|
3
|
-
import { useMonacoSDK } from "../useMonaco";
|
|
4
|
-
/**
|
|
5
|
-
* Convert a LedgerMovement from the REST API to a UserMovementEvent format
|
|
6
|
-
*/
|
|
7
|
-
function ledgerMovementToEvent(movement, userId) {
|
|
8
|
-
return {
|
|
9
|
-
eventType: "movement",
|
|
10
|
-
userId,
|
|
11
|
-
data: {
|
|
12
|
-
id: movement.id,
|
|
13
|
-
entryType: movement.entry_type,
|
|
14
|
-
transactionType: movement.transaction_type,
|
|
15
|
-
tokenAddress: movement.token,
|
|
16
|
-
symbol: movement.symbol ?? undefined,
|
|
17
|
-
decimals: movement.decimals,
|
|
18
|
-
amount: movement.amount,
|
|
19
|
-
amountRaw: movement.amount_raw,
|
|
20
|
-
balanceBefore: movement.balance_before ?? undefined,
|
|
21
|
-
balanceBeforeRaw: movement.balance_before_raw ?? undefined,
|
|
22
|
-
balanceAfter: movement.balance_after ?? undefined,
|
|
23
|
-
balanceAfterRaw: movement.balance_after_raw ?? undefined,
|
|
24
|
-
lockedBefore: movement.locked_before ?? undefined,
|
|
25
|
-
lockedBeforeRaw: movement.locked_before_raw ?? undefined,
|
|
26
|
-
lockedAfter: movement.locked_after ?? undefined,
|
|
27
|
-
lockedAfterRaw: movement.locked_after_raw ?? undefined,
|
|
28
|
-
referenceId: movement.reference_id ?? undefined,
|
|
29
|
-
referenceType: movement.reference_type ?? undefined,
|
|
30
|
-
description: movement.description ?? undefined,
|
|
31
|
-
txHash: movement.tx_hash ?? undefined,
|
|
32
|
-
createdAt: movement.created_at ?? undefined,
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Hook for subscribing to real-time user movement events via WebSocket (authenticated)
|
|
38
|
-
*
|
|
39
|
-
* Fetches initial movements from the REST API, then subscribes to real-time updates.
|
|
40
|
-
* Requires authentication - the user must be logged in with a valid JWT token.
|
|
41
|
-
* User is identified on the backend via the JWT token.
|
|
42
|
-
*
|
|
43
|
-
* Re-fetches movements whenever filter options change.
|
|
44
|
-
*
|
|
45
|
-
* @param options - Optional filter and pagination options
|
|
46
|
-
* @param options.maxMovements - Maximum number of movements to keep in state (default: 50)
|
|
47
|
-
* @param options.page_size - Number of items per page for the API call (default: maxMovements)
|
|
48
|
-
* @param options.entry_type - Filter by entry type (CREDIT, DEBIT, LOCK, UNLOCK, FEE)
|
|
49
|
-
* @param options.transaction_type - Filter by transaction type (DEPOSIT, WITHDRAWAL, TRADE, etc.)
|
|
50
|
-
* @param options.asset_id - Filter by asset ID (UUID)
|
|
51
|
-
*/
|
|
52
|
-
export function useUserMovements(options = {}) {
|
|
53
|
-
const { sdk } = useMonacoSDK();
|
|
54
|
-
const { authenticationStatus } = useMonacoContext();
|
|
55
|
-
const { maxMovements = 50, page_size, entry_type, transaction_type, asset_id } = options;
|
|
56
|
-
const [movements, setMovements] = useState([]);
|
|
57
|
-
const [loading, setLoading] = useState(false);
|
|
58
|
-
const [error, setError] = useState(null);
|
|
59
|
-
const [subscribed, setSubscribed] = useState(false);
|
|
60
|
-
const clearError = useCallback(() => setError(null), []);
|
|
61
|
-
const sliceSize = Number.isFinite(maxMovements) && maxMovements > 0 ? maxMovements : 50;
|
|
62
|
-
const requestLimit = page_size ?? Math.min(Math.max(Math.round(sliceSize), 1), 100);
|
|
63
|
-
// Derive userId reactively — authenticationStatus changes on login/logout, triggering a re-render
|
|
64
|
-
const userId = authenticationStatus === "authenticated" ? sdk?.getAuthState()?.user.id : undefined;
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
if (!sdk?.ws || !sdk?.profile || !userId) {
|
|
67
|
-
setSubscribed(false);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
setMovements([]);
|
|
71
|
-
setError(null);
|
|
72
|
-
setLoading(true);
|
|
73
|
-
// Fetch initial movements via REST API, then subscribe to WebSocket updates
|
|
74
|
-
let unsubscribe;
|
|
75
|
-
sdk.profile
|
|
76
|
-
.getPaginatedUserMovements({ page_size: requestLimit, entry_type, transaction_type, asset_id })
|
|
77
|
-
.then(async (response) => {
|
|
78
|
-
// Combine latest_movements (from Redis) with movements (from PostgreSQL)
|
|
79
|
-
// latest_movements contains real-time data that may not yet be in PostgreSQL
|
|
80
|
-
// Deduplicate by id, preferring latest_movements (newer data)
|
|
81
|
-
const latestMovements = (response.latest_movements || []).map((m) => ledgerMovementToEvent(m, userId));
|
|
82
|
-
const historicalMovements = response.movements.map((m) => ledgerMovementToEvent(m, userId));
|
|
83
|
-
// Merge: latest_movements first, then historical, deduplicated by id
|
|
84
|
-
const seenIds = new Set();
|
|
85
|
-
const mergedMovements = [];
|
|
86
|
-
for (const movement of [...latestMovements, ...historicalMovements]) {
|
|
87
|
-
if (!seenIds.has(movement.data.id)) {
|
|
88
|
-
seenIds.add(movement.data.id);
|
|
89
|
-
mergedMovements.push(movement);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
setMovements(mergedMovements.slice(0, sliceSize));
|
|
93
|
-
// Subscribe to WebSocket movement updates after initial data is loaded
|
|
94
|
-
// This prevents race conditions where WS events could be overwritten by REST response
|
|
95
|
-
try {
|
|
96
|
-
unsubscribe = sdk.ws.movements((event) => {
|
|
97
|
-
setMovements((prev) => {
|
|
98
|
-
// Deduplicate by id and keep newest first
|
|
99
|
-
const exists = prev.some((movement) => movement.data.id === event.data.id);
|
|
100
|
-
if (exists) {
|
|
101
|
-
// Update existing movement
|
|
102
|
-
return prev.map((movement) => (movement.data.id === event.data.id ? event : movement));
|
|
103
|
-
}
|
|
104
|
-
return [event, ...prev].slice(0, sliceSize);
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
setSubscribed(true);
|
|
108
|
-
}
|
|
109
|
-
catch (err) {
|
|
110
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
111
|
-
setSubscribed(false);
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
.catch((err) => setError(err instanceof Error ? err : new Error(String(err))))
|
|
115
|
-
.finally(() => setLoading(false));
|
|
116
|
-
return () => {
|
|
117
|
-
unsubscribe?.();
|
|
118
|
-
setSubscribed(false);
|
|
119
|
-
};
|
|
120
|
-
}, [sdk?.ws, sdk?.profile, userId, sliceSize, requestLimit, entry_type, transaction_type, asset_id]);
|
|
121
|
-
return { movements, loading, subscribed, error, clearError };
|
|
122
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { Order } from "@0xmonaco/types";
|
|
2
|
-
/**
|
|
3
|
-
* Return type for the useUserOrders hook
|
|
4
|
-
*/
|
|
5
|
-
export interface UseUserOrdersReturn {
|
|
6
|
-
/** Array of user orders (merged from REST API and WebSocket updates) */
|
|
7
|
-
orders: Order[];
|
|
8
|
-
/** Whether initial data is being loaded */
|
|
9
|
-
loading: boolean;
|
|
10
|
-
/** Whether currently subscribed to orders channel */
|
|
11
|
-
subscribed: boolean;
|
|
12
|
-
/** Any error that occurred during connection or subscription */
|
|
13
|
-
error: Error | null;
|
|
14
|
-
/** Clear the current error state */
|
|
15
|
-
clearError: () => void;
|
|
16
|
-
/** Manually refresh orders from REST API */
|
|
17
|
-
refresh: () => Promise<void>;
|
|
18
|
-
}
|
|
File without changes
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { UseUserOrdersReturn } from "./types";
|
|
2
|
-
/**
|
|
3
|
-
* Hook for subscribing to real-time user order events via WebSocket (authenticated)
|
|
4
|
-
*
|
|
5
|
-
* Fetches initial orders from the REST API, then subscribes to real-time updates.
|
|
6
|
-
* Requires authentication - the user must be logged in with a valid JWT token.
|
|
7
|
-
* User is identified on the backend via the JWT token.
|
|
8
|
-
*
|
|
9
|
-
* @param maxOrders - Maximum number of orders to keep in state (default: 50)
|
|
10
|
-
*/
|
|
11
|
-
export declare function useUserOrders(maxOrders?: number): UseUserOrdersReturn;
|