context-markets-cli 0.1.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.
@@ -0,0 +1,448 @@
1
+ import {
2
+ formatAddress,
3
+ formatDate,
4
+ formatPrice,
5
+ truncate
6
+ } from "./chunk-IRVQREUN.js";
7
+ import {
8
+ readClient,
9
+ tradingClient
10
+ } from "./chunk-BUZKJ7FR.js";
11
+ import {
12
+ confirmAction,
13
+ confirmOrder
14
+ } from "./chunk-BJIFIOK6.js";
15
+ import {
16
+ fail,
17
+ out,
18
+ requireFlag,
19
+ requirePositional
20
+ } from "./chunk-QC6BGRUQ.js";
21
+
22
+ // src/commands/orders.ts
23
+ var HELP = `Usage: context orders <subcommand> [options]
24
+
25
+ Subcommands:
26
+ list List orders
27
+ --trader <address> Filter by trader (uses readClient)
28
+ --market <id> Filter by market
29
+ --status <status> Filter by status
30
+ --cursor <token> Pagination cursor
31
+ --limit <n> Max results
32
+
33
+ mine List your own orders (requires signer)
34
+ --market <id> Filter by market
35
+
36
+ get <id> Get a single order by ID
37
+
38
+ recent Recent orders (requires signer)
39
+ --trader <address> Filter by trader
40
+ --market <id> Filter by market
41
+ --status <status> Filter by status
42
+ --limit <n> Max results
43
+ --window-seconds <n> Time window in seconds
44
+
45
+ simulate Simulate an order (read-only)
46
+ --market <id> (required) Market ID
47
+ --outcome <yes|no> Outcome (default: yes)
48
+ --side <bid|ask> Side (default: bid)
49
+ --price <n> Max price
50
+ --size <n> Max size
51
+ --trader <address> Trader address
52
+
53
+ create Place a limit order (requires signer)
54
+ --market <id> (required) Market ID
55
+ --outcome <yes|no> (required) Outcome
56
+ --side <buy|sell> (required) Side
57
+ --price <1-99> (required) Price in cents
58
+ --size <n> (required) Size (>=1)
59
+ --expiry-seconds <n> Expiry in seconds (optional)
60
+ --inventory-mode <mode> any (default), hold (require tokens), mint (mint on fill)
61
+ --maker-role <role> any (default), taker (fill-only). Do NOT use maker \u2014 breaks settlement.
62
+
63
+ market Place a market order (requires signer)
64
+ --market <id> (required) Market ID
65
+ --outcome <yes|no> (required) Outcome
66
+ --side <buy|sell> (required) Side
67
+ --max-price <1-99> (required) Max price in cents
68
+ --max-size <n> (required) Max size (>=1)
69
+ --expiry-seconds <n> Expiry in seconds (optional)
70
+
71
+ cancel <nonce> Cancel an order by nonce (requires signer)
72
+
73
+ cancel-replace <nonce> Cancel and replace an order (requires signer)
74
+ (same flags as create)
75
+
76
+ bulk-create Create multiple orders (requires signer)
77
+ --orders <json> JSON array of PlaceOrderRequest objects
78
+
79
+ bulk-cancel Cancel multiple orders (requires signer)
80
+ --nonces <hex,hex,...> Comma-separated nonces
81
+
82
+ bulk Create and cancel in one call (requires signer)
83
+ --creates <json> JSON array of PlaceOrderRequest objects
84
+ --cancels <hex,hex,...> Comma-separated nonces to cancel
85
+
86
+ help Show this help text
87
+
88
+ Global options:
89
+ --api-key <key> Context API key (or CONTEXT_API_KEY env)
90
+ --private-key <key> Private key for signing (or CONTEXT_PRIVATE_KEY env)`;
91
+ async function handleOrders(parsed) {
92
+ const { subcommand, positional, flags } = parsed;
93
+ switch (subcommand) {
94
+ case "list":
95
+ return list(flags);
96
+ case "mine":
97
+ return mine(flags);
98
+ case "get":
99
+ return get(positional, flags);
100
+ case "recent":
101
+ return recent(flags);
102
+ case "simulate":
103
+ return simulate(flags);
104
+ case "create":
105
+ return create(flags);
106
+ case "market":
107
+ return marketOrder(flags);
108
+ case "cancel":
109
+ return cancel(positional, flags);
110
+ case "cancel-replace":
111
+ return cancelReplace(positional, flags);
112
+ case "bulk-create":
113
+ return bulkCreate(flags);
114
+ case "bulk-cancel":
115
+ return bulkCancel(flags);
116
+ case "bulk":
117
+ return bulk(flags);
118
+ case "help":
119
+ case void 0:
120
+ console.log(HELP);
121
+ return;
122
+ default:
123
+ fail(`Unknown orders subcommand: "${subcommand}". Run "context orders help" for usage.`);
124
+ }
125
+ }
126
+ var ORDER_LIST_COLUMNS = [
127
+ { key: "nonce", label: "Nonce", format: (v) => truncate(v, 14) },
128
+ { key: "marketId", label: "Market", format: (v) => truncate(v, 14) },
129
+ { key: "side", label: "Side", format: (v) => String(v ?? "\u2014").toUpperCase() },
130
+ { key: "outcomeIndex", label: "Outcome", format: (v) => v === 1 || v === "1" ? "YES" : "NO" },
131
+ { key: "price", label: "Price", format: (v) => formatPrice(v) },
132
+ { key: "size", label: "Size", format: (v) => String(v ?? "\u2014") },
133
+ { key: "status", label: "Status", format: (v) => String(v ?? "\u2014") },
134
+ { key: "percentFilled", label: "Filled", format: (v) => v != null ? `${v}%` : "\u2014" }
135
+ ];
136
+ async function list(flags) {
137
+ const ctx = flags["trader"] ? readClient(flags) : tradingClient(flags);
138
+ const result = await ctx.orders.list({
139
+ trader: flags["trader"] || void 0,
140
+ marketId: flags["market"] || void 0,
141
+ status: flags["status"] || void 0,
142
+ cursor: flags["cursor"] || void 0,
143
+ limit: flags["limit"] ? parseInt(flags["limit"], 10) : void 0
144
+ });
145
+ out(result, {
146
+ rows: result.orders || [],
147
+ columns: ORDER_LIST_COLUMNS,
148
+ numbered: true,
149
+ emptyMessage: "No orders found.",
150
+ cursor: result.cursor || null
151
+ });
152
+ }
153
+ async function mine(flags) {
154
+ const ctx = tradingClient(flags);
155
+ const result = await ctx.orders.mine(flags["market"] || void 0);
156
+ out(result, {
157
+ rows: result.orders || [],
158
+ columns: ORDER_LIST_COLUMNS,
159
+ numbered: true,
160
+ emptyMessage: "No orders found.",
161
+ cursor: result.cursor || null
162
+ });
163
+ }
164
+ async function get(positional, flags) {
165
+ const id = requirePositional(positional, 0, "id", "context orders get <id>");
166
+ const ctx = readClient(flags);
167
+ const order = await ctx.orders.get(id);
168
+ const o = order;
169
+ out(order, {
170
+ detail: [
171
+ ["Nonce", String(o.nonce || "\u2014")],
172
+ ["Market", String(o.marketId || "\u2014")],
173
+ ["Status", String(o.status || "\u2014")],
174
+ ["Side", String(o.side ?? "\u2014").toUpperCase()],
175
+ ["Outcome", o.outcomeIndex === 1 || o.outcomeIndex === "1" ? "YES" : "NO"],
176
+ ["Price", formatPrice(o.price)],
177
+ ["Size", String(o.size || "\u2014")],
178
+ ["Filled", o.percentFilled != null ? `${o.percentFilled}%` : "\u2014"],
179
+ ["Trader", formatAddress(o.trader)],
180
+ ["Created", formatDate(o.insertedAt)]
181
+ ]
182
+ });
183
+ }
184
+ async function recent(flags) {
185
+ const ctx = tradingClient(flags);
186
+ const result = await ctx.orders.recent({
187
+ trader: flags["trader"] || void 0,
188
+ marketId: flags["market"] || void 0,
189
+ status: flags["status"] || void 0,
190
+ limit: flags["limit"] ? parseInt(flags["limit"], 10) : void 0,
191
+ windowSeconds: flags["window-seconds"] ? parseInt(flags["window-seconds"], 10) : void 0
192
+ });
193
+ out(result, {
194
+ rows: result.orders || [],
195
+ columns: ORDER_LIST_COLUMNS,
196
+ numbered: true,
197
+ emptyMessage: "No orders found.",
198
+ cursor: result.cursor || null
199
+ });
200
+ }
201
+ async function simulate(flags) {
202
+ const marketId = requireFlag(flags, "market", "context orders simulate --market <id>");
203
+ const trader = requireFlag(flags, "trader", "context orders simulate --market <id> --trader <address> --size <n> --price <n>");
204
+ const sizeRaw = requireFlag(flags, "size", "context orders simulate --market <id> --trader <address> --size <n> --price <n>");
205
+ const priceRaw = requireFlag(flags, "price", "context orders simulate --market <id> --trader <address> --size <n> --price <n>");
206
+ const outcome = flags["outcome"] ?? "yes";
207
+ if (outcome !== "yes" && outcome !== "no") {
208
+ fail("--outcome must be 'yes' or 'no'", { received: outcome });
209
+ }
210
+ const side = flags["side"] ?? "bid";
211
+ if (side !== "bid" && side !== "ask") {
212
+ fail("--side must be 'bid' or 'ask'", { received: side });
213
+ }
214
+ const ctx = readClient(flags);
215
+ const result = await ctx.orders.simulate({
216
+ marketId,
217
+ trader,
218
+ maxSize: sizeRaw,
219
+ maxPrice: priceRaw,
220
+ outcomeIndex: outcome === "yes" ? 1 : 0,
221
+ side
222
+ });
223
+ out(result);
224
+ }
225
+ function parsePlaceOrderFlags(flags, usage) {
226
+ const marketId = requireFlag(flags, "market", usage);
227
+ const outcome = requireFlag(flags, "outcome", usage);
228
+ const side = requireFlag(flags, "side", usage);
229
+ const priceRaw = requireFlag(flags, "price", usage);
230
+ const sizeRaw = requireFlag(flags, "size", usage);
231
+ if (outcome !== "yes" && outcome !== "no") {
232
+ fail("--outcome must be 'yes' or 'no'", { received: outcome });
233
+ }
234
+ if (side !== "buy" && side !== "sell") {
235
+ fail("--side must be 'buy' or 'sell'", { received: side });
236
+ }
237
+ const priceCents = parseInt(priceRaw, 10);
238
+ if (isNaN(priceCents) || priceCents < 1 || priceCents > 99) {
239
+ fail("--price must be between 1 and 99 (cents)", { received: priceRaw });
240
+ }
241
+ const size = parseFloat(sizeRaw);
242
+ if (isNaN(size) || size < 1) {
243
+ fail("--size must be >= 1", { received: sizeRaw });
244
+ }
245
+ const INVENTORY_MODES = { any: 0, hold: 1, mint: 2 };
246
+ const MAKER_ROLES = { any: 0, taker: 2 };
247
+ let inventoryMode;
248
+ if (flags["inventory-mode"]) {
249
+ inventoryMode = INVENTORY_MODES[flags["inventory-mode"]];
250
+ if (inventoryMode === void 0) {
251
+ fail("--inventory-mode must be 'any', 'hold', or 'mint'", { received: flags["inventory-mode"] });
252
+ }
253
+ }
254
+ let makerRole;
255
+ if (flags["maker-role"]) {
256
+ if (flags["maker-role"] === "maker" || flags["maker-role"] === "1") {
257
+ fail("makerRoleConstraint=1 (maker/post-only) breaks settlement when two maker-only orders cross \u2014 use 'any' instead", { received: flags["maker-role"] });
258
+ }
259
+ makerRole = MAKER_ROLES[flags["maker-role"]];
260
+ if (makerRole === void 0) {
261
+ fail("--maker-role must be 'any' or 'taker'", { received: flags["maker-role"] });
262
+ }
263
+ }
264
+ return {
265
+ marketId,
266
+ outcome,
267
+ side,
268
+ priceCents,
269
+ size,
270
+ expirySeconds: flags["expiry-seconds"] ? parseInt(flags["expiry-seconds"], 10) : void 0,
271
+ inventoryModeConstraint: inventoryMode,
272
+ makerRoleConstraint: makerRole
273
+ };
274
+ }
275
+ async function create(flags) {
276
+ const usage = "context orders create --market <id> --outcome <yes|no> --side <buy|sell> --price <1-99> --size <n>";
277
+ const order = parsePlaceOrderFlags(flags, usage);
278
+ await confirmOrder({
279
+ market: order.marketId,
280
+ side: order.side,
281
+ outcome: order.outcome,
282
+ price: `${order.priceCents}\xA2`,
283
+ size: String(order.size),
284
+ estimatedCost: `$${(order.priceCents / 100 * order.size).toFixed(2)} USDC`
285
+ }, flags);
286
+ const ctx = tradingClient(flags);
287
+ const result = await ctx.orders.create(order);
288
+ const r = result;
289
+ out(result, {
290
+ detail: [
291
+ ["Status", r.success ? "\u2713 Order placed" : "\u2717 Failed"],
292
+ ["Nonce", String(r.order?.nonce || "\u2014")],
293
+ ["Market", String(r.order?.marketId || "\u2014")],
294
+ ["Type", String(r.order?.type || "\u2014")],
295
+ ["Order Status", String(r.order?.status || "\u2014")],
296
+ ["Filled", r.order?.percentFilled != null ? `${r.order.percentFilled}%` : "\u2014"]
297
+ ]
298
+ });
299
+ }
300
+ async function cancel(positional, flags) {
301
+ const nonce = requirePositional(
302
+ positional,
303
+ 0,
304
+ "nonce",
305
+ "context orders cancel <nonce>"
306
+ );
307
+ await confirmAction(`Cancel order ${nonce}?`, flags);
308
+ const ctx = tradingClient(flags);
309
+ const result = await ctx.orders.cancel(nonce);
310
+ const r = result;
311
+ out(result, {
312
+ detail: [
313
+ ["Status", r.success ? "\u2713 Cancelled" : "\u2717 Failed"],
314
+ ["Already Cancelled", String(r.alreadyCancelled ?? "\u2014")]
315
+ ]
316
+ });
317
+ }
318
+ async function cancelReplace(positional, flags) {
319
+ const nonce = requirePositional(
320
+ positional,
321
+ 0,
322
+ "nonce",
323
+ "context orders cancel-replace <nonce> --market <id> --outcome <yes|no> --side <buy|sell> --price <1-99> --size <n>"
324
+ );
325
+ const usage = "context orders cancel-replace <nonce> --market <id> --outcome <yes|no> --side <buy|sell> --price <1-99> --size <n>";
326
+ const newOrder = parsePlaceOrderFlags(flags, usage);
327
+ await confirmAction(`Cancel order ${nonce} and place replacement?`, flags);
328
+ const ctx = tradingClient(flags);
329
+ const result = await ctx.orders.cancelReplace(nonce, newOrder);
330
+ const r = result;
331
+ out(result, {
332
+ detail: [
333
+ ["Cancel", r.cancel?.success ? "\u2713 Cancelled" : "\u2717 Failed"],
334
+ ["New Order", r.create?.success ? "\u2713 Created" : "\u2717 Failed"],
335
+ ["New Nonce", String(r.create?.order?.nonce || "\u2014")]
336
+ ]
337
+ });
338
+ }
339
+ async function bulkCreate(flags) {
340
+ const raw = requireFlag(
341
+ flags,
342
+ "orders",
343
+ `context orders bulk-create --orders '[{"marketId":"...","outcome":"yes","side":"buy","priceCents":50,"size":10}]'`
344
+ );
345
+ let orders;
346
+ try {
347
+ orders = JSON.parse(raw);
348
+ } catch {
349
+ fail("--orders must be valid JSON", { received: raw });
350
+ }
351
+ if (!Array.isArray(orders)) {
352
+ fail("--orders must be a JSON array", { received: raw });
353
+ }
354
+ const ctx = tradingClient(flags);
355
+ const result = await ctx.orders.bulkCreate(orders);
356
+ out(result);
357
+ }
358
+ async function bulkCancel(flags) {
359
+ const raw = requireFlag(
360
+ flags,
361
+ "nonces",
362
+ "context orders bulk-cancel --nonces 0xabc,0xdef"
363
+ );
364
+ const nonces = raw.split(",").map((s) => s.trim());
365
+ if (nonces.length === 0) {
366
+ fail("--nonces must contain at least one nonce");
367
+ }
368
+ const ctx = tradingClient(flags);
369
+ const result = await ctx.orders.bulkCancel(nonces);
370
+ out(result);
371
+ }
372
+ async function bulk(flags) {
373
+ const createsRaw = flags["creates"];
374
+ const cancelsRaw = flags["cancels"];
375
+ if (!createsRaw && !cancelsRaw) {
376
+ fail("At least one of --creates or --cancels is required", {
377
+ usage: "context orders bulk --creates '[...]' --cancels 0xabc,0xdef"
378
+ });
379
+ }
380
+ let creates = [];
381
+ if (createsRaw) {
382
+ try {
383
+ creates = JSON.parse(createsRaw);
384
+ } catch {
385
+ fail("--creates must be valid JSON", { received: createsRaw });
386
+ }
387
+ if (!Array.isArray(creates)) {
388
+ fail("--creates must be a JSON array", { received: createsRaw });
389
+ }
390
+ }
391
+ const cancelNonces = cancelsRaw ? cancelsRaw.split(",").map((s) => s.trim()) : [];
392
+ const ctx = tradingClient(flags);
393
+ const result = await ctx.orders.bulk(creates, cancelNonces);
394
+ out(result);
395
+ }
396
+ async function marketOrder(flags) {
397
+ const usage = "context orders market --market <id> --outcome <yes|no> --side <buy|sell> --max-price <1-99> --max-size <n>";
398
+ const marketId = requireFlag(flags, "market", usage);
399
+ const outcome = requireFlag(flags, "outcome", usage);
400
+ const side = requireFlag(flags, "side", usage);
401
+ const maxPriceRaw = requireFlag(flags, "max-price", usage);
402
+ const maxSizeRaw = requireFlag(flags, "max-size", usage);
403
+ if (outcome !== "yes" && outcome !== "no") {
404
+ fail("--outcome must be 'yes' or 'no'", { received: outcome });
405
+ }
406
+ if (side !== "buy" && side !== "sell") {
407
+ fail("--side must be 'buy' or 'sell'", { received: side });
408
+ }
409
+ const maxPriceCents = parseInt(maxPriceRaw, 10);
410
+ if (isNaN(maxPriceCents) || maxPriceCents < 1 || maxPriceCents > 99) {
411
+ fail("--max-price must be between 1 and 99 (cents)", { received: maxPriceRaw });
412
+ }
413
+ const maxSize = parseFloat(maxSizeRaw);
414
+ if (isNaN(maxSize) || maxSize < 1) {
415
+ fail("--max-size must be >= 1", { received: maxSizeRaw });
416
+ }
417
+ await confirmOrder({
418
+ market: marketId,
419
+ side,
420
+ outcome,
421
+ price: `max ${maxPriceCents}\xA2`,
422
+ size: `max ${maxSize}`,
423
+ estimatedCost: `up to $${(maxPriceCents / 100 * maxSize).toFixed(2)} USDC`
424
+ }, flags);
425
+ const ctx = tradingClient(flags);
426
+ const result = await ctx.orders.createMarket({
427
+ marketId,
428
+ outcome,
429
+ side,
430
+ maxPriceCents,
431
+ maxSize,
432
+ expirySeconds: flags["expiry-seconds"] ? parseInt(flags["expiry-seconds"], 10) : void 0
433
+ });
434
+ const r = result;
435
+ out(result, {
436
+ detail: [
437
+ ["Status", r.success ? "\u2713 Order placed" : "\u2717 Failed"],
438
+ ["Nonce", String(r.order?.nonce || "\u2014")],
439
+ ["Market", String(r.order?.marketId || "\u2014")],
440
+ ["Type", String(r.order?.type || "\u2014")],
441
+ ["Order Status", String(r.order?.status || "\u2014")],
442
+ ["Filled", r.order?.percentFilled != null ? `${r.order.percentFilled}%` : "\u2014"]
443
+ ]
444
+ });
445
+ }
446
+ export {
447
+ handleOrders as default
448
+ };
@@ -0,0 +1,147 @@
1
+ import {
2
+ formatAddress,
3
+ formatVolume,
4
+ truncate
5
+ } from "./chunk-IRVQREUN.js";
6
+ import {
7
+ readClient,
8
+ tradingClient
9
+ } from "./chunk-BUZKJ7FR.js";
10
+ import {
11
+ fail,
12
+ out,
13
+ requirePositional
14
+ } from "./chunk-QC6BGRUQ.js";
15
+
16
+ // src/commands/portfolio.ts
17
+ var HELP = `Usage: context portfolio <subcommand> [options]
18
+
19
+ Subcommands:
20
+ get Get portfolio positions
21
+ --address <addr> Query a specific address (read-only)
22
+ --kind <all|active|won|lost|claimable> Filter by position kind
23
+ --market <id> Filter by market
24
+ --cursor <token> Pagination cursor
25
+ --page-size <n> Results per page
26
+
27
+ claimable Get claimable winnings
28
+ --address <addr> Query a specific address (read-only)
29
+
30
+ stats Get portfolio statistics
31
+ --address <addr> Query a specific address (read-only)
32
+
33
+ balance Get account balance
34
+ --address <addr> Query a specific address (read-only)
35
+
36
+ token-balance <address> <token-address>
37
+ Get token balance for an address (read-only)
38
+
39
+ help Show this help text
40
+
41
+ Client behaviour:
42
+ If --address is given the command uses a read-only client (no signer needed).
43
+ Otherwise the trading client is used and the signer's own address is implied.
44
+
45
+ Global options:
46
+ --api-key <key> Context API key (or CONTEXT_API_KEY env)
47
+ --private-key <key> Private key for signing (or CONTEXT_PRIVATE_KEY env)`;
48
+ async function handlePortfolio(parsed) {
49
+ const { subcommand, positional, flags } = parsed;
50
+ switch (subcommand) {
51
+ case "get":
52
+ return getPortfolio(flags);
53
+ case "claimable":
54
+ return claimable(flags);
55
+ case "stats":
56
+ return stats(flags);
57
+ case "balance":
58
+ return balance(flags);
59
+ case "token-balance":
60
+ return tokenBalance(positional, flags);
61
+ case "help":
62
+ case void 0:
63
+ console.log(HELP);
64
+ return;
65
+ default:
66
+ fail(`Unknown portfolio subcommand: "${subcommand}". Run "context portfolio help" for usage.`);
67
+ }
68
+ }
69
+ function clientFor(flags) {
70
+ return flags["address"] ? readClient(flags) : tradingClient(flags);
71
+ }
72
+ function addressFlag(flags) {
73
+ return flags["address"] || void 0;
74
+ }
75
+ async function getPortfolio(flags) {
76
+ const ctx = clientFor(flags);
77
+ const address = addressFlag(flags);
78
+ const result = await ctx.portfolio.get(address, {
79
+ kind: flags["kind"] || void 0,
80
+ marketId: flags["market"] || void 0,
81
+ cursor: flags["cursor"] || void 0,
82
+ pageSize: flags["page-size"] ? parseInt(flags["page-size"], 10) : void 0
83
+ });
84
+ out(result, {
85
+ rows: result.portfolio || [],
86
+ columns: [
87
+ { key: "marketId", label: "Market", format: (v) => truncate(v, 14) },
88
+ { key: "outcomeName", label: "Outcome", format: (v) => String(v ?? "\u2014") },
89
+ { key: "balance", label: "Shares", format: formatVolume },
90
+ { key: "netInvestment", label: "Invested", format: formatVolume },
91
+ { key: "currentValue", label: "Value", format: formatVolume }
92
+ ],
93
+ numbered: true,
94
+ emptyMessage: "No positions found.",
95
+ cursor: result.cursor || null
96
+ });
97
+ }
98
+ async function claimable(flags) {
99
+ const ctx = clientFor(flags);
100
+ const address = addressFlag(flags);
101
+ const result = await ctx.portfolio.claimable(address);
102
+ const c = result;
103
+ out(result, {
104
+ detail: [
105
+ ["Total Claimable", formatVolume(c.totalClaimable)],
106
+ ["Positions", String((c.positions || []).length)]
107
+ ]
108
+ });
109
+ }
110
+ async function stats(flags) {
111
+ const ctx = clientFor(flags);
112
+ const address = addressFlag(flags);
113
+ const result = await ctx.portfolio.stats(address);
114
+ out(result);
115
+ }
116
+ async function balance(flags) {
117
+ const ctx = clientFor(flags);
118
+ const address = addressFlag(flags);
119
+ const result = await ctx.portfolio.balance(address);
120
+ const b = result;
121
+ out(result, {
122
+ detail: [
123
+ ["Address", String(b.address || "\u2014")],
124
+ ["USDC Balance", formatVolume(b.usdc?.balance)],
125
+ ["Settlement", formatVolume(b.usdc?.settlementBalance)],
126
+ ["Wallet", formatVolume(b.usdc?.walletBalance)]
127
+ ]
128
+ });
129
+ }
130
+ async function tokenBalance(positional, flags) {
131
+ const usage = "context portfolio token-balance <address> <token-address>";
132
+ const address = requirePositional(positional, 0, "address", usage);
133
+ const tokenAddress = requirePositional(positional, 1, "token-address", usage);
134
+ const ctx = readClient(flags);
135
+ const result = await ctx.portfolio.tokenBalance(address, tokenAddress);
136
+ const tb = result;
137
+ out(result, {
138
+ detail: [
139
+ ["Address", formatAddress(tb.address || tb.owner)],
140
+ ["Token", formatAddress(tb.token || tb.tokenAddress)],
141
+ ["Balance", String(tb.balance ?? "\u2014")]
142
+ ]
143
+ });
144
+ }
145
+ export {
146
+ handlePortfolio as default
147
+ };