context-markets-cli 0.1.1 → 0.2.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/README.md +2 -2
- package/dist/account-LO4UG4T2.js +208 -0
- package/dist/cli.js +4 -4
- package/dist/setup-WFYFDNT7.js +230 -0
- package/dist/shell-NY7LFFW2.js +203 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -80,8 +80,8 @@ context portfolio get
|
|
|
80
80
|
| Package | Description |
|
|
81
81
|
|---------|-------------|
|
|
82
82
|
| **[context-markets](https://github.com/contextwtf/context-sdk)** | TypeScript SDK for trading |
|
|
83
|
-
| **[
|
|
84
|
-
| **[
|
|
83
|
+
| **[context-markets-react](https://github.com/contextwtf/context-react)** | React hooks for market data and trading |
|
|
84
|
+
| **[context-markets-mcp](https://github.com/contextwtf/context-mcp)** | MCP server for AI agents |
|
|
85
85
|
| **[context-markets-cli](https://github.com/contextwtf/context-cli)** | CLI for trading from the terminal |
|
|
86
86
|
| **[context-skills](https://github.com/contextwtf/context-skills)** | AI agent skill files |
|
|
87
87
|
| **[context-plugin](https://github.com/contextwtf/context-plugin)** | Claude Code plugin |
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatAddress,
|
|
3
|
+
formatMoney,
|
|
4
|
+
truncate
|
|
5
|
+
} from "./chunk-IRVQREUN.js";
|
|
6
|
+
import {
|
|
7
|
+
tradingClient
|
|
8
|
+
} from "./chunk-Q7JYRQZG.js";
|
|
9
|
+
import {
|
|
10
|
+
fail,
|
|
11
|
+
out,
|
|
12
|
+
requirePositional
|
|
13
|
+
} from "./chunk-QC6BGRUQ.js";
|
|
14
|
+
|
|
15
|
+
// src/commands/account.ts
|
|
16
|
+
var HELP = `Usage: context account <subcommand> [options]
|
|
17
|
+
|
|
18
|
+
Subcommands:
|
|
19
|
+
status Check wallet status (balances, approvals)
|
|
20
|
+
setup Approve contracts for gasless trading
|
|
21
|
+
mint-test-usdc Mint test USDC on testnet
|
|
22
|
+
--amount <n> Amount to mint (default: 1000)
|
|
23
|
+
|
|
24
|
+
deposit <amount> Deposit USDC into the exchange
|
|
25
|
+
withdraw <amount> Withdraw USDC from the exchange
|
|
26
|
+
|
|
27
|
+
mint-complete-sets <market-id> <amount>
|
|
28
|
+
Mint complete sets of outcome tokens
|
|
29
|
+
burn-complete-sets <market-id> <amount>
|
|
30
|
+
Burn complete sets of outcome tokens
|
|
31
|
+
--credit-internal <true|false> Credit internal balance (default: true)
|
|
32
|
+
|
|
33
|
+
help Show this help text
|
|
34
|
+
|
|
35
|
+
All account commands require a signer (--private-key or CONTEXT_PRIVATE_KEY).
|
|
36
|
+
|
|
37
|
+
Global options:
|
|
38
|
+
--api-key <key> Context API key (or CONTEXT_API_KEY env)
|
|
39
|
+
--private-key <key> Private key for signing (or CONTEXT_PRIVATE_KEY env)`;
|
|
40
|
+
async function handleAccount(parsed) {
|
|
41
|
+
const { subcommand, positional, flags } = parsed;
|
|
42
|
+
switch (subcommand) {
|
|
43
|
+
case "status":
|
|
44
|
+
return status(flags);
|
|
45
|
+
case "setup":
|
|
46
|
+
return setup(flags);
|
|
47
|
+
case "mint-test-usdc":
|
|
48
|
+
return mintTestUsdc(flags);
|
|
49
|
+
case "deposit":
|
|
50
|
+
return deposit(positional, flags);
|
|
51
|
+
case "withdraw":
|
|
52
|
+
return withdraw(positional, flags);
|
|
53
|
+
case "mint-complete-sets":
|
|
54
|
+
return mintCompleteSets(positional, flags);
|
|
55
|
+
case "burn-complete-sets":
|
|
56
|
+
return burnCompleteSets(positional, flags);
|
|
57
|
+
case "relay-operator-approval":
|
|
58
|
+
return fail(
|
|
59
|
+
"Use `context gasless-approve` for gasless operator approval."
|
|
60
|
+
);
|
|
61
|
+
case "relay-deposit":
|
|
62
|
+
return fail(
|
|
63
|
+
"Use `context gasless-deposit <amount>` for gasless deposit."
|
|
64
|
+
);
|
|
65
|
+
case "help":
|
|
66
|
+
case void 0:
|
|
67
|
+
console.log(HELP);
|
|
68
|
+
return;
|
|
69
|
+
default:
|
|
70
|
+
fail(
|
|
71
|
+
`Unknown account subcommand: "${subcommand}". Run "context account help" for usage.`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function status(flags) {
|
|
76
|
+
const ctx = tradingClient(flags);
|
|
77
|
+
const result = await ctx.account.status();
|
|
78
|
+
const s = result;
|
|
79
|
+
out(result, {
|
|
80
|
+
detail: [
|
|
81
|
+
["Address", formatAddress(s.address)],
|
|
82
|
+
["ETH Balance", s.ethBalance || "\u2014"],
|
|
83
|
+
["USDC Allowance", s.usdcAllowance ? "\u2713 Approved" : "\u2717 None"],
|
|
84
|
+
["Operator", s.isOperatorApproved ? "\u2713 Approved" : "\u2717 Not approved"],
|
|
85
|
+
["USDC Balance", s.usdcBalance || "\u2014"],
|
|
86
|
+
["Needs Setup", s.isReady ? "No" : "Yes \u2014 run `context setup`"]
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async function setup(flags) {
|
|
91
|
+
const ctx = tradingClient(flags);
|
|
92
|
+
const result = await ctx.account.setup();
|
|
93
|
+
out(result, {
|
|
94
|
+
detail: [
|
|
95
|
+
["Status", "\u2713 Contracts approved"]
|
|
96
|
+
]
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
async function mintTestUsdc(flags) {
|
|
100
|
+
const amountRaw = flags["amount"];
|
|
101
|
+
let amount;
|
|
102
|
+
if (amountRaw) {
|
|
103
|
+
amount = parseFloat(amountRaw);
|
|
104
|
+
if (isNaN(amount) || amount <= 0) {
|
|
105
|
+
fail("--amount must be a positive number", { received: amountRaw });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const ctx = tradingClient(flags);
|
|
109
|
+
const result = await ctx.account.mintTestUsdc(amount);
|
|
110
|
+
const r = result;
|
|
111
|
+
out(result, {
|
|
112
|
+
detail: [
|
|
113
|
+
["Status", "\u2713 Minted"],
|
|
114
|
+
["Amount", formatMoney(r.amount ?? amount)],
|
|
115
|
+
["Tx Hash", formatAddress(r.txHash || r.tx_hash)]
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
async function deposit(positional, flags) {
|
|
120
|
+
const raw = requirePositional(
|
|
121
|
+
positional,
|
|
122
|
+
0,
|
|
123
|
+
"amount",
|
|
124
|
+
"context account deposit <amount>"
|
|
125
|
+
);
|
|
126
|
+
const amount = parseFloat(raw);
|
|
127
|
+
if (isNaN(amount) || amount <= 0) {
|
|
128
|
+
fail("Deposit amount must be a positive number", { received: raw });
|
|
129
|
+
}
|
|
130
|
+
const ctx = tradingClient(flags);
|
|
131
|
+
const result = await ctx.account.deposit(amount);
|
|
132
|
+
out({ status: "deposited", amount_usdc: amount, tx_hash: result.txHash }, {
|
|
133
|
+
detail: [
|
|
134
|
+
["Status", "\u2713 Deposited"],
|
|
135
|
+
["Amount", formatMoney(amount)],
|
|
136
|
+
["Tx Hash", formatAddress(result.txHash)]
|
|
137
|
+
]
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async function withdraw(positional, flags) {
|
|
141
|
+
const raw = requirePositional(
|
|
142
|
+
positional,
|
|
143
|
+
0,
|
|
144
|
+
"amount",
|
|
145
|
+
"context account withdraw <amount>"
|
|
146
|
+
);
|
|
147
|
+
const amount = parseFloat(raw);
|
|
148
|
+
if (isNaN(amount) || amount <= 0) {
|
|
149
|
+
fail("Withdraw amount must be a positive number", { received: raw });
|
|
150
|
+
}
|
|
151
|
+
const ctx = tradingClient(flags);
|
|
152
|
+
const txHash = await ctx.account.withdraw(amount);
|
|
153
|
+
out({ status: "withdrawn", amount_usdc: amount, tx_hash: txHash }, {
|
|
154
|
+
detail: [
|
|
155
|
+
["Status", "\u2713 Withdrawn"],
|
|
156
|
+
["Amount", formatMoney(amount)],
|
|
157
|
+
["Tx Hash", formatAddress(txHash)]
|
|
158
|
+
]
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
async function mintCompleteSets(positional, flags) {
|
|
162
|
+
const usage = "context account mint-complete-sets <market-id> <amount>";
|
|
163
|
+
const marketId = requirePositional(positional, 0, "market-id", usage);
|
|
164
|
+
const amountRaw = requirePositional(positional, 1, "amount", usage);
|
|
165
|
+
const amount = parseFloat(amountRaw);
|
|
166
|
+
if (isNaN(amount) || amount <= 0) {
|
|
167
|
+
fail("Amount must be a positive number", { received: amountRaw });
|
|
168
|
+
}
|
|
169
|
+
const ctx = tradingClient(flags);
|
|
170
|
+
const txHash = await ctx.account.mintCompleteSets(marketId, amount);
|
|
171
|
+
out({ status: "minted", market_id: marketId, amount, tx_hash: txHash }, {
|
|
172
|
+
detail: [
|
|
173
|
+
["Status", "\u2713 Minted complete sets"],
|
|
174
|
+
["Market", truncate(marketId, 20)],
|
|
175
|
+
["Amount", String(amount)],
|
|
176
|
+
["Tx Hash", formatAddress(txHash)]
|
|
177
|
+
]
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
async function burnCompleteSets(positional, flags) {
|
|
181
|
+
const usage = "context account burn-complete-sets <market-id> <amount>";
|
|
182
|
+
const marketId = requirePositional(positional, 0, "market-id", usage);
|
|
183
|
+
const amountRaw = requirePositional(positional, 1, "amount", usage);
|
|
184
|
+
const amount = parseFloat(amountRaw);
|
|
185
|
+
if (isNaN(amount) || amount <= 0) {
|
|
186
|
+
fail("Amount must be a positive number", { received: amountRaw });
|
|
187
|
+
}
|
|
188
|
+
const creditInternalRaw = flags["credit-internal"];
|
|
189
|
+
const creditInternal = creditInternalRaw !== "false";
|
|
190
|
+
const ctx = tradingClient(flags);
|
|
191
|
+
const txHash = await ctx.account.burnCompleteSets(
|
|
192
|
+
marketId,
|
|
193
|
+
amount,
|
|
194
|
+
creditInternal
|
|
195
|
+
);
|
|
196
|
+
out({ status: "burned", market_id: marketId, amount, credit_internal: creditInternal, tx_hash: txHash }, {
|
|
197
|
+
detail: [
|
|
198
|
+
["Status", "\u2713 Burned complete sets"],
|
|
199
|
+
["Market", truncate(marketId, 20)],
|
|
200
|
+
["Amount", String(amount)],
|
|
201
|
+
["Credit Internal", String(creditInternal)],
|
|
202
|
+
["Tx Hash", formatAddress(txHash)]
|
|
203
|
+
]
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
export {
|
|
207
|
+
handleAccount as default
|
|
208
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -89,7 +89,7 @@ async function main() {
|
|
|
89
89
|
const parsed = parseArgs(process.argv);
|
|
90
90
|
setOutputMode(parsed.flags);
|
|
91
91
|
if (parsed.command === "help" && process.stdout.isTTY && process.stdin.isTTY) {
|
|
92
|
-
const { runShell } = await import("./shell-
|
|
92
|
+
const { runShell } = await import("./shell-NY7LFFW2.js");
|
|
93
93
|
await runShell();
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
@@ -116,7 +116,7 @@ async function main() {
|
|
|
116
116
|
break;
|
|
117
117
|
}
|
|
118
118
|
case "account": {
|
|
119
|
-
const mod = await import("./account-
|
|
119
|
+
const mod = await import("./account-LO4UG4T2.js");
|
|
120
120
|
await mod.default(parsed);
|
|
121
121
|
break;
|
|
122
122
|
}
|
|
@@ -125,7 +125,7 @@ async function main() {
|
|
|
125
125
|
case "deposit":
|
|
126
126
|
case "gasless-approve":
|
|
127
127
|
case "gasless-deposit": {
|
|
128
|
-
const mod = await import("./setup-
|
|
128
|
+
const mod = await import("./setup-WFYFDNT7.js");
|
|
129
129
|
const positional = parsed.subcommand ? [parsed.subcommand, ...parsed.positional] : parsed.positional;
|
|
130
130
|
await mod.default({ ...parsed, subcommand: parsed.command, positional });
|
|
131
131
|
break;
|
|
@@ -136,7 +136,7 @@ async function main() {
|
|
|
136
136
|
break;
|
|
137
137
|
}
|
|
138
138
|
case "shell": {
|
|
139
|
-
const { runShell } = await import("./shell-
|
|
139
|
+
const { runShell } = await import("./shell-NY7LFFW2.js");
|
|
140
140
|
await runShell();
|
|
141
141
|
break;
|
|
142
142
|
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import {
|
|
2
|
+
tradingClient
|
|
3
|
+
} from "./chunk-Q7JYRQZG.js";
|
|
4
|
+
import {
|
|
5
|
+
fail,
|
|
6
|
+
getOutputMode,
|
|
7
|
+
out,
|
|
8
|
+
requirePositional
|
|
9
|
+
} from "./chunk-QC6BGRUQ.js";
|
|
10
|
+
|
|
11
|
+
// src/commands/setup.ts
|
|
12
|
+
import * as p from "@clack/prompts";
|
|
13
|
+
import chalk from "chalk";
|
|
14
|
+
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
15
|
+
async function handleSetup(parsed) {
|
|
16
|
+
const { subcommand, positional, flags } = parsed;
|
|
17
|
+
switch (subcommand) {
|
|
18
|
+
case "setup":
|
|
19
|
+
return setup(flags);
|
|
20
|
+
case "approve":
|
|
21
|
+
return approve(flags);
|
|
22
|
+
case "deposit":
|
|
23
|
+
return deposit(positional, flags);
|
|
24
|
+
case "gasless-approve":
|
|
25
|
+
return gaslessApprove(flags);
|
|
26
|
+
case "gasless-deposit":
|
|
27
|
+
return gaslessDeposit(positional, flags);
|
|
28
|
+
default:
|
|
29
|
+
fail(`Unknown setup subcommand: "${subcommand}"`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function setup(flags) {
|
|
33
|
+
const privateKey = flags["private-key"] ?? process.env.CONTEXT_PRIVATE_KEY;
|
|
34
|
+
if (getOutputMode() === "json") {
|
|
35
|
+
if (!privateKey) {
|
|
36
|
+
const newKey = generatePrivateKey();
|
|
37
|
+
const account = privateKeyToAccount(newKey);
|
|
38
|
+
out({
|
|
39
|
+
status: "new_wallet",
|
|
40
|
+
address: account.address,
|
|
41
|
+
privateKey: newKey,
|
|
42
|
+
nextSteps: [
|
|
43
|
+
"Save the private key securely \u2014 it cannot be recovered.",
|
|
44
|
+
"Export it: export CONTEXT_PRIVATE_KEY=<key>",
|
|
45
|
+
"Fund the wallet with testnet ETH and USDC on Base Sepolia.",
|
|
46
|
+
"Run `context approve` to approve contracts for trading.",
|
|
47
|
+
"Run `context deposit <amount>` to deposit USDC into the exchange."
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const ctx = tradingClient(flags);
|
|
53
|
+
const walletStatus = await ctx.account.status();
|
|
54
|
+
out({
|
|
55
|
+
status: "existing_wallet",
|
|
56
|
+
...walletStatus,
|
|
57
|
+
nextSteps: !walletStatus.isReady ? [
|
|
58
|
+
"Run `context approve` to approve contracts.",
|
|
59
|
+
"Run `context deposit <amount>` to deposit."
|
|
60
|
+
] : ["Wallet is fully set up. You can start trading."]
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
p.intro(chalk.bold("Context Markets \u2014 Setup"));
|
|
65
|
+
if (privateKey) {
|
|
66
|
+
const account = privateKeyToAccount(privateKey);
|
|
67
|
+
p.log.success(
|
|
68
|
+
`Wallet detected from ${flags["private-key"] ? "--private-key flag" : "CONTEXT_PRIVATE_KEY env"}`
|
|
69
|
+
);
|
|
70
|
+
p.log.info(`Address: ${account.address}`);
|
|
71
|
+
const ctx = tradingClient(flags);
|
|
72
|
+
const status = await ctx.account.status();
|
|
73
|
+
if (!status.isReady) {
|
|
74
|
+
const doApprove = await p.confirm({
|
|
75
|
+
message: "Approve contracts for trading? (gasless)"
|
|
76
|
+
});
|
|
77
|
+
if (p.isCancel(doApprove)) {
|
|
78
|
+
p.outro("Setup cancelled.");
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
if (doApprove) {
|
|
82
|
+
const s = p.spinner();
|
|
83
|
+
s.start("Approving contracts...");
|
|
84
|
+
await ctx.account.gaslessSetup();
|
|
85
|
+
s.stop("Contracts approved");
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
p.log.success("Contracts already approved");
|
|
89
|
+
}
|
|
90
|
+
const doMint = await p.confirm({
|
|
91
|
+
message: "Mint test USDC? (1000 USDC)"
|
|
92
|
+
});
|
|
93
|
+
if (p.isCancel(doMint)) {
|
|
94
|
+
p.outro("Setup cancelled.");
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}
|
|
97
|
+
if (doMint) {
|
|
98
|
+
const s = p.spinner();
|
|
99
|
+
s.start("Minting test USDC...");
|
|
100
|
+
await ctx.account.mintTestUsdc(1e3);
|
|
101
|
+
s.stop("Minted 1,000 USDC");
|
|
102
|
+
}
|
|
103
|
+
const doDeposit = await p.confirm({
|
|
104
|
+
message: "Deposit USDC to start trading?"
|
|
105
|
+
});
|
|
106
|
+
if (p.isCancel(doDeposit)) {
|
|
107
|
+
p.outro("Setup cancelled.");
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
if (doDeposit) {
|
|
111
|
+
const amount = await p.text({
|
|
112
|
+
message: "Enter amount to deposit:",
|
|
113
|
+
placeholder: "500",
|
|
114
|
+
validate: (v = "") => {
|
|
115
|
+
const n = parseFloat(v);
|
|
116
|
+
if (isNaN(n) || n <= 0) return "Must be a positive number";
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
if (p.isCancel(amount)) {
|
|
120
|
+
p.outro("Setup cancelled.");
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
const s = p.spinner();
|
|
124
|
+
s.start("Depositing USDC...");
|
|
125
|
+
await ctx.account.gaslessDeposit(parseFloat(amount));
|
|
126
|
+
s.stop(`Deposited $${parseFloat(amount).toFixed(2)} USDC`);
|
|
127
|
+
}
|
|
128
|
+
p.outro(chalk.green("Setup complete! You're ready to trade."));
|
|
129
|
+
} else {
|
|
130
|
+
const hasKey = await p.select({
|
|
131
|
+
message: "Do you have an existing private key?",
|
|
132
|
+
options: [
|
|
133
|
+
{ value: "no", label: "No, generate one" },
|
|
134
|
+
{ value: "yes", label: "Yes, import one" }
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
if (p.isCancel(hasKey)) {
|
|
138
|
+
p.outro("Setup cancelled.");
|
|
139
|
+
process.exit(0);
|
|
140
|
+
}
|
|
141
|
+
if (hasKey === "yes") {
|
|
142
|
+
const key = await p.text({
|
|
143
|
+
message: "Enter your private key:",
|
|
144
|
+
placeholder: "0x...",
|
|
145
|
+
validate: (v = "") => {
|
|
146
|
+
if (!v.startsWith("0x") || v.length !== 66)
|
|
147
|
+
return "Invalid private key format (must be 0x + 64 hex chars)";
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
if (p.isCancel(key)) {
|
|
151
|
+
p.outro("Setup cancelled.");
|
|
152
|
+
process.exit(0);
|
|
153
|
+
}
|
|
154
|
+
const account = privateKeyToAccount(key);
|
|
155
|
+
p.log.success("Wallet imported");
|
|
156
|
+
p.log.info(`Address: ${account.address}`);
|
|
157
|
+
p.log.warning(`Set your key: export CONTEXT_PRIVATE_KEY="${key}"`);
|
|
158
|
+
} else {
|
|
159
|
+
const newKey = generatePrivateKey();
|
|
160
|
+
const account = privateKeyToAccount(newKey);
|
|
161
|
+
p.log.success("Wallet created");
|
|
162
|
+
p.log.info(`Address: ${account.address}`);
|
|
163
|
+
p.log.warning("Back up your private key! It cannot be recovered.");
|
|
164
|
+
p.log.info(`export CONTEXT_PRIVATE_KEY="${newKey}"`);
|
|
165
|
+
}
|
|
166
|
+
p.outro("Set CONTEXT_PRIVATE_KEY and re-run `context setup` to continue.");
|
|
167
|
+
}
|
|
168
|
+
console.log();
|
|
169
|
+
console.log(chalk.dim(" Next steps:"));
|
|
170
|
+
console.log(chalk.dim(" context markets list Browse markets"));
|
|
171
|
+
console.log(chalk.dim(" context guides trading Learn to trade"));
|
|
172
|
+
console.log(chalk.dim(" context shell Interactive mode"));
|
|
173
|
+
console.log();
|
|
174
|
+
}
|
|
175
|
+
async function approve(flags) {
|
|
176
|
+
const ctx = tradingClient(flags);
|
|
177
|
+
const result = await ctx.account.setup();
|
|
178
|
+
const walletStatus = await ctx.account.status();
|
|
179
|
+
out({
|
|
180
|
+
status: "approved",
|
|
181
|
+
usdcApprovalTx: result.usdcApproval.txHash,
|
|
182
|
+
operatorApprovalTx: result.operatorApproval.txHash,
|
|
183
|
+
wallet: walletStatus,
|
|
184
|
+
nextSteps: [
|
|
185
|
+
"Run `context deposit <amount>` to deposit USDC into the exchange."
|
|
186
|
+
]
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async function deposit(positional, flags) {
|
|
190
|
+
const raw = requirePositional(
|
|
191
|
+
positional,
|
|
192
|
+
0,
|
|
193
|
+
"amount",
|
|
194
|
+
"context deposit <amount>"
|
|
195
|
+
);
|
|
196
|
+
const amount = parseFloat(raw);
|
|
197
|
+
if (isNaN(amount) || amount <= 0) {
|
|
198
|
+
fail("Deposit amount must be a positive number.", { received: raw });
|
|
199
|
+
}
|
|
200
|
+
const ctx = tradingClient(flags);
|
|
201
|
+
const result = await ctx.account.deposit(amount);
|
|
202
|
+
out({
|
|
203
|
+
status: "deposited",
|
|
204
|
+
amount,
|
|
205
|
+
txHash: result.txHash
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
async function gaslessApprove(flags) {
|
|
209
|
+
const ctx = tradingClient(flags);
|
|
210
|
+
const result = await ctx.account.gaslessSetup();
|
|
211
|
+
out(result);
|
|
212
|
+
}
|
|
213
|
+
async function gaslessDeposit(positional, flags) {
|
|
214
|
+
const raw = requirePositional(
|
|
215
|
+
positional,
|
|
216
|
+
0,
|
|
217
|
+
"amount",
|
|
218
|
+
"context gasless-deposit <amount>"
|
|
219
|
+
);
|
|
220
|
+
const amount = parseFloat(raw);
|
|
221
|
+
if (isNaN(amount) || amount <= 0) {
|
|
222
|
+
fail("Deposit amount must be a positive number.", { received: raw });
|
|
223
|
+
}
|
|
224
|
+
const ctx = tradingClient(flags);
|
|
225
|
+
const result = await ctx.account.gaslessDeposit(amount);
|
|
226
|
+
out(result);
|
|
227
|
+
}
|
|
228
|
+
export {
|
|
229
|
+
handleSetup as default
|
|
230
|
+
};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setShellReadline
|
|
3
|
+
} from "./chunk-BJIFIOK6.js";
|
|
4
|
+
import {
|
|
5
|
+
onResults,
|
|
6
|
+
parseArgs,
|
|
7
|
+
setOutputMode
|
|
8
|
+
} from "./chunk-QC6BGRUQ.js";
|
|
9
|
+
|
|
10
|
+
// src/shell.ts
|
|
11
|
+
import * as readline from "readline";
|
|
12
|
+
import chalk from "chalk";
|
|
13
|
+
var lastResults = [];
|
|
14
|
+
var lastCursor = null;
|
|
15
|
+
var lastCommand = null;
|
|
16
|
+
function resolveRefs(input) {
|
|
17
|
+
return input.replace(/#(\d+)/g, (match, num) => {
|
|
18
|
+
const idx = parseInt(num, 10) - 1;
|
|
19
|
+
const item = lastResults[idx];
|
|
20
|
+
if (!item) return match;
|
|
21
|
+
const id = item.id || item.marketId || item.nonce;
|
|
22
|
+
return id ? String(id) : match;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function splitArgs(input) {
|
|
26
|
+
const args = [];
|
|
27
|
+
let current = "";
|
|
28
|
+
let inQuote = false;
|
|
29
|
+
let quoteChar = "";
|
|
30
|
+
for (const ch of input) {
|
|
31
|
+
if (inQuote) {
|
|
32
|
+
if (ch === quoteChar) {
|
|
33
|
+
inQuote = false;
|
|
34
|
+
} else {
|
|
35
|
+
current += ch;
|
|
36
|
+
}
|
|
37
|
+
} else if (ch === '"' || ch === "'") {
|
|
38
|
+
inQuote = true;
|
|
39
|
+
quoteChar = ch;
|
|
40
|
+
} else if (ch === " " || ch === " ") {
|
|
41
|
+
if (current) {
|
|
42
|
+
args.push(current);
|
|
43
|
+
current = "";
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
current += ch;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (current) args.push(current);
|
|
50
|
+
return args;
|
|
51
|
+
}
|
|
52
|
+
var BANNER = [
|
|
53
|
+
" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
|
|
54
|
+
" \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D \u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D",
|
|
55
|
+
" \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 ",
|
|
56
|
+
" \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 ",
|
|
57
|
+
" \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u255D \u2588\u2588\u2557 \u2588\u2588\u2551 ",
|
|
58
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D "
|
|
59
|
+
];
|
|
60
|
+
var GRADIENT = [
|
|
61
|
+
"#a78bfa",
|
|
62
|
+
// violet-400
|
|
63
|
+
"#818cf8",
|
|
64
|
+
// indigo-400
|
|
65
|
+
"#6366f1",
|
|
66
|
+
// indigo-500
|
|
67
|
+
"#4f46e5",
|
|
68
|
+
// indigo-600
|
|
69
|
+
"#4338ca",
|
|
70
|
+
// indigo-700
|
|
71
|
+
"#3730a3"
|
|
72
|
+
// indigo-800
|
|
73
|
+
];
|
|
74
|
+
async function runShell() {
|
|
75
|
+
console.log();
|
|
76
|
+
for (let i = 0; i < BANNER.length; i++) {
|
|
77
|
+
console.log(chalk.hex(GRADIENT[i])(BANNER[i]));
|
|
78
|
+
}
|
|
79
|
+
console.log();
|
|
80
|
+
console.log(chalk.bold(" Prediction Markets") + chalk.dim(" \xB7 Interactive Shell"));
|
|
81
|
+
console.log(chalk.dim(" Type 'help' for commands, 'exit' to quit."));
|
|
82
|
+
console.log();
|
|
83
|
+
setOutputMode({ output: "table" });
|
|
84
|
+
onResults((items, cursor) => {
|
|
85
|
+
lastResults = items;
|
|
86
|
+
lastCursor = cursor || null;
|
|
87
|
+
});
|
|
88
|
+
const rl = readline.createInterface({
|
|
89
|
+
input: process.stdin,
|
|
90
|
+
output: process.stdout,
|
|
91
|
+
prompt: chalk.dim("context> "),
|
|
92
|
+
terminal: true
|
|
93
|
+
});
|
|
94
|
+
setShellReadline(rl);
|
|
95
|
+
rl.prompt();
|
|
96
|
+
rl.on("line", async (line) => {
|
|
97
|
+
const trimmed = line.trim();
|
|
98
|
+
if (!trimmed) {
|
|
99
|
+
rl.prompt();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (trimmed === "exit" || trimmed === "quit") {
|
|
103
|
+
console.log(chalk.dim("Goodbye!"));
|
|
104
|
+
rl.close();
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
if (trimmed === "help") {
|
|
108
|
+
console.log();
|
|
109
|
+
console.log(chalk.bold(" Commands:"));
|
|
110
|
+
console.log(" markets <subcommand> Browse and search markets");
|
|
111
|
+
console.log(" orders <subcommand> Manage orders");
|
|
112
|
+
console.log(" portfolio <subcommand> View positions and balances");
|
|
113
|
+
console.log(" account <subcommand> Wallet and account operations");
|
|
114
|
+
console.log(" questions <subcommand> Submit questions for AI markets");
|
|
115
|
+
console.log(" guides [topic] View usage guides");
|
|
116
|
+
console.log();
|
|
117
|
+
console.log(chalk.bold(" Shell features:"));
|
|
118
|
+
console.log(" #N Reference row N from last result");
|
|
119
|
+
console.log(" next Load next page of last result");
|
|
120
|
+
console.log(" exit / quit Leave the shell");
|
|
121
|
+
console.log();
|
|
122
|
+
rl.prompt();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let commandLine = trimmed;
|
|
126
|
+
if (trimmed === "next") {
|
|
127
|
+
if (!lastCommand || !lastCursor) {
|
|
128
|
+
console.log(chalk.dim(" No previous paginated result."));
|
|
129
|
+
rl.prompt();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
commandLine = `${lastCommand} --cursor ${lastCursor}`;
|
|
133
|
+
}
|
|
134
|
+
commandLine = resolveRefs(commandLine);
|
|
135
|
+
if (commandLine.startsWith("setup")) {
|
|
136
|
+
console.log(chalk.dim(" Run 'context setup' outside the shell."));
|
|
137
|
+
rl.prompt();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (commandLine.startsWith("shell")) {
|
|
141
|
+
console.log(chalk.dim(" Already in shell mode."));
|
|
142
|
+
rl.prompt();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
lastCommand = commandLine.replace(/\s+--cursor\s+\S+/g, "");
|
|
146
|
+
const argv = ["bun", "cli.ts", ...splitArgs(commandLine)];
|
|
147
|
+
const parsed = parseArgs(argv);
|
|
148
|
+
try {
|
|
149
|
+
switch (parsed.command) {
|
|
150
|
+
case "markets": {
|
|
151
|
+
const mod = await import("./markets-WZG67OAH.js");
|
|
152
|
+
await mod.default(parsed);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case "orders": {
|
|
156
|
+
const mod = await import("./orders-KGS5MLNX.js");
|
|
157
|
+
await mod.default(parsed);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case "portfolio": {
|
|
161
|
+
const mod = await import("./portfolio-2R52VSBA.js");
|
|
162
|
+
await mod.default(parsed);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case "account": {
|
|
166
|
+
const mod = await import("./account-LO4UG4T2.js");
|
|
167
|
+
await mod.default(parsed);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case "questions": {
|
|
171
|
+
const mod = await import("./questions-NJZXH3AZ.js");
|
|
172
|
+
await mod.default(parsed);
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
case "guides": {
|
|
176
|
+
const mod = await import("./guides-Y2YWEZCY.js");
|
|
177
|
+
await mod.default(parsed);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
default:
|
|
181
|
+
console.log(
|
|
182
|
+
chalk.dim(
|
|
183
|
+
` Unknown command: "${parsed.command}". Type 'help' for commands.`
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
} catch (err) {
|
|
188
|
+
if (err instanceof Error && (err.name === "CancelError" || err.name === "FailError")) {
|
|
189
|
+
} else {
|
|
190
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
191
|
+
console.error(chalk.red(` Error: ${message}`));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
console.log();
|
|
195
|
+
rl.prompt();
|
|
196
|
+
});
|
|
197
|
+
rl.on("close", () => {
|
|
198
|
+
process.exit(0);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
export {
|
|
202
|
+
runShell
|
|
203
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-markets-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for trading on Context prediction markets",
|
|
6
6
|
"author": "Context",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@clack/prompts": "^1.0.1",
|
|
42
|
-
"context-markets": "^0.5.0",
|
|
43
42
|
"chalk": "^5.6.2",
|
|
44
43
|
"cli-table3": "^0.6.5",
|
|
44
|
+
"context-markets": "^0.6.0",
|
|
45
45
|
"viem": "^2.23.2"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|