@0xmonaco/react 0.8.5 → 0.8.7-develop.0f12336

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/README.md CHANGED
@@ -47,7 +47,7 @@ function App() {
47
47
  return (
48
48
  <WagmiProvider config={wagmiConfig}>
49
49
  <MonacoProvider
50
- network="development"
50
+ network="staging"
51
51
  seiRpcUrl="https://evm-rpc-testnet.sei-apis.com"
52
52
  >
53
53
  <YourApp />
@@ -372,4 +372,3 @@ For support, please:
372
372
  - Join our [Discord community](https://discord.gg/monaco)
373
373
  - Visit our [documentation site](https://docs.monaco.xyz)
374
374
  - Check our [API documentation](https://docs.0xmonaco.com)
375
-
@@ -0,0 +1,93 @@
1
+ /** operationId → the @0xmonaco/react hook that covers it. */
2
+ export declare const COVERED: {
3
+ add_position_margin: string;
4
+ attach_position_tp_sl: string;
5
+ batch_cancel_all: string;
6
+ batch_cancel_all_by_pair: string;
7
+ batch_cancel_orders: string;
8
+ batch_create_orders: string;
9
+ batch_replace_orders: string;
10
+ cancel_conditional_order: string;
11
+ cancel_order: string;
12
+ close_position: string;
13
+ batch_close_all_positions: string;
14
+ create_challenge: string;
15
+ create_order: string;
16
+ get_candles: string;
17
+ get_funding_state: string;
18
+ get_index_price: string;
19
+ get_mark_price: string;
20
+ get_market_metadata: string;
21
+ get_open_interest: string;
22
+ get_order_by_id: string;
23
+ get_orderbook_snapshot: string;
24
+ get_orders: string;
25
+ get_perp_market_config: string;
26
+ get_perp_market_summary: string;
27
+ get_position: string;
28
+ get_position_risk: string;
29
+ get_trades: string;
30
+ get_user_balance_by_asset: string;
31
+ get_user_balances: string;
32
+ get_user_movements: string;
33
+ get_user_profile: string;
34
+ get_withdrawal: string;
35
+ initiate_withdrawal: string;
36
+ list_pending_withdrawals: string;
37
+ list_conditional_orders: string;
38
+ list_funding_history: string;
39
+ list_position_history: string;
40
+ list_positions: string;
41
+ list_trading_pairs: string;
42
+ reduce_position_margin: string;
43
+ refresh_session: string;
44
+ replace_order: string;
45
+ revoke_session: string;
46
+ simulate_fees: string;
47
+ };
48
+ /** operationId → reason it is intentionally not covered by @0xmonaco/react. */
49
+ export declare const INTENTIONALLY_EXCLUDED: {
50
+ authenticate_backend: string;
51
+ create_delegated_session: string;
52
+ create_sub_account_limit: string;
53
+ delete_sub_account_limit: string;
54
+ get_application_config: string;
55
+ get_application_stats: string;
56
+ get_available_collateral: string;
57
+ get_margin_account_movements: string;
58
+ get_margin_account_summary: string;
59
+ get_market_stats: string;
60
+ get_parent_margin_account_movements: string;
61
+ get_parent_margin_account_summary: string;
62
+ get_portfolio_chart: string;
63
+ get_portfolio_stats: string;
64
+ get_screener: string;
65
+ get_sub_account_limits: string;
66
+ get_trade_by_id: string;
67
+ get_trading_pair_by_id: string;
68
+ get_user_trades: string;
69
+ health_check: string;
70
+ list_application_balances: string;
71
+ list_application_movements: string;
72
+ list_application_orders: string;
73
+ list_application_users: string;
74
+ list_delegated_agent_owners: string;
75
+ list_delegated_agents: string;
76
+ list_funding_payments: string;
77
+ list_margin_accounts: string;
78
+ list_sub_accounts_with_balances: string;
79
+ mint_tokens: string;
80
+ revoke_delegated_agent: string;
81
+ simulate_risk_bucket_order_risk: string;
82
+ simulate_order_risk: string;
83
+ simulate_parent_margin_order_risk: string;
84
+ submit_whitelist: string;
85
+ transfer_collateral_from_parent_margin_account: string;
86
+ transfer_collateral_from_margin_account: string;
87
+ transfer_collateral_to_margin_account: string;
88
+ transfer_collateral_to_parent_margin_account: string;
89
+ transfer_collateral_to_risk_bucket: string;
90
+ update_sub_account_limit: string;
91
+ upsert_delegated_agent: string;
92
+ verify_signature: string;
93
+ };
@@ -0,0 +1,93 @@
1
+ /** operationId → the @0xmonaco/react hook that covers it. */
2
+ export const COVERED = {
3
+ add_position_margin: "usePositions",
4
+ attach_position_tp_sl: "usePositions",
5
+ batch_cancel_all: "useTrade",
6
+ batch_cancel_all_by_pair: "useTrade",
7
+ batch_cancel_orders: "useTrade",
8
+ batch_create_orders: "useTrade",
9
+ batch_replace_orders: "useTrade",
10
+ cancel_conditional_order: "useTrade",
11
+ cancel_order: "useTrade",
12
+ close_position: "usePositions",
13
+ batch_close_all_positions: "usePositions",
14
+ create_challenge: "useAuth",
15
+ create_order: "useTrade",
16
+ get_candles: "useMarket",
17
+ get_funding_state: "useMarket",
18
+ get_index_price: "useMarket",
19
+ get_mark_price: "useMarket",
20
+ get_market_metadata: "useMarket",
21
+ get_open_interest: "useMarket",
22
+ get_order_by_id: "useTrade",
23
+ get_orderbook_snapshot: "useOrderbook",
24
+ get_orders: "useTrade",
25
+ get_perp_market_config: "useMarket",
26
+ get_perp_market_summary: "useMarket",
27
+ get_position: "usePositions",
28
+ get_position_risk: "usePositions",
29
+ get_trades: "useTradeFeed",
30
+ get_user_balance_by_asset: "useProfile",
31
+ get_user_balances: "useUserBalances",
32
+ get_user_movements: "useUserMovements",
33
+ get_user_profile: "useProfile",
34
+ get_withdrawal: "useVault (retryWithdrawal)",
35
+ initiate_withdrawal: "useVault (withdraw)",
36
+ list_pending_withdrawals: "useVault (listPendingWithdrawals)",
37
+ list_conditional_orders: "useTrade",
38
+ list_funding_history: "useMarket",
39
+ list_position_history: "usePositions",
40
+ list_positions: "usePositions",
41
+ list_trading_pairs: "useMarket",
42
+ reduce_position_margin: "usePositions",
43
+ refresh_session: "useAuth",
44
+ replace_order: "useTrade",
45
+ revoke_session: "useAuth",
46
+ simulate_fees: "useFees",
47
+ };
48
+ /** operationId → reason it is intentionally not covered by @0xmonaco/react. */
49
+ export const INTENTIONALLY_EXCLUDED = {
50
+ authenticate_backend: "Backend auth is header-based via setServerKey()/the x-server-key header, not an endpoint method (MON-1486).",
51
+ create_delegated_session: "Delegated-agent management is an automation/agent surface, not a UI workflow; no React hook.",
52
+ create_sub_account_limit: "Sub-account administration; no React hook.",
53
+ delete_sub_account_limit: "Sub-account administration; no React hook.",
54
+ get_application_config: "Application/backend (server-key) admin endpoint; not a user-wallet React workflow.",
55
+ get_application_stats: "Application/backend (server-key) admin endpoint; not a user-wallet React workflow.",
56
+ get_available_collateral: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
57
+ get_margin_account_movements: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
58
+ get_margin_account_summary: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
59
+ get_market_stats: "Exchange-wide cumulative stats endpoint; available via the core client but no dedicated React hook yet.",
60
+ get_parent_margin_account_movements: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
61
+ get_parent_margin_account_summary: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
62
+ get_portfolio_chart: "Portfolio analytics endpoint; no React hook yet.",
63
+ get_portfolio_stats: "Portfolio analytics endpoint; no React hook yet.",
64
+ get_screener: "Market lookup available via the core client / list+symbol hooks; no dedicated React hook.",
65
+ get_sub_account_limits: "Sub-account administration; no React hook.",
66
+ get_trade_by_id: "Trade-history lookup with a core client method but no dedicated React hook yet.",
67
+ get_trading_pair_by_id: "Market lookup available via the core client / list+symbol hooks; no dedicated React hook.",
68
+ get_user_trades: "Trade-history lookup with a core client method but no dedicated React hook yet.",
69
+ health_check: "Infrastructure liveness probe (GET /health); not part of the data SDK surface.",
70
+ list_application_balances: "Application/backend (server-key) admin endpoint; not a user-wallet React workflow.",
71
+ list_application_movements: "Application/backend (server-key) admin endpoint; not a user-wallet React workflow.",
72
+ list_application_orders: "Application/backend (server-key) admin endpoint; not a user-wallet React workflow.",
73
+ list_application_users: "Application/backend (server-key) admin endpoint; not a user-wallet React workflow.",
74
+ list_delegated_agent_owners: "Delegated-agent management is an automation/agent surface, not a UI workflow; no React hook.",
75
+ list_delegated_agents: "Delegated-agent management is an automation/agent surface, not a UI workflow; no React hook.",
76
+ list_funding_payments: "Perps funding-payment history; no React hook yet.",
77
+ list_margin_accounts: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
78
+ list_sub_accounts_with_balances: "Sub-account administration; no React hook.",
79
+ mint_tokens: "Test-net faucet; no React hook (use the MCP/core faucet path).",
80
+ revoke_delegated_agent: "Delegated-agent management is an automation/agent surface, not a UI workflow; no React hook.",
81
+ simulate_risk_bucket_order_risk: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
82
+ simulate_order_risk: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
83
+ simulate_parent_margin_order_risk: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
84
+ submit_whitelist: "Whitelist submission; no React hook.",
85
+ transfer_collateral_from_parent_margin_account: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
86
+ transfer_collateral_from_margin_account: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
87
+ transfer_collateral_to_margin_account: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
88
+ transfer_collateral_to_parent_margin_account: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
89
+ transfer_collateral_to_risk_bucket: "Margin-account management/collateral/simulation endpoint; no React hook yet.",
90
+ update_sub_account_limit: "Sub-account administration; no React hook.",
91
+ upsert_delegated_agent: "Delegated-agent management is an automation/agent surface, not a UI workflow; no React hook.",
92
+ verify_signature: "Auth verification runs inside login()/authenticate(); useAuth does not expose verifySignature as its own hook method.",
93
+ };
@@ -1,4 +1,4 @@
1
- import type { AuthState, ChallengeResponse, TokenRefreshResponse } from "@0xmonaco/types";
1
+ import type { AuthState, ChallengeResponse, SessionRefreshResponse } from "@0xmonaco/types";
2
2
  import type { AuthenticationStatus } from "../../provider";
3
3
  export interface UseAuthState {
4
4
  /** Current authentication status */
@@ -6,25 +6,30 @@ export interface UseAuthState {
6
6
  }
7
7
  export interface UseAuthReturn extends UseAuthState {
8
8
  /**
9
- * Complete authentication flow. Returns AuthState with accessToken and refreshToken.
9
+ * Complete authentication flow. Generates a session keypair, has the wallet
10
+ * authorize it, and returns the AuthState (including the session keypair).
10
11
  * @param options - Optional configuration
11
12
  * @param options.connectWebSocket - Auto-connect all authenticated WebSocket channels after login (currently Orders) (default: false)
12
13
  */
13
14
  login: (options?: {
14
15
  connectWebSocket?: boolean;
15
16
  }) => Promise<AuthState>;
16
- /** Logout user and clear state. Revokes the refresh token on the server. */
17
+ /** Logout user and clear state. Revokes the session on the server. */
17
18
  logout: () => Promise<void>;
18
- /** Refresh authentication tokens using the stored refresh token. */
19
+ /** Refresh the current session, extending its expiry. */
19
20
  refreshAuth: () => Promise<AuthState>;
20
21
  /** Sign a challenge message with the connected wallet. */
21
22
  signChallenge: (message: string) => Promise<string>;
22
- /** Create authentication challenge for the given address. */
23
- createChallenge: (address: string) => Promise<ChallengeResponse>;
24
- /** Complete authentication with signature. Returns tokens. */
23
+ /**
24
+ * Create an authentication challenge for the given address, binding the
25
+ * provided session public key. Advanced/manual flow — most callers should
26
+ * use `login`/`authenticate`, which manage the keypair for you.
27
+ */
28
+ createChallenge: (address: string, sessionPublicKey: string) => Promise<ChallengeResponse>;
29
+ /** Complete authentication with signature. Returns the AuthState. */
25
30
  authenticate: () => Promise<AuthState>;
26
- /** Refresh access token. Pass the refreshToken from authState. */
27
- refreshToken: (refreshToken: string) => Promise<TokenRefreshResponse>;
28
- /** Revoke the current session's refresh token on the server. */
29
- revokeToken: () => Promise<void>;
31
+ /** Extend the current session's expiry (signed with the active session key). */
32
+ refreshSession: () => Promise<SessionRefreshResponse>;
33
+ /** Revoke the current session on the server. */
34
+ revokeSession: () => Promise<void>;
30
35
  }
@@ -65,14 +65,16 @@ export const useAuth = () => {
65
65
  throw new Error("Message is required and cannot be empty");
66
66
  return await sdk.auth.signChallenge(message);
67
67
  }, [sdk]);
68
- const createChallenge = useCallback(async (address) => {
68
+ const createChallenge = useCallback(async (address, sessionPublicKey) => {
69
69
  if (!sdk)
70
70
  throw new Error("SDK not available");
71
71
  if (!address?.trim())
72
72
  throw new Error("Address is required and cannot be empty");
73
+ if (!sessionPublicKey?.trim())
74
+ throw new Error("Session public key is required and cannot be empty");
73
75
  if (!clientId?.trim())
74
76
  throw new Error("Client ID is required and cannot be empty");
75
- return await sdk.auth.createChallenge(address, clientId);
77
+ return await sdk.auth.createChallenge(address, clientId, sessionPublicKey);
76
78
  }, [sdk, clientId]);
77
79
  const authenticate = useCallback(async () => {
78
80
  if (!sdk)
@@ -84,26 +86,19 @@ export const useAuth = () => {
84
86
  const result = await sdk.auth.authenticate(clientId);
85
87
  const authenticated = sdk.isAuthenticated();
86
88
  setAuthenticationStatus(authenticated ? AuthenticationStatus.AUTHENTICATED : AuthenticationStatus.UNAUTHENTICATED);
87
- return {
88
- accessToken: result.accessToken,
89
- refreshToken: result.refreshToken,
90
- expiresAt: result.expiresAt,
91
- user: result.user,
92
- };
89
+ return result;
93
90
  }
94
91
  catch (error) {
95
92
  setAuthenticationStatus(AuthenticationStatus.UNAUTHENTICATED);
96
93
  throw error;
97
94
  }
98
95
  }, [sdk, clientId, setAuthenticationStatus]);
99
- const refreshToken = useCallback(async (token) => {
96
+ const refreshSession = useCallback(async () => {
100
97
  if (!sdk)
101
98
  throw new Error("SDK not available");
102
- if (!token?.trim())
103
- throw new Error("Refresh token is required and cannot be empty");
104
99
  setAuthenticationStatus(AuthenticationStatus.AUTHENTICATING);
105
100
  try {
106
- const result = await sdk.auth.refreshToken(token);
101
+ const result = await sdk.auth.refreshSession();
107
102
  const authenticated = sdk.isAuthenticated();
108
103
  setAuthenticationStatus(authenticated ? AuthenticationStatus.AUTHENTICATED : AuthenticationStatus.UNAUTHENTICATED);
109
104
  return result;
@@ -113,12 +108,12 @@ export const useAuth = () => {
113
108
  throw error;
114
109
  }
115
110
  }, [sdk, setAuthenticationStatus]);
116
- const revokeToken = useCallback(async () => {
111
+ const revokeSession = useCallback(async () => {
117
112
  if (!sdk)
118
113
  throw new Error("SDK not available");
119
114
  setAuthenticationStatus(AuthenticationStatus.AUTHENTICATING);
120
115
  try {
121
- await sdk.auth.revokeToken();
116
+ await sdk.auth.revokeSession();
122
117
  const authenticated = sdk.isAuthenticated();
123
118
  setAuthenticationStatus(authenticated ? AuthenticationStatus.AUTHENTICATED : AuthenticationStatus.UNAUTHENTICATED);
124
119
  }
@@ -133,10 +128,10 @@ export const useAuth = () => {
133
128
  // Primary auth actions
134
129
  login,
135
130
  logout,
136
- // Token management
131
+ // Session management
137
132
  refreshAuth,
138
- refreshToken,
139
- revokeToken,
133
+ refreshSession,
134
+ revokeSession,
140
135
  // Low-level auth functions
141
136
  authenticate,
142
137
  signChallenge,
@@ -1,8 +1,9 @@
1
- import type { AddPositionMarginRequest, AttachPositionTpSlRequest, AttachPositionTpSlResponse, ClosePositionRequest, ClosePositionResponse, GetPositionResponse, ListPositionHistoryParams, ListPositionHistoryResponse, ListPositionsParams, ListPositionsResponse, PositionMarginResponse, PositionRisk, ReducePositionMarginRequest } from "@0xmonaco/types";
1
+ import type { AddPositionMarginRequest, AttachPositionTpSlRequest, AttachPositionTpSlResponse, BatchCloseAllRequest, BatchCloseAllResponse, ClosePositionRequest, ClosePositionResponse, GetPositionResponse, ListPositionHistoryParams, ListPositionHistoryResponse, ListPositionsParams, ListPositionsResponse, PositionMarginResponse, PositionRisk, ReducePositionMarginRequest } from "@0xmonaco/types";
2
2
  export interface UsePositionsReturn {
3
3
  listPositions: (params?: ListPositionsParams) => Promise<ListPositionsResponse>;
4
4
  getPosition: (positionId: string) => Promise<GetPositionResponse>;
5
5
  closePosition: (positionId: string, request: ClosePositionRequest) => Promise<ClosePositionResponse>;
6
+ batchCloseAllPositions: (request?: BatchCloseAllRequest) => Promise<BatchCloseAllResponse>;
6
7
  getPositionRisk: (positionId: string) => Promise<PositionRisk>;
7
8
  addPositionMargin: (positionId: string, request: AddPositionMarginRequest) => Promise<PositionMarginResponse>;
8
9
  reducePositionMargin: (positionId: string, request: ReducePositionMarginRequest) => Promise<PositionMarginResponse>;
@@ -23,6 +23,11 @@ export const usePositions = () => {
23
23
  requirePositionId(positionId);
24
24
  return await sdk.positions.closePosition(positionId, request);
25
25
  }, [sdk]);
26
+ const batchCloseAllPositions = useCallback(async (request) => {
27
+ if (!sdk)
28
+ throw new Error("SDK not available");
29
+ return await sdk.positions.batchCloseAllPositions(request);
30
+ }, [sdk]);
26
31
  const getPositionRisk = useCallback(async (positionId) => {
27
32
  if (!sdk)
28
33
  throw new Error("SDK not available");
@@ -56,6 +61,7 @@ export const usePositions = () => {
56
61
  listPositions,
57
62
  getPosition,
58
63
  closePosition,
64
+ batchCloseAllPositions,
59
65
  getPositionRisk,
60
66
  addPositionMargin,
61
67
  reducePositionMargin,
@@ -51,9 +51,9 @@ export const useProfile = () => {
51
51
  try {
52
52
  const [userProfileResult, balancesResult, movementsResult, ordersResult] = await Promise.allSettled([
53
53
  sdk.profile.getProfile(),
54
- sdk.profile.getUserBalances({ page_size: DEFAULT_PAGE_SIZE, page: 1 }),
55
- sdk.profile.getPaginatedUserMovements({ page: 1, page_size: DEFAULT_PAGE_SIZE }),
56
- sdk.trading.getPaginatedOrders({ page: 1, page_size: DEFAULT_PAGE_SIZE }),
54
+ sdk.profile.getUserBalances({ pageSize: DEFAULT_PAGE_SIZE, page: 1 }),
55
+ sdk.profile.getPaginatedUserMovements({ page: 1, pageSize: DEFAULT_PAGE_SIZE }),
56
+ sdk.trading.getPaginatedOrders({ page: 1, pageSize: DEFAULT_PAGE_SIZE }),
57
57
  ]);
58
58
  const userProfile = getSettledValueOrThrow(userProfileResult);
59
59
  const balances = getFulfilledValue(balancesResult);
@@ -53,8 +53,8 @@ export const useTokenLifecycle = (sdk, config = {}) => {
53
53
  return refreshPromiseRef.current;
54
54
  }
55
55
  const currentAuthState = currentAuthStateRef.current;
56
- if (!currentAuthState?.refreshToken) {
57
- console.warn("No refresh token available for token refresh");
56
+ if (!currentAuthState) {
57
+ console.warn("No active session available for refresh");
58
58
  return null;
59
59
  }
60
60
  const refreshPromise = (async () => {
@@ -1,35 +1,13 @@
1
- import type { BatchCancelOrdersResponse, BatchCreateOrderParams, BatchCreateOrdersResponse, BatchReplaceOrderParams, BatchReplaceOrdersResponse, CancelConditionalOrderResponse, CancelOrderResponse, CreateConditionalOrderParams, CreateConditionalOrderResponse, CreateOrderResponse, GetOrderResponse, GetPaginatedOrdersParams, GetPaginatedOrdersResponse, ListConditionalOrdersParams, ListConditionalOrdersResponse, OrderSide, ParentTpSlLegParams, PositionSide, ReplaceOrderResponse, TimeInForce, TradingMode } from "@0xmonaco/types";
1
+ import type { BatchCancelOrdersResponse, BatchCreateOrderParams, BatchCreateOrdersResponse, BatchReplaceOrderParams, BatchReplaceOrdersResponse, CancelConditionalOrderResponse, CancelOrderResponse, CreateOrderResponse, GetOrderResponse, GetPaginatedOrdersParams, GetPaginatedOrdersResponse, ListConditionalOrdersParams, ListConditionalOrdersResponse, OrderSide, ReplaceOrderResponse, TradingAPI } from "@0xmonaco/types";
2
+ type PlaceLimitOrderOptions = NonNullable<Parameters<TradingAPI["placeLimitOrder"]>[4]>;
3
+ type PlaceMarketOrderOptions = NonNullable<Parameters<TradingAPI["placeMarketOrder"]>[3]>;
2
4
  export interface UseTradeReturn {
3
5
  /** Place a limit order */
4
- placeLimitOrder: (tradingPairId: string, side: OrderSide, quantity: string, price: string, options?: {
5
- tradingMode?: TradingMode;
6
- useMasterBalance?: boolean;
7
- expirationDate?: string;
8
- timeInForce?: TimeInForce;
9
- marginAccountId?: string;
10
- strategyKey?: string;
11
- positionSide?: PositionSide;
12
- leverage?: string;
13
- reduceOnly?: boolean;
14
- takeProfit?: ParentTpSlLegParams;
15
- stopLoss?: ParentTpSlLegParams;
16
- }) => Promise<CreateOrderResponse>;
6
+ placeLimitOrder: (tradingPairId: string, side: OrderSide, quantity: string, price: string, options?: PlaceLimitOrderOptions) => Promise<CreateOrderResponse>;
17
7
  /** Place a market order */
18
- placeMarketOrder: (tradingPairId: string, side: OrderSide, quantity: string, options?: {
19
- tradingMode?: TradingMode;
20
- slippageTolerance?: number;
21
- marginAccountId?: string;
22
- strategyKey?: string;
23
- positionSide?: PositionSide;
24
- leverage?: string;
25
- reduceOnly?: boolean;
26
- takeProfit?: ParentTpSlLegParams;
27
- stopLoss?: ParentTpSlLegParams;
28
- }) => Promise<CreateOrderResponse>;
8
+ placeMarketOrder: (tradingPairId: string, side: OrderSide, quantity: string, options?: PlaceMarketOrderOptions) => Promise<CreateOrderResponse>;
29
9
  /** Cancel an existing order */
30
10
  cancelOrder: (orderId: string) => Promise<CancelOrderResponse>;
31
- /** Create a standalone conditional TP/SL order */
32
- createConditionalOrder: (params: CreateConditionalOrderParams) => Promise<CreateConditionalOrderResponse>;
33
11
  /** Cancel an active conditional TP/SL order */
34
12
  cancelConditionalOrder: (conditionalOrderId: string) => Promise<CancelConditionalOrderResponse>;
35
13
  /** List conditional TP/SL orders */
@@ -53,3 +31,4 @@ export interface UseTradeReturn {
53
31
  /** Get a single order by ID */
54
32
  getOrder: (orderId: string) => Promise<GetOrderResponse>;
55
33
  }
34
+ export {};
@@ -39,11 +39,6 @@ export const useTrade = () => {
39
39
  throw new Error("Order ID is required and cannot be empty");
40
40
  return await sdk.trading.cancelOrder(orderId);
41
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
42
  const cancelConditionalOrder = useCallback(async (conditionalOrderId) => {
48
43
  if (!sdk)
49
44
  throw new Error("SDK not available");
@@ -117,7 +112,6 @@ export const useTrade = () => {
117
112
  placeMarketOrder,
118
113
  // Order management
119
114
  cancelOrder,
120
- createConditionalOrder,
121
115
  cancelConditionalOrder,
122
116
  listConditionalOrders,
123
117
  batchCancel,
@@ -19,7 +19,7 @@ export function useTradeFeed(tradingPairId) {
19
19
  if (!sdk?.ws || !sdk?.trades || !tradingPairId) {
20
20
  return;
21
21
  }
22
- const fetchInitialTrades = () => sdk.trades.getTrades(tradingPairId, { page_size: MAX_TRADES });
22
+ const fetchInitialTrades = () => sdk.trades.getTrades(tradingPairId, { pageSize: MAX_TRADES });
23
23
  const subscribeToWs = (handler) => sdk.ws.trades(tradingPairId, handler);
24
24
  return subscribe(tradingPairId, fetchInitialTrades, subscribeToWs);
25
25
  }, [sdk?.ws, sdk?.trades, tradingPairId, subscribe]);
@@ -1,4 +1,9 @@
1
+ import type { AccountBalance, UserBalanceEvent } from "@0xmonaco/types";
1
2
  import type { UseUserBalancesReturn } from "./types";
3
+ /**
4
+ * Update an AccountBalance with data from a WebSocket balance event
5
+ */
6
+ export declare function updateBalanceFromEvent(balance: AccountBalance, event: UserBalanceEvent): AccountBalance;
2
7
  /**
3
8
  * Hook for subscribing to real-time user balance updates via WebSocket (authenticated)
4
9
  *
@@ -3,15 +3,17 @@ import { useMonacoSDK } from "../useMonaco";
3
3
  /**
4
4
  * Update an AccountBalance with data from a WebSocket balance event
5
5
  */
6
- function updateBalanceFromEvent(balance, event) {
6
+ export function updateBalanceFromEvent(balance, event) {
7
7
  const totalBalance = totalBalanceFromEvent(balance, event);
8
+ const totalBalanceRaw = totalBalanceRawFromEvent(balance, event);
8
9
  return {
9
10
  ...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,
11
+ availableBalance: event.data.available,
12
+ availableBalanceRaw: event.data.availableRaw,
13
+ lockedBalance: event.data.locked,
14
+ lockedBalanceRaw: event.data.lockedRaw,
15
+ totalBalance: totalBalance,
16
+ totalBalanceRaw: totalBalanceRaw,
15
17
  };
16
18
  }
17
19
  function parseDecimal(value) {
@@ -66,12 +68,26 @@ function totalBalanceFromEvent(balance, event) {
66
68
  if (eventExtraTotal && decimalGreaterThanZero(eventExtraTotal)) {
67
69
  return event.data.total;
68
70
  }
69
- const previousMarginTotal = decimalDifference(balance.total_balance, balance.available_balance, balance.locked_balance);
71
+ const previousMarginTotal = decimalDifference(balance.totalBalance, balance.availableBalance, balance.lockedBalance);
70
72
  if (!previousMarginTotal || !decimalGreaterThanZero(previousMarginTotal)) {
71
73
  return event.data.total;
72
74
  }
73
75
  return decimalSum(event.data.total, previousMarginTotal) ?? event.data.total;
74
76
  }
77
+ function totalBalanceRawFromEvent(balance, event) {
78
+ if (event.data.reason === "margin_transfer_in" || event.data.reason === "margin_transfer_out") {
79
+ return event.data.totalRaw;
80
+ }
81
+ const eventExtraTotalRaw = decimalDifference(event.data.totalRaw, event.data.availableRaw, event.data.lockedRaw);
82
+ if (eventExtraTotalRaw && decimalGreaterThanZero(eventExtraTotalRaw)) {
83
+ return event.data.totalRaw;
84
+ }
85
+ const previousMarginTotalRaw = decimalDifference(balance.totalBalanceRaw, balance.availableBalanceRaw, balance.lockedBalanceRaw);
86
+ if (!previousMarginTotalRaw || !decimalGreaterThanZero(previousMarginTotalRaw)) {
87
+ return event.data.totalRaw;
88
+ }
89
+ return decimalSum(event.data.totalRaw, previousMarginTotalRaw) ?? event.data.totalRaw;
90
+ }
75
91
  /**
76
92
  * Hook for subscribing to real-time user balance updates via WebSocket (authenticated)
77
93
  *
@@ -10,9 +10,9 @@ import type { UseUserMovementsOptions, UseUserMovementsReturn } from "./types";
10
10
  *
11
11
  * @param options - Optional filter and pagination options
12
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)
13
+ * @param options.pageSize - Number of items per page for the API call (default: maxMovements)
14
+ * @param options.entryType - Filter by entry type (CREDIT, DEBIT, LOCK, UNLOCK, FEE)
15
+ * @param options.transactionType - Filter by transaction type (DEPOSIT, WITHDRAWAL, TRADE, etc.)
16
+ * @param options.assetId - Filter by asset ID (UUID)
17
17
  */
18
18
  export declare function useUserMovements(options?: UseUserMovementsOptions): UseUserMovementsReturn;
@@ -10,26 +10,26 @@ function ledgerMovementToEvent(movement, userId) {
10
10
  userId,
11
11
  data: {
12
12
  id: movement.id,
13
- entryType: movement.entry_type,
14
- transactionType: movement.transaction_type,
13
+ entryType: movement.entryType,
14
+ transactionType: movement.transactionType,
15
15
  tokenAddress: movement.token,
16
16
  symbol: movement.symbol ?? undefined,
17
17
  decimals: movement.decimals,
18
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,
19
+ amountRaw: movement.amountRaw,
20
+ balanceBefore: movement.balanceBefore ?? undefined,
21
+ balanceBeforeRaw: movement.balanceBeforeRaw ?? undefined,
22
+ balanceAfter: movement.balanceAfter ?? undefined,
23
+ balanceAfterRaw: movement.balanceAfterRaw ?? undefined,
24
+ lockedBefore: movement.lockedBefore ?? undefined,
25
+ lockedBeforeRaw: movement.lockedBeforeRaw ?? undefined,
26
+ lockedAfter: movement.lockedAfter ?? undefined,
27
+ lockedAfterRaw: movement.lockedAfterRaw ?? undefined,
28
+ referenceId: movement.referenceId ?? undefined,
29
+ referenceType: movement.referenceType ?? undefined,
30
30
  description: movement.description ?? undefined,
31
- txHash: movement.tx_hash ?? undefined,
32
- createdAt: movement.created_at ?? undefined,
31
+ txHash: movement.txHash ?? undefined,
32
+ createdAt: movement.createdAt ?? undefined,
33
33
  },
34
34
  };
35
35
  }
@@ -44,22 +44,22 @@ function ledgerMovementToEvent(movement, userId) {
44
44
  *
45
45
  * @param options - Optional filter and pagination options
46
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)
47
+ * @param options.pageSize - Number of items per page for the API call (default: maxMovements)
48
+ * @param options.entryType - Filter by entry type (CREDIT, DEBIT, LOCK, UNLOCK, FEE)
49
+ * @param options.transactionType - Filter by transaction type (DEPOSIT, WITHDRAWAL, TRADE, etc.)
50
+ * @param options.assetId - Filter by asset ID (UUID)
51
51
  */
52
52
  export function useUserMovements(options = {}) {
53
53
  const { sdk } = useMonacoSDK();
54
54
  const { authenticationStatus } = useMonacoContext();
55
- const { maxMovements = 50, page_size, entry_type, transaction_type, asset_id } = options;
55
+ const { maxMovements = 50, pageSize, entryType, transactionType, assetId } = options;
56
56
  const [movements, setMovements] = useState([]);
57
57
  const [loading, setLoading] = useState(false);
58
58
  const [error, setError] = useState(null);
59
59
  const [subscribed, setSubscribed] = useState(false);
60
60
  const clearError = useCallback(() => setError(null), []);
61
61
  const sliceSize = Number.isFinite(maxMovements) && maxMovements > 0 ? maxMovements : 50;
62
- const requestLimit = page_size ?? Math.min(Math.max(Math.round(sliceSize), 1), 100);
62
+ const requestLimit = pageSize ?? Math.min(Math.max(Math.round(sliceSize), 1), 100);
63
63
  // Derive userId reactively — authenticationStatus changes on login/logout, triggering a re-render
64
64
  const userId = authenticationStatus === "authenticated" ? sdk?.getAuthState()?.user.id : undefined;
65
65
  useEffect(() => {
@@ -73,9 +73,9 @@ export function useUserMovements(options = {}) {
73
73
  // Fetch initial movements via REST API, then subscribe to WebSocket updates
74
74
  let unsubscribe;
75
75
  sdk.profile
76
- .getPaginatedUserMovements({ page_size: requestLimit, entry_type, transaction_type, asset_id })
76
+ .getPaginatedUserMovements({ pageSize: requestLimit, entryType, transactionType, assetId })
77
77
  .then(async (response) => {
78
- // Combine latest_movements (from Redis) with movements (from PostgreSQL)
78
+ // Combine latest_movements (from the live engine cache) with movements (from PostgreSQL)
79
79
  // latest_movements contains real-time data that may not yet be in PostgreSQL
80
80
  // Deduplicate by id, preferring latest_movements (newer data)
81
81
  const latestMovements = (response.latest_movements || []).map((m) => ledgerMovementToEvent(m, userId));
@@ -117,6 +117,6 @@ export function useUserMovements(options = {}) {
117
117
  unsubscribe?.();
118
118
  setSubscribed(false);
119
119
  };
120
- }, [sdk?.ws, sdk?.profile, userId, sliceSize, requestLimit, entry_type, transaction_type, asset_id]);
120
+ }, [sdk?.ws, sdk?.profile, userId, sliceSize, requestLimit, entryType, transactionType, assetId]);
121
121
  return { movements, loading, subscribed, error, clearError };
122
122
  }
@@ -23,9 +23,9 @@ export function useUserOrders(maxOrders = 50) {
23
23
  try {
24
24
  const response = await sdk.trading.getPaginatedOrders({
25
25
  page: 1,
26
- page_size: maxOrders,
26
+ pageSize: maxOrders,
27
27
  });
28
- // Combine latest_orders (from Redis) with orders (from PostgreSQL)
28
+ // Combine latest_orders (from the live engine cache) with orders (from PostgreSQL)
29
29
  // latest_orders contains real-time data that may not yet be in PostgreSQL
30
30
  // Deduplicate by id, preferring latest_orders (newer data)
31
31
  const latestOrders = response.latest_orders || [];
@@ -123,18 +123,18 @@ function orderFromEvent(event) {
123
123
  return null;
124
124
  return {
125
125
  id: event.orderId,
126
- trading_pair_id: tradingPairId,
127
- order_type: (data.orderType || "LIMIT"),
126
+ tradingPairId: tradingPairId,
127
+ orderType: (data.orderType || "LIMIT"),
128
128
  side: (data.side || "BUY"),
129
129
  price: data.price,
130
130
  quantity: data.quantity || "0",
131
- filled_quantity: "0",
132
- average_fill_price: undefined,
131
+ filledQuantity: "0",
132
+ averageFillPrice: undefined,
133
133
  status: data.status,
134
- trading_mode: (data.tradingMode || "SPOT"),
135
- time_in_force: data.timeInForce,
136
- created_at: event.timestamp,
137
- updated_at: event.timestamp,
134
+ tradingMode: (data.tradingMode || "SPOT"),
135
+ timeInForce: data.timeInForce,
136
+ createdAt: event.timestamp,
137
+ updatedAt: event.timestamp,
138
138
  };
139
139
  }
140
140
  /**
@@ -170,8 +170,8 @@ function updateOrderFromEvent(order, event) {
170
170
  }
171
171
  }
172
172
  // Get filled quantity from different event types
173
- let filledQuantity = order.filled_quantity;
174
- let avgFillPrice = order.average_fill_price;
173
+ let filledQuantity = order.filledQuantity;
174
+ let avgFillPrice = order.averageFillPrice;
175
175
  if ("totalFilled" in data && data.totalFilled) {
176
176
  filledQuantity = data.totalFilled;
177
177
  }
@@ -184,8 +184,8 @@ function updateOrderFromEvent(order, event) {
184
184
  return {
185
185
  ...order,
186
186
  status: newStatus,
187
- filled_quantity: filledQuantity,
188
- average_fill_price: avgFillPrice,
189
- updated_at: event.timestamp,
187
+ filledQuantity: filledQuantity,
188
+ averageFillPrice: avgFillPrice,
189
+ updatedAt: event.timestamp,
190
190
  };
191
191
  }
@@ -1,13 +1,15 @@
1
- import type { TransactionResult, WithdrawResult } from "@0xmonaco/types";
1
+ import type { ListPendingWithdrawalsParams, ListPendingWithdrawalsResponse, TransactionResult, WithdrawalSource, WithdrawResult } from "@0xmonaco/types";
2
2
  export interface UseVaultReturn {
3
3
  /** Approve the vault to spend tokens */
4
4
  approve: (assetId: string, amount: bigint, autoWait?: boolean) => Promise<TransactionResult>;
5
5
  /** Deposit tokens into the vault */
6
6
  deposit: (assetId: string, amount: bigint, autoWait?: boolean) => Promise<TransactionResult>;
7
7
  /** Initiate a withdrawal and submit the pre-signed calldata on-chain */
8
- withdraw: (assetId: string, amount: bigint, autoWait?: boolean) => Promise<WithdrawResult>;
8
+ withdraw: (assetId: string, amount: bigint, autoWait?: boolean, source?: WithdrawalSource) => Promise<WithdrawResult>;
9
9
  /** Retry a withdrawal whose on-chain submission never landed — does NOT create a new one */
10
10
  retryWithdrawal: (withdrawalIndex: number, autoWait?: boolean) => Promise<WithdrawResult>;
11
+ /** List the caller's pending withdrawals (awaiting on-chain confirmation), newest first */
12
+ listPendingWithdrawals: (params?: ListPendingWithdrawalsParams) => Promise<ListPendingWithdrawalsResponse>;
11
13
  /** Get the allowance for a token */
12
14
  getAllowance: (assetId: string) => Promise<bigint>;
13
15
  /** Check if a token needs approval for an amount */
@@ -20,14 +20,14 @@ export const useVault = () => {
20
20
  throw new Error("Amount must be greater than 0");
21
21
  return await sdk.vault.deposit(assetId, amount, autoWait);
22
22
  }, [sdk]);
23
- const withdraw = useCallback(async (assetId, amount, autoWait) => {
23
+ const withdraw = useCallback(async (assetId, amount, autoWait, source) => {
24
24
  if (!sdk)
25
25
  throw new Error("SDK not available");
26
26
  if (!assetId?.trim())
27
27
  throw new Error("Asset ID is required and cannot be empty");
28
28
  if (amount <= 0n)
29
29
  throw new Error("Amount must be greater than 0");
30
- return await sdk.vault.withdraw(assetId, amount, autoWait);
30
+ return await sdk.vault.withdraw(assetId, amount, autoWait, source);
31
31
  }, [sdk]);
32
32
  const retryWithdrawal = useCallback(async (withdrawalIndex, autoWait) => {
33
33
  if (!sdk)
@@ -37,6 +37,11 @@ export const useVault = () => {
37
37
  }
38
38
  return await sdk.vault.retryWithdrawal(withdrawalIndex, autoWait);
39
39
  }, [sdk]);
40
+ const listPendingWithdrawals = useCallback(async (params) => {
41
+ if (!sdk)
42
+ throw new Error("SDK not available");
43
+ return await sdk.withdrawals.listPendingWithdrawals(params);
44
+ }, [sdk]);
40
45
  const getAllowance = useCallback(async (assetId) => {
41
46
  if (!sdk)
42
47
  throw new Error("SDK not available");
@@ -59,6 +64,7 @@ export const useVault = () => {
59
64
  deposit,
60
65
  withdraw,
61
66
  retryWithdrawal,
67
+ listPendingWithdrawals,
62
68
  // Approval and allowance queries
63
69
  getAllowance,
64
70
  needsApproval,
@@ -2,14 +2,18 @@ import type { AuthState } from "@0xmonaco/types";
2
2
  /**
3
3
  * Save auth state to localStorage
4
4
  *
5
- * @security This function stores authentication tokens (including refresh tokens) in localStorage,
6
- * which is accessible to any JavaScript running on the page. This makes tokens vulnerable to XSS attacks.
5
+ * @security This function stores the session keypair (including the private
6
+ * key) in localStorage, which is accessible to any JavaScript running on the
7
+ * page. This is the same XSS exposure as the previous JWT-based scheme — an
8
+ * attacker who can read localStorage can act as the user until the session
9
+ * expires either way.
7
10
  *
8
11
  * Security recommendations:
9
12
  * - Implement Content Security Policy (CSP) headers to mitigate XSS risks
10
13
  * - Sanitize all user input to prevent XSS vulnerabilities
11
14
  * - Consider the tradeoffs: localStorage provides persistence across sessions but sacrifices XSS protection
12
- * - For high-security requirements, consider httpOnly cookies (requires backend changes)
15
+ * - For higher-security requirements, back the session key with a
16
+ * non-extractable WebCrypto key (out of scope for this default helper)
13
17
  *
14
18
  * @param authState - The authentication state to persist
15
19
  */
@@ -5,22 +5,26 @@ const STORAGE_KEY = "monaco_auth_state";
5
5
  /**
6
6
  * Save auth state to localStorage
7
7
  *
8
- * @security This function stores authentication tokens (including refresh tokens) in localStorage,
9
- * which is accessible to any JavaScript running on the page. This makes tokens vulnerable to XSS attacks.
8
+ * @security This function stores the session keypair (including the private
9
+ * key) in localStorage, which is accessible to any JavaScript running on the
10
+ * page. This is the same XSS exposure as the previous JWT-based scheme — an
11
+ * attacker who can read localStorage can act as the user until the session
12
+ * expires either way.
10
13
  *
11
14
  * Security recommendations:
12
15
  * - Implement Content Security Policy (CSP) headers to mitigate XSS risks
13
16
  * - Sanitize all user input to prevent XSS vulnerabilities
14
17
  * - Consider the tradeoffs: localStorage provides persistence across sessions but sacrifices XSS protection
15
- * - For high-security requirements, consider httpOnly cookies (requires backend changes)
18
+ * - For higher-security requirements, back the session key with a
19
+ * non-extractable WebCrypto key (out of scope for this default helper)
16
20
  *
17
21
  * @param authState - The authentication state to persist
18
22
  */
19
23
  export function saveAuthState(authState) {
20
24
  try {
21
25
  const data = JSON.stringify({
22
- accessToken: authState.accessToken,
23
- refreshToken: authState.refreshToken,
26
+ sessionPublicKey: authState.sessionPublicKey,
27
+ sessionPrivateKey: authState.sessionPrivateKey,
24
28
  expiresAt: authState.expiresAt,
25
29
  user: authState.user,
26
30
  });
@@ -41,10 +45,10 @@ export function loadAuthState() {
41
45
  return null;
42
46
  const parsed = JSON.parse(data);
43
47
  // Validate required fields and types
44
- if (typeof parsed.accessToken !== "string" ||
45
- parsed.accessToken.length === 0 ||
46
- typeof parsed.refreshToken !== "string" ||
47
- parsed.refreshToken.length === 0 ||
48
+ if (typeof parsed.sessionPublicKey !== "string" ||
49
+ parsed.sessionPublicKey.length === 0 ||
50
+ typeof parsed.sessionPrivateKey !== "string" ||
51
+ parsed.sessionPrivateKey.length === 0 ||
48
52
  typeof parsed.expiresAt !== "number" ||
49
53
  !Number.isFinite(parsed.expiresAt) ||
50
54
  parsed.expiresAt <= 0 ||
@@ -58,8 +62,8 @@ export function loadAuthState() {
58
62
  return null;
59
63
  }
60
64
  return {
61
- accessToken: parsed.accessToken,
62
- refreshToken: parsed.refreshToken,
65
+ sessionPublicKey: parsed.sessionPublicKey,
66
+ sessionPrivateKey: parsed.sessionPrivateKey,
63
67
  expiresAt: parsed.expiresAt,
64
68
  user: parsed.user,
65
69
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xmonaco/react",
3
- "version": "0.8.5",
3
+ "version": "0.8.7-develop.0f12336",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,8 +20,8 @@
20
20
  "lint": "biome lint ."
21
21
  },
22
22
  "dependencies": {
23
- "@0xmonaco/core": "0.8.5",
24
- "@0xmonaco/types": "0.8.5"
23
+ "@0xmonaco/core": "0.8.7-develop.0f12336",
24
+ "@0xmonaco/types": "0.8.7-develop.0f12336"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/react": "^19.1.12",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "peerDependencies": {
31
31
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
32
- "wagmi": "^2.0.0 || ^3.0.0",
33
- "viem": "^2.45.2"
32
+ "viem": "^2.45.2",
33
+ "wagmi": "^2.0.0 || ^3.0.0"
34
34
  },
35
35
  "exports": {
36
36
  ".": {