@t2000/cli 0.22.26 → 0.24.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 +12 -98
- package/dist/{ccip-JEEJV65M.js → ccip-XP27NGI7.js} +3 -3
- package/dist/{chunk-A5X4KG7U.js → chunk-3I6VJOM6.js} +210 -970
- package/dist/chunk-3I6VJOM6.js.map +1 -0
- package/dist/chunk-EI3GHTKX.js +968 -0
- package/dist/chunk-EI3GHTKX.js.map +1 -0
- package/dist/{chunk-3WKGZRWT.js → chunk-JJCGJTSI.js} +44787 -55564
- package/dist/chunk-JJCGJTSI.js.map +1 -0
- package/dist/{chunk-XOAZJ42V.js → chunk-Q2LY5BHK.js} +589 -584
- package/dist/{chunk-XOAZJ42V.js.map → chunk-Q2LY5BHK.js.map} +1 -1
- package/dist/{chunk-EEPD7SHV.js → chunk-TYYJRUQI.js} +15755 -15918
- package/dist/chunk-TYYJRUQI.js.map +1 -0
- package/dist/{client-R3NRAXMD.js → client-IXUBQ3HM.js} +334 -638
- package/dist/client-IXUBQ3HM.js.map +1 -0
- package/dist/client-YNWQPUC5.js +84 -0
- package/dist/client-YNWQPUC5.js.map +1 -0
- package/dist/{dist-KJM2NT74.js → dist-22NK522A.js} +124 -511
- package/dist/{dist-KJM2NT74.js.map → dist-22NK522A.js.map} +1 -1
- package/dist/{dist-NBWIWHHS.js → dist-2P6AEWCE.js} +5 -29
- package/dist/index.js +179 -1034
- package/dist/index.js.map +1 -1
- package/package.json +5 -6
- package/dist/chunk-3WKGZRWT.js.map +0 -1
- package/dist/chunk-77SWBATH.js +0 -204
- package/dist/chunk-77SWBATH.js.map +0 -1
- package/dist/chunk-A5X4KG7U.js.map +0 -1
- package/dist/chunk-EEPD7SHV.js.map +0 -1
- package/dist/client-CK5OR2TP.js +0 -746
- package/dist/client-CK5OR2TP.js.map +0 -1
- package/dist/client-R3NRAXMD.js.map +0 -1
- /package/dist/{ccip-JEEJV65M.js.map → ccip-XP27NGI7.js.map} +0 -0
- /package/dist/{dist-NBWIWHHS.js.map → dist-2P6AEWCE.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
} from "./chunk-QM6OQC5D.js";
|
|
7
7
|
import {
|
|
8
8
|
ContactManager,
|
|
9
|
-
INVESTMENT_ASSETS,
|
|
10
9
|
STABLE_ASSETS,
|
|
11
10
|
SUPPORTED_ASSETS,
|
|
12
11
|
SafeguardEnforcer,
|
|
@@ -18,9 +17,9 @@ import {
|
|
|
18
17
|
saveKey,
|
|
19
18
|
truncateAddress,
|
|
20
19
|
walletExists
|
|
21
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-JJCGJTSI.js";
|
|
22
21
|
import "./chunk-V7PXDEKG.js";
|
|
23
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-Q2LY5BHK.js";
|
|
24
23
|
import "./chunk-3XUF7GM3.js";
|
|
25
24
|
import {
|
|
26
25
|
__commonJS,
|
|
@@ -3649,7 +3648,7 @@ function registerInit(program3) {
|
|
|
3649
3648
|
printBlank();
|
|
3650
3649
|
printInfo("Setting up accounts...");
|
|
3651
3650
|
printLine(
|
|
3652
|
-
` ${import_picocolors2.default.green("\u2713")} Checking ${import_picocolors2.default.green("\u2713")} Savings ${import_picocolors2.default.green("\u2713")} Credit
|
|
3651
|
+
` ${import_picocolors2.default.green("\u2713")} Checking ${import_picocolors2.default.green("\u2713")} Savings ${import_picocolors2.default.green("\u2713")} Credit`
|
|
3653
3652
|
);
|
|
3654
3653
|
printBlank();
|
|
3655
3654
|
printLine(` \u{1F389} ${import_picocolors2.default.green("Bank account created")}`);
|
|
@@ -3707,7 +3706,7 @@ function registerInit(program3) {
|
|
|
3707
3706
|
} else {
|
|
3708
3707
|
console.log(` \u2502 Use the CLI directly: \u2502`);
|
|
3709
3708
|
console.log(` \u2502 ${import_picocolors2.default.cyan("t2000 balance")} \u2502`);
|
|
3710
|
-
console.log(` \u2502 ${import_picocolors2.default.cyan("t2000
|
|
3709
|
+
console.log(` \u2502 ${import_picocolors2.default.cyan("t2000 save 100")} \u2502`);
|
|
3711
3710
|
console.log(` \u2502 \u2502`);
|
|
3712
3711
|
}
|
|
3713
3712
|
console.log(` \u2502 Your address: \u2502`);
|
|
@@ -3805,24 +3804,6 @@ function registerBalance(program3) {
|
|
|
3805
3804
|
const borrowApy = borrows.length > 0 ? borrows.reduce((sum, p) => sum + (p.amountUsd ?? p.amount) * p.apy, 0) / borrows.reduce((sum, p) => sum + (p.amountUsd ?? p.amount), 0) : 0;
|
|
3806
3805
|
printKeyValue("Credit", `${import_picocolors3.default.red(`-${formatUsd(bal.debt)}`)} ${import_picocolors3.default.dim(`(${borrowApy.toFixed(2)}% APY)`)}`);
|
|
3807
3806
|
}
|
|
3808
|
-
if (bal.investment > 0.01) {
|
|
3809
|
-
const pnlColor = bal.investmentPnL >= 0 ? import_picocolors3.default.green : import_picocolors3.default.red;
|
|
3810
|
-
const pnlSign = bal.investmentPnL >= 0 ? "+" : "";
|
|
3811
|
-
const pnlPct = bal.investment > 0 ? bal.investmentPnL / (bal.investment - bal.investmentPnL) * 100 : 0;
|
|
3812
|
-
let earningInfo = "";
|
|
3813
|
-
try {
|
|
3814
|
-
const portfolio = await agent.getPortfolio();
|
|
3815
|
-
const earningPositions = portfolio.positions.filter((p) => p.earning && p.earningApy);
|
|
3816
|
-
if (earningPositions.length > 0) {
|
|
3817
|
-
const avgApy = earningPositions.reduce((s, p) => s + (p.earningApy ?? 0) * p.currentValue, 0) / earningPositions.reduce((s, p) => s + p.currentValue, 0);
|
|
3818
|
-
earningInfo = `, earning ${avgApy.toFixed(1)}% APY`;
|
|
3819
|
-
}
|
|
3820
|
-
} catch {
|
|
3821
|
-
}
|
|
3822
|
-
printKeyValue("Investment", `${formatUsd(bal.investment)} ${pnlColor(`(${pnlSign}${pnlPct.toFixed(1)}%${earningInfo})`)}`);
|
|
3823
|
-
} else {
|
|
3824
|
-
printKeyValue("Investment", import_picocolors3.default.dim("\u2014"));
|
|
3825
|
-
}
|
|
3826
3807
|
if (bal.gasReserve && bal.gasReserve.usdEquiv >= 0.01) {
|
|
3827
3808
|
printKeyValue("Gas reserve", `${formatUsd(bal.gasReserve.usdEquiv)} ${import_picocolors3.default.dim(`(${bal.gasReserve.sui.toFixed(2)} SUI)`)}`);
|
|
3828
3809
|
}
|
|
@@ -3838,24 +3819,6 @@ function registerBalance(program3) {
|
|
|
3838
3819
|
if (bal.savings > 5e-3) {
|
|
3839
3820
|
printKeyValue("Savings", `${formatUsd(bal.savings)}`);
|
|
3840
3821
|
}
|
|
3841
|
-
if (bal.investment > 0.01) {
|
|
3842
|
-
const pnlColor = bal.investmentPnL >= 0 ? import_picocolors3.default.green : import_picocolors3.default.red;
|
|
3843
|
-
const pnlSign = bal.investmentPnL >= 0 ? "+" : "";
|
|
3844
|
-
const pnlPct = bal.investment > 0 ? bal.investmentPnL / (bal.investment - bal.investmentPnL) * 100 : 0;
|
|
3845
|
-
let earningInfo = "";
|
|
3846
|
-
try {
|
|
3847
|
-
const portfolio = await agent.getPortfolio();
|
|
3848
|
-
const earningPositions = portfolio.positions.filter((p) => p.earning && p.earningApy);
|
|
3849
|
-
if (earningPositions.length > 0) {
|
|
3850
|
-
const avgApy = earningPositions.reduce((s, p) => s + (p.earningApy ?? 0) * p.currentValue, 0) / earningPositions.reduce((s, p) => s + p.currentValue, 0);
|
|
3851
|
-
earningInfo = `, earning ${avgApy.toFixed(1)}% APY`;
|
|
3852
|
-
}
|
|
3853
|
-
} catch {
|
|
3854
|
-
}
|
|
3855
|
-
printKeyValue("Investment", `${formatUsd(bal.investment)} ${pnlColor(`(${pnlSign}${pnlPct.toFixed(1)}%${earningInfo})`)}`);
|
|
3856
|
-
} else {
|
|
3857
|
-
printKeyValue("Investment", import_picocolors3.default.dim("\u2014"));
|
|
3858
|
-
}
|
|
3859
3822
|
if (bal.gasReserve && bal.gasReserve.usdEquiv >= 0.01) {
|
|
3860
3823
|
printKeyValue("Gas reserve", `${formatUsd(bal.gasReserve.usdEquiv)} ${import_picocolors3.default.dim(`(${bal.gasReserve.sui.toFixed(2)} SUI)`)}`);
|
|
3861
3824
|
}
|
|
@@ -3921,7 +3884,6 @@ var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
|
3921
3884
|
var ACTION_LABELS = {
|
|
3922
3885
|
send: "\u2197 send",
|
|
3923
3886
|
lending: "\u{1F3E6} lend",
|
|
3924
|
-
swap: "\u{1F504} swap",
|
|
3925
3887
|
transaction: "\u{1F4E6} tx"
|
|
3926
3888
|
};
|
|
3927
3889
|
function relativeTime(ts) {
|
|
@@ -4128,13 +4090,14 @@ function registerSave(program3) {
|
|
|
4128
4090
|
if (amount !== "all" && (isNaN(amount) || amount <= 0)) {
|
|
4129
4091
|
throw new Error('Amount must be a positive number or "all"');
|
|
4130
4092
|
}
|
|
4093
|
+
const asset = opts.asset?.toUpperCase() ?? "USDC";
|
|
4131
4094
|
const pin = await resolvePin();
|
|
4132
4095
|
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
4133
4096
|
let gasManagerUsdc = 0;
|
|
4134
4097
|
agent.on("gasAutoTopUp", (data) => {
|
|
4135
4098
|
gasManagerUsdc = data.usdcSpent;
|
|
4136
4099
|
});
|
|
4137
|
-
const result = await agent.save({ amount, protocol: opts.protocol });
|
|
4100
|
+
const result = await agent.save({ amount, asset, protocol: opts.protocol });
|
|
4138
4101
|
if (isJsonMode()) {
|
|
4139
4102
|
printJson(result);
|
|
4140
4103
|
return;
|
|
@@ -4144,26 +4107,26 @@ function registerSave(program3) {
|
|
|
4144
4107
|
printSuccess(`Gas manager: ${import_picocolors5.default.yellow(formatUsd(gasManagerUsdc))} USDC \u2192 SUI`);
|
|
4145
4108
|
}
|
|
4146
4109
|
const protocolName = opts.protocol ?? "best rate";
|
|
4147
|
-
printSuccess(`Saved ${import_picocolors5.default.yellow(formatUsd(result.amount))}
|
|
4110
|
+
printSuccess(`Saved ${import_picocolors5.default.yellow(formatUsd(result.amount))} ${asset} to ${protocolName}`);
|
|
4148
4111
|
if (result.fee > 0) {
|
|
4149
4112
|
const feeRate = (result.fee / result.amount * 100).toFixed(1);
|
|
4150
|
-
printSuccess(`Protocol fee: ${import_picocolors5.default.dim(`${formatUsd(result.fee)}
|
|
4113
|
+
printSuccess(`Protocol fee: ${import_picocolors5.default.dim(`${formatUsd(result.fee)} ${asset} (${feeRate}%)`)}`);
|
|
4151
4114
|
}
|
|
4152
4115
|
printSuccess(`Current APY: ${import_picocolors5.default.green(`${result.apy.toFixed(2)}%`)}`);
|
|
4153
|
-
printSuccess(`Savings balance: ${import_picocolors5.default.yellow(formatUsd(result.savingsBalance))}
|
|
4116
|
+
printSuccess(`Savings balance: ${import_picocolors5.default.yellow(formatUsd(result.savingsBalance))} ${asset}`);
|
|
4154
4117
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
4155
4118
|
printBlank();
|
|
4156
4119
|
} catch (error) {
|
|
4157
4120
|
handleError(error);
|
|
4158
4121
|
}
|
|
4159
4122
|
};
|
|
4160
|
-
program3.command("save").description("Deposit USDC
|
|
4161
|
-
program3.command("supply").description("Deposit
|
|
4123
|
+
program3.command("save").description("Deposit into NAVI lending to earn yield (USDC, USDT, SUI, USDe, USDsui)").argument("<amount>", 'Amount to save (or "all")').option("--key <path>", "Key file path").option("--protocol <name>", "Protocol to use (e.g. navi)").option("--asset <token>", "Asset to deposit (default: USDC)").action(action);
|
|
4124
|
+
program3.command("supply").description("Deposit into NAVI lending (alias for save)").argument("<amount>", 'Amount to save (or "all")').option("--key <path>", "Key file path").option("--protocol <name>", "Protocol to use (e.g. navi)").option("--asset <token>", "Asset to deposit (default: USDC)").action(action);
|
|
4162
4125
|
}
|
|
4163
4126
|
|
|
4164
4127
|
// src/commands/withdraw.ts
|
|
4165
4128
|
function registerWithdraw(program3) {
|
|
4166
|
-
program3.command("withdraw").description("Withdraw USDC
|
|
4129
|
+
program3.command("withdraw").description("Withdraw from NAVI lending (USDC, USDT, SUI, USDe, USDsui)").argument("<amount>", 'Amount to withdraw (or "all")').option("--key <path>", "Key file path").option("--protocol <name>", "Protocol to use (e.g. navi)").option("--asset <token>", "Asset to withdraw (default: auto-detect)").action(async (amountStr, opts) => {
|
|
4167
4130
|
try {
|
|
4168
4131
|
const amount = amountStr === "all" ? "all" : parseFloat(amountStr);
|
|
4169
4132
|
if (amount !== "all" && (isNaN(amount) || amount <= 0)) {
|
|
@@ -4171,13 +4134,14 @@ function registerWithdraw(program3) {
|
|
|
4171
4134
|
}
|
|
4172
4135
|
const pin = await resolvePin();
|
|
4173
4136
|
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
4174
|
-
const result = await agent.withdraw({ amount, protocol: opts.protocol });
|
|
4137
|
+
const result = await agent.withdraw({ amount, asset: opts.asset, protocol: opts.protocol });
|
|
4175
4138
|
if (isJsonMode()) {
|
|
4176
4139
|
printJson(result);
|
|
4177
4140
|
return;
|
|
4178
4141
|
}
|
|
4142
|
+
const assetLabel = opts.asset ?? "USDC";
|
|
4179
4143
|
printBlank();
|
|
4180
|
-
printSuccess(`Withdrew ${formatUsd(result.amount)}
|
|
4144
|
+
printSuccess(`Withdrew ${formatUsd(result.amount)} ${assetLabel}`);
|
|
4181
4145
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
4182
4146
|
printBlank();
|
|
4183
4147
|
} catch (error) {
|
|
@@ -4279,7 +4243,6 @@ function registerHealth(program3) {
|
|
|
4279
4243
|
|
|
4280
4244
|
// src/commands/rates.ts
|
|
4281
4245
|
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
4282
|
-
var INVEST_ASSETS = Object.keys(INVESTMENT_ASSETS);
|
|
4283
4246
|
function registerRates(program3) {
|
|
4284
4247
|
program3.command("rates").description("Show current APY rates across protocols and stablecoins").option("--key <path>", "Key file path").action(async (opts) => {
|
|
4285
4248
|
try {
|
|
@@ -4308,20 +4271,6 @@ function registerRates(program3) {
|
|
|
4308
4271
|
}
|
|
4309
4272
|
printBlank();
|
|
4310
4273
|
}
|
|
4311
|
-
const investRates = allRates.filter((r) => INVEST_ASSETS.includes(r.asset));
|
|
4312
|
-
if (investRates.length > 0) {
|
|
4313
|
-
printLine(import_picocolors6.default.bold("Investment Assets"));
|
|
4314
|
-
printDivider();
|
|
4315
|
-
for (const asset of INVEST_ASSETS) {
|
|
4316
|
-
const assetRates = investRates.filter((r) => r.asset === asset);
|
|
4317
|
-
if (assetRates.length === 0) continue;
|
|
4318
|
-
const display = SUPPORTED_ASSETS[asset]?.displayName ?? asset;
|
|
4319
|
-
for (const entry of assetRates) {
|
|
4320
|
-
printKeyValue(`${display} (${entry.protocol})`, `Lend ${entry.rates.saveApy.toFixed(2)}%`);
|
|
4321
|
-
}
|
|
4322
|
-
}
|
|
4323
|
-
printBlank();
|
|
4324
|
-
}
|
|
4325
4274
|
if (allRates.length === 0) {
|
|
4326
4275
|
printInfo("No protocol rates available");
|
|
4327
4276
|
printBlank();
|
|
@@ -7887,7 +7836,7 @@ function registerLock(program3) {
|
|
|
7887
7836
|
});
|
|
7888
7837
|
program3.command("unlock").description("Unlock agent \u2014 resume operations").action(async () => {
|
|
7889
7838
|
try {
|
|
7890
|
-
const { T2000: T20003 } = await import("./dist-
|
|
7839
|
+
const { T2000: T20003 } = await import("./dist-2P6AEWCE.js");
|
|
7891
7840
|
const MAX_ATTEMPTS2 = 3;
|
|
7892
7841
|
let pin;
|
|
7893
7842
|
for (let attempt = 1; attempt <= MAX_ATTEMPTS2; attempt++) {
|
|
@@ -7941,21 +7890,18 @@ function registerLock(program3) {
|
|
|
7941
7890
|
// src/commands/earn.ts
|
|
7942
7891
|
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
7943
7892
|
function registerEarn(program3) {
|
|
7944
|
-
program3.command("earn").description("Show all earning opportunities \u2014 savings yield
|
|
7893
|
+
program3.command("earn").description("Show all earning opportunities \u2014 savings yield").option("--key <path>", "Key file path").action(async (opts) => {
|
|
7945
7894
|
try {
|
|
7946
7895
|
const pin = await resolvePin();
|
|
7947
7896
|
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
7948
|
-
const [positionsResult,
|
|
7897
|
+
const [positionsResult, ratesResult] = await Promise.allSettled([
|
|
7949
7898
|
agent.positions(),
|
|
7950
|
-
agent.getPortfolio(),
|
|
7951
7899
|
agent.allRates("USDC")
|
|
7952
7900
|
]);
|
|
7953
7901
|
const posData = positionsResult.status === "fulfilled" ? positionsResult.value : null;
|
|
7954
|
-
const portfolio = portfolioResult.status === "fulfilled" ? portfolioResult.value : null;
|
|
7955
7902
|
const ratesData = ratesResult.status === "fulfilled" ? ratesResult.value : null;
|
|
7956
7903
|
const savePositions = posData?.positions.filter((p) => p.type === "save") ?? [];
|
|
7957
7904
|
const totalSaved = savePositions.reduce((s, p) => s + p.amount, 0);
|
|
7958
|
-
const earningInvestments = portfolio?.positions.filter((p) => p.earning && p.currentValue > 0) ?? [];
|
|
7959
7905
|
const bestSaveApy = ratesData?.length ? Math.max(...ratesData.map((r) => r.rates.saveApy)) : 0;
|
|
7960
7906
|
if (isJsonMode()) {
|
|
7961
7907
|
printJson({
|
|
@@ -7970,14 +7916,7 @@ function registerEarn(program3) {
|
|
|
7970
7916
|
protocol: r.protocol,
|
|
7971
7917
|
asset: "USDC",
|
|
7972
7918
|
saveApy: r.rates.saveApy
|
|
7973
|
-
})) ?? []
|
|
7974
|
-
investments: earningInvestments.map((p) => ({
|
|
7975
|
-
asset: p.asset,
|
|
7976
|
-
amount: p.totalAmount,
|
|
7977
|
-
value: p.currentValue,
|
|
7978
|
-
protocol: p.earningProtocol,
|
|
7979
|
-
apy: p.earningApy
|
|
7980
|
-
}))
|
|
7919
|
+
})) ?? []
|
|
7981
7920
|
});
|
|
7982
7921
|
return;
|
|
7983
7922
|
}
|
|
@@ -8014,298 +7953,16 @@ function registerEarn(program3) {
|
|
|
8014
7953
|
} else {
|
|
8015
7954
|
printInfo("Savings data unavailable");
|
|
8016
7955
|
}
|
|
8017
|
-
if (earningInvestments.length > 0) {
|
|
8018
|
-
printBlank();
|
|
8019
|
-
printLine(import_picocolors11.default.bold("INVESTMENTS") + import_picocolors11.default.dim(" \u2014 Earning Yield"));
|
|
8020
|
-
printDivider();
|
|
8021
|
-
let totalInvestValue = 0;
|
|
8022
|
-
for (const pos of earningInvestments) {
|
|
8023
|
-
const dailyYield = pos.currentValue * (pos.earningApy ?? 0) / 100 / 365;
|
|
8024
|
-
const apyStr = pos.earningApy ? `${pos.earningApy.toFixed(2)}%` : "\u2014";
|
|
8025
|
-
printKeyValue(
|
|
8026
|
-
`${pos.asset} via ${pos.earningProtocol ?? "unknown"}`,
|
|
8027
|
-
`${formatUsd(pos.currentValue)} (${pos.totalAmount.toFixed(4)} ${pos.asset}) @ ${apyStr} APY`
|
|
8028
|
-
);
|
|
8029
|
-
if (dailyYield > 1e-4) {
|
|
8030
|
-
const dailyStr = dailyYield < 0.01 ? `$${dailyYield.toFixed(4)}` : formatUsd(dailyYield);
|
|
8031
|
-
const monthlyStr = dailyYield * 30 < 0.01 ? `$${(dailyYield * 30).toFixed(4)}` : formatUsd(dailyYield * 30);
|
|
8032
|
-
printLine(import_picocolors11.default.dim(` ~${dailyStr}/day \xB7 ~${monthlyStr}/month`));
|
|
8033
|
-
}
|
|
8034
|
-
totalInvestValue += pos.currentValue;
|
|
8035
|
-
}
|
|
8036
|
-
if (earningInvestments.length > 1) {
|
|
8037
|
-
printBlank();
|
|
8038
|
-
printKeyValue("Total Earning", formatUsd(totalInvestValue));
|
|
8039
|
-
}
|
|
8040
|
-
}
|
|
8041
7956
|
printBlank();
|
|
8042
7957
|
printLine(import_picocolors11.default.bold("Quick Actions"));
|
|
8043
7958
|
printDivider();
|
|
8044
7959
|
printLine(` ${import_picocolors11.default.dim("t2000 save <amount> [asset]")} Save stablecoins for yield`);
|
|
8045
|
-
printLine(` ${import_picocolors11.default.dim("t2000 invest earn <asset>")} Earn yield on investments`);
|
|
8046
|
-
printBlank();
|
|
8047
|
-
} catch (error) {
|
|
8048
|
-
handleError(error);
|
|
8049
|
-
}
|
|
8050
|
-
});
|
|
8051
|
-
}
|
|
8052
|
-
|
|
8053
|
-
// src/commands/rebalance.ts
|
|
8054
|
-
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
8055
|
-
function registerRebalance(program3) {
|
|
8056
|
-
program3.command("rebalance").description("Optimize yield \u2014 move savings to the best rate across protocols and stablecoins").option("--key <path>", "Key file path").option("--dry-run", "Show what would happen without executing").option("--min-diff <pct>", "Minimum APY difference to trigger (default: 0.5)", "0.5").option("--max-break-even <days>", "Max break-even days for cross-asset moves (default: 30)", "30").action(async (opts) => {
|
|
8057
|
-
try {
|
|
8058
|
-
const pin = await resolvePin();
|
|
8059
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8060
|
-
const minYieldDiff = parseFloat(opts.minDiff ?? "0.5");
|
|
8061
|
-
const maxBreakEven = parseInt(opts.maxBreakEven ?? "30", 10);
|
|
8062
|
-
const plan = await agent.rebalance({
|
|
8063
|
-
dryRun: true,
|
|
8064
|
-
minYieldDiff,
|
|
8065
|
-
maxBreakEven
|
|
8066
|
-
});
|
|
8067
|
-
if (isJsonMode()) {
|
|
8068
|
-
if (opts.dryRun) {
|
|
8069
|
-
printJson(plan);
|
|
8070
|
-
} else {
|
|
8071
|
-
const result2 = await agent.rebalance({ dryRun: false, minYieldDiff, maxBreakEven });
|
|
8072
|
-
printJson(result2);
|
|
8073
|
-
}
|
|
8074
|
-
return;
|
|
8075
|
-
}
|
|
8076
|
-
printBlank();
|
|
8077
|
-
if (plan.steps.length === 0) {
|
|
8078
|
-
const diff = plan.newApy - plan.currentApy;
|
|
8079
|
-
if (diff < minYieldDiff) {
|
|
8080
|
-
printInfo(`Already optimized \u2014 ${plan.currentApy.toFixed(2)}% APY on ${plan.fromProtocol}`);
|
|
8081
|
-
printLine(import_picocolors12.default.dim(` Best available: ${plan.newApy.toFixed(2)}% (${displayAsset(plan.toAsset)} on ${plan.toProtocol})`));
|
|
8082
|
-
printLine(import_picocolors12.default.dim(` Difference: ${diff.toFixed(2)}% (below ${minYieldDiff}% threshold)`));
|
|
8083
|
-
} else if (plan.breakEvenDays > maxBreakEven && plan.estimatedSwapCost > 0) {
|
|
8084
|
-
printInfo(`Skipped \u2014 break-even of ${plan.breakEvenDays} days exceeds ${maxBreakEven}-day limit`);
|
|
8085
|
-
printLine(import_picocolors12.default.dim(` ${displayAsset(plan.fromAsset)} on ${plan.fromProtocol} (${plan.currentApy.toFixed(2)}%) \u2192 ${displayAsset(plan.toAsset)} on ${plan.toProtocol} (${plan.newApy.toFixed(2)}%)`));
|
|
8086
|
-
} else {
|
|
8087
|
-
printInfo("Already at the best rate. Nothing to rebalance.");
|
|
8088
|
-
}
|
|
8089
|
-
printBlank();
|
|
8090
|
-
return;
|
|
8091
|
-
}
|
|
8092
|
-
printLine(import_picocolors12.default.bold("Rebalance Plan"));
|
|
8093
|
-
printDivider();
|
|
8094
|
-
printKeyValue("From", `${displayAsset(plan.fromAsset)} on ${plan.fromProtocol} (${plan.currentApy.toFixed(2)}% APY)`);
|
|
8095
|
-
printKeyValue("To", `${displayAsset(plan.toAsset)} on ${plan.toProtocol} (${plan.newApy.toFixed(2)}% APY)`);
|
|
8096
|
-
printKeyValue("Amount", formatUsd(plan.amount));
|
|
8097
|
-
printBlank();
|
|
8098
|
-
printLine(import_picocolors12.default.bold("Economics"));
|
|
8099
|
-
printDivider();
|
|
8100
|
-
printKeyValue("APY Gain", `+${(plan.newApy - plan.currentApy).toFixed(2)}%`);
|
|
8101
|
-
printKeyValue("Annual Gain", `${formatUsd(plan.annualGain)}/year`);
|
|
8102
|
-
if (plan.estimatedSwapCost > 0) {
|
|
8103
|
-
printKeyValue("Swap Cost", `~${formatUsd(plan.estimatedSwapCost)}`);
|
|
8104
|
-
printKeyValue("Break-even", `${plan.breakEvenDays} days`);
|
|
8105
|
-
}
|
|
8106
|
-
printBlank();
|
|
8107
|
-
if (plan.steps.length > 0) {
|
|
8108
|
-
printLine(import_picocolors12.default.bold("Steps"));
|
|
8109
|
-
printDivider();
|
|
8110
|
-
for (let i = 0; i < plan.steps.length; i++) {
|
|
8111
|
-
const step = plan.steps[i];
|
|
8112
|
-
const num = `${i + 1}.`;
|
|
8113
|
-
if (step.action === "withdraw") {
|
|
8114
|
-
printLine(` ${num} Withdraw ${formatUsd(step.amount)} ${displayAsset(step.fromAsset ?? "")} from ${step.protocol}`);
|
|
8115
|
-
} else if (step.action === "swap") {
|
|
8116
|
-
printLine(` ${num} Swap ${displayAsset(step.fromAsset ?? "")} \u2192 ${displayAsset(step.toAsset ?? "")} (~${formatUsd(step.estimatedOutput ?? 0)})`);
|
|
8117
|
-
} else if (step.action === "deposit") {
|
|
8118
|
-
printLine(` ${num} Deposit ${formatUsd(step.amount)} ${displayAsset(step.toAsset ?? "")} into ${step.protocol}`);
|
|
8119
|
-
}
|
|
8120
|
-
}
|
|
8121
|
-
printBlank();
|
|
8122
|
-
}
|
|
8123
|
-
if (opts.dryRun) {
|
|
8124
|
-
printLine(import_picocolors12.default.bold(import_picocolors12.default.yellow("DRY RUN \u2014 Preview only, no transactions executed")));
|
|
8125
|
-
printLine(import_picocolors12.default.dim(" Run `t2000 rebalance` to execute."));
|
|
8126
|
-
printBlank();
|
|
8127
|
-
return;
|
|
8128
|
-
}
|
|
8129
|
-
const result = await agent.rebalance({ dryRun: false, minYieldDiff, maxBreakEven });
|
|
8130
|
-
if (result.executed) {
|
|
8131
|
-
printSuccess(`Rebalanced ${formatUsd(result.amount)} \u2192 ${result.newApy.toFixed(2)}% APY`);
|
|
8132
|
-
for (const digest of result.txDigests) {
|
|
8133
|
-
printKeyValue("Tx", explorerUrl(digest));
|
|
8134
|
-
}
|
|
8135
|
-
printKeyValue("Gas", `${result.totalGasCost.toFixed(4)} SUI`);
|
|
8136
|
-
}
|
|
8137
7960
|
printBlank();
|
|
8138
7961
|
} catch (error) {
|
|
8139
7962
|
handleError(error);
|
|
8140
7963
|
}
|
|
8141
7964
|
});
|
|
8142
7965
|
}
|
|
8143
|
-
function displayAsset(asset) {
|
|
8144
|
-
return SUPPORTED_ASSETS[asset]?.displayName ?? asset;
|
|
8145
|
-
}
|
|
8146
|
-
|
|
8147
|
-
// src/commands/exchange.ts
|
|
8148
|
-
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
8149
|
-
function resolveAssetName(input) {
|
|
8150
|
-
const upper = input.toUpperCase();
|
|
8151
|
-
for (const key of Object.keys(SUPPORTED_ASSETS)) {
|
|
8152
|
-
if (key.toUpperCase() === upper) return key;
|
|
8153
|
-
}
|
|
8154
|
-
return input;
|
|
8155
|
-
}
|
|
8156
|
-
function registerExchange(program3) {
|
|
8157
|
-
program3.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) => {
|
|
8158
|
-
try {
|
|
8159
|
-
console.error(import_picocolors13.default.yellow(' \u26A0 "exchange" is deprecated. Use "swap" instead: t2000 swap %s %s %s'), amount, from, to);
|
|
8160
|
-
const pin = await resolvePin();
|
|
8161
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8162
|
-
const parsedAmount = parseFloat(amount);
|
|
8163
|
-
if (isNaN(parsedAmount) || parsedAmount <= 0) throw new Error("Amount must be a positive number");
|
|
8164
|
-
const result = await agent.swap({
|
|
8165
|
-
from: resolveAssetName(from),
|
|
8166
|
-
to: resolveAssetName(to),
|
|
8167
|
-
amount: parsedAmount,
|
|
8168
|
-
maxSlippage: parseFloat(opts.slippage ?? "3") / 100
|
|
8169
|
-
});
|
|
8170
|
-
if (isJsonMode()) {
|
|
8171
|
-
printJson(result);
|
|
8172
|
-
return;
|
|
8173
|
-
}
|
|
8174
|
-
console.log(import_picocolors13.default.green(" \u2713 Swapped. Tx: %s"), result.tx);
|
|
8175
|
-
} catch (error) {
|
|
8176
|
-
handleError(error);
|
|
8177
|
-
}
|
|
8178
|
-
});
|
|
8179
|
-
}
|
|
8180
|
-
|
|
8181
|
-
// src/commands/swap.ts
|
|
8182
|
-
function resolveAssetName2(input) {
|
|
8183
|
-
const upper = input.toUpperCase();
|
|
8184
|
-
for (const key of Object.keys(SUPPORTED_ASSETS)) {
|
|
8185
|
-
if (key.toUpperCase() === upper) return key;
|
|
8186
|
-
}
|
|
8187
|
-
return input;
|
|
8188
|
-
}
|
|
8189
|
-
function fmtTokenAmount(amount, asset) {
|
|
8190
|
-
if (["USDC", "USDT", "USDE"].includes(asset)) return formatUsd(amount);
|
|
8191
|
-
if (amount > 0 && amount < 1e-3) return amount.toFixed(8);
|
|
8192
|
-
if (amount > 0 && amount < 1) return amount.toFixed(6);
|
|
8193
|
-
return amount.toFixed(4);
|
|
8194
|
-
}
|
|
8195
|
-
async function executeSwap(from, to, amount, opts, label) {
|
|
8196
|
-
const pin = await resolvePin();
|
|
8197
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8198
|
-
const fromAsset = resolveAssetName2(from);
|
|
8199
|
-
const toAsset = resolveAssetName2(to);
|
|
8200
|
-
const result = await agent.swap({
|
|
8201
|
-
from: fromAsset,
|
|
8202
|
-
to: toAsset,
|
|
8203
|
-
amount,
|
|
8204
|
-
maxSlippage: parseFloat(opts.slippage ?? "3") / 100
|
|
8205
|
-
});
|
|
8206
|
-
if (isJsonMode()) {
|
|
8207
|
-
printJson(result);
|
|
8208
|
-
return;
|
|
8209
|
-
}
|
|
8210
|
-
const fromDisplay = SUPPORTED_ASSETS[fromAsset]?.displayName ?? fromAsset;
|
|
8211
|
-
const toDisplay = SUPPORTED_ASSETS[toAsset]?.displayName ?? toAsset;
|
|
8212
|
-
printBlank();
|
|
8213
|
-
if (label === "Bought") {
|
|
8214
|
-
printSuccess(`Bought ${fmtTokenAmount(result.toAmount, toAsset)} ${toDisplay} for ${formatUsd(amount)}`);
|
|
8215
|
-
} else if (label === "Sold") {
|
|
8216
|
-
printSuccess(`Sold ${fmtTokenAmount(amount, fromAsset)} ${fromDisplay} for ${formatUsd(result.toAmount)}`);
|
|
8217
|
-
} else {
|
|
8218
|
-
printSuccess(`Swapped ${fmtTokenAmount(amount, fromAsset)} ${fromDisplay} \u2192 ${fmtTokenAmount(result.toAmount, toAsset)} ${toDisplay}`);
|
|
8219
|
-
}
|
|
8220
|
-
printKeyValue("Tx", explorerUrl(result.tx));
|
|
8221
|
-
printKeyValue("Gas", `${result.gasCost.toFixed(4)} SUI (${result.gasMethod})`);
|
|
8222
|
-
printBlank();
|
|
8223
|
-
}
|
|
8224
|
-
function registerSwap(program3) {
|
|
8225
|
-
program3.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) => {
|
|
8226
|
-
try {
|
|
8227
|
-
const parsedAmount = parseFloat(amount);
|
|
8228
|
-
if (isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
8229
|
-
throw new Error("Amount must be a positive number");
|
|
8230
|
-
}
|
|
8231
|
-
await executeSwap(from, to, parsedAmount, opts, "Swapped");
|
|
8232
|
-
} catch (error) {
|
|
8233
|
-
handleError(error);
|
|
8234
|
-
}
|
|
8235
|
-
});
|
|
8236
|
-
program3.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) => {
|
|
8237
|
-
try {
|
|
8238
|
-
const parsedAmount = parseFloat(amount);
|
|
8239
|
-
if (isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
8240
|
-
throw new Error("Amount must be a positive number");
|
|
8241
|
-
}
|
|
8242
|
-
const resolved = resolveAssetName2(asset);
|
|
8243
|
-
if (resolved in INVESTMENT_ASSETS) {
|
|
8244
|
-
const pin = await resolvePin();
|
|
8245
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8246
|
-
const result = await agent.investBuy({
|
|
8247
|
-
asset: resolved,
|
|
8248
|
-
usdAmount: parsedAmount,
|
|
8249
|
-
maxSlippage: parseFloat(opts.slippage ?? "3") / 100
|
|
8250
|
-
});
|
|
8251
|
-
if (isJsonMode()) {
|
|
8252
|
-
printJson(result);
|
|
8253
|
-
return;
|
|
8254
|
-
}
|
|
8255
|
-
const display = SUPPORTED_ASSETS[resolved]?.displayName ?? resolved;
|
|
8256
|
-
printBlank();
|
|
8257
|
-
printSuccess(`Bought ${fmtTokenAmount(result.amount, resolved)} ${display} for ${formatUsd(parsedAmount)}`);
|
|
8258
|
-
printKeyValue("Tx", explorerUrl(result.tx));
|
|
8259
|
-
printBlank();
|
|
8260
|
-
} else {
|
|
8261
|
-
await executeSwap("USDC", asset, parsedAmount, opts, "Bought");
|
|
8262
|
-
}
|
|
8263
|
-
} catch (error) {
|
|
8264
|
-
handleError(error);
|
|
8265
|
-
}
|
|
8266
|
-
});
|
|
8267
|
-
program3.command("sell <amount> <asset>").description("Sell an asset for USDC (e.g. sell 0.001 BTC, sell all SUI)").option("--key <path>", "Key file path").option("--slippage <pct>", "Max slippage percentage (default: 3)", "3").action(async (amount, asset, opts) => {
|
|
8268
|
-
try {
|
|
8269
|
-
const resolved = resolveAssetName2(asset);
|
|
8270
|
-
const isAll = amount.toLowerCase() === "all";
|
|
8271
|
-
if (resolved in INVESTMENT_ASSETS) {
|
|
8272
|
-
const pin = await resolvePin();
|
|
8273
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8274
|
-
const usdAmount = isAll ? "all" : parseFloat(amount);
|
|
8275
|
-
if (usdAmount !== "all" && (isNaN(usdAmount) || usdAmount <= 0)) {
|
|
8276
|
-
throw new Error('Amount must be a positive number or "all"');
|
|
8277
|
-
}
|
|
8278
|
-
const result = await agent.investSell({
|
|
8279
|
-
asset: resolved,
|
|
8280
|
-
usdAmount,
|
|
8281
|
-
maxSlippage: parseFloat(opts.slippage ?? "3") / 100
|
|
8282
|
-
});
|
|
8283
|
-
if (isJsonMode()) {
|
|
8284
|
-
printJson(result);
|
|
8285
|
-
return;
|
|
8286
|
-
}
|
|
8287
|
-
const display = SUPPORTED_ASSETS[resolved]?.displayName ?? resolved;
|
|
8288
|
-
printBlank();
|
|
8289
|
-
printSuccess(`Sold ${fmtTokenAmount(result.amount, resolved)} ${display} at ${formatUsd(result.price)}`);
|
|
8290
|
-
printKeyValue("Proceeds", formatUsd(result.usdValue));
|
|
8291
|
-
if (result.realizedPnL !== void 0) {
|
|
8292
|
-
const pnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
8293
|
-
printKeyValue("Realized P&L", `${pnlSign}${formatUsd(result.realizedPnL)}`);
|
|
8294
|
-
}
|
|
8295
|
-
printKeyValue("Tx", explorerUrl(result.tx));
|
|
8296
|
-
printBlank();
|
|
8297
|
-
} else {
|
|
8298
|
-
const parsedAmount = parseFloat(amount);
|
|
8299
|
-
if (isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
8300
|
-
throw new Error("Amount must be a positive number");
|
|
8301
|
-
}
|
|
8302
|
-
await executeSwap(asset, "USDC", parsedAmount, opts, "Sold");
|
|
8303
|
-
}
|
|
8304
|
-
} catch (error) {
|
|
8305
|
-
handleError(error);
|
|
8306
|
-
}
|
|
8307
|
-
});
|
|
8308
|
-
}
|
|
8309
7966
|
|
|
8310
7967
|
// src/commands/mcp.ts
|
|
8311
7968
|
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
@@ -8353,7 +8010,7 @@ function registerMcp(program3) {
|
|
|
8353
8010
|
mcp.command("start", { isDefault: true }).description("Start MCP server (stdio transport)").option("--key <path>", "Key file path").action(async (opts) => {
|
|
8354
8011
|
let mod;
|
|
8355
8012
|
try {
|
|
8356
|
-
mod = await import("./dist-
|
|
8013
|
+
mod = await import("./dist-22NK522A.js");
|
|
8357
8014
|
} catch {
|
|
8358
8015
|
console.error(
|
|
8359
8016
|
"MCP server not installed. Run:\n npm install -g @t2000/mcp"
|
|
@@ -8503,735 +8160,227 @@ function registerContacts(program3) {
|
|
|
8503
8160
|
});
|
|
8504
8161
|
}
|
|
8505
8162
|
|
|
8506
|
-
// src/commands/
|
|
8507
|
-
var
|
|
8508
|
-
function
|
|
8509
|
-
|
|
8510
|
-
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) => {
|
|
8163
|
+
// src/commands/claimRewards.ts
|
|
8164
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
8165
|
+
function registerClaimRewards(program3) {
|
|
8166
|
+
program3.command("claim-rewards").description("Claim pending protocol rewards").option("--key <path>", "Key file path").action(async (opts) => {
|
|
8511
8167
|
try {
|
|
8512
|
-
console.error(import_picocolors14.default.yellow(` \u26A0 "invest buy" is deprecated. Use: t2000 buy ${amount} ${asset}`));
|
|
8513
|
-
const parsed = parseFloat(amount);
|
|
8514
|
-
if (isNaN(parsed) || parsed <= 0 || !isFinite(parsed)) {
|
|
8515
|
-
console.error(import_picocolors14.default.red(" \u2717 Amount must be greater than $0"));
|
|
8516
|
-
process.exitCode = 1;
|
|
8517
|
-
return;
|
|
8518
|
-
}
|
|
8519
8168
|
const pin = await resolvePin();
|
|
8520
8169
|
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8521
|
-
const result = await agent.
|
|
8522
|
-
asset: asset.toUpperCase(),
|
|
8523
|
-
usdAmount: parsed,
|
|
8524
|
-
maxSlippage: parseFloat(opts.slippage) / 100
|
|
8525
|
-
});
|
|
8170
|
+
const result = await agent.claimRewards();
|
|
8526
8171
|
if (isJsonMode()) {
|
|
8527
8172
|
printJson(result);
|
|
8528
8173
|
return;
|
|
8529
8174
|
}
|
|
8530
8175
|
printBlank();
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8176
|
+
if (result.rewards.length === 0) {
|
|
8177
|
+
printLine(` ${import_picocolors12.default.dim("No rewards to claim")}`);
|
|
8178
|
+
printBlank();
|
|
8179
|
+
return;
|
|
8180
|
+
}
|
|
8181
|
+
const protocols = [...new Set(result.rewards.map((r) => r.protocol))];
|
|
8182
|
+
printLine(` ${import_picocolors12.default.green("\u2713")} Claimed rewards`);
|
|
8183
|
+
printSeparator();
|
|
8184
|
+
const received = result.totalValueUsd;
|
|
8185
|
+
if (received >= 0.01) {
|
|
8186
|
+
printKeyValue("Value", `${import_picocolors12.default.green(formatUsd(received))}`);
|
|
8187
|
+
} else if (received > 0) {
|
|
8188
|
+
printKeyValue("Value", `${import_picocolors12.default.green("< $0.01")}`);
|
|
8189
|
+
} else {
|
|
8190
|
+
printKeyValue("Value", `${import_picocolors12.default.dim("< $0.01 (rewards are still accruing)")}`);
|
|
8191
|
+
}
|
|
8192
|
+
printKeyValue("Source", protocols.join(", "));
|
|
8193
|
+
if (result.tx) {
|
|
8194
|
+
printKeyValue("Tx", `https://suiscan.xyz/mainnet/tx/${result.tx}`);
|
|
8195
|
+
}
|
|
8535
8196
|
printBlank();
|
|
8536
8197
|
} catch (error) {
|
|
8537
8198
|
handleError(error);
|
|
8538
8199
|
}
|
|
8539
8200
|
});
|
|
8540
|
-
|
|
8201
|
+
}
|
|
8202
|
+
|
|
8203
|
+
// src/commands/gas.ts
|
|
8204
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
8205
|
+
function registerGas(program3) {
|
|
8206
|
+
program3.command("gas").description("Check gas station status and wallet gas balance").option("--key <path>", "Key file path").action(async (opts) => {
|
|
8541
8207
|
try {
|
|
8542
|
-
|
|
8543
|
-
const
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8208
|
+
const pin = await resolvePin();
|
|
8209
|
+
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8210
|
+
const address = agent.address();
|
|
8211
|
+
const [status, bal] = await Promise.allSettled([
|
|
8212
|
+
getGasStatus(address),
|
|
8213
|
+
agent.balance()
|
|
8214
|
+
]);
|
|
8215
|
+
const gasStatus = status.status === "fulfilled" ? status.value : null;
|
|
8216
|
+
const balData = bal.status === "fulfilled" ? bal.value : null;
|
|
8217
|
+
if (isJsonMode()) {
|
|
8218
|
+
printJson({
|
|
8219
|
+
gasStation: gasStatus ?? { error: status.status === "rejected" ? String(status.reason) : "unavailable" },
|
|
8220
|
+
wallet: balData ? { sui: balData.gasReserve.sui, available: balData.available } : null
|
|
8221
|
+
});
|
|
8222
|
+
return;
|
|
8223
|
+
}
|
|
8224
|
+
printHeader("Gas Status");
|
|
8225
|
+
if (gasStatus) {
|
|
8226
|
+
const cbStatus = gasStatus.circuitBreaker ? import_picocolors13.default.red("TRIPPED \u2014 sponsorship paused") : import_picocolors13.default.green("OK");
|
|
8227
|
+
printKeyValue("Gas Station", cbStatus);
|
|
8228
|
+
printKeyValue("SUI Price (TWAP)", `$${gasStatus.suiPrice.toFixed(4)}`);
|
|
8229
|
+
if (gasStatus.bootstrapRemaining !== void 0) {
|
|
8230
|
+
printKeyValue("Bootstrap", `${gasStatus.bootstrapUsed}/10 used (${gasStatus.bootstrapRemaining} remaining)`);
|
|
8231
|
+
}
|
|
8232
|
+
} else {
|
|
8233
|
+
printKeyValue("Gas Station", import_picocolors13.default.red("unreachable"));
|
|
8234
|
+
const reason = status.status === "rejected" ? status.reason : "unknown";
|
|
8235
|
+
printLine(` ${import_picocolors13.default.dim(reason instanceof Error ? reason.message : String(reason))}`);
|
|
8236
|
+
}
|
|
8237
|
+
printDivider();
|
|
8238
|
+
if (balData) {
|
|
8239
|
+
const suiBal = balData.gasReserve.sui;
|
|
8240
|
+
const suiColor = suiBal < 0.05 ? import_picocolors13.default.red : import_picocolors13.default.green;
|
|
8241
|
+
printKeyValue("SUI (gas)", suiColor(`${suiBal.toFixed(4)} SUI`));
|
|
8242
|
+
if (suiBal < 0.05) {
|
|
8243
|
+
printLine(` ${import_picocolors13.default.yellow("\u26A0")} Below gas threshold (0.05 SUI) \u2014 transactions will need sponsorship`);
|
|
8550
8244
|
}
|
|
8245
|
+
printKeyValue("Available", `$${balData.available.toFixed(2)}`);
|
|
8246
|
+
} else {
|
|
8247
|
+
printKeyValue("Wallet", import_picocolors13.default.dim("could not fetch balances"));
|
|
8248
|
+
}
|
|
8249
|
+
printBlank();
|
|
8250
|
+
if (gasStatus && !gasStatus.circuitBreaker && (balData?.gasReserve.sui ?? 0) >= 0.05) {
|
|
8251
|
+
printLine(` ${import_picocolors13.default.green("\u2713")} Gas is healthy \u2014 transactions should succeed`);
|
|
8252
|
+
} else if (gasStatus && !gasStatus.circuitBreaker) {
|
|
8253
|
+
printLine(` ${import_picocolors13.default.yellow("\u26A0")} Low SUI but gas station is online \u2014 sponsorship available`);
|
|
8254
|
+
} else {
|
|
8255
|
+
printLine(` ${import_picocolors13.default.red("\u2717")} Gas station issues detected \u2014 fund wallet with SUI directly`);
|
|
8256
|
+
printInfo("Send SUI to your address: t2000 address");
|
|
8257
|
+
}
|
|
8258
|
+
printBlank();
|
|
8259
|
+
} catch (error) {
|
|
8260
|
+
handleError(error);
|
|
8261
|
+
}
|
|
8262
|
+
});
|
|
8263
|
+
}
|
|
8264
|
+
|
|
8265
|
+
// src/commands/swap.ts
|
|
8266
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
8267
|
+
function registerSwap(program3) {
|
|
8268
|
+
program3.command("swap").description("Swap tokens via Cetus Aggregator (20+ DEXs)").argument("<amount>", "Amount to swap").argument("<from>", "Source token (e.g. SUI, USDC, CETUS)").argument("[to_keyword]", '"for" keyword (optional)').argument("<to>", "Target token (e.g. USDC, SUI, DEEP)").option("--slippage <pct>", "Max slippage percentage (default: 1)", "1").option("--key <path>", "Key file path").action(async (amountStr, from, toKeywordOrTo, to, opts) => {
|
|
8269
|
+
try {
|
|
8270
|
+
const amount = parseFloat(amountStr);
|
|
8271
|
+
if (isNaN(amount) || amount <= 0) {
|
|
8272
|
+
throw new Error("Amount must be a positive number");
|
|
8551
8273
|
}
|
|
8274
|
+
if (toKeywordOrTo?.toLowerCase() === "for" && !to) {
|
|
8275
|
+
throw new Error("Usage: t2000 swap <amount> <from> [for] <to>");
|
|
8276
|
+
}
|
|
8277
|
+
const actualTo = to ?? toKeywordOrTo;
|
|
8278
|
+
const slippage = Math.min(parseFloat(opts.slippage ?? "1") / 100, 0.05);
|
|
8552
8279
|
const pin = await resolvePin();
|
|
8553
8280
|
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8554
|
-
const
|
|
8555
|
-
const usdAmount = isAll ? "all" : parseFloat(amount);
|
|
8556
|
-
const result = await agent.investSell({
|
|
8557
|
-
asset: sym,
|
|
8558
|
-
usdAmount,
|
|
8559
|
-
maxSlippage: parseFloat(opts.slippage) / 100
|
|
8560
|
-
});
|
|
8281
|
+
const result = await agent.swap({ from, to: actualTo, amount, slippage });
|
|
8561
8282
|
if (isJsonMode()) {
|
|
8562
8283
|
printJson(result);
|
|
8563
8284
|
return;
|
|
8564
8285
|
}
|
|
8565
8286
|
printBlank();
|
|
8566
|
-
printSuccess(`
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
const pnlColor = result.realizedPnL >= 0 ? import_picocolors14.default.green : import_picocolors14.default.red;
|
|
8570
|
-
const pnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
8571
|
-
printKeyValue("Realized P&L", pnlColor(`${pnlSign}${formatUsd(result.realizedPnL)}`));
|
|
8287
|
+
printSuccess(`Swapped ${import_picocolors14.default.yellow(String(result.fromAmount))} ${result.fromToken} for ${import_picocolors14.default.green(result.toAmount.toFixed(4))} ${result.toToken}`);
|
|
8288
|
+
if (result.priceImpact > 5e-3) {
|
|
8289
|
+
printKeyValue("Price Impact", import_picocolors14.default.yellow(`${(result.priceImpact * 100).toFixed(2)}%`));
|
|
8572
8290
|
}
|
|
8291
|
+
printKeyValue("Route", `${result.fromToken} \u2192 ${result.toToken} (${result.route})`);
|
|
8292
|
+
printKeyValue("Gas", `${result.gasCost.toFixed(4)} SUI (${result.gasMethod})`);
|
|
8573
8293
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
8574
8294
|
printBlank();
|
|
8575
8295
|
} catch (error) {
|
|
8576
8296
|
handleError(error);
|
|
8577
8297
|
}
|
|
8578
8298
|
});
|
|
8579
|
-
|
|
8299
|
+
}
|
|
8300
|
+
|
|
8301
|
+
// src/commands/swapQuote.ts
|
|
8302
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
8303
|
+
function registerSwapQuote(program3) {
|
|
8304
|
+
program3.command("swap-quote").description("Preview a swap quote without executing (shows output, price impact, route)").argument("<amount>", "Amount to swap").argument("<from>", "Source token (e.g. SUI, USDC)").argument("[to_keyword]", '"for" keyword (optional)').argument("<to>", "Target token (e.g. USDC, SUI)").option("--key <path>", "Key file path").action(async (amountStr, from, toKeywordOrTo, to, opts) => {
|
|
8580
8305
|
try {
|
|
8306
|
+
const amount = parseFloat(amountStr);
|
|
8307
|
+
if (isNaN(amount) || amount <= 0) {
|
|
8308
|
+
throw new Error("Amount must be a positive number");
|
|
8309
|
+
}
|
|
8310
|
+
if (toKeywordOrTo?.toLowerCase() === "for" && !to) {
|
|
8311
|
+
throw new Error("Usage: t2000 swap-quote <amount> <from> [for] <to>");
|
|
8312
|
+
}
|
|
8313
|
+
const actualTo = to ?? toKeywordOrTo;
|
|
8581
8314
|
const pin = await resolvePin();
|
|
8582
8315
|
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8583
|
-
const result = await agent.
|
|
8584
|
-
asset: asset.toUpperCase(),
|
|
8585
|
-
protocol: opts.protocol?.toLowerCase()
|
|
8586
|
-
});
|
|
8316
|
+
const result = await agent.swapQuote({ from, to: actualTo, amount });
|
|
8587
8317
|
if (isJsonMode()) {
|
|
8588
8318
|
printJson(result);
|
|
8589
8319
|
return;
|
|
8590
8320
|
}
|
|
8591
8321
|
printBlank();
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
printSuccess(`${sym} deposited into ${result.protocol} (${result.apy.toFixed(1)}% APY)`);
|
|
8597
|
-
printKeyValue("Amount", `${formatAssetAmount(result.amount, sym)} ${sym}`);
|
|
8598
|
-
printKeyValue("Protocol", result.protocol);
|
|
8599
|
-
printKeyValue("APY", `${result.apy.toFixed(2)}%`);
|
|
8600
|
-
printKeyValue("Tx", explorerUrl(result.tx));
|
|
8322
|
+
printKeyValue("Input", `${result.fromAmount} ${result.fromToken}`);
|
|
8323
|
+
printKeyValue("Output", import_picocolors15.default.green(`${result.toAmount.toFixed(6)} ${result.toToken}`));
|
|
8324
|
+
if (result.priceImpact > 1e-3) {
|
|
8325
|
+
printKeyValue("Price Impact", import_picocolors15.default.yellow(`${(result.priceImpact * 100).toFixed(2)}%`));
|
|
8601
8326
|
}
|
|
8327
|
+
printKeyValue("Route", `${result.fromToken} \u2192 ${result.toToken} (${result.route})`);
|
|
8602
8328
|
printBlank();
|
|
8603
8329
|
} catch (error) {
|
|
8604
8330
|
handleError(error);
|
|
8605
8331
|
}
|
|
8606
8332
|
});
|
|
8607
|
-
|
|
8333
|
+
}
|
|
8334
|
+
|
|
8335
|
+
// src/commands/stake.ts
|
|
8336
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
8337
|
+
function registerStake(program3) {
|
|
8338
|
+
program3.command("stake").description("Stake SUI for vSUI via VOLO liquid staking (earn ~3-5% APY)").argument("<amount>", "Amount of SUI to stake (minimum 1)").option("--key <path>", "Key file path").action(async (amountStr, opts) => {
|
|
8608
8339
|
try {
|
|
8340
|
+
const amount = parseFloat(amountStr);
|
|
8341
|
+
if (isNaN(amount) || amount < 1) {
|
|
8342
|
+
throw new Error("Amount must be at least 1 SUI");
|
|
8343
|
+
}
|
|
8609
8344
|
const pin = await resolvePin();
|
|
8610
8345
|
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8611
|
-
const result = await agent.
|
|
8612
|
-
asset: asset.toUpperCase()
|
|
8613
|
-
});
|
|
8346
|
+
const result = await agent.stakeVSui({ amount });
|
|
8614
8347
|
if (isJsonMode()) {
|
|
8615
8348
|
printJson(result);
|
|
8616
8349
|
return;
|
|
8617
8350
|
}
|
|
8618
8351
|
printBlank();
|
|
8619
|
-
|
|
8620
|
-
printSuccess(`
|
|
8621
|
-
printKeyValue("
|
|
8352
|
+
printSuccess(`Staked ${import_picocolors16.default.yellow(String(result.amountSui))} SUI for ${import_picocolors16.default.green(result.vSuiReceived.toFixed(4))} vSUI`);
|
|
8353
|
+
printSuccess(`APY: ${import_picocolors16.default.green(`${(result.apy * 100).toFixed(2)}%`)}`);
|
|
8354
|
+
printKeyValue("Gas", `${result.gasCost.toFixed(4)} SUI (${result.gasMethod})`);
|
|
8622
8355
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
8623
8356
|
printBlank();
|
|
8624
8357
|
} catch (error) {
|
|
8625
8358
|
handleError(error);
|
|
8626
8359
|
}
|
|
8627
8360
|
});
|
|
8628
|
-
|
|
8361
|
+
}
|
|
8362
|
+
|
|
8363
|
+
// src/commands/unstake.ts
|
|
8364
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
8365
|
+
function registerUnstake(program3) {
|
|
8366
|
+
program3.command("unstake").description("Unstake vSUI back to SUI (returns SUI including accumulated yield)").argument("<amount>", 'Amount of vSUI to unstake (or "all")').option("--key <path>", "Key file path").action(async (amountStr, opts) => {
|
|
8629
8367
|
try {
|
|
8368
|
+
const amount = amountStr === "all" ? "all" : parseFloat(amountStr);
|
|
8369
|
+
if (amount !== "all" && (isNaN(amount) || amount <= 0)) {
|
|
8370
|
+
throw new Error('Amount must be a positive number or "all"');
|
|
8371
|
+
}
|
|
8630
8372
|
const pin = await resolvePin();
|
|
8631
8373
|
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8632
|
-
const result = await agent.
|
|
8633
|
-
dryRun: opts.dryRun,
|
|
8634
|
-
minYieldDiff: opts.minDiff ? parseFloat(opts.minDiff) : void 0
|
|
8635
|
-
});
|
|
8374
|
+
const result = await agent.unstakeVSui({ amount });
|
|
8636
8375
|
if (isJsonMode()) {
|
|
8637
8376
|
printJson(result);
|
|
8638
8377
|
return;
|
|
8639
8378
|
}
|
|
8640
8379
|
printBlank();
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
printLine(` ${s.asset}: ${s.apy.toFixed(2)}% on ${s.protocol} (best: ${s.bestApy.toFixed(2)}% \u2014 ${s.reason.replace(/_/g, " ")})`);
|
|
8646
|
-
}
|
|
8647
|
-
}
|
|
8648
|
-
printBlank();
|
|
8649
|
-
return;
|
|
8650
|
-
}
|
|
8651
|
-
if (opts.dryRun) {
|
|
8652
|
-
printHeader("Rebalance Preview");
|
|
8653
|
-
for (const m of result.moves) {
|
|
8654
|
-
printLine(` ${m.asset}: ${m.fromProtocol} (${m.oldApy.toFixed(2)}%) \u2192 ${m.toProtocol} (${m.newApy.toFixed(2)}%)`);
|
|
8655
|
-
printLine(` Gain: +${(m.newApy - m.oldApy).toFixed(2)}% APY`);
|
|
8656
|
-
}
|
|
8657
|
-
} else {
|
|
8658
|
-
printSuccess("Rebalanced earning positions");
|
|
8659
|
-
printSeparator();
|
|
8660
|
-
for (const m of result.moves) {
|
|
8661
|
-
printLine(` ${m.asset}: ${m.fromProtocol} (${m.oldApy.toFixed(2)}%) \u2192 ${m.toProtocol} (${m.newApy.toFixed(2)}%)`);
|
|
8662
|
-
printKeyValue("Amount", `${formatAssetAmount(m.amount, m.asset)} ${m.asset}`);
|
|
8663
|
-
printKeyValue("APY gain", `+${(m.newApy - m.oldApy).toFixed(2)}%`);
|
|
8664
|
-
if (m.txDigests.length > 0) {
|
|
8665
|
-
printKeyValue("Tx", explorerUrl(m.txDigests[m.txDigests.length - 1]));
|
|
8666
|
-
}
|
|
8667
|
-
}
|
|
8668
|
-
printSeparator();
|
|
8669
|
-
printKeyValue("Gas", `${result.totalGasCost.toFixed(6)} SUI`);
|
|
8670
|
-
}
|
|
8671
|
-
if (result.skipped.length > 0) {
|
|
8672
|
-
printBlank();
|
|
8673
|
-
for (const s of result.skipped) {
|
|
8674
|
-
printLine(` ${s.asset}: kept on ${s.protocol} (${s.reason.replace(/_/g, " ")})`);
|
|
8675
|
-
}
|
|
8676
|
-
}
|
|
8677
|
-
printBlank();
|
|
8678
|
-
} catch (error) {
|
|
8679
|
-
handleError(error);
|
|
8680
|
-
}
|
|
8681
|
-
});
|
|
8682
|
-
const strategyCmd = investCmd.command("strategy").description("Manage investment strategies");
|
|
8683
|
-
strategyCmd.command("list").description("List available strategies").option("--key <path>", "Key file path").action(async (opts) => {
|
|
8684
|
-
try {
|
|
8685
|
-
const pin = await resolvePin();
|
|
8686
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8687
|
-
const all = agent.strategies.getAll();
|
|
8688
|
-
if (isJsonMode()) {
|
|
8689
|
-
printJson(all);
|
|
8690
|
-
return;
|
|
8691
|
-
}
|
|
8692
|
-
printBlank();
|
|
8693
|
-
printHeader("Investment Strategies");
|
|
8694
|
-
printSeparator();
|
|
8695
|
-
for (const [key, def] of Object.entries(all)) {
|
|
8696
|
-
const allocs = Object.entries(def.allocations).map(([a, p]) => `${a} ${p}%`).join(", ");
|
|
8697
|
-
const tag = def.custom ? import_picocolors14.default.dim(" (custom)") : "";
|
|
8698
|
-
printKeyValue(key, `${allocs}${tag}`);
|
|
8699
|
-
printLine(` ${import_picocolors14.default.dim(def.description)}`);
|
|
8700
|
-
}
|
|
8701
|
-
printSeparator();
|
|
8702
|
-
const hasPositions = Object.keys(all).some((k) => agent.portfolio.hasStrategyPositions(k));
|
|
8703
|
-
if (!hasPositions) {
|
|
8704
|
-
printInfo("Buy into a strategy: t2000 invest strategy buy bluechip 100");
|
|
8705
|
-
}
|
|
8706
|
-
printBlank();
|
|
8707
|
-
} catch (error) {
|
|
8708
|
-
handleError(error);
|
|
8709
|
-
}
|
|
8710
|
-
});
|
|
8711
|
-
strategyCmd.command("buy <name> <amount>").description("Buy into a strategy").option("--key <path>", "Key file path").option("--dry-run", "Preview allocation without executing").action(async (name, amount, opts) => {
|
|
8712
|
-
try {
|
|
8713
|
-
const parsed = parseFloat(amount);
|
|
8714
|
-
if (isNaN(parsed) || parsed <= 0) {
|
|
8715
|
-
console.error(import_picocolors14.default.red(" \u2717 Amount must be greater than $0"));
|
|
8716
|
-
process.exitCode = 1;
|
|
8717
|
-
return;
|
|
8718
|
-
}
|
|
8719
|
-
const pin = await resolvePin();
|
|
8720
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8721
|
-
const result = await agent.investStrategy({ strategy: name.toLowerCase(), usdAmount: parsed, dryRun: opts.dryRun });
|
|
8722
|
-
if (isJsonMode()) {
|
|
8723
|
-
printJson(result);
|
|
8724
|
-
return;
|
|
8725
|
-
}
|
|
8726
|
-
printBlank();
|
|
8727
|
-
if (opts.dryRun) {
|
|
8728
|
-
printHeader(`Strategy: ${name} \u2014 Dry Run (${formatUsd(parsed)})`);
|
|
8729
|
-
printSeparator();
|
|
8730
|
-
for (const buy of result.buys) {
|
|
8731
|
-
printKeyValue(buy.asset, `${formatUsd(buy.usdAmount)} \u2192 ~${formatAssetAmount(buy.amount, buy.asset)} ${buy.asset} @ ${formatUsd(buy.price)}`);
|
|
8732
|
-
}
|
|
8733
|
-
printSeparator();
|
|
8734
|
-
printInfo("Run without --dry-run to execute");
|
|
8735
|
-
} else {
|
|
8736
|
-
const txDigests = [...new Set(result.buys.map((b) => b.tx))];
|
|
8737
|
-
const isSingleTx = txDigests.length === 1;
|
|
8738
|
-
printSuccess(`Invested ${formatUsd(parsed)} in ${name} strategy`);
|
|
8739
|
-
printSeparator();
|
|
8740
|
-
for (const buy of result.buys) {
|
|
8741
|
-
printKeyValue(buy.asset, `${formatAssetAmount(buy.amount, buy.asset)} @ ${formatUsd(buy.price)}`);
|
|
8742
|
-
}
|
|
8743
|
-
printSeparator();
|
|
8744
|
-
printKeyValue("Total invested", formatUsd(result.totalInvested));
|
|
8745
|
-
if (isSingleTx) {
|
|
8746
|
-
printKeyValue("Tx", explorerUrl(txDigests[0]));
|
|
8747
|
-
} else {
|
|
8748
|
-
for (const buy of result.buys) {
|
|
8749
|
-
printLine(` ${import_picocolors14.default.dim(`${buy.asset}: ${explorerUrl(buy.tx)}`)}`);
|
|
8750
|
-
}
|
|
8751
|
-
}
|
|
8752
|
-
}
|
|
8753
|
-
printBlank();
|
|
8754
|
-
} catch (error) {
|
|
8755
|
-
handleError(error);
|
|
8756
|
-
}
|
|
8757
|
-
});
|
|
8758
|
-
strategyCmd.command("sell <name>").description("Sell all positions in a strategy").option("--key <path>", "Key file path").action(async (name, opts) => {
|
|
8759
|
-
try {
|
|
8760
|
-
const pin = await resolvePin();
|
|
8761
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8762
|
-
const result = await agent.sellStrategy({ strategy: name.toLowerCase() });
|
|
8763
|
-
if (isJsonMode()) {
|
|
8764
|
-
printJson(result);
|
|
8765
|
-
return;
|
|
8766
|
-
}
|
|
8767
|
-
printBlank();
|
|
8768
|
-
printSuccess(`Sold all ${name} strategy positions`);
|
|
8769
|
-
printSeparator();
|
|
8770
|
-
for (const sell of result.sells) {
|
|
8771
|
-
const pnlColor = sell.realizedPnL >= 0 ? import_picocolors14.default.green : import_picocolors14.default.red;
|
|
8772
|
-
const pnlSign = sell.realizedPnL >= 0 ? "+" : "";
|
|
8773
|
-
printKeyValue(sell.asset, `${formatAssetAmount(sell.amount, sell.asset)} \u2192 ${formatUsd(sell.usdValue)} ${pnlColor(`${pnlSign}${formatUsd(sell.realizedPnL)}`)}`);
|
|
8774
|
-
}
|
|
8775
|
-
if (result.failed && result.failed.length > 0) {
|
|
8776
|
-
for (const f of result.failed) {
|
|
8777
|
-
console.error(import_picocolors14.default.yellow(` \u26A0 ${f.asset}: ${f.reason}`));
|
|
8778
|
-
}
|
|
8779
|
-
}
|
|
8780
|
-
printSeparator();
|
|
8781
|
-
printKeyValue("Total proceeds", formatUsd(result.totalProceeds));
|
|
8782
|
-
const rpnlColor = result.realizedPnL >= 0 ? import_picocolors14.default.green : import_picocolors14.default.red;
|
|
8783
|
-
const rpnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
8784
|
-
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd(result.realizedPnL)}`));
|
|
8785
|
-
printBlank();
|
|
8786
|
-
} catch (error) {
|
|
8787
|
-
handleError(error);
|
|
8788
|
-
}
|
|
8789
|
-
});
|
|
8790
|
-
strategyCmd.command("status <name>").description("Show current status and weights of a strategy").option("--key <path>", "Key file path").action(async (name, opts) => {
|
|
8791
|
-
try {
|
|
8792
|
-
const pin = await resolvePin();
|
|
8793
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8794
|
-
const status = await agent.getStrategyStatus(name.toLowerCase());
|
|
8795
|
-
if (isJsonMode()) {
|
|
8796
|
-
printJson(status);
|
|
8797
|
-
return;
|
|
8798
|
-
}
|
|
8799
|
-
printBlank();
|
|
8800
|
-
printHeader(`Strategy: ${status.definition.name}`);
|
|
8801
|
-
printSeparator();
|
|
8802
|
-
if (status.positions.length === 0) {
|
|
8803
|
-
printInfo("No positions yet. Buy in with: t2000 invest strategy buy " + name + " 100");
|
|
8804
|
-
} else {
|
|
8805
|
-
for (const pos of status.positions) {
|
|
8806
|
-
const target = status.definition.allocations[pos.asset] ?? 0;
|
|
8807
|
-
const actual = status.currentWeights[pos.asset] ?? 0;
|
|
8808
|
-
const drift = actual - target;
|
|
8809
|
-
const driftColor = Math.abs(drift) > 3 ? import_picocolors14.default.yellow : import_picocolors14.default.dim;
|
|
8810
|
-
const pnlColor = pos.unrealizedPnL >= 0 ? import_picocolors14.default.green : import_picocolors14.default.red;
|
|
8811
|
-
const pnlSign = pos.unrealizedPnL >= 0 ? "+" : "";
|
|
8812
|
-
printKeyValue(
|
|
8813
|
-
pos.asset,
|
|
8814
|
-
`${formatAssetAmount(pos.totalAmount, pos.asset)} ${formatUsd(pos.currentValue)} ${pnlColor(`${pnlSign}${formatUsd(pos.unrealizedPnL)}`)} ${driftColor(`${actual.toFixed(0)}% / ${target}% target`)}`
|
|
8815
|
-
);
|
|
8816
|
-
}
|
|
8817
|
-
printSeparator();
|
|
8818
|
-
printKeyValue("Total value", formatUsd(status.totalValue));
|
|
8819
|
-
}
|
|
8820
|
-
printBlank();
|
|
8821
|
-
} catch (error) {
|
|
8822
|
-
handleError(error);
|
|
8823
|
-
}
|
|
8824
|
-
});
|
|
8825
|
-
strategyCmd.command("rebalance <name>").description("Rebalance a strategy to target weights").option("--key <path>", "Key file path").action(async (name, opts) => {
|
|
8826
|
-
try {
|
|
8827
|
-
const pin = await resolvePin();
|
|
8828
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8829
|
-
const result = await agent.rebalanceStrategy({ strategy: name.toLowerCase() });
|
|
8830
|
-
if (isJsonMode()) {
|
|
8831
|
-
printJson(result);
|
|
8832
|
-
return;
|
|
8833
|
-
}
|
|
8834
|
-
printBlank();
|
|
8835
|
-
if (result.trades.length === 0) {
|
|
8836
|
-
printInfo(`Strategy '${name}' is already balanced (within 3% threshold)`);
|
|
8837
|
-
} else {
|
|
8838
|
-
printSuccess(`Rebalanced ${name} strategy`);
|
|
8839
|
-
printSeparator();
|
|
8840
|
-
for (const t of result.trades) {
|
|
8841
|
-
const action = t.action === "buy" ? import_picocolors14.default.green("BUY") : import_picocolors14.default.red("SELL");
|
|
8842
|
-
printKeyValue(t.asset, `${action} ${formatUsd(t.usdAmount)} (${formatAssetAmount(t.amount, t.asset)})`);
|
|
8843
|
-
}
|
|
8844
|
-
printSeparator();
|
|
8845
|
-
printInfo("Weights: " + Object.entries(result.afterWeights).map(([a, w]) => `${a} ${w.toFixed(0)}%`).join(", "));
|
|
8846
|
-
}
|
|
8847
|
-
printBlank();
|
|
8848
|
-
} catch (error) {
|
|
8849
|
-
handleError(error);
|
|
8850
|
-
}
|
|
8851
|
-
});
|
|
8852
|
-
strategyCmd.command("create <name>").description("Create a custom strategy").requiredOption("--alloc <pairs...>", "Allocations e.g. SUI:40 BTC:20 ETH:20 GOLD:20").option("--description <desc>", "Strategy description").action(async (name, opts) => {
|
|
8853
|
-
try {
|
|
8854
|
-
const allocations = {};
|
|
8855
|
-
for (const pair of opts.alloc) {
|
|
8856
|
-
const [asset, pctStr] = pair.split(":");
|
|
8857
|
-
if (!asset || !pctStr) {
|
|
8858
|
-
console.error(import_picocolors14.default.red(` \u2717 Invalid allocation: '${pair}'. Use ASSET:PCT format (e.g. SUI:60)`));
|
|
8859
|
-
process.exitCode = 1;
|
|
8860
|
-
return;
|
|
8861
|
-
}
|
|
8862
|
-
allocations[asset.toUpperCase()] = parseFloat(pctStr);
|
|
8863
|
-
}
|
|
8864
|
-
const pin = await resolvePin();
|
|
8865
|
-
const agent = await T2000.create({ pin });
|
|
8866
|
-
const definition = agent.strategies.create({ name, allocations, description: opts.description });
|
|
8867
|
-
if (isJsonMode()) {
|
|
8868
|
-
printJson(definition);
|
|
8869
|
-
return;
|
|
8870
|
-
}
|
|
8871
|
-
printBlank();
|
|
8872
|
-
printSuccess(`Created strategy '${name}'`);
|
|
8873
|
-
const allocs = Object.entries(definition.allocations).map(([a, p]) => `${a} ${p}%`).join(", ");
|
|
8874
|
-
printKeyValue("Allocations", allocs);
|
|
8875
|
-
printBlank();
|
|
8876
|
-
} catch (error) {
|
|
8877
|
-
handleError(error);
|
|
8878
|
-
}
|
|
8879
|
-
});
|
|
8880
|
-
strategyCmd.command("delete <name>").description("Delete a custom strategy").option("--key <path>", "Key file path").action(async (name, opts) => {
|
|
8881
|
-
try {
|
|
8882
|
-
const pin = await resolvePin();
|
|
8883
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8884
|
-
if (agent.portfolio.hasStrategyPositions(name.toLowerCase())) {
|
|
8885
|
-
console.error(import_picocolors14.default.red(` \u2717 Strategy '${name}' has open positions. Sell first: t2000 invest strategy sell ${name}`));
|
|
8886
|
-
process.exitCode = 1;
|
|
8887
|
-
return;
|
|
8888
|
-
}
|
|
8889
|
-
agent.strategies.delete(name.toLowerCase());
|
|
8890
|
-
if (isJsonMode()) {
|
|
8891
|
-
printJson({ deleted: name });
|
|
8892
|
-
return;
|
|
8893
|
-
}
|
|
8894
|
-
printBlank();
|
|
8895
|
-
printSuccess(`Deleted strategy '${name}'`);
|
|
8896
|
-
printBlank();
|
|
8897
|
-
} catch (error) {
|
|
8898
|
-
handleError(error);
|
|
8899
|
-
}
|
|
8900
|
-
});
|
|
8901
|
-
const autoCmd = investCmd.command("auto").description("Dollar-cost averaging (DCA) schedules");
|
|
8902
|
-
autoCmd.command("setup <amount> <frequency> [target]").description("Create a DCA schedule (target = strategy name or asset)").option("--key <path>", "Key file path").option("--day <num>", "Day of week (1-7) or month (1-28)").action(async (amount, frequency, target, opts) => {
|
|
8903
|
-
try {
|
|
8904
|
-
const parsed = parseFloat(amount);
|
|
8905
|
-
if (isNaN(parsed) || parsed < 1) {
|
|
8906
|
-
console.error(import_picocolors14.default.red(" \u2717 Amount must be at least $1"));
|
|
8907
|
-
process.exitCode = 1;
|
|
8908
|
-
return;
|
|
8909
|
-
}
|
|
8910
|
-
if (!["daily", "weekly", "monthly"].includes(frequency)) {
|
|
8911
|
-
console.error(import_picocolors14.default.red(" \u2717 Frequency must be daily, weekly, or monthly"));
|
|
8912
|
-
process.exitCode = 1;
|
|
8913
|
-
return;
|
|
8914
|
-
}
|
|
8915
|
-
const pin = await resolvePin();
|
|
8916
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8917
|
-
const allStrategies = agent.strategies.getAll();
|
|
8918
|
-
const isStrategy = target ? target.toLowerCase() in allStrategies : false;
|
|
8919
|
-
const isAsset = target ? target.toUpperCase() in INVESTMENT_ASSETS : false;
|
|
8920
|
-
if (target && !isStrategy && !isAsset) {
|
|
8921
|
-
console.error(import_picocolors14.default.red(` \u2717 '${target}' is not a valid strategy or asset`));
|
|
8922
|
-
process.exitCode = 1;
|
|
8923
|
-
return;
|
|
8924
|
-
}
|
|
8925
|
-
const dayNum = opts.day ? parseInt(opts.day, 10) : void 0;
|
|
8926
|
-
const schedule = agent.setupAutoInvest({
|
|
8927
|
-
amount: parsed,
|
|
8928
|
-
frequency,
|
|
8929
|
-
strategy: isStrategy ? target.toLowerCase() : void 0,
|
|
8930
|
-
asset: isAsset ? target.toUpperCase() : void 0,
|
|
8931
|
-
dayOfWeek: frequency === "weekly" ? dayNum : void 0,
|
|
8932
|
-
dayOfMonth: frequency === "monthly" ? dayNum : void 0
|
|
8933
|
-
});
|
|
8934
|
-
if (isJsonMode()) {
|
|
8935
|
-
printJson(schedule);
|
|
8936
|
-
return;
|
|
8937
|
-
}
|
|
8938
|
-
printBlank();
|
|
8939
|
-
const targetLabel = schedule.strategy ?? schedule.asset ?? "unknown";
|
|
8940
|
-
printSuccess(`Auto-invest created: ${formatUsd(schedule.amount)} ${schedule.frequency} \u2192 ${targetLabel}`);
|
|
8941
|
-
printKeyValue("Schedule ID", schedule.id);
|
|
8942
|
-
printKeyValue("Next run", new Date(schedule.nextRun).toLocaleDateString());
|
|
8943
|
-
printInfo("Run manually: t2000 invest auto run");
|
|
8944
|
-
printBlank();
|
|
8945
|
-
} catch (error) {
|
|
8946
|
-
handleError(error);
|
|
8947
|
-
}
|
|
8948
|
-
});
|
|
8949
|
-
autoCmd.command("status").description("Show all DCA schedules").option("--key <path>", "Key file path").action(async (opts) => {
|
|
8950
|
-
try {
|
|
8951
|
-
const pin = await resolvePin();
|
|
8952
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8953
|
-
const status = agent.getAutoInvestStatus();
|
|
8954
|
-
if (isJsonMode()) {
|
|
8955
|
-
printJson(status);
|
|
8956
|
-
return;
|
|
8957
|
-
}
|
|
8958
|
-
printBlank();
|
|
8959
|
-
if (status.schedules.length === 0) {
|
|
8960
|
-
printInfo("No auto-invest schedules. Set one up: t2000 invest auto setup 50 weekly bluechip");
|
|
8961
|
-
printBlank();
|
|
8962
|
-
return;
|
|
8963
|
-
}
|
|
8964
|
-
printHeader("Auto-Invest Schedules");
|
|
8965
|
-
printSeparator();
|
|
8966
|
-
for (const s of status.schedules) {
|
|
8967
|
-
const target = s.strategy ?? s.asset ?? "?";
|
|
8968
|
-
const statusTag = s.enabled ? import_picocolors14.default.green("active") : import_picocolors14.default.dim("paused");
|
|
8969
|
-
printKeyValue(s.id, `${formatUsd(s.amount)} ${s.frequency} \u2192 ${target} ${statusTag}`);
|
|
8970
|
-
printLine(` ${import_picocolors14.default.dim(`Next: ${new Date(s.nextRun).toLocaleDateString()} \xB7 Runs: ${s.runCount} \xB7 Total: ${formatUsd(s.totalInvested)}`)}`);
|
|
8971
|
-
}
|
|
8972
|
-
printSeparator();
|
|
8973
|
-
if (status.pendingRuns.length > 0) {
|
|
8974
|
-
printInfo(`${status.pendingRuns.length} pending run(s). Execute: t2000 invest auto run`);
|
|
8975
|
-
} else {
|
|
8976
|
-
printInfo("All schedules up to date");
|
|
8977
|
-
}
|
|
8978
|
-
printBlank();
|
|
8979
|
-
} catch (error) {
|
|
8980
|
-
handleError(error);
|
|
8981
|
-
}
|
|
8982
|
-
});
|
|
8983
|
-
autoCmd.command("run").description("Execute pending DCA purchases").option("--key <path>", "Key file path").action(async (opts) => {
|
|
8984
|
-
try {
|
|
8985
|
-
const pin = await resolvePin();
|
|
8986
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
8987
|
-
const status = agent.getAutoInvestStatus();
|
|
8988
|
-
if (status.pendingRuns.length === 0) {
|
|
8989
|
-
if (isJsonMode()) {
|
|
8990
|
-
printJson({ executed: [], skipped: [] });
|
|
8991
|
-
return;
|
|
8992
|
-
}
|
|
8993
|
-
printBlank();
|
|
8994
|
-
printInfo("No pending auto-invest runs. All schedules are up to date.");
|
|
8995
|
-
printBlank();
|
|
8996
|
-
return;
|
|
8997
|
-
}
|
|
8998
|
-
const result = await agent.runAutoInvest();
|
|
8999
|
-
if (isJsonMode()) {
|
|
9000
|
-
printJson(result);
|
|
9001
|
-
return;
|
|
9002
|
-
}
|
|
9003
|
-
printBlank();
|
|
9004
|
-
if (result.executed.length > 0) {
|
|
9005
|
-
printSuccess(`Executed ${result.executed.length} auto-invest run(s)`);
|
|
9006
|
-
for (const exec of result.executed) {
|
|
9007
|
-
const target = exec.strategy ?? exec.asset ?? "?";
|
|
9008
|
-
printKeyValue(target, formatUsd(exec.amount));
|
|
9009
|
-
}
|
|
9010
|
-
}
|
|
9011
|
-
if (result.skipped.length > 0) {
|
|
9012
|
-
for (const skip of result.skipped) {
|
|
9013
|
-
printLine(` ${import_picocolors14.default.yellow("\u26A0")} Skipped ${skip.scheduleId}: ${skip.reason}`);
|
|
9014
|
-
}
|
|
9015
|
-
}
|
|
9016
|
-
printBlank();
|
|
9017
|
-
} catch (error) {
|
|
9018
|
-
handleError(error);
|
|
9019
|
-
}
|
|
9020
|
-
});
|
|
9021
|
-
autoCmd.command("stop <id>").description("Stop an auto-invest schedule").option("--key <path>", "Key file path").action(async (id, opts) => {
|
|
9022
|
-
try {
|
|
9023
|
-
const pin = await resolvePin();
|
|
9024
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
9025
|
-
agent.stopAutoInvest(id);
|
|
9026
|
-
if (isJsonMode()) {
|
|
9027
|
-
printJson({ stopped: id });
|
|
9028
|
-
return;
|
|
9029
|
-
}
|
|
9030
|
-
printBlank();
|
|
9031
|
-
printSuccess(`Stopped auto-invest schedule ${id}`);
|
|
9032
|
-
printBlank();
|
|
9033
|
-
} catch (error) {
|
|
9034
|
-
handleError(error);
|
|
9035
|
-
}
|
|
9036
|
-
});
|
|
9037
|
-
}
|
|
9038
|
-
|
|
9039
|
-
// src/commands/portfolio.ts
|
|
9040
|
-
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
9041
|
-
function printPositionLine(pos, rewardKeys) {
|
|
9042
|
-
if (pos.currentPrice === 0 && pos.totalAmount > 0) {
|
|
9043
|
-
printKeyValue(
|
|
9044
|
-
pos.asset,
|
|
9045
|
-
`${formatAssetAmount(pos.totalAmount, pos.asset)} Avg: ${formatUsd(pos.avgPrice)} Now: ${import_picocolors15.default.yellow("unavailable")}`
|
|
9046
|
-
);
|
|
9047
|
-
} else {
|
|
9048
|
-
const pnlColor = pos.unrealizedPnL >= 0 ? import_picocolors15.default.green : import_picocolors15.default.red;
|
|
9049
|
-
const pnlSign = pos.unrealizedPnL >= 0 ? "+" : "";
|
|
9050
|
-
let yieldSuffix = "";
|
|
9051
|
-
if (pos.earning && pos.earningApy) {
|
|
9052
|
-
const hasRewards = rewardKeys?.has(`${pos.earningProtocol}:${pos.asset}`);
|
|
9053
|
-
const rewardTag = hasRewards ? ` ${import_picocolors15.default.yellow("+rewards")}` : "";
|
|
9054
|
-
yieldSuffix = ` ${import_picocolors15.default.cyan(`${pos.earningApy.toFixed(1)}% APY (${pos.earningProtocol})`)}${rewardTag}`;
|
|
9055
|
-
}
|
|
9056
|
-
printKeyValue(
|
|
9057
|
-
pos.asset,
|
|
9058
|
-
`${formatAssetAmount(pos.totalAmount, pos.asset)} Avg: ${formatUsd(pos.avgPrice)} Now: ${formatUsd(pos.currentPrice)} ${pnlColor(`${pnlSign}${formatUsd(pos.unrealizedPnL)} (${pnlSign}${pos.unrealizedPnLPct.toFixed(1)}%)`)}${yieldSuffix}`
|
|
9059
|
-
);
|
|
9060
|
-
}
|
|
9061
|
-
}
|
|
9062
|
-
function registerPortfolio(program3) {
|
|
9063
|
-
program3.command("portfolio").description("Show investment portfolio").option("--key <path>", "Key file path").action(async (opts) => {
|
|
9064
|
-
try {
|
|
9065
|
-
const pin = await resolvePin();
|
|
9066
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
9067
|
-
const portfolio = await agent.getPortfolio();
|
|
9068
|
-
if (isJsonMode()) {
|
|
9069
|
-
printJson(portfolio);
|
|
9070
|
-
return;
|
|
9071
|
-
}
|
|
9072
|
-
const rewardKeys = /* @__PURE__ */ new Set();
|
|
9073
|
-
try {
|
|
9074
|
-
const pending = await agent.getPendingRewards();
|
|
9075
|
-
for (const r of pending) rewardKeys.add(`${r.protocol}:${r.asset}`);
|
|
9076
|
-
} catch {
|
|
9077
|
-
}
|
|
9078
|
-
printBlank();
|
|
9079
|
-
const hasDirectPositions = portfolio.positions.length > 0;
|
|
9080
|
-
const hasStrategyPositions = portfolio.strategyPositions && Object.keys(portfolio.strategyPositions).length > 0;
|
|
9081
|
-
if (!hasDirectPositions && !hasStrategyPositions) {
|
|
9082
|
-
printInfo("No investments yet. Try: t2000 buy 100 SUI");
|
|
9083
|
-
printBlank();
|
|
9084
|
-
return;
|
|
9085
|
-
}
|
|
9086
|
-
printHeader("Investment Portfolio");
|
|
9087
|
-
if (hasStrategyPositions) {
|
|
9088
|
-
for (const [key, positions] of Object.entries(portfolio.strategyPositions)) {
|
|
9089
|
-
let stratLabel = key;
|
|
9090
|
-
try {
|
|
9091
|
-
const def = agent.strategies.get(key);
|
|
9092
|
-
stratLabel = def.name;
|
|
9093
|
-
} catch {
|
|
9094
|
-
}
|
|
9095
|
-
printLine(` ${import_picocolors15.default.bold(import_picocolors15.default.cyan(`\u25B8 ${stratLabel}`))}`);
|
|
9096
|
-
printSeparator();
|
|
9097
|
-
for (const pos of positions) {
|
|
9098
|
-
printPositionLine(pos, rewardKeys);
|
|
9099
|
-
}
|
|
9100
|
-
const stratValue = positions.reduce((s, p) => s + p.currentValue, 0);
|
|
9101
|
-
printLine(` ${import_picocolors15.default.dim(`Subtotal: ${formatUsd(stratValue)}`)}`);
|
|
9102
|
-
printBlank();
|
|
9103
|
-
}
|
|
9104
|
-
}
|
|
9105
|
-
if (hasDirectPositions) {
|
|
9106
|
-
if (hasStrategyPositions) {
|
|
9107
|
-
printLine(` ${import_picocolors15.default.bold(import_picocolors15.default.cyan("\u25B8 Direct"))}`);
|
|
9108
|
-
}
|
|
9109
|
-
printSeparator();
|
|
9110
|
-
for (const pos of portfolio.positions) {
|
|
9111
|
-
printPositionLine(pos, rewardKeys);
|
|
9112
|
-
}
|
|
9113
|
-
if (hasStrategyPositions) {
|
|
9114
|
-
const directValue = portfolio.positions.reduce((s, p) => s + p.currentValue, 0);
|
|
9115
|
-
printLine(` ${import_picocolors15.default.dim(`Subtotal: ${formatUsd(directValue)}`)}`);
|
|
9116
|
-
}
|
|
9117
|
-
}
|
|
9118
|
-
printSeparator();
|
|
9119
|
-
const hasPriceUnavailable = portfolio.positions.some((p) => p.currentPrice === 0 && p.totalAmount > 0);
|
|
9120
|
-
if (hasPriceUnavailable) {
|
|
9121
|
-
printInfo(import_picocolors15.default.yellow("\u26A0 Price data unavailable for some assets. Values may be inaccurate."));
|
|
9122
|
-
}
|
|
9123
|
-
printKeyValue("Total invested", formatUsd(portfolio.totalInvested));
|
|
9124
|
-
printKeyValue("Current value", formatUsd(portfolio.totalValue));
|
|
9125
|
-
const upnlColor = portfolio.unrealizedPnL >= 0 ? import_picocolors15.default.green : import_picocolors15.default.red;
|
|
9126
|
-
const upnlSign = portfolio.unrealizedPnL >= 0 ? "+" : "";
|
|
9127
|
-
printKeyValue("Unrealized P&L", upnlColor(`${upnlSign}${formatUsd(portfolio.unrealizedPnL)} (${upnlSign}${portfolio.unrealizedPnLPct.toFixed(1)}%)`));
|
|
9128
|
-
if (portfolio.realizedPnL !== 0) {
|
|
9129
|
-
const rpnlColor = portfolio.realizedPnL >= 0 ? import_picocolors15.default.green : import_picocolors15.default.red;
|
|
9130
|
-
const rpnlSign = portfolio.realizedPnL >= 0 ? "+" : "";
|
|
9131
|
-
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd(portfolio.realizedPnL)}`));
|
|
9132
|
-
}
|
|
9133
|
-
printBlank();
|
|
9134
|
-
} catch (error) {
|
|
9135
|
-
handleError(error);
|
|
9136
|
-
}
|
|
9137
|
-
});
|
|
9138
|
-
}
|
|
9139
|
-
|
|
9140
|
-
// src/commands/claimRewards.ts
|
|
9141
|
-
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
9142
|
-
function registerClaimRewards(program3) {
|
|
9143
|
-
program3.command("claim-rewards").description("Claim pending protocol rewards").option("--key <path>", "Key file path").action(async (opts) => {
|
|
9144
|
-
try {
|
|
9145
|
-
const pin = await resolvePin();
|
|
9146
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
9147
|
-
const result = await agent.claimRewards();
|
|
9148
|
-
if (isJsonMode()) {
|
|
9149
|
-
printJson(result);
|
|
9150
|
-
return;
|
|
9151
|
-
}
|
|
9152
|
-
printBlank();
|
|
9153
|
-
if (result.rewards.length === 0) {
|
|
9154
|
-
printLine(` ${import_picocolors16.default.dim("No rewards to claim")}`);
|
|
9155
|
-
printBlank();
|
|
9156
|
-
return;
|
|
9157
|
-
}
|
|
9158
|
-
const protocols = [...new Set(result.rewards.map((r) => r.protocol))];
|
|
9159
|
-
printLine(` ${import_picocolors16.default.green("\u2713")} Claimed and converted rewards to USDC`);
|
|
9160
|
-
printSeparator();
|
|
9161
|
-
const received = result.usdcReceived;
|
|
9162
|
-
if (received >= 0.01) {
|
|
9163
|
-
printKeyValue("Received", `${import_picocolors16.default.green(formatUsd(received))} USDC`);
|
|
9164
|
-
} else if (received > 0) {
|
|
9165
|
-
printKeyValue("Received", `${import_picocolors16.default.green("< $0.01")} USDC`);
|
|
9166
|
-
} else {
|
|
9167
|
-
printKeyValue("Received", `${import_picocolors16.default.dim("< $0.01 USDC (rewards are still accruing)")}`);
|
|
9168
|
-
}
|
|
9169
|
-
printKeyValue("Source", protocols.join(", "));
|
|
9170
|
-
if (result.tx) {
|
|
9171
|
-
printKeyValue("Tx", `https://suiscan.xyz/mainnet/tx/${result.tx}`);
|
|
9172
|
-
}
|
|
9173
|
-
printBlank();
|
|
9174
|
-
} catch (error) {
|
|
9175
|
-
handleError(error);
|
|
9176
|
-
}
|
|
9177
|
-
});
|
|
9178
|
-
}
|
|
9179
|
-
|
|
9180
|
-
// src/commands/gas.ts
|
|
9181
|
-
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
9182
|
-
function registerGas(program3) {
|
|
9183
|
-
program3.command("gas").description("Check gas station status and wallet gas balance").option("--key <path>", "Key file path").action(async (opts) => {
|
|
9184
|
-
try {
|
|
9185
|
-
const pin = await resolvePin();
|
|
9186
|
-
const agent = await T2000.create({ pin, keyPath: opts.key });
|
|
9187
|
-
const address = agent.address();
|
|
9188
|
-
const [status, bal] = await Promise.allSettled([
|
|
9189
|
-
getGasStatus(address),
|
|
9190
|
-
agent.balance()
|
|
9191
|
-
]);
|
|
9192
|
-
const gasStatus = status.status === "fulfilled" ? status.value : null;
|
|
9193
|
-
const balData = bal.status === "fulfilled" ? bal.value : null;
|
|
9194
|
-
if (isJsonMode()) {
|
|
9195
|
-
printJson({
|
|
9196
|
-
gasStation: gasStatus ?? { error: status.status === "rejected" ? String(status.reason) : "unavailable" },
|
|
9197
|
-
wallet: balData ? { sui: balData.gasReserve.sui, available: balData.available } : null
|
|
9198
|
-
});
|
|
9199
|
-
return;
|
|
9200
|
-
}
|
|
9201
|
-
printHeader("Gas Status");
|
|
9202
|
-
if (gasStatus) {
|
|
9203
|
-
const cbStatus = gasStatus.circuitBreaker ? import_picocolors17.default.red("TRIPPED \u2014 sponsorship paused") : import_picocolors17.default.green("OK");
|
|
9204
|
-
printKeyValue("Gas Station", cbStatus);
|
|
9205
|
-
printKeyValue("SUI Price (TWAP)", `$${gasStatus.suiPrice.toFixed(4)}`);
|
|
9206
|
-
if (gasStatus.bootstrapRemaining !== void 0) {
|
|
9207
|
-
printKeyValue("Bootstrap", `${gasStatus.bootstrapUsed}/10 used (${gasStatus.bootstrapRemaining} remaining)`);
|
|
9208
|
-
}
|
|
9209
|
-
} else {
|
|
9210
|
-
printKeyValue("Gas Station", import_picocolors17.default.red("unreachable"));
|
|
9211
|
-
const reason = status.status === "rejected" ? status.reason : "unknown";
|
|
9212
|
-
printLine(` ${import_picocolors17.default.dim(reason instanceof Error ? reason.message : String(reason))}`);
|
|
9213
|
-
}
|
|
9214
|
-
printDivider();
|
|
9215
|
-
if (balData) {
|
|
9216
|
-
const suiBal = balData.gasReserve.sui;
|
|
9217
|
-
const suiColor = suiBal < 0.05 ? import_picocolors17.default.red : import_picocolors17.default.green;
|
|
9218
|
-
printKeyValue("SUI (gas)", suiColor(`${suiBal.toFixed(4)} SUI`));
|
|
9219
|
-
if (suiBal < 0.05) {
|
|
9220
|
-
printLine(` ${import_picocolors17.default.yellow("\u26A0")} Below gas threshold (0.05 SUI) \u2014 transactions will need sponsorship`);
|
|
9221
|
-
}
|
|
9222
|
-
printKeyValue("Available", `$${balData.available.toFixed(2)}`);
|
|
9223
|
-
} else {
|
|
9224
|
-
printKeyValue("Wallet", import_picocolors17.default.dim("could not fetch balances"));
|
|
9225
|
-
}
|
|
9226
|
-
printBlank();
|
|
9227
|
-
if (gasStatus && !gasStatus.circuitBreaker && (balData?.gasReserve.sui ?? 0) >= 0.05) {
|
|
9228
|
-
printLine(` ${import_picocolors17.default.green("\u2713")} Gas is healthy \u2014 transactions should succeed`);
|
|
9229
|
-
} else if (gasStatus && !gasStatus.circuitBreaker) {
|
|
9230
|
-
printLine(` ${import_picocolors17.default.yellow("\u26A0")} Low SUI but gas station is online \u2014 sponsorship available`);
|
|
9231
|
-
} else {
|
|
9232
|
-
printLine(` ${import_picocolors17.default.red("\u2717")} Gas station issues detected \u2014 fund wallet with SUI directly`);
|
|
9233
|
-
printInfo("Send SUI to your address: t2000 address");
|
|
9234
|
-
}
|
|
8380
|
+
printSuccess(`Unstaked ${import_picocolors17.default.yellow(result.vSuiAmount.toFixed(4))} vSUI`);
|
|
8381
|
+
printSuccess(`Received ${import_picocolors17.default.green(result.suiReceived.toFixed(4))} SUI`);
|
|
8382
|
+
printKeyValue("Gas", `${result.gasCost.toFixed(4)} SUI (${result.gasMethod})`);
|
|
8383
|
+
printKeyValue("Tx", explorerUrl(result.tx));
|
|
9235
8384
|
printBlank();
|
|
9236
8385
|
} catch (error) {
|
|
9237
8386
|
handleError(error);
|
|
@@ -9255,9 +8404,6 @@ Examples:
|
|
|
9255
8404
|
$ t2000 send 50 to 0xabc... Send $50 USDC
|
|
9256
8405
|
$ t2000 borrow 200 Borrow $200 against savings
|
|
9257
8406
|
$ t2000 pay openai ... Pay for an API via MPP gateway
|
|
9258
|
-
$ t2000 buy 100 BTC Buy $100 of BTC
|
|
9259
|
-
$ t2000 sell 0.001 BTC Sell BTC for USDC
|
|
9260
|
-
$ t2000 swap 100 USDC SUI Swap between any tokens
|
|
9261
8407
|
$ t2000 mcp install Install MCP for AI platforms`);
|
|
9262
8408
|
registerInit(program3);
|
|
9263
8409
|
registerSend(program3);
|
|
@@ -9281,15 +8427,14 @@ Examples:
|
|
|
9281
8427
|
registerPay(program3);
|
|
9282
8428
|
registerLock(program3);
|
|
9283
8429
|
registerEarn(program3);
|
|
9284
|
-
registerRebalance(program3);
|
|
9285
|
-
registerSwap(program3);
|
|
9286
|
-
registerExchange(program3);
|
|
9287
8430
|
registerMcp(program3);
|
|
9288
8431
|
registerContacts(program3);
|
|
9289
|
-
registerInvest(program3);
|
|
9290
|
-
registerPortfolio(program3);
|
|
9291
8432
|
registerClaimRewards(program3);
|
|
9292
8433
|
registerGas(program3);
|
|
8434
|
+
registerSwap(program3);
|
|
8435
|
+
registerSwapQuote(program3);
|
|
8436
|
+
registerStake(program3);
|
|
8437
|
+
registerUnstake(program3);
|
|
9293
8438
|
return program3;
|
|
9294
8439
|
}
|
|
9295
8440
|
|