@temple-digital-group/temple-canton-js 2.0.2 → 2.0.3-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +457 -457
  2. package/index.js +15 -15
  3. package/package.json +49 -49
  4. package/src/api/config.d.ts +20 -20
  5. package/src/api/index.ts +322 -322
  6. package/src/api/tokenStore.ts +30 -30
  7. package/src/api/types.ts +196 -196
  8. package/src/auth0/index.d.ts +1 -1
  9. package/src/auth0/index.js +50 -50
  10. package/src/canton/deposits.ts +563 -563
  11. package/src/canton/helpers.ts +266 -266
  12. package/src/canton/index.d.ts +41 -41
  13. package/src/canton/index.js +3472 -3472
  14. package/src/canton/instrumentCatalog.d.ts +7 -7
  15. package/src/canton/instrumentCatalog.js +283 -283
  16. package/src/canton/request_schemas/cancel_orders_amulet.json +77 -77
  17. package/src/canton/request_schemas/cancel_orders_utility.json +68 -68
  18. package/src/canton/request_schemas/create_order_proposal_amulet.json +94 -94
  19. package/src/canton/request_schemas/create_order_proposal_utility.json +121 -121
  20. package/src/canton/request_schemas/create_utility_credential.json +31 -31
  21. package/src/canton/request_schemas/execute_transfer_factory.json +43 -43
  22. package/src/canton/request_schemas/get_allocation_factory.json +21 -21
  23. package/src/canton/request_schemas/get_amulet_holdings.json +21 -21
  24. package/src/canton/request_schemas/get_instrument_configurations.json +21 -21
  25. package/src/canton/request_schemas/get_locked_amulet_holdings.json +21 -21
  26. package/src/canton/request_schemas/get_order_proposals.json +21 -21
  27. package/src/canton/request_schemas/get_orders.json +21 -21
  28. package/src/canton/request_schemas/get_sender_credentials.json +22 -22
  29. package/src/canton/request_schemas/get_transfer_factory.json +28 -28
  30. package/src/canton/request_schemas/get_utility_holdings.json +21 -21
  31. package/src/canton/request_schemas/unlock_amulet.json +38 -38
  32. package/src/canton/walletAdapter.d.ts +7 -7
  33. package/src/canton/walletAdapter.js +112 -112
  34. package/src/canton/withdrawals.ts +511 -511
  35. package/src/config/index.d.ts +63 -63
  36. package/src/config/index.js +188 -188
  37. package/src/websocket/index.ts +341 -341
  38. package/src/websocket/ws.d.ts +24 -24
package/src/api/index.ts CHANGED
@@ -1,322 +1,322 @@
1
- import axios, { type AxiosRequestConfig } from "axios";
2
- import config, { initializeConfig, setWalletAdapter } from "../../src/config/index.js";
3
- import {
4
- getAuthHeader,
5
- setUserId,
6
- } from "./tokenStore.js";
7
- import type {
8
- ApiError,
9
- Ticker,
10
- OrderBook,
11
- OrderBookOptions,
12
- SymbolConfig,
13
- OpenInterest,
14
- Trade,
15
- RecentTradesOptions,
16
- ActiveOrder,
17
- ActiveOrdersOptions,
18
- CancelOrderResponse,
19
- CancelAllOrdersOptions,
20
- CancelAllOrdersResponse,
21
- CreateOrderRequestOpts,
22
- CreateOrderRequestResponse,
23
- DelegationResponse,
24
- WithdrawalResponse,
25
- WithdrawalStatusResponse,
26
- TradingBalanceResponse,
27
- AmuletDisclosure,
28
- DisclosuresResponse,
29
- } from "./types.js";
30
-
31
- // Re-export types and token utilities consumers may need
32
- export type {
33
- ApiError,
34
- Ticker,
35
- OrderBook,
36
- OrderBookOptions,
37
- SymbolConfig,
38
- OpenInterest,
39
- Trade,
40
- RecentTradesOptions,
41
- ActiveOrder,
42
- ActiveOrdersOptions,
43
- CancelOrderResponse,
44
- CancelAllOrdersOptions,
45
- CancelAllOrdersResponse,
46
- CreateOrderRequestResponse,
47
- DelegationResponse,
48
- WithdrawalResponse,
49
- WithdrawalStatusResponse,
50
- TradingBalanceResponse,
51
- AmuletDisclosure,
52
- DisclosuresResponse,
53
- };
54
- export { getUserId } from "./tokenStore.js";
55
- export { setWalletAdapter } from "../../src/config/index.js";
56
-
57
- // ── Initialization ──
58
-
59
- /**
60
- * Initialize the Temple SDK.
61
- * API_KEY is required. Throws if not provided.
62
- */
63
- export function initialize(cfg: Record<string, unknown>): void {
64
- if (!cfg.API_KEY) {
65
- throw new Error("initialize: API_KEY is required.");
66
- }
67
-
68
- initializeConfig(cfg);
69
-
70
- if (cfg.WALLET_ADAPTER) {
71
- setWalletAdapter(cfg.WALLET_ADAPTER);
72
- }
73
-
74
- const userIdValue = cfg.USER_ID as string | undefined;
75
- if (userIdValue) {
76
- setUserId(userIdValue);
77
- }
78
- }
79
-
80
- // ── Internal helpers ──
81
-
82
- function handleApiError(error: unknown, context: string): ApiError {
83
- const err = error as { response?: { status?: number; data?: { message?: string; error?: string; code?: string } }; message?: string };
84
- const status = err.response?.status ?? null;
85
- const message =
86
- err.response?.data?.message ??
87
- err.response?.data?.error ??
88
- err.message ??
89
- "Unknown error";
90
- const code = err.response?.data?.code ?? null;
91
-
92
- console.error(`[Temple API] ${context}: ${message}${status ? ` (HTTP ${status})` : ""}`);
93
-
94
- return { error: true, status, code, message };
95
- }
96
-
97
- function ensureAuthenticated(): ApiError | null {
98
- if (config.API_KEY) return null;
99
- return { error: true, status: 401, code: "NOT_AUTHENTICATED", message: "API key required. Pass API_KEY in initialize()." };
100
- }
101
-
102
- async function authenticatedGet<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T | ApiError> {
103
- const authError = ensureAuthenticated();
104
- if (authError) return authError;
105
-
106
- const headers = {
107
- ...getAuthHeader(),
108
- "Content-Type": "application/json",
109
- };
110
-
111
- // Filter out undefined params
112
- const cleanParams: Record<string, string | number> = {};
113
- if (params) {
114
- for (const [key, value] of Object.entries(params)) {
115
- if (value !== undefined) cleanParams[key] = value;
116
- }
117
- }
118
-
119
- try {
120
- const response = await axios.get<T>(`${config.API_BASE_URL}${path}`, {
121
- headers,
122
- params: Object.keys(cleanParams).length > 0 ? cleanParams : undefined,
123
- } as AxiosRequestConfig);
124
- return response.data;
125
- } catch (error) {
126
- return handleApiError(error, `GET ${path}`);
127
- }
128
- }
129
-
130
- async function authenticatedPost<T>(path: string, body?: Record<string, unknown> | Record<string, unknown>[]): Promise<T | ApiError> {
131
- const authError = ensureAuthenticated();
132
- if (authError) return authError;
133
-
134
- const headers = {
135
- ...getAuthHeader(),
136
- "Content-Type": "application/json",
137
- };
138
-
139
- try {
140
- const response = await axios.post<T>(`${config.API_BASE_URL}${path}`, body ?? {}, { headers } as AxiosRequestConfig);
141
- return response.data;
142
- } catch (error) {
143
- return handleApiError(error, `POST ${path}`);
144
- }
145
- }
146
-
147
- // ── Helpers ──
148
-
149
- /** Normalize CC → Amulet in symbol strings (e.g. "CC/SBC" → "Amulet/SBC", "CC" → "Amulet") */
150
- function normalizeSymbol(symbol: string): string {
151
- return symbol.replace(/\bCC\b/g, "Amulet");
152
- }
153
-
154
- // ── Market Data ──
155
-
156
- /**
157
- * Get ticker data for one or all trading pairs.
158
- * @param symbol - Optional symbol filter (e.g., "Amulet/USDCx")
159
- */
160
- export async function getTicker(symbol?: string): Promise<Ticker | Ticker[] | ApiError> {
161
- return authenticatedGet("/api/v1/market/ticker", { symbol: symbol ? normalizeSymbol(symbol) : undefined });
162
- }
163
-
164
- /**
165
- * Get the order book for a trading pair.
166
- * @param symbol - Trading pair symbol (required)
167
- * @param options - Optional levels and precision parameters
168
- */
169
- export async function getOrderBook(symbol: string, options: OrderBookOptions = {}): Promise<OrderBook | ApiError> {
170
- if (!symbol) {
171
- return { error: true, status: null, code: "INVALID_PARAMS", message: "Symbol is required." };
172
- }
173
- return authenticatedGet("/api/v1/market/orderbook", {
174
- symbol: normalizeSymbol(symbol),
175
- levels: options.levels,
176
- precision: options.precision,
177
- });
178
- }
179
-
180
- /**
181
- * Get symbol configuration (paused status, decimals, minimum quantity).
182
- * @param symbol - Trading pair symbol (required)
183
- */
184
- export async function getSymbolConfig(symbol: string): Promise<SymbolConfig | ApiError> {
185
- if (!symbol) {
186
- return { error: true, status: null, code: "INVALID_PARAMS", message: "Symbol is required." };
187
- }
188
- return authenticatedGet("/api/v1/trading/symbol-config", { symbol: normalizeSymbol(symbol) });
189
- }
190
-
191
- /**
192
- * Get open interest for a trading pair.
193
- * @param symbol - Trading pair symbol (required)
194
- */
195
- export async function getOpenInterest(symbol: string): Promise<OpenInterest | ApiError> {
196
- if (!symbol) {
197
- return { error: true, status: null, code: "INVALID_PARAMS", message: "Symbol is required." };
198
- }
199
- return authenticatedGet("/api/v1/market/open-interest", { symbol: normalizeSymbol(symbol) });
200
- }
201
-
202
- /**
203
- * Get recent trades for a trading pair.
204
- * @param symbol - Trading pair symbol (required)
205
- * @param options - Optional limit (max 500)
206
- */
207
- export async function getRecentTrades(symbol: string, options: RecentTradesOptions = {}): Promise<Trade[] | ApiError> {
208
- if (!symbol) {
209
- return { error: true, status: null, code: "INVALID_PARAMS", message: "Symbol is required." };
210
- }
211
- return authenticatedGet("/api/v1/market/trades", {
212
- symbol: normalizeSymbol(symbol),
213
- limit: options.limit,
214
- });
215
- }
216
-
217
- // ── Orders ──
218
-
219
- /**
220
- * Get active orders, optionally filtered by symbol.
221
- * @param options - Optional symbol and limit filters
222
- */
223
- export async function getActiveOrders(options: ActiveOrdersOptions = {}): Promise<ActiveOrder[] | ApiError> {
224
- return authenticatedGet("/api/trading/orders/active", {
225
- symbol: options.symbol ? normalizeSymbol(options.symbol) : undefined,
226
- limit: options.limit,
227
- });
228
- }
229
-
230
- /**
231
- * Cancel a specific order by ID.
232
- * @param orderId - The order ID to cancel
233
- */
234
- export async function cancelOrder(orderId: string): Promise<CancelOrderResponse | ApiError> {
235
- if (!orderId) {
236
- return { error: true, status: null, code: "INVALID_PARAMS", message: "Order ID is required." };
237
- }
238
- return authenticatedPost(`/api/trading/orders/${encodeURIComponent(orderId)}/cancel`);
239
- }
240
-
241
- /**
242
- * Cancel all active orders, optionally filtered by symbol.
243
- * @param options - Optional symbol filter
244
- */
245
- export async function cancelAllOrders(options: CancelAllOrdersOptions = {}): Promise<CancelAllOrdersResponse | ApiError> {
246
- return authenticatedPost("/api/trading/orders/cancel-all", options.symbol ? { symbol: normalizeSymbol(options.symbol) } : undefined);
247
- }
248
-
249
- // ── Disclosures ──
250
-
251
- /**
252
- * Get amulet disclosure data for a party from the Temple REST API.
253
- * Returns protocol disclosures (amulet rules, open mining rounds, external party amulet rules).
254
- * @param partyId - Canton party ID
255
- */
256
- export async function getDisclosures(partyId: string): Promise<DisclosuresResponse | ApiError> {
257
- if (!partyId) {
258
- return { error: true, status: null, code: "INVALID_PARAMS", message: "Party ID is required." };
259
- }
260
- return authenticatedGet("/api/amulet/disclosures", { partyId });
261
- }
262
-
263
- // ── Delegation ──
264
-
265
- /**
266
- * Get the user's trading delegation status.
267
- */
268
- export async function getDelegation(): Promise<DelegationResponse | ApiError> {
269
- return authenticatedGet("/api/trading/delegation");
270
- }
271
-
272
- // ── Order Requests ──
273
-
274
- /**
275
- * Create an order request (limit buy/sell) on the Temple trading backend.
276
- * @param opts - Order parameters: symbol, side, quantity, price, order_type, expires_at
277
- */
278
- export async function createOrderRequest(opts: CreateOrderRequestOpts): Promise<CreateOrderRequestResponse | ApiError> {
279
- const { symbol: rawSymbol, side, quantity, price, order_type = "limit", order_subtype, expires_at } = opts || {};
280
- if (!rawSymbol || !side || quantity == null || price == null) {
281
- return { error: true, status: null, code: "INVALID_PARAMS", message: "symbol, side, quantity, and price are required." };
282
- }
283
- const symbol = normalizeSymbol(rawSymbol);
284
- const body: Record<string, unknown> = { symbol, side, quantity: Number(quantity), price: Number(price), order_type };
285
- if (order_subtype) body.order_subtype = order_subtype;
286
- if (expires_at) body.expires_at = expires_at;
287
- return authenticatedPost("/api/trading/orders", body);
288
- }
289
-
290
- // ── Withdrawals ──
291
-
292
- /**
293
- * Create a withdrawal request.
294
- * @param assetId - Instrument symbol (e.g. "USDCx", "Amulet")
295
- * @param amount - Amount to withdraw
296
- */
297
- export async function createWithdrawalRequest(assetId: string, amount: string | number): Promise<WithdrawalResponse | ApiError> {
298
- if (!assetId || amount == null) {
299
- return { error: true, status: null, code: "INVALID_PARAMS", message: "asset_id and amount are required." };
300
- }
301
- return authenticatedPost("/api/trading/withdrawals", { asset_id: normalizeSymbol(assetId), amount: String(amount) });
302
- }
303
-
304
- /**
305
- * Get the status of a withdrawal request.
306
- * @param requestId - The request ID returned by createWithdrawalRequest
307
- */
308
- export async function getWithdrawalRequestStatus(requestId: string | number): Promise<WithdrawalStatusResponse | ApiError> {
309
- if (requestId == null) {
310
- return { error: true, status: null, code: "INVALID_PARAMS", message: "requestId is required." };
311
- }
312
- return authenticatedGet(`/api/trading/withdrawals/${encodeURIComponent(requestId)}`);
313
- }
314
-
315
- /**
316
- * Get the user's trading balances.
317
- *
318
- * GET /api/trading/balances
319
- */
320
- export async function getTradingBalance(): Promise<TradingBalanceResponse | ApiError> {
321
- return authenticatedGet("/api/trading/balances");
322
- }
1
+ import axios, { type AxiosRequestConfig } from "axios";
2
+ import config, { initializeConfig, setWalletAdapter } from "../../src/config/index.js";
3
+ import {
4
+ getAuthHeader,
5
+ setUserId,
6
+ } from "./tokenStore.js";
7
+ import type {
8
+ ApiError,
9
+ Ticker,
10
+ OrderBook,
11
+ OrderBookOptions,
12
+ SymbolConfig,
13
+ OpenInterest,
14
+ Trade,
15
+ RecentTradesOptions,
16
+ ActiveOrder,
17
+ ActiveOrdersOptions,
18
+ CancelOrderResponse,
19
+ CancelAllOrdersOptions,
20
+ CancelAllOrdersResponse,
21
+ CreateOrderRequestOpts,
22
+ CreateOrderRequestResponse,
23
+ DelegationResponse,
24
+ WithdrawalResponse,
25
+ WithdrawalStatusResponse,
26
+ TradingBalanceResponse,
27
+ AmuletDisclosure,
28
+ DisclosuresResponse,
29
+ } from "./types.js";
30
+
31
+ // Re-export types and token utilities consumers may need
32
+ export type {
33
+ ApiError,
34
+ Ticker,
35
+ OrderBook,
36
+ OrderBookOptions,
37
+ SymbolConfig,
38
+ OpenInterest,
39
+ Trade,
40
+ RecentTradesOptions,
41
+ ActiveOrder,
42
+ ActiveOrdersOptions,
43
+ CancelOrderResponse,
44
+ CancelAllOrdersOptions,
45
+ CancelAllOrdersResponse,
46
+ CreateOrderRequestResponse,
47
+ DelegationResponse,
48
+ WithdrawalResponse,
49
+ WithdrawalStatusResponse,
50
+ TradingBalanceResponse,
51
+ AmuletDisclosure,
52
+ DisclosuresResponse,
53
+ };
54
+ export { getUserId } from "./tokenStore.js";
55
+ export { setWalletAdapter } from "../../src/config/index.js";
56
+
57
+ // ── Initialization ──
58
+
59
+ /**
60
+ * Initialize the Temple SDK.
61
+ * API_KEY is required. Throws if not provided.
62
+ */
63
+ export function initialize(cfg: Record<string, unknown>): void {
64
+ if (!cfg.API_KEY) {
65
+ throw new Error("initialize: API_KEY is required.");
66
+ }
67
+
68
+ initializeConfig(cfg);
69
+
70
+ if (cfg.WALLET_ADAPTER) {
71
+ setWalletAdapter(cfg.WALLET_ADAPTER);
72
+ }
73
+
74
+ const userIdValue = cfg.USER_ID as string | undefined;
75
+ if (userIdValue) {
76
+ setUserId(userIdValue);
77
+ }
78
+ }
79
+
80
+ // ── Internal helpers ──
81
+
82
+ function handleApiError(error: unknown, context: string): ApiError {
83
+ const err = error as { response?: { status?: number; data?: { message?: string; error?: string; code?: string } }; message?: string };
84
+ const status = err.response?.status ?? null;
85
+ const message =
86
+ err.response?.data?.message ??
87
+ err.response?.data?.error ??
88
+ err.message ??
89
+ "Unknown error";
90
+ const code = err.response?.data?.code ?? null;
91
+
92
+ console.error(`[Temple API] ${context}: ${message}${status ? ` (HTTP ${status})` : ""}`);
93
+
94
+ return { error: true, status, code, message };
95
+ }
96
+
97
+ function ensureAuthenticated(): ApiError | null {
98
+ if (config.API_KEY) return null;
99
+ return { error: true, status: 401, code: "NOT_AUTHENTICATED", message: "API key required. Pass API_KEY in initialize()." };
100
+ }
101
+
102
+ async function authenticatedGet<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T | ApiError> {
103
+ const authError = ensureAuthenticated();
104
+ if (authError) return authError;
105
+
106
+ const headers = {
107
+ ...getAuthHeader(),
108
+ "Content-Type": "application/json",
109
+ };
110
+
111
+ // Filter out undefined params
112
+ const cleanParams: Record<string, string | number> = {};
113
+ if (params) {
114
+ for (const [key, value] of Object.entries(params)) {
115
+ if (value !== undefined) cleanParams[key] = value;
116
+ }
117
+ }
118
+
119
+ try {
120
+ const response = await axios.get<T>(`${config.API_BASE_URL}${path}`, {
121
+ headers,
122
+ params: Object.keys(cleanParams).length > 0 ? cleanParams : undefined,
123
+ } as AxiosRequestConfig);
124
+ return response.data;
125
+ } catch (error) {
126
+ return handleApiError(error, `GET ${path}`);
127
+ }
128
+ }
129
+
130
+ async function authenticatedPost<T>(path: string, body?: Record<string, unknown> | Record<string, unknown>[]): Promise<T | ApiError> {
131
+ const authError = ensureAuthenticated();
132
+ if (authError) return authError;
133
+
134
+ const headers = {
135
+ ...getAuthHeader(),
136
+ "Content-Type": "application/json",
137
+ };
138
+
139
+ try {
140
+ const response = await axios.post<T>(`${config.API_BASE_URL}${path}`, body ?? {}, { headers } as AxiosRequestConfig);
141
+ return response.data;
142
+ } catch (error) {
143
+ return handleApiError(error, `POST ${path}`);
144
+ }
145
+ }
146
+
147
+ // ── Helpers ──
148
+
149
+ /** Normalize CC → Amulet in symbol strings (e.g. "CC/SBC" → "Amulet/SBC", "CC" → "Amulet") */
150
+ function normalizeSymbol(symbol: string): string {
151
+ return symbol.replace(/\bCC\b/g, "Amulet");
152
+ }
153
+
154
+ // ── Market Data ──
155
+
156
+ /**
157
+ * Get ticker data for one or all trading pairs.
158
+ * @param symbol - Optional symbol filter (e.g., "Amulet/USDCx")
159
+ */
160
+ export async function getTicker(symbol?: string): Promise<Ticker | Ticker[] | ApiError> {
161
+ return authenticatedGet("/api/v1/market/ticker", { symbol: symbol ? normalizeSymbol(symbol) : undefined });
162
+ }
163
+
164
+ /**
165
+ * Get the order book for a trading pair.
166
+ * @param symbol - Trading pair symbol (required)
167
+ * @param options - Optional levels and precision parameters
168
+ */
169
+ export async function getOrderBook(symbol: string, options: OrderBookOptions = {}): Promise<OrderBook | ApiError> {
170
+ if (!symbol) {
171
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "Symbol is required." };
172
+ }
173
+ return authenticatedGet("/api/v1/market/orderbook", {
174
+ symbol: normalizeSymbol(symbol),
175
+ levels: options.levels,
176
+ precision: options.precision,
177
+ });
178
+ }
179
+
180
+ /**
181
+ * Get symbol configuration (paused status, decimals, minimum quantity).
182
+ * @param symbol - Trading pair symbol (required)
183
+ */
184
+ export async function getSymbolConfig(symbol: string): Promise<SymbolConfig | ApiError> {
185
+ if (!symbol) {
186
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "Symbol is required." };
187
+ }
188
+ return authenticatedGet("/api/v1/trading/symbol-config", { symbol: normalizeSymbol(symbol) });
189
+ }
190
+
191
+ /**
192
+ * Get open interest for a trading pair.
193
+ * @param symbol - Trading pair symbol (required)
194
+ */
195
+ export async function getOpenInterest(symbol: string): Promise<OpenInterest | ApiError> {
196
+ if (!symbol) {
197
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "Symbol is required." };
198
+ }
199
+ return authenticatedGet("/api/v1/market/open-interest", { symbol: normalizeSymbol(symbol) });
200
+ }
201
+
202
+ /**
203
+ * Get recent trades for a trading pair.
204
+ * @param symbol - Trading pair symbol (required)
205
+ * @param options - Optional limit (max 500)
206
+ */
207
+ export async function getRecentTrades(symbol: string, options: RecentTradesOptions = {}): Promise<Trade[] | ApiError> {
208
+ if (!symbol) {
209
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "Symbol is required." };
210
+ }
211
+ return authenticatedGet("/api/v1/market/trades", {
212
+ symbol: normalizeSymbol(symbol),
213
+ limit: options.limit,
214
+ });
215
+ }
216
+
217
+ // ── Orders ──
218
+
219
+ /**
220
+ * Get active orders, optionally filtered by symbol.
221
+ * @param options - Optional symbol and limit filters
222
+ */
223
+ export async function getActiveOrders(options: ActiveOrdersOptions = {}): Promise<ActiveOrder[] | ApiError> {
224
+ return authenticatedGet("/api/trading/orders/active", {
225
+ symbol: options.symbol ? normalizeSymbol(options.symbol) : undefined,
226
+ limit: options.limit,
227
+ });
228
+ }
229
+
230
+ /**
231
+ * Cancel a specific order by ID.
232
+ * @param orderId - The order ID to cancel
233
+ */
234
+ export async function cancelOrder(orderId: string): Promise<CancelOrderResponse | ApiError> {
235
+ if (!orderId) {
236
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "Order ID is required." };
237
+ }
238
+ return authenticatedPost(`/api/trading/orders/${encodeURIComponent(orderId)}/cancel`);
239
+ }
240
+
241
+ /**
242
+ * Cancel all active orders, optionally filtered by symbol.
243
+ * @param options - Optional symbol filter
244
+ */
245
+ export async function cancelAllOrders(options: CancelAllOrdersOptions = {}): Promise<CancelAllOrdersResponse | ApiError> {
246
+ return authenticatedPost("/api/trading/orders/cancel-all", options.symbol ? { symbol: normalizeSymbol(options.symbol) } : undefined);
247
+ }
248
+
249
+ // ── Disclosures ──
250
+
251
+ /**
252
+ * Get amulet disclosure data for a party from the Temple REST API.
253
+ * Returns protocol disclosures (amulet rules, open mining rounds, external party amulet rules).
254
+ * @param partyId - Canton party ID
255
+ */
256
+ export async function getDisclosures(partyId: string): Promise<DisclosuresResponse | ApiError> {
257
+ if (!partyId) {
258
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "Party ID is required." };
259
+ }
260
+ return authenticatedGet("/api/amulet/disclosures", { partyId });
261
+ }
262
+
263
+ // ── Delegation ──
264
+
265
+ /**
266
+ * Get the user's trading delegation status.
267
+ */
268
+ export async function getDelegation(): Promise<DelegationResponse | ApiError> {
269
+ return authenticatedGet("/api/trading/delegation");
270
+ }
271
+
272
+ // ── Order Requests ──
273
+
274
+ /**
275
+ * Create an order request (limit buy/sell) on the Temple trading backend.
276
+ * @param opts - Order parameters: symbol, side, quantity, price, order_type, expires_at
277
+ */
278
+ export async function createOrderRequest(opts: CreateOrderRequestOpts): Promise<CreateOrderRequestResponse | ApiError> {
279
+ const { symbol: rawSymbol, side, quantity, price, order_type = "limit", order_subtype, expires_at } = opts || {};
280
+ if (!rawSymbol || !side || quantity == null || price == null) {
281
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "symbol, side, quantity, and price are required." };
282
+ }
283
+ const symbol = normalizeSymbol(rawSymbol);
284
+ const body: Record<string, unknown> = { symbol, side, quantity: Number(quantity), price: Number(price), order_type };
285
+ if (order_subtype) body.order_subtype = order_subtype;
286
+ if (expires_at) body.expires_at = expires_at;
287
+ return authenticatedPost("/api/trading/orders", body);
288
+ }
289
+
290
+ // ── Withdrawals ──
291
+
292
+ /**
293
+ * Create a withdrawal request.
294
+ * @param assetId - Instrument symbol (e.g. "USDCx", "Amulet")
295
+ * @param amount - Amount to withdraw
296
+ */
297
+ export async function createWithdrawalRequest(assetId: string, amount: string | number): Promise<WithdrawalResponse | ApiError> {
298
+ if (!assetId || amount == null) {
299
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "asset_id and amount are required." };
300
+ }
301
+ return authenticatedPost("/api/trading/withdrawals", { asset_id: normalizeSymbol(assetId), amount: String(amount) });
302
+ }
303
+
304
+ /**
305
+ * Get the status of a withdrawal request.
306
+ * @param requestId - The request ID returned by createWithdrawalRequest
307
+ */
308
+ export async function getWithdrawalRequestStatus(requestId: string | number): Promise<WithdrawalStatusResponse | ApiError> {
309
+ if (requestId == null) {
310
+ return { error: true, status: null, code: "INVALID_PARAMS", message: "requestId is required." };
311
+ }
312
+ return authenticatedGet(`/api/trading/withdrawals/${encodeURIComponent(requestId)}`);
313
+ }
314
+
315
+ /**
316
+ * Get the user's trading balances.
317
+ *
318
+ * GET /api/trading/balances
319
+ */
320
+ export async function getTradingBalance(): Promise<TradingBalanceResponse | ApiError> {
321
+ return authenticatedGet("/api/trading/balances");
322
+ }