@temple-digital-group/temple-canton-js 1.0.39-beta.0 → 1.0.39-beta.2

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
@@ -1,6 +1,6 @@
1
1
  # Temple Canton JS
2
2
 
3
- JavaScript SDK for interacting with the Temple Canton blockchain exchange. Supports CC, USDCx, and CBTC tokens on the Canton network.
3
+ JavaScript SDK for interacting with the Temple Canton blockchain exchange. Supports Amulet (CC), USDCx, and CBTC tokens on the Canton network.
4
4
 
5
5
  ## Installation
6
6
 
@@ -49,7 +49,7 @@ await initialize({
49
49
  AUTH0_CLIENT_ID: "your-client-id",
50
50
  AUTH0_CLIENT_SECRET: "your-client-secret",
51
51
  AUTH0_AUDIENCE: "your-audience",
52
- API_EMAIL: "user@example.com", // REST API login (optional)
52
+ API_EMAIL: "user@example.com",
53
53
  API_PASSWORD: "password",
54
54
  });
55
55
  ```
@@ -57,19 +57,19 @@ await initialize({
57
57
  | Key | Required | Description |
58
58
  | ------------------------- | -------- | ---------------------------------------------------- |
59
59
  | `NETWORK` | Yes | `mainnet`, `testnet`, or `localhost` |
60
- | `VALIDATOR_API_URL` | Yes | Base URL of the Canton validator ledger API |
61
- | `VALIDATOR_SCAN_API_URL` | Yes | Base URL of the Canton Scan API |
62
- | `VALIDATOR_USER_PARTY_ID` | Yes | The user's party ID on the network |
63
- | `JWT_TOKEN` | Yes\* | Pre-authenticated JWT token for ledger API calls |
64
- | `AUTH0_TOKEN_URL` | Yes\* | Auth0 OAuth token endpoint |
65
- | `AUTH0_CLIENT_ID` | Yes\* | Auth0 application client ID |
66
- | `AUTH0_CLIENT_SECRET` | Yes\* | Auth0 application client secret |
67
- | `AUTH0_AUDIENCE` | Yes\* | Auth0 API audience identifier |
68
- | `AUTH0_USER_ID` | Yes\* | Auth0 user ID for the service account |
60
+ | `VALIDATOR_API_URL` | No | Base URL of the Canton validator ledger API |
61
+ | `VALIDATOR_SCAN_API_URL` | No | Base URL of the Canton Scan API |
62
+ | `VALIDATOR_USER_PARTY_ID` | No | The user's party ID on the network |
63
+ | `JWT_TOKEN` | No\* | Pre-authenticated JWT token for ledger API calls |
64
+ | `AUTH0_TOKEN_URL` | No\* | Auth0 OAuth token endpoint |
65
+ | `AUTH0_CLIENT_ID` | No\* | Auth0 application client ID |
66
+ | `AUTH0_CLIENT_SECRET` | No\* | Auth0 application client secret |
67
+ | `AUTH0_AUDIENCE` | No\* | Auth0 API audience identifier |
68
+ | `AUTH0_USER_ID` | No\* | Auth0 user ID for the service account |
69
69
  | `API_EMAIL` | No | Temple REST API email (triggers login at init) |
70
70
  | `API_PASSWORD` | No | Temple REST API password (required with `API_EMAIL`) |
71
71
 
72
- \* Provide either `JWT_TOKEN` (browser) or the `AUTH0_*` fields (server-side). The SDK fetches and caches JWT tokens automatically when Auth0 credentials are provided.
72
+ \* Provide either `JWT_TOKEN` (browser) or the `AUTH0_*` fields (server-side). The SDK fetches and caches JWT tokens automatically when Auth0 credentials are provided. Only needed when using a custom validator.
73
73
 
74
74
  To update the JWT token later without re-initializing:
75
75
 
@@ -87,18 +87,12 @@ For apps using Loop Wallet. Pass the Loop SDK instance as `WALLET_ADAPTER` — t
87
87
  - **Client-side:** uses `loop.provider.submitTransaction()` (delegates signing to Loop Wallet via WebSocket)
88
88
 
89
89
  ```javascript
90
- import { initialize, createOrderProposal } from "@temple-digital-group/temple-canton-js";
90
+ import { initialize } from "@temple-digital-group/temple-canton-js";
91
91
 
92
92
  await initialize({
93
93
  NETWORK: "mainnet",
94
94
  WALLET_ADAPTER: loop, // Pass the Loop SDK instance
95
95
  });
96
-
97
- // Auto-submit: SDK handles signing and submission
98
- const result = await createOrderProposal(orderArgs);
99
-
100
- // Or get the raw command back for manual submission
101
- const command = await createOrderProposal(orderArgs, true);
102
96
  ```
103
97
 
104
98
  You can also set or change the wallet adapter after init:
@@ -120,137 +114,218 @@ setWalletAdapter(loop);
120
114
 
121
115
  ## Supported Instruments
122
116
 
123
- | Asset | Type | Networks |
124
- | ----- | ----------- | ---------------- |
125
- | CC | Canton Coin | testnet, mainnet |
126
- | USDCx | Utility | testnet, mainnet |
127
- | CBTC | Utility | testnet, mainnet |
117
+ | Asset | Type | Networks |
118
+ | ------ | ----------- | ---------------- |
119
+ | CC | Canton Coin | testnet, mainnet |
120
+ | USDCx | Utility | testnet, mainnet |
121
+ | CBTC | Utility | testnet, mainnet |
122
+
123
+ > **Symbol normalization:** `CC` is automatically normalized to `Amulet` in all API methods that accept a symbol (e.g. `CC/USDCx` becomes `Amulet/USDCx`).
128
124
 
129
125
  ## Supported Trading Pairs
130
126
 
131
127
  - `CC/USDCx`
132
128
  - `CBTC/USDCx`
133
129
 
134
- ## Usage
130
+ ## v2 Trading Flow
135
131
 
136
- ### Get User Balances
132
+ The v2 flow covers the full trading lifecycle: onboarding, deposits, trading, and withdrawals.
137
133
 
138
- ```javascript
139
- import { getUserBalances } from "@temple-digital-group/temple-canton-js";
134
+ ```
135
+ 1. Check onboarding → isUserOnboarded(party)
136
+ If NOT onboarded → onboardUser(party)
140
137
 
141
- // Both params are optional falls back to wallet adapter / config
142
- const balances = await getUserBalances();
138
+ 2. Deposit funds → depositFunds({ sender, assetId, amount, holdingCids, ... })
143
139
 
144
- // Or pass explicitly
145
- const balances = await getUserBalances(partyId);
146
- const balances = await getUserBalances(partyId, walletProvider);
140
+ 3. Check balance → getTradingBalance()
141
+
142
+ 4. Place orders → createOrderRequest({ symbol, side, quantity, price, ... })
143
+
144
+ 5. Cancel orders → cancelOrder(orderId) or cancelAllOrders({ symbol })
145
+
146
+ 6. Withdraw funds → withdrawFunds({ asset_id, amount })
147
+
148
+ 7. Withdraw delegation → withdrawDelegation(delegationId, user)
147
149
  ```
148
150
 
149
- Each entry in the returned array contains:
151
+ ### 1. Onboarding
152
+
153
+ Check if a user has a delegation contract, and create one if not:
150
154
 
151
155
  ```javascript
152
- {
153
- asset: 'USDCx', // Catalog symbol
154
- total_balance: 170.5, // Unlocked + locked combined
155
- available_balance: 150.5, // Unlocked balance (usable for orders)
156
- locked_balance: 20.0, // Locked balance
157
- dso: null, // DSO party (CC only)
158
- registrar: '...', // Registrar party (utility tokens)
159
- operator: '...', // Operator party
160
- provider: '...', // Provider party
161
- merge_warning: true, // true if multiple unlocked holdings exist
162
- holdings: [...], // Unlocked holding contracts
163
- locked_holdings: [...], // Locked holding contracts
164
- utilityContext: { ... } // CIP-56 context (null when using wallet provider)
156
+ import { isUserOnboarded, onboardUser } from "@temple-digital-group/temple-canton-js";
157
+
158
+ const delegation = await isUserOnboarded(party);
159
+ if (!delegation) {
160
+ await onboardUser(party);
165
161
  }
166
162
  ```
167
163
 
168
- > **Note:** `utilityContext` is only resolved when using a custom validator (ledger API access). When using a wallet provider, it will be `null`.
164
+ ### 2. Deposit Funds
169
165
 
170
- ### Create an Order
166
+ Deposit funds into the user's trading balance. Use `prepareDepositHoldings` to resolve the holdings for the deposit amount.
171
167
 
172
168
  ```javascript
173
- import { createOrderProposal } from "@temple-digital-group/temple-canton-js";
169
+ import { prepareDepositHoldings, depositFunds } from "@temple-digital-group/temple-canton-js";
174
170
 
175
- const result = await createOrderProposal({
176
- party: partyId,
177
- symbol: "CC/USDCx",
178
- side: "Buy",
179
- quantity: "100",
180
- pricePerUnit: "1.5",
181
- expiration: new Date(Date.now() + 3600000).toISOString(),
182
- userId: auth0UserId, // Optional if authenticated via REST API — auto-resolved from login
183
- orderType: "limit",
184
- });
171
+ // Prepare holdings for the deposit
172
+ const depositOpts = await prepareDepositHoldings(100, "USDCx");
173
+
174
+ // Submit the deposit
175
+ const result = await depositFunds(depositOpts);
185
176
  ```
186
177
 
187
- #### Handling Stale Holdings (Wallet Provider)
178
+ `depositFunds` accepts:
188
179
 
189
- When a holding is used in an order, the contract is archived on-ledger and a new one is created. If the wallet provider hasn't caught up yet, it may still return the old (archived) holding, causing the next order to fail.
180
+ | Option | Required | Description |
181
+ | ---------------- | -------- | ------------------------------------------------------------- |
182
+ | `sender` | Yes | Party allocating the assets |
183
+ | `assetId` | Yes | Instrument symbol (`USDCx`, `Amulet`, `CBTC`) |
184
+ | `amount` | Yes | Amount to allocate |
185
+ | `holdingCids` | Yes | Holding contract IDs that fund the allocation |
186
+ | `receiver` | No | Counterparty (defaults to sender) |
187
+ | `settlementId` | No | Reference ID for the settlement |
188
+ | `transferLegId` | No | Unique ID for this transfer leg |
189
+ | `allocateBefore` | No | ISO timestamp; allocation deadline (default: +1h) |
190
+ | `settleBefore` | No | ISO timestamp; settlement deadline (default: +2h) |
191
+ | `disclosures` | No | Pre-fetched Amulet disclosures (for FE without API access) |
192
+ | `userId` | No | Ledger API user ID (falls back to wallet adapter / config) |
190
193
 
191
- **Auto-submit (`returnCommand = false`):** The SDK handles this automatically. If a stale holding error is detected, it waits for the provider to sync and retries up to 3 times.
194
+ For Amulet deposits without direct ledger or Scan API access, the SDK fetches disclosures from `/api/amulet/disclosures` automatically. You can also pass them manually via `opts.disclosures`.
192
195
 
193
- **Manual submit (`returnCommand = true`):** You are responsible for handling stale holdings. `createOrderProposal` returns a `holdingContractId` — the contract ID of the holding that was selected. You can poll until it disappears from the provider's active contracts:
196
+ ### 3. Trading Balance
194
197
 
195
198
  ```javascript
196
- import { createOrderProposal, getAmuletHoldingsForParty } from "@temple-digital-group/temple-canton-js";
199
+ import { getTradingBalance } from "@temple-digital-group/temple-canton-js";
197
200
 
198
- const { command, holdingContractId } = await createOrderProposal(orderArgs, true);
199
- const result = await walletProvider.submitTransaction(command);
201
+ const balances = await getTradingBalance();
202
+ // Returns { balances: [{ asset, unlocked, locked, in_flight, ... }] }
203
+ ```
200
204
 
201
- // Poll until the provider catches up before creating next order
202
- async function waitForProviderSync(contractId, party, provider, interval = 500, maxAttempts = 20) {
203
- for (let i = 0; i < maxAttempts; i++) {
204
- const holdings = await getAmuletHoldingsForParty(party, false, provider);
205
- const stillActive = holdings?.some((h) => h.contractEntry?.JsActiveContract?.createdEvent?.contractId === contractId);
206
- if (!stillActive) return true; // Provider caught up
207
- await new Promise((r) => setTimeout(r, interval));
208
- }
209
- return false; // Timed out
210
- }
205
+ ### 4. Place Orders
206
+
207
+ ```javascript
208
+ import { createOrderRequest } from "@temple-digital-group/temple-canton-js";
209
+
210
+ const result = await createOrderRequest({
211
+ symbol: "Amulet/USDCx",
212
+ side: "buy",
213
+ quantity: 10.5,
214
+ price: 1.25,
215
+ order_type: "limit",
216
+ expires_at: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
217
+ });
218
+ ```
211
219
 
212
- await waitForProviderSync(holdingContractId, party, walletProvider);
213
- // Safe to create next order
220
+ ### 5. Cancel Orders
221
+
222
+ ```javascript
223
+ import { cancelOrder, cancelAllOrders } from "@temple-digital-group/temple-canton-js";
224
+
225
+ // Cancel a specific order
226
+ await cancelOrder("order-id-123");
227
+
228
+ // Cancel all orders for a symbol
229
+ await cancelAllOrders({ symbol: "Amulet/USDCx" });
230
+
231
+ // Cancel ALL orders
232
+ await cancelAllOrders();
214
233
  ```
215
234
 
216
- > `holdingContractId` is included in success responses, error responses, and `returnCommand` responses.
235
+ ### 6. Withdraw Funds
217
236
 
218
- ### Get Orders and Proposals
237
+ Withdraws available (unlocked, non-in-flight) trading balance back to the user's wallet.
219
238
 
220
239
  ```javascript
221
- import { getOrdersForParty, getOrderProposalsForParty } from "@temple-digital-group/temple-canton-js";
240
+ import { withdrawFunds } from "@temple-digital-group/temple-canton-js";
222
241
 
223
- const orders = await getOrdersForParty(partyId);
224
- const proposals = await getOrderProposalsForParty(partyId);
242
+ const result = await withdrawFunds({
243
+ asset_id: "USDCx",
244
+ amount: "250.50",
245
+ });
225
246
  ```
226
247
 
227
- ### REST API (Optional) — Market Data and Orders
248
+ ### 7. Emergency Withdraw
228
249
 
229
- The REST API functions are optional. If you pass `API_EMAIL`/`API_PASSWORD` in `initialize()`, the SDK authenticates at init time. You can also call `login()` directly.
250
+ Cancels ALL orders, rolls back pending settlements, and withdraws everything immediately.
230
251
 
231
252
  ```javascript
232
- import { initialize, getTicker, getOrderBook, getActiveOrders, cancelOrder } from "@temple-digital-group/temple-canton-js";
253
+ import { emergencyWithdrawFunds } from "@temple-digital-group/temple-canton-js";
233
254
 
234
- await initialize({
235
- NETWORK: "mainnet",
236
- API_EMAIL: "user@example.com",
237
- API_PASSWORD: "password",
255
+ const result = await emergencyWithdrawFunds({
256
+ allocationId: "allocation-contract-id",
257
+ sender: partyId,
258
+ assetId: "USDCx",
238
259
  });
260
+ ```
261
+
262
+ ### 8. Withdraw Delegation
263
+
264
+ Archives the user's delegation contract. The user must re-onboard to trade again.
239
265
 
240
- // Market data
241
- const ticker = await getTicker("CC/USDCx");
242
- const book = await getOrderBook("CC/USDCx", { levels: 10 });
266
+ ```javascript
267
+ import { withdrawDelegation } from "@temple-digital-group/temple-canton-js";
268
+
269
+ // Auto-fetches delegation from API if not passed
270
+ await withdrawDelegation();
271
+
272
+ // Or pass explicitly
273
+ await withdrawDelegation(delegationContractId, partyId);
274
+ ```
275
+
276
+ ## Wallet Balances
277
+
278
+ ### Get User Balances
243
279
 
244
- // Orders
245
- const orders = await getActiveOrders({ symbol: "CC/USDCx" });
246
- const result = await cancelOrder("order-id-123");
280
+ ```javascript
281
+ import { getUserBalances } from "@temple-digital-group/temple-canton-js";
247
282
 
248
- // All functions return { error: true, status, code, message } on failure
249
- if (result.error) {
250
- console.log(`Failed: ${result.message}`);
283
+ // Both params are optional falls back to wallet adapter / config
284
+ const balances = await getUserBalances();
285
+
286
+ // Or pass explicitly
287
+ const balances = await getUserBalances(partyId);
288
+ const balances = await getUserBalances(partyId, walletProvider);
289
+ ```
290
+
291
+ Each entry in the returned array contains:
292
+
293
+ ```javascript
294
+ {
295
+ asset: 'USDCx',
296
+ total_balance: 170.5,
297
+ available_balance: 150.5,
298
+ locked_balance: 20.0,
299
+ dso: null,
300
+ registrar: '...',
301
+ operator: '...',
302
+ provider: '...',
303
+ merge_warning: true,
304
+ holdings: [...],
305
+ locked_holdings: [...],
306
+ utilityContext: { ... }
251
307
  }
252
308
  ```
253
309
 
310
+ ## Legacy Order Creation
311
+
312
+ > `createOrderProposal` is the legacy on-ledger order creation method. For v2 trading, use `createOrderRequest` instead.
313
+
314
+ ```javascript
315
+ import { createOrderProposal } from "@temple-digital-group/temple-canton-js";
316
+
317
+ const result = await createOrderProposal({
318
+ party: partyId,
319
+ symbol: "CC/USDCx",
320
+ side: "Buy",
321
+ quantity: "100",
322
+ pricePerUnit: "1.5",
323
+ expiration: new Date(Date.now() + 3600000).toISOString(),
324
+ userId: auth0UserId,
325
+ orderType: "limit",
326
+ });
327
+ ```
328
+
254
329
  ### Merge Holdings
255
330
 
256
331
  ```javascript
@@ -269,17 +344,13 @@ const disclosures = await getAmuletDisclosures(partyId);
269
344
  const cmd = await mergeAmuletHoldingsForParty(partyId, true, walletProvider, 5, disclosures);
270
345
  const res = await walletProvider.submitTransaction(cmd);
271
346
 
272
- // Check UTXO status after merge — confirm the order amount is now covered
347
+ // Check UTXO status after merge
273
348
  const counts = await getUtxoCount(partyId, "USDCx", walletProvider);
274
- // { total: 5, unlocked: 1, locked: 4, largestUnlocked: 27.26, unlockedBalance: 27.26 }
275
- if (counts.largestUnlocked >= requiredAmount) {
276
- // Safe to retry createOrderProposal
277
- }
278
349
  ```
279
350
 
280
351
  ## API Reference
281
352
 
282
- > Functions marked with **W** support Loop Wallet via the wallet adapter. All other functions require a custom validator (ledger access via `VALIDATOR_API_URL` and `JWT_TOKEN`).
353
+ > Functions marked with **W** support Loop Wallet via the wallet adapter.
283
354
 
284
355
  ### Configuration
285
356
 
@@ -296,17 +367,43 @@ if (counts.largestUnlocked >= requiredAmount) {
296
367
  | `getSupportedTradingPairs()` | Get the list of supported trading pairs |
297
368
  | `getInstrumentCatalog()` | Get the full instrument catalog |
298
369
 
370
+ ### Onboarding & Delegation
371
+
372
+ | Function | Provider | Description |
373
+ | ------------------------------------- | -------- | ------------------------------------------------------ |
374
+ | `isUserOnboarded(party)` | **W** | Check if user has a delegation contract on ledger |
375
+ | `onboardUser(party)` | **W** | Create the delegation contract needed for trading |
376
+ | `withdrawDelegation(delegationId?, user?)` | **W** | Archive the delegation contract (user must re-onboard) |
377
+
378
+ ### Deposits & Withdrawals
379
+
380
+ | Function | Provider | Description |
381
+ | ---------------------------------------- | -------- | ------------------------------------------------------------ |
382
+ | `prepareDepositHoldings(amount, assetId)` | **W** | Resolve holdings for a deposit amount |
383
+ | `depositFunds(opts)` | **W** | Deposit funds into the user's trading balance |
384
+ | `withdrawFunds({ asset_id, amount })` | **W** | Withdraw available trading balance back to wallet |
385
+ | `emergencyWithdrawFunds(opts)` | **W** | Cancel all orders and withdraw everything immediately |
386
+
299
387
  ### Holdings
300
388
 
301
389
  | Function | Provider | Description |
302
390
  | ----------------------------------------------------------------- | -------- | -------------------------------------------------------------- |
303
- | `getUserBalances(party?, provider?)` | **W** | Get all balances grouped by asset (CC, locked CC, and utility) |
304
- | `getAmuletHoldingsForParty(party, returnCommand, provider)` | **W** | Get CC holdings |
305
- | `getLockedAmuletHoldingsForParty(party, returnCommand, provider)`| **W** | Get locked CC holdings |
391
+ | `getUserBalances(party?, provider?)` | **W** | Get all balances grouped by asset (Amulet, locked, and utility) |
392
+ | `getAmuletHoldingsForParty(party, returnCommand, provider)` | **W** | Get Amulet holdings |
393
+ | `getLockedAmuletHoldingsForParty(party, returnCommand, provider)`| **W** | Get locked Amulet holdings |
306
394
  | `getUtilityHoldingsForParty(party, returnCommand, provider)` | **W** | Get utility token holdings |
307
395
  | `getUtxoCount(party, assetId, provider)` | **W** | Get UTXO summary: counts, largest unlocked amount, and total unlocked balance |
308
396
 
309
- ### Orders
397
+ ### Holding Operations
398
+
399
+ | Function | Provider | Description |
400
+ | ------------------------------------------------------------------------------------------ | -------- | ------------------------------ |
401
+ | `mergeAmuletHoldingsForParty(party, returnCommand, provider, maxUtxos, amuletDisclosures)` | **W** | Merge Amulet holdings into one |
402
+ | `mergeUtilityHoldingsForParty(party, utilityAsset, returnCommand, provider, maxUtxos)` | **W** | Merge utility holdings into one |
403
+ | `splitAmuletHoldingForParty(party, outputQuantity)` | | Split an Amulet holding |
404
+ | `unlockLockedAmulets(party)` | | Unlock locked Amulet holdings |
405
+
406
+ ### Legacy Orders (On-Ledger)
310
407
 
311
408
  | Function | Provider | Description |
312
409
  | ------------------------------------- | -------- | --------------------------- |
@@ -314,18 +411,9 @@ if (counts.largestUnlocked >= requiredAmount) {
314
411
  | `getOrderProposalsForParty(party)` | | Get pending order proposals |
315
412
  | `getOrdersForParty(party)` | | Get active orders |
316
413
 
317
- ### Holding Operations
318
-
319
- | Function | Provider | Description |
320
- | ------------------------------------------------------------------------------------------ | -------- | --------------------------- |
321
- | `mergeAmuletHoldingsForParty(party, returnCommand, provider, maxUtxos, amuletDisclosures)` | **W** | Merge CC holdings into one |
322
- | `mergeUtilityHoldingsForParty(party, utilityAsset, returnCommand, provider, maxUtxos)` | **W** | Merge utility holdings into one |
323
- | `splitAmuletHoldingForParty(party, outputQuantity)` | | Split a CC holding |
324
- | `unlockLockedAmulets(party)` | | Unlock locked CC holdings |
414
+ ### Temple REST API
325
415
 
326
- ### Temple REST API (Optional)
327
-
328
- > These functions call the Temple public REST API and are entirely optional. Pass `API_EMAIL`/`API_PASSWORD` in `initialize()`, or call `login()` directly — tokens are stored and auto-refreshed.
416
+ > These functions call the Temple REST API. Pass `API_EMAIL`/`API_PASSWORD` in `initialize()`, or call `login()` directly — tokens are stored and auto-refreshed.
329
417
 
330
418
  #### Auth
331
419
 
@@ -334,7 +422,7 @@ if (counts.largestUnlocked >= requiredAmount) {
334
422
  | `login(email, password)` | Login and store access/refresh tokens and user profile |
335
423
  | `refreshAccessToken(refreshToken?)` | Refresh the access token (auto-called when expired) |
336
424
  | `logout()` | Clear stored tokens |
337
- | `getUserId()` | Get the stored user ID from login (used automatically by `createOrderProposal`) |
425
+ | `getUserId()` | Get the stored user ID from login |
338
426
 
339
427
  #### Market Data
340
428
 
@@ -346,16 +434,26 @@ if (counts.largestUnlocked >= requiredAmount) {
346
434
  | `getOpenInterest(symbol)` | Get open interest for a trading pair |
347
435
  | `getRecentTrades(symbol, options?)` | Get recent trades (options: `limit`, max 500) |
348
436
 
349
- #### Orders
437
+ #### Trading
438
+
439
+ | Function | Description |
440
+ | ------------------------------------------- | ---------------------------------------------- |
441
+ | `createOrderRequest(opts)` | Place a buy/sell order via the trading backend |
442
+ | `cancelOrder(orderId)` | Cancel a specific order |
443
+ | `cancelAllOrders(options?)` | Cancel all orders (options: `symbol` filter) |
444
+ | `getTradingBalance()` | Get user's trading balance (unlocked/locked/in-flight) |
445
+ | `getActiveOrders(options?)` | Get active orders (options: `symbol`, `limit`) |
446
+
447
+ #### Withdrawals
350
448
 
351
- | Function | Description |
352
- | --------------------------- | ---------------------------------------------- |
353
- | `getActiveOrders(options?)` | Get active orders (options: `symbol`, `limit`) |
354
- | `cancelOrder(orderId)` | Cancel a specific order |
355
- | `cancelAllOrders(options?)` | Cancel all orders (options: `symbol` filter) |
449
+ | Function | Description |
450
+ | ------------------------------------------- | ------------------------------------------------------ |
451
+ | `createWithdrawalRequest(assetId, amount)` | Submit a withdrawal request to the backend |
452
+ | `getWithdrawalRequestStatus(requestId)` | Poll withdrawal status until ready |
356
453
 
357
- #### Disclosures
454
+ #### Disclosures & Delegation
358
455
 
359
456
  | Function | Description |
360
457
  | ------------------------- | ------------------------------------------------------------------------------- |
361
- | `getDisclosures(partyId)` | Get CC disclosure data (amulet rules, open mining rounds, external party rules) |
458
+ | `getDisclosures(partyId)` | Get Amulet disclosure data (factory ID, choice context, disclosed contracts) |
459
+ | `getDelegation()` | Get the user's delegation contract from the API |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temple-digital-group/temple-canton-js",
3
- "version": "1.0.39-beta.0",
3
+ "version": "1.0.39-beta.2",
4
4
  "description": "JavaScript library for interacting with Temple Canton blockchain",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -2847,11 +2847,15 @@ export async function unlockLockedAmulets(party, returnCommand = false) {
2847
2847
  * @param {Object|null} [provider=null] - Optional wallet provider.
2848
2848
  * @returns {Promise<Object>} Object matching depositFunds opts shape, or { error }.
2849
2849
  */
2850
- export async function prepareDepositHoldings(amount, symbol, provider = null) {
2851
- provider = resolveProvider(provider);
2850
+ export async function prepareDepositHoldings(amount, symbol) {
2851
+ const provider = resolveProvider(null);
2852
+ if (!provider && !config.VALIDATOR_SCAN_API_URL) {
2853
+ return { error: "prepareDepositHoldings: wallet provider is required to prepare holdings. Connect a wallet adapter." };
2854
+ }
2855
+
2852
2856
  const party = getAdapterPartyId() ?? config.VALIDATOR_USER_PARTY_ID;
2853
2857
  if (!party) {
2854
- return { error: "prepareDepositHoldings: party ID is required. Set WALLET_ADAPTER or configure VALIDATOR_USER_PARTY_ID." };
2858
+ return { error: "prepareDepositHoldings: party ID is required. Connect a wallet adapter or configure VALIDATOR_USER_PARTY_ID." };
2855
2859
  }
2856
2860
 
2857
2861
  // Normalize symbol: CC → Amulet
@@ -2880,6 +2884,10 @@ export async function prepareDepositHoldings(amount, symbol, provider = null) {
2880
2884
  const createdEvent = h.contractEntry?.JsActiveContract?.createdEvent;
2881
2885
  if (!createdEvent) continue;
2882
2886
 
2887
+ // Skip asset types that don't match the requested symbol
2888
+ const createdAssetId = createdEvent.createArgument?.instrument?.id || (isAmulet ? "Amulet" : null);
2889
+ if (createdAssetId !== assetId) continue;
2890
+
2883
2891
  // Skip locked utility holdings
2884
2892
  if (!isAmulet && createdEvent.createArgument?.lock) continue;
2885
2893
 
@@ -3752,9 +3760,14 @@ export async function isUserOnboarded(user = null, returnCommand = false) {
3752
3760
  */
3753
3761
  export async function getUserBalances(party = null, provider = null) {
3754
3762
  provider = resolveProvider(provider);
3763
+ if (!provider && !config.VALIDATOR_API_URL) {
3764
+ const msg = "getUserBalances: no provider or API URL configured. Set up a wallet adapter or configure VALIDATOR_API_URL.";
3765
+ console.error(msg);
3766
+ return { error: msg };
3767
+ }
3755
3768
  party = party ?? getAdapterPartyId() ?? config.VALIDATOR_USER_PARTY_ID;
3756
3769
  if (!party) {
3757
- return { error: "Party ID is required. Pass it directly, set WALLET_ADAPTER, or configure VALIDATOR_USER_PARTY_ID." };
3770
+ return { error: "Party ID is required. Pass it directly, connect a wallet adapter, or configure VALIDATOR_USER_PARTY_ID." };
3758
3771
  }
3759
3772
  // Get all supported instrument IDs from the catalog
3760
3773
  const supportedInstruments = new Set(Object.keys(instrumentCatalog));