@t2000/cli 0.22.8 → 0.22.10
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 +14 -12
- package/dist/{dist-NXFA54RO.js → dist-3RLXPNZ5.js} +16 -14
- package/dist/{dist-NXFA54RO.js.map → dist-3RLXPNZ5.js.map} +1 -1
- package/dist/index.js +186 -173
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -288,7 +288,7 @@ function registerInit(program2) {
|
|
|
288
288
|
} else {
|
|
289
289
|
console.log(` \u2502 Use the CLI directly: \u2502`);
|
|
290
290
|
console.log(` \u2502 ${pc2.cyan("t2000 balance")} \u2502`);
|
|
291
|
-
console.log(` \u2502 ${pc2.cyan("t2000
|
|
291
|
+
console.log(` \u2502 ${pc2.cyan("t2000 buy 100 BTC")} \u2502`);
|
|
292
292
|
console.log(` \u2502 \u2502`);
|
|
293
293
|
}
|
|
294
294
|
console.log(` \u2502 Deposit USDC to get started: \u2502`);
|
|
@@ -1605,7 +1605,7 @@ function registerLock(program2) {
|
|
|
1605
1605
|
});
|
|
1606
1606
|
program2.command("unlock").description("Unlock agent \u2014 resume operations").action(async () => {
|
|
1607
1607
|
try {
|
|
1608
|
-
const { T2000:
|
|
1608
|
+
const { T2000: T200029 } = await import("@t2000/sdk");
|
|
1609
1609
|
const MAX_ATTEMPTS2 = 3;
|
|
1610
1610
|
let pin;
|
|
1611
1611
|
for (let attempt = 1; attempt <= MAX_ATTEMPTS2; attempt++) {
|
|
@@ -1614,7 +1614,7 @@ function registerLock(program2) {
|
|
|
1614
1614
|
throw new Error("PIN required to unlock agent");
|
|
1615
1615
|
}
|
|
1616
1616
|
try {
|
|
1617
|
-
await
|
|
1617
|
+
await T200029.create({ pin });
|
|
1618
1618
|
break;
|
|
1619
1619
|
} catch (error) {
|
|
1620
1620
|
const msg = error instanceof Error ? error.message : "";
|
|
@@ -2034,7 +2034,8 @@ function displayAsset(asset) {
|
|
|
2034
2034
|
}
|
|
2035
2035
|
|
|
2036
2036
|
// src/commands/exchange.ts
|
|
2037
|
-
import { T2000 as T200023,
|
|
2037
|
+
import { T2000 as T200023, SUPPORTED_ASSETS as SUPPORTED_ASSETS3 } from "@t2000/sdk";
|
|
2038
|
+
import pc14 from "picocolors";
|
|
2038
2039
|
function resolveAssetName(input) {
|
|
2039
2040
|
const upper = input.toUpperCase();
|
|
2040
2041
|
for (const key of Object.keys(SUPPORTED_ASSETS3)) {
|
|
@@ -2043,19 +2044,16 @@ function resolveAssetName(input) {
|
|
|
2043
2044
|
return input;
|
|
2044
2045
|
}
|
|
2045
2046
|
function registerExchange(program2) {
|
|
2046
|
-
program2.command("exchange <amount> <from> <to>").description(
|
|
2047
|
+
program2.command("exchange <amount> <from> <to>").description('[deprecated \u2014 use "swap" instead] Exchange between tokens').option("--key <path>", "Key file path").option("--slippage <pct>", "Max slippage percentage (default: 3)", "3").action(async (amount, from, to, opts) => {
|
|
2047
2048
|
try {
|
|
2049
|
+
console.error(pc14.yellow(' \u26A0 "exchange" is deprecated. Use "swap" instead: t2000 swap %s %s %s'), amount, from, to);
|
|
2048
2050
|
const pin = await resolvePin();
|
|
2049
2051
|
const agent = await T200023.create({ pin, keyPath: opts.key });
|
|
2050
|
-
const fromAsset = resolveAssetName(from);
|
|
2051
|
-
const toAsset = resolveAssetName(to);
|
|
2052
2052
|
const parsedAmount = parseFloat(amount);
|
|
2053
|
-
if (isNaN(parsedAmount) || parsedAmount <= 0)
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
from: fromAsset,
|
|
2058
|
-
to: toAsset,
|
|
2053
|
+
if (isNaN(parsedAmount) || parsedAmount <= 0) throw new Error("Amount must be a positive number");
|
|
2054
|
+
const result = await agent.swap({
|
|
2055
|
+
from: resolveAssetName(from),
|
|
2056
|
+
to: resolveAssetName(to),
|
|
2059
2057
|
amount: parsedAmount,
|
|
2060
2058
|
maxSlippage: parseFloat(opts.slippage ?? "3") / 100
|
|
2061
2059
|
});
|
|
@@ -2063,15 +2061,87 @@ function registerExchange(program2) {
|
|
|
2063
2061
|
printJson(result);
|
|
2064
2062
|
return;
|
|
2065
2063
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2064
|
+
console.log(pc14.green(" \u2713 Swapped. Tx: %s"), result.tx);
|
|
2065
|
+
} catch (error) {
|
|
2066
|
+
handleError(error);
|
|
2067
|
+
}
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
// src/commands/swap.ts
|
|
2072
|
+
import { T2000 as T200024, formatUsd as formatUsd14, SUPPORTED_ASSETS as SUPPORTED_ASSETS4 } from "@t2000/sdk";
|
|
2073
|
+
function resolveAssetName2(input) {
|
|
2074
|
+
const upper = input.toUpperCase();
|
|
2075
|
+
for (const key of Object.keys(SUPPORTED_ASSETS4)) {
|
|
2076
|
+
if (key.toUpperCase() === upper) return key;
|
|
2077
|
+
}
|
|
2078
|
+
return input;
|
|
2079
|
+
}
|
|
2080
|
+
function fmtTokenAmount(amount, asset) {
|
|
2081
|
+
if (["USDC", "USDT", "USDE"].includes(asset)) return formatUsd14(amount);
|
|
2082
|
+
if (amount > 0 && amount < 1e-3) return amount.toFixed(8);
|
|
2083
|
+
if (amount > 0 && amount < 1) return amount.toFixed(6);
|
|
2084
|
+
return amount.toFixed(4);
|
|
2085
|
+
}
|
|
2086
|
+
async function executeSwap(from, to, amount, opts, label) {
|
|
2087
|
+
const pin = await resolvePin();
|
|
2088
|
+
const agent = await T200024.create({ pin, keyPath: opts.key });
|
|
2089
|
+
const fromAsset = resolveAssetName2(from);
|
|
2090
|
+
const toAsset = resolveAssetName2(to);
|
|
2091
|
+
const result = await agent.swap({
|
|
2092
|
+
from: fromAsset,
|
|
2093
|
+
to: toAsset,
|
|
2094
|
+
amount,
|
|
2095
|
+
maxSlippage: parseFloat(opts.slippage ?? "3") / 100
|
|
2096
|
+
});
|
|
2097
|
+
if (isJsonMode()) {
|
|
2098
|
+
printJson(result);
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
const fromDisplay = SUPPORTED_ASSETS4[fromAsset]?.displayName ?? fromAsset;
|
|
2102
|
+
const toDisplay = SUPPORTED_ASSETS4[toAsset]?.displayName ?? toAsset;
|
|
2103
|
+
printBlank();
|
|
2104
|
+
if (label === "Bought") {
|
|
2105
|
+
printSuccess(`Bought ${fmtTokenAmount(result.toAmount, toAsset)} ${toDisplay} for ${formatUsd14(amount)}`);
|
|
2106
|
+
} else if (label === "Sold") {
|
|
2107
|
+
printSuccess(`Sold ${fmtTokenAmount(amount, fromAsset)} ${fromDisplay} for ${formatUsd14(result.toAmount)}`);
|
|
2108
|
+
} else {
|
|
2109
|
+
printSuccess(`Swapped ${fmtTokenAmount(amount, fromAsset)} ${fromDisplay} \u2192 ${fmtTokenAmount(result.toAmount, toAsset)} ${toDisplay}`);
|
|
2110
|
+
}
|
|
2111
|
+
printKeyValue("Tx", explorerUrl(result.tx));
|
|
2112
|
+
printKeyValue("Gas", `${result.gasCost.toFixed(4)} SUI (${result.gasMethod})`);
|
|
2113
|
+
printBlank();
|
|
2114
|
+
}
|
|
2115
|
+
function registerSwap(program2) {
|
|
2116
|
+
program2.command("swap <amount> <from> <to>").description("Swap tokens (e.g. swap 100 USDC SUI)").option("--key <path>", "Key file path").option("--slippage <pct>", "Max slippage percentage (default: 3)", "3").action(async (amount, from, to, opts) => {
|
|
2117
|
+
try {
|
|
2118
|
+
const parsedAmount = parseFloat(amount);
|
|
2119
|
+
if (isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
2120
|
+
throw new Error("Amount must be a positive number");
|
|
2121
|
+
}
|
|
2122
|
+
await executeSwap(from, to, parsedAmount, opts, "Swapped");
|
|
2123
|
+
} catch (error) {
|
|
2124
|
+
handleError(error);
|
|
2125
|
+
}
|
|
2126
|
+
});
|
|
2127
|
+
program2.command("buy <amount> <asset>").description("Buy an asset with USDC (e.g. buy 100 BTC)").option("--key <path>", "Key file path").option("--slippage <pct>", "Max slippage percentage (default: 3)", "3").action(async (amount, asset, opts) => {
|
|
2128
|
+
try {
|
|
2129
|
+
const parsedAmount = parseFloat(amount);
|
|
2130
|
+
if (isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
2131
|
+
throw new Error("Amount must be a positive number");
|
|
2132
|
+
}
|
|
2133
|
+
await executeSwap("USDC", asset, parsedAmount, opts, "Bought");
|
|
2134
|
+
} catch (error) {
|
|
2135
|
+
handleError(error);
|
|
2136
|
+
}
|
|
2137
|
+
});
|
|
2138
|
+
program2.command("sell <amount> <asset>").description("Sell an asset for USDC (e.g. sell 0.001 BTC)").option("--key <path>", "Key file path").option("--slippage <pct>", "Max slippage percentage (default: 3)", "3").action(async (amount, asset, opts) => {
|
|
2139
|
+
try {
|
|
2140
|
+
const parsedAmount = parseFloat(amount);
|
|
2141
|
+
if (isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
2142
|
+
throw new Error("Amount must be a positive number");
|
|
2143
|
+
}
|
|
2144
|
+
await executeSwap(asset, "USDC", parsedAmount, opts, "Sold");
|
|
2075
2145
|
} catch (error) {
|
|
2076
2146
|
handleError(error);
|
|
2077
2147
|
}
|
|
@@ -2124,7 +2194,7 @@ function registerMcp(program2) {
|
|
|
2124
2194
|
mcp.command("start", { isDefault: true }).description("Start MCP server (stdio transport)").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2125
2195
|
let mod;
|
|
2126
2196
|
try {
|
|
2127
|
-
mod = await import("./dist-
|
|
2197
|
+
mod = await import("./dist-3RLXPNZ5.js");
|
|
2128
2198
|
} catch {
|
|
2129
2199
|
console.error(
|
|
2130
2200
|
"MCP server not installed. Run:\n npm install -g @t2000/mcp"
|
|
@@ -2276,20 +2346,21 @@ function registerContacts(program2) {
|
|
|
2276
2346
|
}
|
|
2277
2347
|
|
|
2278
2348
|
// src/commands/invest.ts
|
|
2279
|
-
import
|
|
2280
|
-
import { T2000 as
|
|
2349
|
+
import pc15 from "picocolors";
|
|
2350
|
+
import { T2000 as T200025, formatUsd as formatUsd15, formatAssetAmount as formatAssetAmount4, INVESTMENT_ASSETS as INVESTMENT_ASSETS2 } from "@t2000/sdk";
|
|
2281
2351
|
function registerInvest(program2) {
|
|
2282
|
-
const investCmd = program2.command("invest").description("
|
|
2283
|
-
investCmd.command("buy <amount> <asset>").description("
|
|
2352
|
+
const investCmd = program2.command("invest").description("Investment strategies, DCA, and yield earning");
|
|
2353
|
+
investCmd.command("buy <amount> <asset>").description('[deprecated \u2014 use "buy" instead] Buy an asset').option("--key <path>", "Key file path").option("--slippage <pct>", "Max slippage percent", "3").action(async (amount, asset, opts) => {
|
|
2284
2354
|
try {
|
|
2355
|
+
console.error(pc15.yellow(` \u26A0 "invest buy" is deprecated. Use: t2000 buy ${amount} ${asset}`));
|
|
2285
2356
|
const parsed = parseFloat(amount);
|
|
2286
2357
|
if (isNaN(parsed) || parsed <= 0 || !isFinite(parsed)) {
|
|
2287
|
-
console.error(
|
|
2358
|
+
console.error(pc15.red(" \u2717 Amount must be greater than $0"));
|
|
2288
2359
|
process.exitCode = 1;
|
|
2289
2360
|
return;
|
|
2290
2361
|
}
|
|
2291
2362
|
const pin = await resolvePin();
|
|
2292
|
-
const agent = await
|
|
2363
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2293
2364
|
const result = await agent.investBuy({
|
|
2294
2365
|
asset: asset.toUpperCase(),
|
|
2295
2366
|
usdAmount: parsed,
|
|
@@ -2303,33 +2374,27 @@ function registerInvest(program2) {
|
|
|
2303
2374
|
const sym = asset.toUpperCase();
|
|
2304
2375
|
printSuccess(`Bought ${formatAssetAmount4(result.amount, sym)} ${sym} at ${formatUsd15(result.price)}`);
|
|
2305
2376
|
printKeyValue("Invested", formatUsd15(result.usdValue));
|
|
2306
|
-
printKeyValue("Portfolio", `${formatAssetAmount4(result.position.totalAmount, sym)} ${sym} (avg ${formatUsd15(result.position.avgPrice)})`);
|
|
2307
2377
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
2308
2378
|
printBlank();
|
|
2309
2379
|
} catch (error) {
|
|
2310
2380
|
handleError(error);
|
|
2311
2381
|
}
|
|
2312
2382
|
});
|
|
2313
|
-
investCmd.command("sell <amount> <asset>").description('
|
|
2383
|
+
investCmd.command("sell <amount> <asset>").description('[deprecated \u2014 use "sell" instead] Sell an asset').option("--key <path>", "Key file path").option("--slippage <pct>", "Max slippage percent", "3").action(async (amount, asset, opts) => {
|
|
2314
2384
|
try {
|
|
2385
|
+
console.error(pc15.yellow(` \u26A0 "invest sell" is deprecated. Use: t2000 sell ${amount} ${asset}`));
|
|
2315
2386
|
const isAll = amount.toLowerCase() === "all";
|
|
2316
2387
|
if (!isAll) {
|
|
2317
2388
|
const parsed = parseFloat(amount);
|
|
2318
2389
|
if (isNaN(parsed) || parsed <= 0 || !isFinite(parsed)) {
|
|
2319
|
-
console.error(
|
|
2390
|
+
console.error(pc15.red(" \u2717 Amount must be greater than $0"));
|
|
2320
2391
|
process.exitCode = 1;
|
|
2321
2392
|
return;
|
|
2322
2393
|
}
|
|
2323
2394
|
}
|
|
2324
2395
|
const pin = await resolvePin();
|
|
2325
|
-
const agent = await
|
|
2396
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2326
2397
|
const sym = asset.toUpperCase();
|
|
2327
|
-
const strategyAmount = agent.portfolio.getStrategyAmountForAsset(sym);
|
|
2328
|
-
const directAmount = agent.portfolio.getDirectAmount(sym);
|
|
2329
|
-
if (isAll && strategyAmount > 0) {
|
|
2330
|
-
console.log(pc14.yellow(` \u26A0 This will sell ALL ${sym} including ${formatAssetAmount4(strategyAmount, sym)} from strategies`));
|
|
2331
|
-
console.log(pc14.dim(` To sell only strategy positions: t2000 invest strategy sell <strategy-name>`));
|
|
2332
|
-
}
|
|
2333
2398
|
const usdAmount = isAll ? "all" : parseFloat(amount);
|
|
2334
2399
|
const result = await agent.investSell({
|
|
2335
2400
|
asset: sym,
|
|
@@ -2344,84 +2409,20 @@ function registerInvest(program2) {
|
|
|
2344
2409
|
printSuccess(`Sold ${formatAssetAmount4(result.amount, sym)} ${sym} at ${formatUsd15(result.price)}`);
|
|
2345
2410
|
printKeyValue("Proceeds", formatUsd15(result.usdValue));
|
|
2346
2411
|
if (result.realizedPnL !== void 0) {
|
|
2347
|
-
const pnlColor = result.realizedPnL >= 0 ?
|
|
2412
|
+
const pnlColor = result.realizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2348
2413
|
const pnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
2349
2414
|
printKeyValue("Realized P&L", pnlColor(`${pnlSign}${formatUsd15(result.realizedPnL)}`));
|
|
2350
2415
|
}
|
|
2351
|
-
if (result.position.totalAmount > 0) {
|
|
2352
|
-
printKeyValue("Remaining", `${formatAssetAmount4(result.position.totalAmount, sym)} ${sym} (avg ${formatUsd15(result.position.avgPrice)})`);
|
|
2353
|
-
}
|
|
2354
2416
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
2355
2417
|
printBlank();
|
|
2356
2418
|
} catch (error) {
|
|
2357
2419
|
handleError(error);
|
|
2358
2420
|
}
|
|
2359
2421
|
});
|
|
2360
|
-
investCmd.command("sell-all").description("Sell ALL investment positions (direct + strategies)").option("--key <path>", "Key file path").option("--slippage <pct>", "Max slippage percent", "3").action(async (opts) => {
|
|
2361
|
-
try {
|
|
2362
|
-
const pin = await resolvePin();
|
|
2363
|
-
const agent = await T200024.create({ pin, keyPath: opts.key });
|
|
2364
|
-
const positions = agent.portfolio.getPositions();
|
|
2365
|
-
if (positions.length === 0) {
|
|
2366
|
-
if (isJsonMode()) {
|
|
2367
|
-
printJson({ sold: [] });
|
|
2368
|
-
return;
|
|
2369
|
-
}
|
|
2370
|
-
printBlank();
|
|
2371
|
-
printInfo("No investment positions to sell");
|
|
2372
|
-
printBlank();
|
|
2373
|
-
return;
|
|
2374
|
-
}
|
|
2375
|
-
if (isJsonMode()) {
|
|
2376
|
-
const results = [];
|
|
2377
|
-
for (const pos of positions) {
|
|
2378
|
-
const result = await agent.investSell({
|
|
2379
|
-
asset: pos.asset,
|
|
2380
|
-
usdAmount: "all",
|
|
2381
|
-
maxSlippage: parseFloat(opts.slippage) / 100
|
|
2382
|
-
});
|
|
2383
|
-
results.push(result);
|
|
2384
|
-
}
|
|
2385
|
-
printJson(results);
|
|
2386
|
-
return;
|
|
2387
|
-
}
|
|
2388
|
-
printBlank();
|
|
2389
|
-
printHeader("Selling all positions");
|
|
2390
|
-
printSeparator();
|
|
2391
|
-
let totalProceeds = 0;
|
|
2392
|
-
let totalPnL = 0;
|
|
2393
|
-
for (const pos of positions) {
|
|
2394
|
-
try {
|
|
2395
|
-
const result = await agent.investSell({
|
|
2396
|
-
asset: pos.asset,
|
|
2397
|
-
usdAmount: "all",
|
|
2398
|
-
maxSlippage: parseFloat(opts.slippage) / 100
|
|
2399
|
-
});
|
|
2400
|
-
const pnl = result.realizedPnL ?? 0;
|
|
2401
|
-
const pnlColor = pnl >= 0 ? pc14.green : pc14.red;
|
|
2402
|
-
const pnlSign = pnl >= 0 ? "+" : "";
|
|
2403
|
-
printKeyValue(pos.asset, `${formatUsd15(result.usdValue)} ${pnlColor(`${pnlSign}${formatUsd15(pnl)}`)}`);
|
|
2404
|
-
totalProceeds += result.usdValue;
|
|
2405
|
-
totalPnL += pnl;
|
|
2406
|
-
} catch (err) {
|
|
2407
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2408
|
-
console.error(pc14.yellow(` \u26A0 ${pos.asset}: ${msg}`));
|
|
2409
|
-
}
|
|
2410
|
-
}
|
|
2411
|
-
printSeparator();
|
|
2412
|
-
printKeyValue("Total proceeds", formatUsd15(totalProceeds));
|
|
2413
|
-
const rpnlColor = totalPnL >= 0 ? pc14.green : pc14.red;
|
|
2414
|
-
const rpnlSign = totalPnL >= 0 ? "+" : "";
|
|
2415
|
-
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd15(totalPnL)}`));
|
|
2416
|
-
printBlank();
|
|
2417
|
-
} catch (error) {
|
|
2418
|
-
handleError(error);
|
|
2419
|
-
}
|
|
2420
|
-
});
|
|
2421
2422
|
investCmd.command("earn <asset>").description("Deposit invested asset into best-rate lending protocol").option("--key <path>", "Key file path").option("--protocol <name>", "Force a specific protocol (navi, suilend)").action(async (asset, opts) => {
|
|
2422
2423
|
try {
|
|
2423
2424
|
const pin = await resolvePin();
|
|
2424
|
-
const agent = await
|
|
2425
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2425
2426
|
const result = await agent.investEarn({
|
|
2426
2427
|
asset: asset.toUpperCase(),
|
|
2427
2428
|
protocol: opts.protocol?.toLowerCase()
|
|
@@ -2449,7 +2450,7 @@ function registerInvest(program2) {
|
|
|
2449
2450
|
investCmd.command("unearn <asset>").description("Withdraw invested asset from lending (keeps in portfolio)").option("--key <path>", "Key file path").action(async (asset, opts) => {
|
|
2450
2451
|
try {
|
|
2451
2452
|
const pin = await resolvePin();
|
|
2452
|
-
const agent = await
|
|
2453
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2453
2454
|
const result = await agent.investUnearn({
|
|
2454
2455
|
asset: asset.toUpperCase()
|
|
2455
2456
|
});
|
|
@@ -2460,7 +2461,7 @@ function registerInvest(program2) {
|
|
|
2460
2461
|
printBlank();
|
|
2461
2462
|
const sym = asset.toUpperCase();
|
|
2462
2463
|
printSuccess(`Withdrew ${formatAssetAmount4(result.amount, sym)} ${sym} from ${result.protocol}`);
|
|
2463
|
-
printKeyValue("Status", `${sym}
|
|
2464
|
+
printKeyValue("Status", `${sym} withdrawn to wallet`);
|
|
2464
2465
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
2465
2466
|
printBlank();
|
|
2466
2467
|
} catch (error) {
|
|
@@ -2470,7 +2471,7 @@ function registerInvest(program2) {
|
|
|
2470
2471
|
investCmd.command("rebalance").description("Move earning positions to better-rate protocols").option("--key <path>", "Key file path").option("--dry-run", "Preview moves without executing").option("--min-diff <pct>", "Minimum APY difference to trigger move", "0.1").action(async (opts) => {
|
|
2471
2472
|
try {
|
|
2472
2473
|
const pin = await resolvePin();
|
|
2473
|
-
const agent = await
|
|
2474
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2474
2475
|
const result = await agent.investRebalance({
|
|
2475
2476
|
dryRun: opts.dryRun,
|
|
2476
2477
|
minYieldDiff: opts.minDiff ? parseFloat(opts.minDiff) : void 0
|
|
@@ -2525,7 +2526,7 @@ function registerInvest(program2) {
|
|
|
2525
2526
|
strategyCmd.command("list").description("List available strategies").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2526
2527
|
try {
|
|
2527
2528
|
const pin = await resolvePin();
|
|
2528
|
-
const agent = await
|
|
2529
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2529
2530
|
const all = agent.strategies.getAll();
|
|
2530
2531
|
if (isJsonMode()) {
|
|
2531
2532
|
printJson(all);
|
|
@@ -2536,9 +2537,9 @@ function registerInvest(program2) {
|
|
|
2536
2537
|
printSeparator();
|
|
2537
2538
|
for (const [key, def] of Object.entries(all)) {
|
|
2538
2539
|
const allocs = Object.entries(def.allocations).map(([a, p]) => `${a} ${p}%`).join(", ");
|
|
2539
|
-
const tag = def.custom ?
|
|
2540
|
+
const tag = def.custom ? pc15.dim(" (custom)") : "";
|
|
2540
2541
|
printKeyValue(key, `${allocs}${tag}`);
|
|
2541
|
-
printLine(` ${
|
|
2542
|
+
printLine(` ${pc15.dim(def.description)}`);
|
|
2542
2543
|
}
|
|
2543
2544
|
printSeparator();
|
|
2544
2545
|
const hasPositions = Object.keys(all).some((k) => agent.portfolio.hasStrategyPositions(k));
|
|
@@ -2554,12 +2555,12 @@ function registerInvest(program2) {
|
|
|
2554
2555
|
try {
|
|
2555
2556
|
const parsed = parseFloat(amount);
|
|
2556
2557
|
if (isNaN(parsed) || parsed <= 0) {
|
|
2557
|
-
console.error(
|
|
2558
|
+
console.error(pc15.red(" \u2717 Amount must be greater than $0"));
|
|
2558
2559
|
process.exitCode = 1;
|
|
2559
2560
|
return;
|
|
2560
2561
|
}
|
|
2561
2562
|
const pin = await resolvePin();
|
|
2562
|
-
const agent = await
|
|
2563
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2563
2564
|
const result = await agent.investStrategy({ strategy: name.toLowerCase(), usdAmount: parsed, dryRun: opts.dryRun });
|
|
2564
2565
|
if (isJsonMode()) {
|
|
2565
2566
|
printJson(result);
|
|
@@ -2588,7 +2589,7 @@ function registerInvest(program2) {
|
|
|
2588
2589
|
printKeyValue("Tx", explorerUrl(txDigests[0]));
|
|
2589
2590
|
} else {
|
|
2590
2591
|
for (const buy of result.buys) {
|
|
2591
|
-
printLine(` ${
|
|
2592
|
+
printLine(` ${pc15.dim(`${buy.asset}: ${explorerUrl(buy.tx)}`)}`);
|
|
2592
2593
|
}
|
|
2593
2594
|
}
|
|
2594
2595
|
}
|
|
@@ -2600,7 +2601,7 @@ function registerInvest(program2) {
|
|
|
2600
2601
|
strategyCmd.command("sell <name>").description("Sell all positions in a strategy").option("--key <path>", "Key file path").action(async (name, opts) => {
|
|
2601
2602
|
try {
|
|
2602
2603
|
const pin = await resolvePin();
|
|
2603
|
-
const agent = await
|
|
2604
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2604
2605
|
const result = await agent.sellStrategy({ strategy: name.toLowerCase() });
|
|
2605
2606
|
if (isJsonMode()) {
|
|
2606
2607
|
printJson(result);
|
|
@@ -2610,18 +2611,18 @@ function registerInvest(program2) {
|
|
|
2610
2611
|
printSuccess(`Sold all ${name} strategy positions`);
|
|
2611
2612
|
printSeparator();
|
|
2612
2613
|
for (const sell of result.sells) {
|
|
2613
|
-
const pnlColor = sell.realizedPnL >= 0 ?
|
|
2614
|
+
const pnlColor = sell.realizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2614
2615
|
const pnlSign = sell.realizedPnL >= 0 ? "+" : "";
|
|
2615
2616
|
printKeyValue(sell.asset, `${formatAssetAmount4(sell.amount, sell.asset)} \u2192 ${formatUsd15(sell.usdValue)} ${pnlColor(`${pnlSign}${formatUsd15(sell.realizedPnL)}`)}`);
|
|
2616
2617
|
}
|
|
2617
2618
|
if (result.failed && result.failed.length > 0) {
|
|
2618
2619
|
for (const f of result.failed) {
|
|
2619
|
-
console.error(
|
|
2620
|
+
console.error(pc15.yellow(` \u26A0 ${f.asset}: ${f.reason}`));
|
|
2620
2621
|
}
|
|
2621
2622
|
}
|
|
2622
2623
|
printSeparator();
|
|
2623
2624
|
printKeyValue("Total proceeds", formatUsd15(result.totalProceeds));
|
|
2624
|
-
const rpnlColor = result.realizedPnL >= 0 ?
|
|
2625
|
+
const rpnlColor = result.realizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2625
2626
|
const rpnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
2626
2627
|
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd15(result.realizedPnL)}`));
|
|
2627
2628
|
printBlank();
|
|
@@ -2632,7 +2633,7 @@ function registerInvest(program2) {
|
|
|
2632
2633
|
strategyCmd.command("status <name>").description("Show current status and weights of a strategy").option("--key <path>", "Key file path").action(async (name, opts) => {
|
|
2633
2634
|
try {
|
|
2634
2635
|
const pin = await resolvePin();
|
|
2635
|
-
const agent = await
|
|
2636
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2636
2637
|
const status = await agent.getStrategyStatus(name.toLowerCase());
|
|
2637
2638
|
if (isJsonMode()) {
|
|
2638
2639
|
printJson(status);
|
|
@@ -2648,8 +2649,8 @@ function registerInvest(program2) {
|
|
|
2648
2649
|
const target = status.definition.allocations[pos.asset] ?? 0;
|
|
2649
2650
|
const actual = status.currentWeights[pos.asset] ?? 0;
|
|
2650
2651
|
const drift = actual - target;
|
|
2651
|
-
const driftColor = Math.abs(drift) > 3 ?
|
|
2652
|
-
const pnlColor = pos.unrealizedPnL >= 0 ?
|
|
2652
|
+
const driftColor = Math.abs(drift) > 3 ? pc15.yellow : pc15.dim;
|
|
2653
|
+
const pnlColor = pos.unrealizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2653
2654
|
const pnlSign = pos.unrealizedPnL >= 0 ? "+" : "";
|
|
2654
2655
|
printKeyValue(
|
|
2655
2656
|
pos.asset,
|
|
@@ -2667,7 +2668,7 @@ function registerInvest(program2) {
|
|
|
2667
2668
|
strategyCmd.command("rebalance <name>").description("Rebalance a strategy to target weights").option("--key <path>", "Key file path").action(async (name, opts) => {
|
|
2668
2669
|
try {
|
|
2669
2670
|
const pin = await resolvePin();
|
|
2670
|
-
const agent = await
|
|
2671
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2671
2672
|
const result = await agent.rebalanceStrategy({ strategy: name.toLowerCase() });
|
|
2672
2673
|
if (isJsonMode()) {
|
|
2673
2674
|
printJson(result);
|
|
@@ -2680,7 +2681,7 @@ function registerInvest(program2) {
|
|
|
2680
2681
|
printSuccess(`Rebalanced ${name} strategy`);
|
|
2681
2682
|
printSeparator();
|
|
2682
2683
|
for (const t of result.trades) {
|
|
2683
|
-
const action = t.action === "buy" ?
|
|
2684
|
+
const action = t.action === "buy" ? pc15.green("BUY") : pc15.red("SELL");
|
|
2684
2685
|
printKeyValue(t.asset, `${action} ${formatUsd15(t.usdAmount)} (${formatAssetAmount4(t.amount, t.asset)})`);
|
|
2685
2686
|
}
|
|
2686
2687
|
printSeparator();
|
|
@@ -2697,14 +2698,14 @@ function registerInvest(program2) {
|
|
|
2697
2698
|
for (const pair of opts.alloc) {
|
|
2698
2699
|
const [asset, pctStr] = pair.split(":");
|
|
2699
2700
|
if (!asset || !pctStr) {
|
|
2700
|
-
console.error(
|
|
2701
|
+
console.error(pc15.red(` \u2717 Invalid allocation: '${pair}'. Use ASSET:PCT format (e.g. SUI:60)`));
|
|
2701
2702
|
process.exitCode = 1;
|
|
2702
2703
|
return;
|
|
2703
2704
|
}
|
|
2704
2705
|
allocations[asset.toUpperCase()] = parseFloat(pctStr);
|
|
2705
2706
|
}
|
|
2706
2707
|
const pin = await resolvePin();
|
|
2707
|
-
const agent = await
|
|
2708
|
+
const agent = await T200025.create({ pin });
|
|
2708
2709
|
const definition = agent.strategies.create({ name, allocations, description: opts.description });
|
|
2709
2710
|
if (isJsonMode()) {
|
|
2710
2711
|
printJson(definition);
|
|
@@ -2722,9 +2723,9 @@ function registerInvest(program2) {
|
|
|
2722
2723
|
strategyCmd.command("delete <name>").description("Delete a custom strategy").option("--key <path>", "Key file path").action(async (name, opts) => {
|
|
2723
2724
|
try {
|
|
2724
2725
|
const pin = await resolvePin();
|
|
2725
|
-
const agent = await
|
|
2726
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2726
2727
|
if (agent.portfolio.hasStrategyPositions(name.toLowerCase())) {
|
|
2727
|
-
console.error(
|
|
2728
|
+
console.error(pc15.red(` \u2717 Strategy '${name}' has open positions. Sell first: t2000 invest strategy sell ${name}`));
|
|
2728
2729
|
process.exitCode = 1;
|
|
2729
2730
|
return;
|
|
2730
2731
|
}
|
|
@@ -2745,22 +2746,22 @@ function registerInvest(program2) {
|
|
|
2745
2746
|
try {
|
|
2746
2747
|
const parsed = parseFloat(amount);
|
|
2747
2748
|
if (isNaN(parsed) || parsed < 1) {
|
|
2748
|
-
console.error(
|
|
2749
|
+
console.error(pc15.red(" \u2717 Amount must be at least $1"));
|
|
2749
2750
|
process.exitCode = 1;
|
|
2750
2751
|
return;
|
|
2751
2752
|
}
|
|
2752
2753
|
if (!["daily", "weekly", "monthly"].includes(frequency)) {
|
|
2753
|
-
console.error(
|
|
2754
|
+
console.error(pc15.red(" \u2717 Frequency must be daily, weekly, or monthly"));
|
|
2754
2755
|
process.exitCode = 1;
|
|
2755
2756
|
return;
|
|
2756
2757
|
}
|
|
2757
2758
|
const pin = await resolvePin();
|
|
2758
|
-
const agent = await
|
|
2759
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2759
2760
|
const allStrategies = agent.strategies.getAll();
|
|
2760
2761
|
const isStrategy = target ? target.toLowerCase() in allStrategies : false;
|
|
2761
2762
|
const isAsset = target ? target.toUpperCase() in INVESTMENT_ASSETS2 : false;
|
|
2762
2763
|
if (target && !isStrategy && !isAsset) {
|
|
2763
|
-
console.error(
|
|
2764
|
+
console.error(pc15.red(` \u2717 '${target}' is not a valid strategy or asset`));
|
|
2764
2765
|
process.exitCode = 1;
|
|
2765
2766
|
return;
|
|
2766
2767
|
}
|
|
@@ -2791,7 +2792,7 @@ function registerInvest(program2) {
|
|
|
2791
2792
|
autoCmd.command("status").description("Show all DCA schedules").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2792
2793
|
try {
|
|
2793
2794
|
const pin = await resolvePin();
|
|
2794
|
-
const agent = await
|
|
2795
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2795
2796
|
const status = agent.getAutoInvestStatus();
|
|
2796
2797
|
if (isJsonMode()) {
|
|
2797
2798
|
printJson(status);
|
|
@@ -2807,9 +2808,9 @@ function registerInvest(program2) {
|
|
|
2807
2808
|
printSeparator();
|
|
2808
2809
|
for (const s of status.schedules) {
|
|
2809
2810
|
const target = s.strategy ?? s.asset ?? "?";
|
|
2810
|
-
const statusTag = s.enabled ?
|
|
2811
|
+
const statusTag = s.enabled ? pc15.green("active") : pc15.dim("paused");
|
|
2811
2812
|
printKeyValue(s.id, `${formatUsd15(s.amount)} ${s.frequency} \u2192 ${target} ${statusTag}`);
|
|
2812
|
-
printLine(` ${
|
|
2813
|
+
printLine(` ${pc15.dim(`Next: ${new Date(s.nextRun).toLocaleDateString()} \xB7 Runs: ${s.runCount} \xB7 Total: ${formatUsd15(s.totalInvested)}`)}`);
|
|
2813
2814
|
}
|
|
2814
2815
|
printSeparator();
|
|
2815
2816
|
if (status.pendingRuns.length > 0) {
|
|
@@ -2825,7 +2826,7 @@ function registerInvest(program2) {
|
|
|
2825
2826
|
autoCmd.command("run").description("Execute pending DCA purchases").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2826
2827
|
try {
|
|
2827
2828
|
const pin = await resolvePin();
|
|
2828
|
-
const agent = await
|
|
2829
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2829
2830
|
const status = agent.getAutoInvestStatus();
|
|
2830
2831
|
if (status.pendingRuns.length === 0) {
|
|
2831
2832
|
if (isJsonMode()) {
|
|
@@ -2852,7 +2853,7 @@ function registerInvest(program2) {
|
|
|
2852
2853
|
}
|
|
2853
2854
|
if (result.skipped.length > 0) {
|
|
2854
2855
|
for (const skip of result.skipped) {
|
|
2855
|
-
printLine(` ${
|
|
2856
|
+
printLine(` ${pc15.yellow("\u26A0")} Skipped ${skip.scheduleId}: ${skip.reason}`);
|
|
2856
2857
|
}
|
|
2857
2858
|
}
|
|
2858
2859
|
printBlank();
|
|
@@ -2863,7 +2864,7 @@ function registerInvest(program2) {
|
|
|
2863
2864
|
autoCmd.command("stop <id>").description("Stop an auto-invest schedule").option("--key <path>", "Key file path").action(async (id, opts) => {
|
|
2864
2865
|
try {
|
|
2865
2866
|
const pin = await resolvePin();
|
|
2866
|
-
const agent = await
|
|
2867
|
+
const agent = await T200025.create({ pin, keyPath: opts.key });
|
|
2867
2868
|
agent.stopAutoInvest(id);
|
|
2868
2869
|
if (isJsonMode()) {
|
|
2869
2870
|
printJson({ stopped: id });
|
|
@@ -2879,22 +2880,22 @@ function registerInvest(program2) {
|
|
|
2879
2880
|
}
|
|
2880
2881
|
|
|
2881
2882
|
// src/commands/portfolio.ts
|
|
2882
|
-
import
|
|
2883
|
-
import { T2000 as
|
|
2883
|
+
import pc16 from "picocolors";
|
|
2884
|
+
import { T2000 as T200026, formatUsd as formatUsd16, formatAssetAmount as formatAssetAmount5 } from "@t2000/sdk";
|
|
2884
2885
|
function printPositionLine(pos, rewardKeys) {
|
|
2885
2886
|
if (pos.currentPrice === 0 && pos.totalAmount > 0) {
|
|
2886
2887
|
printKeyValue(
|
|
2887
2888
|
pos.asset,
|
|
2888
|
-
`${formatAssetAmount5(pos.totalAmount, pos.asset)} Avg: ${formatUsd16(pos.avgPrice)} Now: ${
|
|
2889
|
+
`${formatAssetAmount5(pos.totalAmount, pos.asset)} Avg: ${formatUsd16(pos.avgPrice)} Now: ${pc16.yellow("unavailable")}`
|
|
2889
2890
|
);
|
|
2890
2891
|
} else {
|
|
2891
|
-
const pnlColor = pos.unrealizedPnL >= 0 ?
|
|
2892
|
+
const pnlColor = pos.unrealizedPnL >= 0 ? pc16.green : pc16.red;
|
|
2892
2893
|
const pnlSign = pos.unrealizedPnL >= 0 ? "+" : "";
|
|
2893
2894
|
let yieldSuffix = "";
|
|
2894
2895
|
if (pos.earning && pos.earningApy) {
|
|
2895
2896
|
const hasRewards = rewardKeys?.has(`${pos.earningProtocol}:${pos.asset}`);
|
|
2896
|
-
const rewardTag = hasRewards ? ` ${
|
|
2897
|
-
yieldSuffix = ` ${
|
|
2897
|
+
const rewardTag = hasRewards ? ` ${pc16.yellow("+rewards")}` : "";
|
|
2898
|
+
yieldSuffix = ` ${pc16.cyan(`${pos.earningApy.toFixed(1)}% APY (${pos.earningProtocol})`)}${rewardTag}`;
|
|
2898
2899
|
}
|
|
2899
2900
|
printKeyValue(
|
|
2900
2901
|
pos.asset,
|
|
@@ -2906,7 +2907,7 @@ function registerPortfolio(program2) {
|
|
|
2906
2907
|
program2.command("portfolio").description("Show investment portfolio").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2907
2908
|
try {
|
|
2908
2909
|
const pin = await resolvePin();
|
|
2909
|
-
const agent = await
|
|
2910
|
+
const agent = await T200026.create({ pin, keyPath: opts.key });
|
|
2910
2911
|
const portfolio = await agent.getPortfolio();
|
|
2911
2912
|
if (isJsonMode()) {
|
|
2912
2913
|
printJson(portfolio);
|
|
@@ -2922,7 +2923,7 @@ function registerPortfolio(program2) {
|
|
|
2922
2923
|
const hasDirectPositions = portfolio.positions.length > 0;
|
|
2923
2924
|
const hasStrategyPositions = portfolio.strategyPositions && Object.keys(portfolio.strategyPositions).length > 0;
|
|
2924
2925
|
if (!hasDirectPositions && !hasStrategyPositions) {
|
|
2925
|
-
printInfo("No investments yet. Try: t2000
|
|
2926
|
+
printInfo("No investments yet. Try: t2000 buy 100 SUI");
|
|
2926
2927
|
printBlank();
|
|
2927
2928
|
return;
|
|
2928
2929
|
}
|
|
@@ -2935,19 +2936,19 @@ function registerPortfolio(program2) {
|
|
|
2935
2936
|
stratLabel = def.name;
|
|
2936
2937
|
} catch {
|
|
2937
2938
|
}
|
|
2938
|
-
printLine(` ${
|
|
2939
|
+
printLine(` ${pc16.bold(pc16.cyan(`\u25B8 ${stratLabel}`))}`);
|
|
2939
2940
|
printSeparator();
|
|
2940
2941
|
for (const pos of positions) {
|
|
2941
2942
|
printPositionLine(pos, rewardKeys);
|
|
2942
2943
|
}
|
|
2943
2944
|
const stratValue = positions.reduce((s, p) => s + p.currentValue, 0);
|
|
2944
|
-
printLine(` ${
|
|
2945
|
+
printLine(` ${pc16.dim(`Subtotal: ${formatUsd16(stratValue)}`)}`);
|
|
2945
2946
|
printBlank();
|
|
2946
2947
|
}
|
|
2947
2948
|
}
|
|
2948
2949
|
if (hasDirectPositions) {
|
|
2949
2950
|
if (hasStrategyPositions) {
|
|
2950
|
-
printLine(` ${
|
|
2951
|
+
printLine(` ${pc16.bold(pc16.cyan("\u25B8 Direct"))}`);
|
|
2951
2952
|
}
|
|
2952
2953
|
printSeparator();
|
|
2953
2954
|
for (const pos of portfolio.positions) {
|
|
@@ -2955,21 +2956,21 @@ function registerPortfolio(program2) {
|
|
|
2955
2956
|
}
|
|
2956
2957
|
if (hasStrategyPositions) {
|
|
2957
2958
|
const directValue = portfolio.positions.reduce((s, p) => s + p.currentValue, 0);
|
|
2958
|
-
printLine(` ${
|
|
2959
|
+
printLine(` ${pc16.dim(`Subtotal: ${formatUsd16(directValue)}`)}`);
|
|
2959
2960
|
}
|
|
2960
2961
|
}
|
|
2961
2962
|
printSeparator();
|
|
2962
2963
|
const hasPriceUnavailable = portfolio.positions.some((p) => p.currentPrice === 0 && p.totalAmount > 0);
|
|
2963
2964
|
if (hasPriceUnavailable) {
|
|
2964
|
-
printInfo(
|
|
2965
|
+
printInfo(pc16.yellow("\u26A0 Price data unavailable for some assets. Values may be inaccurate."));
|
|
2965
2966
|
}
|
|
2966
2967
|
printKeyValue("Total invested", formatUsd16(portfolio.totalInvested));
|
|
2967
2968
|
printKeyValue("Current value", formatUsd16(portfolio.totalValue));
|
|
2968
|
-
const upnlColor = portfolio.unrealizedPnL >= 0 ?
|
|
2969
|
+
const upnlColor = portfolio.unrealizedPnL >= 0 ? pc16.green : pc16.red;
|
|
2969
2970
|
const upnlSign = portfolio.unrealizedPnL >= 0 ? "+" : "";
|
|
2970
2971
|
printKeyValue("Unrealized P&L", upnlColor(`${upnlSign}${formatUsd16(portfolio.unrealizedPnL)} (${upnlSign}${portfolio.unrealizedPnLPct.toFixed(1)}%)`));
|
|
2971
2972
|
if (portfolio.realizedPnL !== 0) {
|
|
2972
|
-
const rpnlColor = portfolio.realizedPnL >= 0 ?
|
|
2973
|
+
const rpnlColor = portfolio.realizedPnL >= 0 ? pc16.green : pc16.red;
|
|
2973
2974
|
const rpnlSign = portfolio.realizedPnL >= 0 ? "+" : "";
|
|
2974
2975
|
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd16(portfolio.realizedPnL)}`));
|
|
2975
2976
|
}
|
|
@@ -2981,13 +2982,13 @@ function registerPortfolio(program2) {
|
|
|
2981
2982
|
}
|
|
2982
2983
|
|
|
2983
2984
|
// src/commands/claimRewards.ts
|
|
2984
|
-
import
|
|
2985
|
-
import { T2000 as
|
|
2985
|
+
import pc17 from "picocolors";
|
|
2986
|
+
import { T2000 as T200027, formatUsd as formatUsd17 } from "@t2000/sdk";
|
|
2986
2987
|
function registerClaimRewards(program2) {
|
|
2987
2988
|
program2.command("claim-rewards").description("Claim pending protocol rewards").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2988
2989
|
try {
|
|
2989
2990
|
const pin = await resolvePin();
|
|
2990
|
-
const agent = await
|
|
2991
|
+
const agent = await T200027.create({ pin, keyPath: opts.key });
|
|
2991
2992
|
const result = await agent.claimRewards();
|
|
2992
2993
|
if (isJsonMode()) {
|
|
2993
2994
|
printJson(result);
|
|
@@ -2995,20 +2996,20 @@ function registerClaimRewards(program2) {
|
|
|
2995
2996
|
}
|
|
2996
2997
|
printBlank();
|
|
2997
2998
|
if (result.rewards.length === 0) {
|
|
2998
|
-
printLine(` ${
|
|
2999
|
+
printLine(` ${pc17.dim("No rewards to claim")}`);
|
|
2999
3000
|
printBlank();
|
|
3000
3001
|
return;
|
|
3001
3002
|
}
|
|
3002
3003
|
const protocols = [...new Set(result.rewards.map((r) => r.protocol))];
|
|
3003
|
-
printLine(` ${
|
|
3004
|
+
printLine(` ${pc17.green("\u2713")} Claimed and converted rewards to USDC`);
|
|
3004
3005
|
printSeparator();
|
|
3005
3006
|
const received = result.usdcReceived;
|
|
3006
3007
|
if (received >= 0.01) {
|
|
3007
|
-
printKeyValue("Received", `${
|
|
3008
|
+
printKeyValue("Received", `${pc17.green(formatUsd17(received))} USDC`);
|
|
3008
3009
|
} else if (received > 0) {
|
|
3009
|
-
printKeyValue("Received", `${
|
|
3010
|
+
printKeyValue("Received", `${pc17.green("< $0.01")} USDC`);
|
|
3010
3011
|
} else {
|
|
3011
|
-
printKeyValue("Received", `${
|
|
3012
|
+
printKeyValue("Received", `${pc17.dim("< $0.01 USDC (rewards are still accruing)")}`);
|
|
3012
3013
|
}
|
|
3013
3014
|
printKeyValue("Source", protocols.join(", "));
|
|
3014
3015
|
if (result.tx) {
|
|
@@ -3022,13 +3023,13 @@ function registerClaimRewards(program2) {
|
|
|
3022
3023
|
}
|
|
3023
3024
|
|
|
3024
3025
|
// src/commands/gas.ts
|
|
3025
|
-
import
|
|
3026
|
-
import { T2000 as
|
|
3026
|
+
import pc18 from "picocolors";
|
|
3027
|
+
import { T2000 as T200028, getGasStatus } from "@t2000/sdk";
|
|
3027
3028
|
function registerGas(program2) {
|
|
3028
3029
|
program2.command("gas").description("Check gas station status and wallet gas balance").option("--key <path>", "Key file path").action(async (opts) => {
|
|
3029
3030
|
try {
|
|
3030
3031
|
const pin = await resolvePin();
|
|
3031
|
-
const agent = await
|
|
3032
|
+
const agent = await T200028.create({ pin, keyPath: opts.key });
|
|
3032
3033
|
const address = agent.address();
|
|
3033
3034
|
const [status, bal] = await Promise.allSettled([
|
|
3034
3035
|
getGasStatus(address),
|
|
@@ -3045,36 +3046,36 @@ function registerGas(program2) {
|
|
|
3045
3046
|
}
|
|
3046
3047
|
printHeader("Gas Status");
|
|
3047
3048
|
if (gasStatus) {
|
|
3048
|
-
const cbStatus = gasStatus.circuitBreaker ?
|
|
3049
|
+
const cbStatus = gasStatus.circuitBreaker ? pc18.red("TRIPPED \u2014 sponsorship paused") : pc18.green("OK");
|
|
3049
3050
|
printKeyValue("Gas Station", cbStatus);
|
|
3050
3051
|
printKeyValue("SUI Price (TWAP)", `$${gasStatus.suiPrice.toFixed(4)}`);
|
|
3051
3052
|
if (gasStatus.bootstrapRemaining !== void 0) {
|
|
3052
3053
|
printKeyValue("Bootstrap", `${gasStatus.bootstrapUsed}/10 used (${gasStatus.bootstrapRemaining} remaining)`);
|
|
3053
3054
|
}
|
|
3054
3055
|
} else {
|
|
3055
|
-
printKeyValue("Gas Station",
|
|
3056
|
+
printKeyValue("Gas Station", pc18.red("unreachable"));
|
|
3056
3057
|
const reason = status.status === "rejected" ? status.reason : "unknown";
|
|
3057
|
-
printLine(` ${
|
|
3058
|
+
printLine(` ${pc18.dim(reason instanceof Error ? reason.message : String(reason))}`);
|
|
3058
3059
|
}
|
|
3059
3060
|
printDivider();
|
|
3060
3061
|
if (balData) {
|
|
3061
3062
|
const suiBal = balData.gasReserve.sui;
|
|
3062
|
-
const suiColor = suiBal < 0.05 ?
|
|
3063
|
+
const suiColor = suiBal < 0.05 ? pc18.red : pc18.green;
|
|
3063
3064
|
printKeyValue("SUI (gas)", suiColor(`${suiBal.toFixed(4)} SUI`));
|
|
3064
3065
|
if (suiBal < 0.05) {
|
|
3065
|
-
printLine(` ${
|
|
3066
|
+
printLine(` ${pc18.yellow("\u26A0")} Below gas threshold (0.05 SUI) \u2014 transactions will need sponsorship`);
|
|
3066
3067
|
}
|
|
3067
3068
|
printKeyValue("Available", `$${balData.available.toFixed(2)}`);
|
|
3068
3069
|
} else {
|
|
3069
|
-
printKeyValue("Wallet",
|
|
3070
|
+
printKeyValue("Wallet", pc18.dim("could not fetch balances"));
|
|
3070
3071
|
}
|
|
3071
3072
|
printBlank();
|
|
3072
3073
|
if (gasStatus && !gasStatus.circuitBreaker && (balData?.gasReserve.sui ?? 0) >= 0.05) {
|
|
3073
|
-
printLine(` ${
|
|
3074
|
+
printLine(` ${pc18.green("\u2713")} Gas is healthy \u2014 transactions should succeed`);
|
|
3074
3075
|
} else if (gasStatus && !gasStatus.circuitBreaker) {
|
|
3075
|
-
printLine(` ${
|
|
3076
|
+
printLine(` ${pc18.yellow("\u26A0")} Low SUI but gas station is online \u2014 sponsorship available`);
|
|
3076
3077
|
} else {
|
|
3077
|
-
printLine(` ${
|
|
3078
|
+
printLine(` ${pc18.red("\u2717")} Gas station issues detected \u2014 fund wallet with SUI directly`);
|
|
3078
3079
|
printInfo("Send SUI to your address: t2000 address");
|
|
3079
3080
|
}
|
|
3080
3081
|
printBlank();
|
|
@@ -3092,7 +3093,18 @@ function createProgram() {
|
|
|
3092
3093
|
program2.name("t2000").description("A bank account for AI agents").version(`${CLI_VERSION} (beta)`).option("--json", "Output in JSON format").hook("preAction", (thisCommand) => {
|
|
3093
3094
|
const opts = thisCommand.optsWithGlobals();
|
|
3094
3095
|
if (opts.json) setJsonMode(true);
|
|
3095
|
-
})
|
|
3096
|
+
}).addHelpText("after", `
|
|
3097
|
+
Examples:
|
|
3098
|
+
$ t2000 init Create a new agent bank account
|
|
3099
|
+
$ t2000 balance Show wallet balance
|
|
3100
|
+
$ t2000 save 100 Save $100 to earn yield
|
|
3101
|
+
$ t2000 send 50 to 0xabc... Send $50 USDC
|
|
3102
|
+
$ t2000 borrow 200 Borrow $200 against savings
|
|
3103
|
+
$ t2000 pay openai ... Pay for an API via MPP gateway
|
|
3104
|
+
$ t2000 buy 100 BTC Buy $100 of BTC
|
|
3105
|
+
$ t2000 sell 0.001 BTC Sell BTC for USDC
|
|
3106
|
+
$ t2000 swap 100 USDC SUI Swap between any tokens
|
|
3107
|
+
$ t2000 mcp install Install MCP for AI platforms`);
|
|
3096
3108
|
registerInit(program2);
|
|
3097
3109
|
registerSend(program2);
|
|
3098
3110
|
registerBalance(program2);
|
|
@@ -3117,6 +3129,7 @@ function createProgram() {
|
|
|
3117
3129
|
registerSentinel(program2);
|
|
3118
3130
|
registerEarn(program2);
|
|
3119
3131
|
registerRebalance(program2);
|
|
3132
|
+
registerSwap(program2);
|
|
3120
3133
|
registerExchange(program2);
|
|
3121
3134
|
registerMcp(program2);
|
|
3122
3135
|
registerContacts(program2);
|