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.
- package/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/account-DL4WGQCC.js +207 -0
- package/dist/chunk-BJIFIOK6.js +75 -0
- package/dist/chunk-BUZKJ7FR.js +37 -0
- package/dist/chunk-IRVQREUN.js +55 -0
- package/dist/chunk-QC6BGRUQ.js +217 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +161 -0
- package/dist/guides-Y2YWEZCY.js +101 -0
- package/dist/markets-WZCKLKJR.js +313 -0
- package/dist/orders-IA2XKE5J.js +448 -0
- package/dist/portfolio-73RM2RAQ.js +147 -0
- package/dist/questions-P6AUM6D4.js +199 -0
- package/dist/setup-KDTGKF6O.js +230 -0
- package/dist/shell-XBM2FEIR.js +203 -0
- package/package.json +51 -0
|
@@ -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
|
+
};
|