@otonix/cli 2.1.8 → 2.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/dist/commands/agent.js +56 -81
- package/dist/commands/launch.js +17 -13
- package/dist/commands/wallet.js +36 -136
- package/dist/lib/chain.d.ts +1 -0
- package/dist/lib/chain.js +1 -0
- package/package.json +1 -1
package/dist/commands/agent.js
CHANGED
|
@@ -7,7 +7,7 @@ import { header, row, success, failure, info, br, warn, mono } from "../lib/disp
|
|
|
7
7
|
export function agentCommand(program) {
|
|
8
8
|
program
|
|
9
9
|
.command("agent:create")
|
|
10
|
-
.description("Create a new autonomous agent
|
|
10
|
+
.description("Create a new autonomous agent — one wallet for everything")
|
|
11
11
|
.requiredOption("--name <name>", "Agent name (alphanumeric, no spaces)")
|
|
12
12
|
.action(async (opts) => {
|
|
13
13
|
header("Create Agent");
|
|
@@ -17,19 +17,6 @@ export function agentCommand(program) {
|
|
|
17
17
|
process.exit(1);
|
|
18
18
|
}
|
|
19
19
|
const cfg = loadConfig();
|
|
20
|
-
if (!cfg.wallet) {
|
|
21
|
-
const autoSpinner = ora("No creator wallet found — generating one automatically...").start();
|
|
22
|
-
await new Promise(r => setTimeout(r, 400));
|
|
23
|
-
const creator = generateWallet();
|
|
24
|
-
autoSpinner.stop();
|
|
25
|
-
cfg.wallet = { address: creator.address, privateKey: creator.privateKey };
|
|
26
|
-
saveConfig(cfg);
|
|
27
|
-
success("Creator wallet generated!");
|
|
28
|
-
br();
|
|
29
|
-
console.log(chalk.dim(" Creator wallet address: ") + chalk.bold.white(creator.address));
|
|
30
|
-
console.log(chalk.dim(" Fund this address with ≥ 200 $OTX + ≥ 0.005 ETH (Base)"));
|
|
31
|
-
br();
|
|
32
|
-
}
|
|
33
20
|
if (cfg.agents[name]) {
|
|
34
21
|
const overwrite = await confirm({
|
|
35
22
|
message: `Agent "${name}" already exists. Replace it?`,
|
|
@@ -40,7 +27,7 @@ export function agentCommand(program) {
|
|
|
40
27
|
return;
|
|
41
28
|
}
|
|
42
29
|
}
|
|
43
|
-
const spinner = ora("Generating
|
|
30
|
+
const spinner = ora("Generating agent wallet on Base...").start();
|
|
44
31
|
await new Promise(r => setTimeout(r, 600));
|
|
45
32
|
const agent = generateWallet();
|
|
46
33
|
spinner.stop();
|
|
@@ -54,28 +41,25 @@ export function agentCommand(program) {
|
|
|
54
41
|
success(`Agent "${name}" created!`);
|
|
55
42
|
br();
|
|
56
43
|
row("Agent name", name);
|
|
57
|
-
row("
|
|
44
|
+
row("Wallet address", agent.address);
|
|
58
45
|
row("Created at", new Date().toLocaleString());
|
|
59
46
|
row("Status", chalk.yellow("⊘ Not registered"));
|
|
60
47
|
br();
|
|
61
48
|
console.log(chalk.dim("─".repeat(44)));
|
|
62
|
-
console.log(chalk.bold("
|
|
49
|
+
console.log(chalk.bold(" Fund this wallet (Base network):"));
|
|
63
50
|
br();
|
|
64
|
-
console.log(" " + chalk.
|
|
65
|
-
console.log("
|
|
66
|
-
console.log(" " + chalk.yellow("≥ 0.005 ETH") + chalk.dim(" (gas for the $OTX transfer)"));
|
|
67
|
-
console.log(" " + chalk.dim(" Check: ") + mono("otonix wallet balance"));
|
|
51
|
+
console.log(" " + chalk.yellow("≥ 200 $OTX") + chalk.dim(" — registration fee (auto-sent by CLI)"));
|
|
52
|
+
console.log(" " + chalk.yellow("≥ 0.005 ETH") + chalk.dim(" — gas for registration + deployment"));
|
|
68
53
|
br();
|
|
69
|
-
console.log(" " + chalk.bold.white(
|
|
70
|
-
console.log(" " + chalk.yellow("≥ 0.003 ETH") + chalk.dim(" → ") + chalk.white(agent.address));
|
|
54
|
+
console.log(" Send to: " + chalk.bold.white(agent.address));
|
|
71
55
|
br();
|
|
72
|
-
console.log(
|
|
73
|
-
console.log("
|
|
56
|
+
console.log(chalk.dim(" After funded, register:"));
|
|
57
|
+
console.log(" " + mono(`otonix agent:register --name ${name}`));
|
|
74
58
|
console.log(chalk.dim("─".repeat(44)));
|
|
75
59
|
});
|
|
76
60
|
program
|
|
77
61
|
.command("agent:register")
|
|
78
|
-
.description("Register an agent — auto-sends 200 $OTX to Otonix treasury
|
|
62
|
+
.description("Register an agent — auto-sends 200 $OTX from agent wallet to Otonix treasury")
|
|
79
63
|
.requiredOption("--name <name>", "Agent name to register")
|
|
80
64
|
.action(async (opts) => {
|
|
81
65
|
header("Agent Registration");
|
|
@@ -93,17 +77,11 @@ export function agentCommand(program) {
|
|
|
93
77
|
row("Registered at", agent.registeredAt ? new Date(agent.registeredAt).toLocaleString() : "—");
|
|
94
78
|
return;
|
|
95
79
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
const balSpinner = ora("Checking balances...").start();
|
|
101
|
-
let creatorOtx, creatorEth;
|
|
102
|
-
let agentOtx, agentEth;
|
|
80
|
+
const balSpinner = ora("Checking agent wallet balance...").start();
|
|
81
|
+
let otxBal;
|
|
82
|
+
let ethBal;
|
|
103
83
|
try {
|
|
104
|
-
[
|
|
105
|
-
getOtxBalance(cfg.wallet.address),
|
|
106
|
-
getEthBalance(cfg.wallet.address),
|
|
84
|
+
[otxBal, ethBal] = await Promise.all([
|
|
107
85
|
getOtxBalance(agent.address),
|
|
108
86
|
getEthBalance(agent.address),
|
|
109
87
|
]);
|
|
@@ -114,46 +92,36 @@ export function agentCommand(program) {
|
|
|
114
92
|
process.exit(1);
|
|
115
93
|
}
|
|
116
94
|
balSpinner.stop();
|
|
117
|
-
const creatorOk = creatorOtx >= OTX_REQUIRED && parseFloat(creatorEth) >= 0.0001;
|
|
118
|
-
const agentOk = agentOtx >= OTX_REQUIRED && parseFloat(agentEth) >= 0.0001;
|
|
119
|
-
const payerKey = creatorOk ? cfg.wallet.privateKey : agent.privateKey;
|
|
120
|
-
const payerAddress = creatorOk ? cfg.wallet.address : agent.address;
|
|
121
|
-
const payerLabel = creatorOk ? "creator wallet" : "agent wallet";
|
|
122
95
|
br();
|
|
123
|
-
|
|
124
|
-
row("
|
|
125
|
-
row("
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
row(" $OTX", formatOtx(agentOtx) + " OTX" + (agentOtx >= OTX_REQUIRED ? chalk.green(" ✓") : chalk.yellow(" ✗")));
|
|
129
|
-
row(" ETH", parseFloat(agentEth).toFixed(6) + " ETH" + (parseFloat(agentEth) >= 0.0001 ? chalk.green(" ✓") : chalk.yellow(" ✗")));
|
|
96
|
+
row("Agent wallet", agent.address);
|
|
97
|
+
row("$OTX balance", formatOtx(otxBal) + " OTX");
|
|
98
|
+
row("ETH balance", parseFloat(ethBal).toFixed(6) + " ETH (for gas)");
|
|
99
|
+
row("Registration fee", "200 $OTX → Otonix treasury");
|
|
100
|
+
row("Treasury", OTONIX_TREASURY);
|
|
130
101
|
br();
|
|
131
|
-
if (
|
|
132
|
-
failure(
|
|
133
|
-
info("
|
|
102
|
+
if (otxBal < OTX_REQUIRED) {
|
|
103
|
+
failure(`Insufficient $OTX. Need 200.000, have ${formatOtx(otxBal)}.`);
|
|
104
|
+
info("Fund your agent wallet: " + agent.address);
|
|
134
105
|
info("Buy $OTX: https://dexscreener.com/base/0xF7E2a6226Ffe0693DD85406AC3A8917cbea5DC40");
|
|
135
106
|
process.exit(1);
|
|
136
107
|
}
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
108
|
+
if (parseFloat(ethBal) < 0.0001) {
|
|
109
|
+
failure("Insufficient ETH for gas. Send ETH (Base) to your agent wallet.");
|
|
110
|
+
info("Agent wallet: " + agent.address);
|
|
111
|
+
process.exit(1);
|
|
140
112
|
}
|
|
141
|
-
row("Paying from", payerLabel + " (" + payerAddress.slice(0, 10) + "...)");
|
|
142
|
-
row("Registration fee", "200 $OTX → Otonix treasury");
|
|
143
|
-
row("Treasury", OTONIX_TREASURY);
|
|
144
|
-
br();
|
|
145
113
|
const confirmed = await confirm({
|
|
146
|
-
message: `Send 200 $OTX from
|
|
114
|
+
message: `Send 200 $OTX from agent wallet to Otonix treasury to activate "${opts.name}"?`,
|
|
147
115
|
default: true,
|
|
148
116
|
});
|
|
149
117
|
if (!confirmed) {
|
|
150
118
|
info("Cancelled.");
|
|
151
119
|
return;
|
|
152
120
|
}
|
|
153
|
-
const sendSpinner = ora(
|
|
121
|
+
const sendSpinner = ora("Sending 200 $OTX to Otonix treasury...").start();
|
|
154
122
|
let txHash;
|
|
155
123
|
try {
|
|
156
|
-
txHash = await sendOtx(
|
|
124
|
+
txHash = await sendOtx(agent.privateKey, OTONIX_TREASURY, OTX_REQUIRED);
|
|
157
125
|
}
|
|
158
126
|
catch (err) {
|
|
159
127
|
sendSpinner.stop();
|
|
@@ -186,10 +154,7 @@ export function agentCommand(program) {
|
|
|
186
154
|
row("Tx hash", txHash);
|
|
187
155
|
row("Basescan", "https://basescan.org/tx/" + txHash);
|
|
188
156
|
br();
|
|
189
|
-
console.log(chalk.dim("You can now deploy tokens
|
|
190
|
-
console.log(" " + chalk.dim("Agent address:") + " " + chalk.white(agent.address));
|
|
191
|
-
br();
|
|
192
|
-
console.log(chalk.dim("Then deploy:"));
|
|
157
|
+
console.log(chalk.dim("You can now deploy tokens:"));
|
|
193
158
|
console.log(" " + mono(`otonix launch token --agent ${opts.name} --name "MyToken" --ticker "MTK" --image "https://..." --description "..."`));
|
|
194
159
|
}
|
|
195
160
|
catch (err) {
|
|
@@ -221,7 +186,7 @@ export function agentCommand(program) {
|
|
|
221
186
|
spinner.stop();
|
|
222
187
|
br();
|
|
223
188
|
row("Agent name", name);
|
|
224
|
-
row("
|
|
189
|
+
row("Wallet address", agent.address);
|
|
225
190
|
row("Created at", new Date(agent.createdAt).toLocaleString());
|
|
226
191
|
row("Status", agent.registered
|
|
227
192
|
? chalk.green("✓ Registered & Active")
|
|
@@ -232,14 +197,22 @@ export function agentCommand(program) {
|
|
|
232
197
|
row("ETH balance", parseFloat(eth).toFixed(6) + " ETH");
|
|
233
198
|
row("$OTX balance", formatOtx(otx) + " OTX");
|
|
234
199
|
br();
|
|
235
|
-
const ethNum = parseFloat(eth);
|
|
236
200
|
if (!agent.registered) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
201
|
+
if (otx >= OTX_REQUIRED && parseFloat(eth) >= 0.0001) {
|
|
202
|
+
console.log(chalk.green("✓ ") + chalk.dim("Wallet funded — ready to register:"));
|
|
203
|
+
console.log(" " + chalk.cyan(`otonix agent:register --name ${name}`));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.log(warn("⚠ ") + chalk.dim("Fund this wallet before registering:"));
|
|
207
|
+
if (otx < OTX_REQUIRED)
|
|
208
|
+
console.log(" " + chalk.yellow(`Need ≥ 200 $OTX (have ${formatOtx(otx)})`));
|
|
209
|
+
if (parseFloat(eth) < 0.0001)
|
|
210
|
+
console.log(" " + chalk.yellow("Need ≥ 0.005 ETH for gas"));
|
|
211
|
+
console.log(" " + chalk.dim("Address: ") + chalk.white(agent.address));
|
|
212
|
+
}
|
|
240
213
|
}
|
|
241
|
-
else if (
|
|
242
|
-
console.log(warn("⚠ ") + chalk.dim("Low ETH — fund
|
|
214
|
+
else if (parseFloat(eth) < 0.0005) {
|
|
215
|
+
console.log(warn("⚠ ") + chalk.dim("Low ETH — fund with ≥ 0.003 ETH for token deployment:"));
|
|
243
216
|
console.log(" " + chalk.white(agent.address));
|
|
244
217
|
}
|
|
245
218
|
else {
|
|
@@ -270,11 +243,14 @@ export function agentCommand(program) {
|
|
|
270
243
|
const results = await Promise.all(names.map(async (n) => {
|
|
271
244
|
const a = cfg.agents[n];
|
|
272
245
|
try {
|
|
273
|
-
const eth = await
|
|
274
|
-
|
|
246
|
+
const [eth, otx] = await Promise.all([
|
|
247
|
+
getEthBalance(a.address),
|
|
248
|
+
getOtxBalance(a.address),
|
|
249
|
+
]);
|
|
250
|
+
return { name: n, address: a.address, eth: parseFloat(eth).toFixed(5), otx: formatOtx(otx), registered: a.registered };
|
|
275
251
|
}
|
|
276
252
|
catch {
|
|
277
|
-
return { name: n, address: a.address, eth: "—", registered: a.registered };
|
|
253
|
+
return { name: n, address: a.address, eth: "—", otx: "—", registered: a.registered };
|
|
278
254
|
}
|
|
279
255
|
}));
|
|
280
256
|
spinner.stop();
|
|
@@ -283,8 +259,8 @@ export function agentCommand(program) {
|
|
|
283
259
|
console.log(status + " " +
|
|
284
260
|
chalk.bold.white(r.name.padEnd(16)) +
|
|
285
261
|
chalk.dim(r.address.slice(0, 10) + "...") +
|
|
286
|
-
" " +
|
|
287
|
-
chalk.
|
|
262
|
+
" " + chalk.yellow(r.eth + " ETH") +
|
|
263
|
+
" " + chalk.dim(r.otx + " OTX"));
|
|
288
264
|
}
|
|
289
265
|
br();
|
|
290
266
|
info(`${names.length} agent(s) total`);
|
|
@@ -326,8 +302,7 @@ export function agentCommand(program) {
|
|
|
326
302
|
br();
|
|
327
303
|
console.log(chalk.bold.red("⚠ SECURITY WARNING"));
|
|
328
304
|
console.log(chalk.dim(" Your private key gives full access to this agent wallet."));
|
|
329
|
-
console.log(chalk.dim(" Never share it.
|
|
330
|
-
console.log(chalk.dim(" Store it offline or in a hardware wallet."));
|
|
305
|
+
console.log(chalk.dim(" Never share it. Store it offline or in a hardware wallet."));
|
|
331
306
|
br();
|
|
332
307
|
const ok = await confirm({
|
|
333
308
|
message: `Show private key for agent "${name}" (${agent.address})?`,
|
|
@@ -339,12 +314,12 @@ export function agentCommand(program) {
|
|
|
339
314
|
}
|
|
340
315
|
br();
|
|
341
316
|
row("Agent name", name);
|
|
342
|
-
row("
|
|
317
|
+
row("Wallet address", agent.address);
|
|
343
318
|
br();
|
|
344
319
|
console.log(chalk.bold("Private key:"));
|
|
345
320
|
console.log(chalk.bold.yellow(agent.privateKey));
|
|
346
321
|
br();
|
|
347
322
|
console.log(chalk.dim("Import into MetaMask: Settings → Import Account → paste key above."));
|
|
348
|
-
console.log(chalk.dim("LP fee rewards (
|
|
323
|
+
console.log(chalk.dim("80% LP fee rewards (WETH) are sent to this wallet address."));
|
|
349
324
|
});
|
|
350
325
|
}
|
package/dist/commands/launch.js
CHANGED
|
@@ -2,7 +2,7 @@ import { confirm } from "@inquirer/prompts";
|
|
|
2
2
|
import ora from "ora";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { loadConfig, OTONIX_TREASURY } from "../lib/config.js";
|
|
5
|
-
import { getEthBalance, BASE_RPC, } from "../lib/chain.js";
|
|
5
|
+
import { getEthBalance, BASE_RPC, BASE_MEV_RPC, } from "../lib/chain.js";
|
|
6
6
|
import { header, row, failure, info, br, warn, } from "../lib/display.js";
|
|
7
7
|
const WETH_BASE = "0x4200000000000000000000000000000000000006";
|
|
8
8
|
const OTONIX_TWITTER = "otonix_tech";
|
|
@@ -18,13 +18,10 @@ export function launchCommand(program) {
|
|
|
18
18
|
.requiredOption("--description <text>", "Token description")
|
|
19
19
|
.option("--twitter <handle>", "Your Twitter/X handle (e.g. yourname) — shown in metadata")
|
|
20
20
|
.option("--devbuy <eth>", "Initial dev buy in ETH (default: 0)", "0")
|
|
21
|
+
.option("--mev-protect", "Route deploy tx through Flashbots private mempool (anti-sandwich)")
|
|
21
22
|
.action(async (opts) => {
|
|
22
23
|
header("Launch Token");
|
|
23
24
|
const cfg = loadConfig();
|
|
24
|
-
if (!cfg.wallet) {
|
|
25
|
-
failure("No wallet. Run: otonix wallet generate");
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
25
|
const agent = cfg.agents[opts.agent];
|
|
29
26
|
if (!agent) {
|
|
30
27
|
failure(`Agent "${opts.agent}" not found. Run: otonix agent:list`);
|
|
@@ -66,6 +63,8 @@ export function launchCommand(program) {
|
|
|
66
63
|
failure("Pre-flight checks failed. Fix the issues above and try again.");
|
|
67
64
|
process.exit(1);
|
|
68
65
|
}
|
|
66
|
+
const useMevProtect = !!opts.mevProtect;
|
|
67
|
+
const activeRpc = useMevProtect ? BASE_MEV_RPC : BASE_RPC;
|
|
69
68
|
br();
|
|
70
69
|
console.log(chalk.bold.white("Token to deploy:"));
|
|
71
70
|
row("Name", opts.name);
|
|
@@ -80,8 +79,11 @@ export function launchCommand(program) {
|
|
|
80
79
|
row("Paired token", "WETH");
|
|
81
80
|
if (devBuyEth > 0)
|
|
82
81
|
row("Dev buy", devBuyEth + " ETH");
|
|
83
|
-
row("Reward 80%",
|
|
82
|
+
row("Reward 80%", agent.address + " (WETH → agent wallet)");
|
|
84
83
|
row("Reward 20%", OTONIX_TREASURY + " ($OTX burn)");
|
|
84
|
+
row("MEV protect", useMevProtect
|
|
85
|
+
? chalk.green("✓ ON") + chalk.dim(" (Flashbots private mempool)")
|
|
86
|
+
: chalk.dim("off (use --mev-protect to enable)"));
|
|
85
87
|
row("Verified by", "✓ Otonix (@" + OTONIX_TWITTER + ")");
|
|
86
88
|
br();
|
|
87
89
|
const confirmed = await confirm({
|
|
@@ -92,7 +94,9 @@ export function launchCommand(program) {
|
|
|
92
94
|
info("Cancelled.");
|
|
93
95
|
return;
|
|
94
96
|
}
|
|
95
|
-
const deploySpinner = ora(
|
|
97
|
+
const deploySpinner = ora(useMevProtect
|
|
98
|
+
? "Deploying token via Flashbots private mempool (MEV protected)..."
|
|
99
|
+
: "Deploying token on Base (Clanker v4 / Uniswap v4)...").start();
|
|
96
100
|
try {
|
|
97
101
|
const { createWalletClient, createPublicClient, http } = await import("viem");
|
|
98
102
|
const { base } = await import("viem/chains");
|
|
@@ -102,12 +106,12 @@ export function launchCommand(program) {
|
|
|
102
106
|
const agentAccount = privateKeyToAccount(agent.privateKey);
|
|
103
107
|
const publicClient = createPublicClient({
|
|
104
108
|
chain: base,
|
|
105
|
-
transport: http(
|
|
109
|
+
transport: http(activeRpc),
|
|
106
110
|
});
|
|
107
111
|
const walletClient = createWalletClient({
|
|
108
112
|
account: agentAccount,
|
|
109
113
|
chain: base,
|
|
110
|
-
transport: http(
|
|
114
|
+
transport: http(activeRpc),
|
|
111
115
|
});
|
|
112
116
|
const clanker = new Clanker({
|
|
113
117
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -124,7 +128,7 @@ export function launchCommand(program) {
|
|
|
124
128
|
const tokenConfig = {
|
|
125
129
|
name: opts.name,
|
|
126
130
|
symbol: opts.ticker.toUpperCase(),
|
|
127
|
-
tokenAdmin:
|
|
131
|
+
tokenAdmin: agent.address,
|
|
128
132
|
image: opts.image,
|
|
129
133
|
metadata: {
|
|
130
134
|
description: opts.description,
|
|
@@ -146,8 +150,8 @@ export function launchCommand(program) {
|
|
|
146
150
|
rewards: {
|
|
147
151
|
recipients: [
|
|
148
152
|
{
|
|
149
|
-
recipient:
|
|
150
|
-
admin:
|
|
153
|
+
recipient: agent.address,
|
|
154
|
+
admin: agent.address,
|
|
151
155
|
bps: 8000,
|
|
152
156
|
token: "Paired",
|
|
153
157
|
},
|
|
@@ -183,7 +187,7 @@ export function launchCommand(program) {
|
|
|
183
187
|
txHash,
|
|
184
188
|
agentName: opts.agent,
|
|
185
189
|
agentAddress: agent.address,
|
|
186
|
-
creatorAddress:
|
|
190
|
+
creatorAddress: agent.address,
|
|
187
191
|
imgUrl: opts.image ?? null,
|
|
188
192
|
description: opts.description ?? null,
|
|
189
193
|
}),
|
package/dist/commands/wallet.js
CHANGED
|
@@ -1,166 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import ora from "ora";
|
|
3
|
-
import { loadConfig, saveConfig } from "../lib/config.js";
|
|
4
|
-
import { getEthBalance, getOtxBalance, formatOtx, generateWallet, addressFromKey, OTX_REQUIRED, } from "../lib/chain.js";
|
|
5
|
-
import { header, row, success, failure, info, br, warn } from "../lib/display.js";
|
|
1
|
+
import { header, br } from "../lib/display.js";
|
|
6
2
|
import chalk from "chalk";
|
|
7
3
|
export function walletCommand(program) {
|
|
8
|
-
const wallet = program.command("wallet").description("
|
|
4
|
+
const wallet = program.command("wallet").description("Wallet info — each agent has its own wallet");
|
|
9
5
|
wallet
|
|
10
6
|
.command("generate")
|
|
11
|
-
.description("
|
|
12
|
-
.action(
|
|
13
|
-
header("Generate
|
|
14
|
-
const cfg = loadConfig();
|
|
15
|
-
if (cfg.wallet) {
|
|
16
|
-
const overwrite = await confirm({
|
|
17
|
-
message: `Wallet ${chalk.dim(cfg.wallet.address)} already exists. Replace it?`,
|
|
18
|
-
default: false,
|
|
19
|
-
});
|
|
20
|
-
if (!overwrite) {
|
|
21
|
-
info("Cancelled. Existing wallet kept.");
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
const spinner = ora("Generating new Base wallet...").start();
|
|
26
|
-
await new Promise(r => setTimeout(r, 500));
|
|
27
|
-
const { address, privateKey } = generateWallet();
|
|
28
|
-
spinner.stop();
|
|
29
|
-
cfg.wallet = { address, privateKey };
|
|
30
|
-
saveConfig(cfg);
|
|
31
|
-
success("Creator wallet generated!");
|
|
32
|
-
br();
|
|
33
|
-
row("Address", address);
|
|
34
|
-
row("Network", "Base Mainnet");
|
|
35
|
-
row("Stored at", "~/.otonix/config.json");
|
|
7
|
+
.description("Wallets are created per-agent. Use: otonix agent:create --name <name>")
|
|
8
|
+
.action(() => {
|
|
9
|
+
header("Wallet Generate");
|
|
36
10
|
br();
|
|
37
|
-
console.log(chalk.
|
|
38
|
-
console.log(chalk.dim("To view your private key: ") + chalk.white("otonix wallet export"));
|
|
11
|
+
console.log(chalk.yellow("ℹ Each agent has its own wallet — no separate creator wallet needed."));
|
|
39
12
|
br();
|
|
40
|
-
console.log(chalk.dim("
|
|
41
|
-
console.log(
|
|
42
|
-
console.log(" " + chalk.yellow("ETH") + chalk.dim(" — for gas fees on Base"));
|
|
13
|
+
console.log(chalk.dim("Create an agent (generates wallet automatically):"));
|
|
14
|
+
console.log(' otonix agent:create --name "MyAgent"');
|
|
43
15
|
br();
|
|
16
|
+
console.log(chalk.dim("View agent wallet:"));
|
|
17
|
+
console.log(" otonix agent:info MyAgent");
|
|
44
18
|
});
|
|
45
19
|
wallet
|
|
46
20
|
.command("import")
|
|
47
|
-
.description("Import
|
|
48
|
-
.action(
|
|
49
|
-
header("Import
|
|
50
|
-
info("Your private key is stored locally at ~/.otonix/config.json");
|
|
51
|
-
info("Never share it. Otonix never transmits it.");
|
|
21
|
+
.description("Import a private key as an agent wallet")
|
|
22
|
+
.action(() => {
|
|
23
|
+
header("Wallet Import");
|
|
52
24
|
br();
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
default: false,
|
|
58
|
-
});
|
|
59
|
-
if (!overwrite) {
|
|
60
|
-
info("Cancelled.");
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const pk = await password({
|
|
65
|
-
message: "Enter your private key (0x...):",
|
|
66
|
-
mask: "•",
|
|
67
|
-
});
|
|
68
|
-
if (!pk.startsWith("0x") || pk.length !== 66) {
|
|
69
|
-
failure("Invalid private key format. Must be 0x followed by 64 hex chars.");
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
const spinner = ora("Verifying key...").start();
|
|
73
|
-
try {
|
|
74
|
-
const address = addressFromKey(pk);
|
|
75
|
-
cfg.wallet = { address, privateKey: pk };
|
|
76
|
-
saveConfig(cfg);
|
|
77
|
-
spinner.stop();
|
|
78
|
-
success("Wallet imported!");
|
|
79
|
-
br();
|
|
80
|
-
row("Address", address);
|
|
81
|
-
row("Config", "~/.otonix/config.json");
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
spinner.stop();
|
|
85
|
-
failure("Invalid private key.");
|
|
86
|
-
process.exit(1);
|
|
87
|
-
}
|
|
25
|
+
console.log(chalk.yellow("ℹ To import an existing private key as an agent wallet, use:"));
|
|
26
|
+
br();
|
|
27
|
+
console.log(chalk.dim("(This feature is coming soon — for now, create a new agent wallet)"));
|
|
28
|
+
console.log(' otonix agent:create --name "MyAgent"');
|
|
88
29
|
});
|
|
89
30
|
wallet
|
|
90
31
|
.command("export")
|
|
91
|
-
.description("
|
|
92
|
-
.action(
|
|
93
|
-
const cfg = loadConfig();
|
|
94
|
-
if (!cfg.wallet) {
|
|
95
|
-
failure("No wallet. Run: otonix wallet generate");
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}
|
|
98
|
-
const confirmed = await confirm({
|
|
99
|
-
message: chalk.red("⚠ This will display your private key. Continue?"),
|
|
100
|
-
default: false,
|
|
101
|
-
});
|
|
102
|
-
if (!confirmed) {
|
|
103
|
-
info("Cancelled.");
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
32
|
+
.description("Export agent private key — use: otonix agent:export <name>")
|
|
33
|
+
.action(() => {
|
|
106
34
|
header("Wallet Export");
|
|
107
35
|
br();
|
|
108
|
-
|
|
109
|
-
row("Private key", cfg.wallet.privateKey);
|
|
36
|
+
console.log(chalk.yellow("ℹ Private keys are stored per-agent. Export with:"));
|
|
110
37
|
br();
|
|
111
|
-
console.log(
|
|
38
|
+
console.log(" otonix agent:export <agent-name>");
|
|
112
39
|
br();
|
|
40
|
+
console.log(chalk.dim("List your agents:"));
|
|
41
|
+
console.log(" otonix agent:list");
|
|
113
42
|
});
|
|
114
43
|
wallet
|
|
115
44
|
.command("balance")
|
|
116
|
-
.description("
|
|
117
|
-
.action(
|
|
45
|
+
.description("Check balance — use: otonix agent:info <name>")
|
|
46
|
+
.action(() => {
|
|
118
47
|
header("Wallet Balance");
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
try {
|
|
127
|
-
const [eth, otx] = await Promise.all([
|
|
128
|
-
getEthBalance(address),
|
|
129
|
-
getOtxBalance(address),
|
|
130
|
-
]);
|
|
131
|
-
spinner.stop();
|
|
132
|
-
br();
|
|
133
|
-
row("Address", address);
|
|
134
|
-
row("Network", "Base Mainnet");
|
|
135
|
-
row("ETH balance", parseFloat(eth).toFixed(6) + " ETH");
|
|
136
|
-
row("$OTX balance", formatOtx(otx) + " OTX");
|
|
137
|
-
br();
|
|
138
|
-
if (otx >= OTX_REQUIRED) {
|
|
139
|
-
console.log(chalk.green("✓ ") + chalk.dim("Eligible to create agents (≥200 $OTX)"));
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
const need = formatOtx(OTX_REQUIRED - otx);
|
|
143
|
-
console.log(warn("⚠ ") + chalk.dim(`Need ${need} more $OTX to activate agents`));
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
spinner.stop();
|
|
148
|
-
failure("Failed to fetch balances. Check your internet connection.");
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
48
|
+
br();
|
|
49
|
+
console.log(chalk.yellow("ℹ Balances are tracked per-agent. Check with:"));
|
|
50
|
+
br();
|
|
51
|
+
console.log(" otonix agent:info <agent-name>");
|
|
52
|
+
br();
|
|
53
|
+
console.log(chalk.dim("List your agents:"));
|
|
54
|
+
console.log(" otonix agent:list");
|
|
151
55
|
});
|
|
152
56
|
wallet
|
|
153
57
|
.command("address")
|
|
154
|
-
.description("Show
|
|
58
|
+
.description("Show agent address — use: otonix agent:info <name>")
|
|
155
59
|
.action(() => {
|
|
156
|
-
const cfg = loadConfig();
|
|
157
|
-
if (!cfg.wallet) {
|
|
158
|
-
failure("No wallet. Run: otonix wallet generate");
|
|
159
|
-
process.exit(1);
|
|
160
|
-
}
|
|
161
60
|
header("Wallet Address");
|
|
162
61
|
br();
|
|
163
|
-
|
|
164
|
-
|
|
62
|
+
console.log(chalk.yellow("ℹ Each agent has its own wallet address. View with:"));
|
|
63
|
+
br();
|
|
64
|
+
console.log(" otonix agent:info <agent-name>");
|
|
165
65
|
});
|
|
166
66
|
}
|
package/dist/lib/chain.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Address } from "viem";
|
|
2
2
|
export declare const OTX_ADDRESS: Address;
|
|
3
3
|
export declare const BASE_RPC = "https://mainnet.base.org";
|
|
4
|
+
export declare const BASE_MEV_RPC = "https://rpc.flashbots.net?chain=8453";
|
|
4
5
|
export declare const OTX_DECIMALS = 18;
|
|
5
6
|
export declare const OTX_REQUIRED: bigint;
|
|
6
7
|
export declare const publicClient: {
|
package/dist/lib/chain.js
CHANGED
|
@@ -3,6 +3,7 @@ import { base } from "viem/chains";
|
|
|
3
3
|
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
4
4
|
export const OTX_ADDRESS = "0xF7E2a6226Ffe0693DD85406AC3A8917cbea5DC40";
|
|
5
5
|
export const BASE_RPC = "https://mainnet.base.org";
|
|
6
|
+
export const BASE_MEV_RPC = "https://rpc.flashbots.net?chain=8453";
|
|
6
7
|
export const OTX_DECIMALS = 18;
|
|
7
8
|
export const OTX_REQUIRED = 200n * 10n ** 18n;
|
|
8
9
|
export const publicClient = createPublicClient({
|