@t2000/cli 0.22.4 → 0.22.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -497,12 +497,73 @@ function registerDeposit(program2) {
|
|
|
497
497
|
}
|
|
498
498
|
|
|
499
499
|
// src/commands/history.ts
|
|
500
|
+
import pc4 from "picocolors";
|
|
500
501
|
import { T2000 as T20006, truncateAddress as truncateAddress2 } from "@t2000/sdk";
|
|
502
|
+
var ACTION_LABELS = {
|
|
503
|
+
send: "\u2197 send",
|
|
504
|
+
lending: "\u{1F3E6} lend",
|
|
505
|
+
swap: "\u{1F504} swap",
|
|
506
|
+
"mpp payment": "\u{1F4B3} mpp",
|
|
507
|
+
transaction: "\u{1F4E6} tx"
|
|
508
|
+
};
|
|
509
|
+
function relativeTime(ts) {
|
|
510
|
+
const diff = Date.now() - ts;
|
|
511
|
+
const mins = Math.floor(diff / 6e4);
|
|
512
|
+
if (mins < 1) return "just now";
|
|
513
|
+
if (mins < 60) return `${mins}m ago`;
|
|
514
|
+
const hours = Math.floor(mins / 60);
|
|
515
|
+
if (hours < 24) return `${hours}h ago`;
|
|
516
|
+
const days = Math.floor(hours / 24);
|
|
517
|
+
if (days < 7) return `${days}d ago`;
|
|
518
|
+
return new Date(ts).toLocaleDateString();
|
|
519
|
+
}
|
|
520
|
+
function formatAmount(tx) {
|
|
521
|
+
if (!tx.amount) return "";
|
|
522
|
+
return pc4.bold(`${tx.amount.toFixed(tx.amount < 0.01 ? 4 : 2)} ${tx.asset ?? ""}`);
|
|
523
|
+
}
|
|
524
|
+
function printTxSummary(tx) {
|
|
525
|
+
const label = ACTION_LABELS[tx.action] ?? `\u{1F4E6} ${tx.action}`;
|
|
526
|
+
const time = tx.timestamp ? relativeTime(tx.timestamp) : "";
|
|
527
|
+
const amount = formatAmount(tx);
|
|
528
|
+
const recipient = tx.recipient ? pc4.dim(`\u2192 ${truncateAddress2(tx.recipient)}`) : "";
|
|
529
|
+
const link = pc4.dim(explorerUrl(tx.digest));
|
|
530
|
+
printLine(`${label} ${amount} ${recipient}`);
|
|
531
|
+
printLine(` ${pc4.dim(truncateAddress2(tx.digest))} ${pc4.dim(time)}`);
|
|
532
|
+
printLine(` ${link}`);
|
|
533
|
+
}
|
|
534
|
+
function printTxDetail(tx) {
|
|
535
|
+
printHeader("Transaction Detail");
|
|
536
|
+
const label = ACTION_LABELS[tx.action] ?? `\u{1F4E6} ${tx.action}`;
|
|
537
|
+
printKeyValue("Type", label);
|
|
538
|
+
printKeyValue("Digest", tx.digest);
|
|
539
|
+
if (tx.amount) printKeyValue("Amount", `${tx.amount.toFixed(tx.amount < 0.01 ? 6 : 4)} ${tx.asset ?? ""}`);
|
|
540
|
+
if (tx.recipient) printKeyValue("Recipient", tx.recipient);
|
|
541
|
+
if (tx.timestamp) {
|
|
542
|
+
printKeyValue("Time", `${new Date(tx.timestamp).toLocaleString()} (${relativeTime(tx.timestamp)})`);
|
|
543
|
+
}
|
|
544
|
+
if (tx.gasCost !== void 0) printKeyValue("Gas", `${tx.gasCost.toFixed(6)} SUI`);
|
|
545
|
+
printBlank();
|
|
546
|
+
printKeyValue("Explorer", explorerUrl(tx.digest));
|
|
547
|
+
printBlank();
|
|
548
|
+
}
|
|
501
549
|
function registerHistory(program2) {
|
|
502
|
-
program2.command("history").description("Show transaction history").option("--limit <n>", "Number of transactions", "20").option("--key <path>", "Key file path").action(async (opts) => {
|
|
550
|
+
program2.command("history").description("Show transaction history, or detail for a specific digest").argument("[digest]", "Transaction digest to view details").option("--limit <n>", "Number of transactions", "20").option("--key <path>", "Key file path").action(async (digest, opts) => {
|
|
503
551
|
try {
|
|
504
552
|
const pin = await resolvePin();
|
|
505
553
|
const agent = await T20006.create({ pin, keyPath: opts.key });
|
|
554
|
+
if (digest) {
|
|
555
|
+
const tx = await agent.transactionDetail(digest);
|
|
556
|
+
if (!tx) {
|
|
557
|
+
handleError(new Error(`Transaction not found: ${digest}`));
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
if (isJsonMode()) {
|
|
561
|
+
printJson(tx);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
printTxDetail(tx);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
506
567
|
const txns = await agent.history({ limit: parseInt(opts.limit, 10) });
|
|
507
568
|
if (isJsonMode()) {
|
|
508
569
|
printJson(txns);
|
|
@@ -513,11 +574,12 @@ function registerHistory(program2) {
|
|
|
513
574
|
printInfo("No transactions yet.");
|
|
514
575
|
} else {
|
|
515
576
|
for (const tx of txns) {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
printLine(`${truncateAddress2(tx.digest)} ${tx.action}${gas} ${time}`);
|
|
577
|
+
printTxSummary(tx);
|
|
578
|
+
printBlank();
|
|
519
579
|
}
|
|
520
580
|
}
|
|
581
|
+
printDivider();
|
|
582
|
+
printInfo(`${txns.length} transaction${txns.length === 1 ? "" : "s"} shown`);
|
|
521
583
|
printBlank();
|
|
522
584
|
} catch (error) {
|
|
523
585
|
handleError(error);
|
|
@@ -629,7 +691,7 @@ function registerImport(program2) {
|
|
|
629
691
|
}
|
|
630
692
|
|
|
631
693
|
// src/commands/save.ts
|
|
632
|
-
import
|
|
694
|
+
import pc5 from "picocolors";
|
|
633
695
|
import { T2000 as T20009, formatUsd as formatUsd3 } from "@t2000/sdk";
|
|
634
696
|
function registerSave(program2) {
|
|
635
697
|
const action = async (amountStr, opts) => {
|
|
@@ -651,16 +713,16 @@ function registerSave(program2) {
|
|
|
651
713
|
}
|
|
652
714
|
printBlank();
|
|
653
715
|
if (gasManagerUsdc > 0) {
|
|
654
|
-
printSuccess(`Gas manager: ${
|
|
716
|
+
printSuccess(`Gas manager: ${pc5.yellow(formatUsd3(gasManagerUsdc))} USDC \u2192 SUI`);
|
|
655
717
|
}
|
|
656
718
|
const protocolName = opts.protocol ?? "best rate";
|
|
657
|
-
printSuccess(`Saved ${
|
|
719
|
+
printSuccess(`Saved ${pc5.yellow(formatUsd3(result.amount))} USDC to ${protocolName}`);
|
|
658
720
|
if (result.fee > 0) {
|
|
659
721
|
const feeRate = (result.fee / result.amount * 100).toFixed(1);
|
|
660
|
-
printSuccess(`Protocol fee: ${
|
|
722
|
+
printSuccess(`Protocol fee: ${pc5.dim(`${formatUsd3(result.fee)} USDC (${feeRate}%)`)}`);
|
|
661
723
|
}
|
|
662
|
-
printSuccess(`Current APY: ${
|
|
663
|
-
printSuccess(`Savings balance: ${
|
|
724
|
+
printSuccess(`Current APY: ${pc5.green(`${result.apy.toFixed(2)}%`)}`);
|
|
725
|
+
printSuccess(`Savings balance: ${pc5.yellow(formatUsd3(result.savingsBalance))} USDC`);
|
|
664
726
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
665
727
|
printBlank();
|
|
666
728
|
} catch (error) {
|
|
@@ -792,7 +854,7 @@ function registerHealth(program2) {
|
|
|
792
854
|
}
|
|
793
855
|
|
|
794
856
|
// src/commands/rates.ts
|
|
795
|
-
import
|
|
857
|
+
import pc6 from "picocolors";
|
|
796
858
|
import { T2000 as T200014, SUPPORTED_ASSETS, INVESTMENT_ASSETS, STABLE_ASSETS } from "@t2000/sdk";
|
|
797
859
|
var INVEST_ASSETS = Object.keys(INVESTMENT_ASSETS);
|
|
798
860
|
function registerRates(program2) {
|
|
@@ -809,14 +871,14 @@ function registerRates(program2) {
|
|
|
809
871
|
if (allRates.length > 0) {
|
|
810
872
|
const best = allRates.reduce((a, b) => b.rates.saveApy > a.rates.saveApy ? b : a);
|
|
811
873
|
const bestDisplay = SUPPORTED_ASSETS[best.asset]?.displayName ?? best.asset;
|
|
812
|
-
printLine(
|
|
874
|
+
printLine(pc6.bold(pc6.green(`Best yield: ${best.rates.saveApy.toFixed(2)}% APY`)) + pc6.dim(` (${bestDisplay} on ${best.protocol})`));
|
|
813
875
|
printBlank();
|
|
814
876
|
}
|
|
815
877
|
for (const asset of STABLE_ASSETS) {
|
|
816
878
|
const assetRates = allRates.filter((r) => r.asset === asset);
|
|
817
879
|
if (assetRates.length === 0) continue;
|
|
818
880
|
const display = SUPPORTED_ASSETS[asset]?.displayName ?? asset;
|
|
819
|
-
printLine(
|
|
881
|
+
printLine(pc6.bold(display));
|
|
820
882
|
printDivider();
|
|
821
883
|
for (const entry of assetRates) {
|
|
822
884
|
printKeyValue(entry.protocol, `Save ${entry.rates.saveApy.toFixed(2)}% Borrow ${entry.rates.borrowApy.toFixed(2)}%`);
|
|
@@ -825,7 +887,7 @@ function registerRates(program2) {
|
|
|
825
887
|
}
|
|
826
888
|
const investRates = allRates.filter((r) => INVEST_ASSETS.includes(r.asset));
|
|
827
889
|
if (investRates.length > 0) {
|
|
828
|
-
printLine(
|
|
890
|
+
printLine(pc6.bold("Investment Assets"));
|
|
829
891
|
printDivider();
|
|
830
892
|
for (const asset of INVEST_ASSETS) {
|
|
831
893
|
const assetRates = investRates.filter((r) => r.asset === asset);
|
|
@@ -848,7 +910,7 @@ function registerRates(program2) {
|
|
|
848
910
|
}
|
|
849
911
|
|
|
850
912
|
// src/commands/positions.ts
|
|
851
|
-
import
|
|
913
|
+
import pc7 from "picocolors";
|
|
852
914
|
import { T2000 as T200015, formatUsd as formatUsd8, formatAssetAmount } from "@t2000/sdk";
|
|
853
915
|
function registerPositions(program2) {
|
|
854
916
|
program2.command("positions").description("Show savings & borrow positions across all protocols and assets").option("--key <path>", "Key file path").action(async (opts) => {
|
|
@@ -877,10 +939,10 @@ function registerPositions(program2) {
|
|
|
877
939
|
const saves = result.positions.filter((p) => p.type === "save");
|
|
878
940
|
const borrows = result.positions.filter((p) => p.type === "borrow");
|
|
879
941
|
if (saves.length > 0) {
|
|
880
|
-
printLine(
|
|
942
|
+
printLine(pc7.bold("Savings"));
|
|
881
943
|
printDivider();
|
|
882
944
|
for (const pos of saves) {
|
|
883
|
-
const earning = rewardsByKey.has(`${pos.protocol}:${pos.asset}`) ? ` ${
|
|
945
|
+
const earning = rewardsByKey.has(`${pos.protocol}:${pos.asset}`) ? ` ${pc7.yellow("+rewards")}` : "";
|
|
884
946
|
const usd = formatUsd8(pos.amountUsd ?? pos.amount);
|
|
885
947
|
printKeyValue(pos.protocol, `${formatAssetAmount(pos.amount, pos.asset)} ${pos.asset} (${usd}) @ ${pos.apy.toFixed(2)}% APY${earning}`);
|
|
886
948
|
}
|
|
@@ -889,12 +951,12 @@ function registerPositions(program2) {
|
|
|
889
951
|
printKeyValue("Total", formatUsd8(totalSaved));
|
|
890
952
|
}
|
|
891
953
|
if (hasRewards) {
|
|
892
|
-
printLine(` ${
|
|
954
|
+
printLine(` ${pc7.dim("Run claim-rewards to collect and convert to USDC")}`);
|
|
893
955
|
}
|
|
894
956
|
printBlank();
|
|
895
957
|
}
|
|
896
958
|
if (borrows.length > 0) {
|
|
897
|
-
printLine(
|
|
959
|
+
printLine(pc7.bold("Borrows"));
|
|
898
960
|
printDivider();
|
|
899
961
|
for (const pos of borrows) {
|
|
900
962
|
const usd = formatUsd8(pos.amountUsd ?? pos.amount);
|
|
@@ -914,7 +976,7 @@ function registerPositions(program2) {
|
|
|
914
976
|
}
|
|
915
977
|
|
|
916
978
|
// src/commands/earnings.ts
|
|
917
|
-
import
|
|
979
|
+
import pc8 from "picocolors";
|
|
918
980
|
import { T2000 as T200016, formatUsd as formatUsd9, formatAssetAmount as formatAssetAmount2 } from "@t2000/sdk";
|
|
919
981
|
function registerEarnings(program2) {
|
|
920
982
|
program2.command("earnings").description("Show yield earned to date").option("--key <path>", "Key file path").action(async (opts) => {
|
|
@@ -932,7 +994,7 @@ function registerEarnings(program2) {
|
|
|
932
994
|
printKeyValue("Total Saved", formatUsd9(result.supplied));
|
|
933
995
|
if (savePositions.length > 0) {
|
|
934
996
|
for (const p of savePositions) {
|
|
935
|
-
printLine(` ${
|
|
997
|
+
printLine(` ${pc8.dim("\u2022")} ${formatAssetAmount2(p.amount, p.asset)} ${p.asset} (${formatUsd9(p.amountUsd ?? p.amount)}) on ${p.protocol} @ ${p.apy.toFixed(2)}% APY`);
|
|
936
998
|
}
|
|
937
999
|
}
|
|
938
1000
|
printKeyValue("Blended APY", `${result.currentApy.toFixed(2)}%`);
|
|
@@ -946,7 +1008,7 @@ function registerEarnings(program2) {
|
|
|
946
1008
|
}
|
|
947
1009
|
|
|
948
1010
|
// src/commands/fundStatus.ts
|
|
949
|
-
import
|
|
1011
|
+
import pc9 from "picocolors";
|
|
950
1012
|
import { T2000 as T200017, formatUsd as formatUsd10, formatAssetAmount as formatAssetAmount3 } from "@t2000/sdk";
|
|
951
1013
|
function registerFundStatus(program2) {
|
|
952
1014
|
program2.command("fund-status").description("Full savings summary").option("--key <path>", "Key file path").action(async (opts) => {
|
|
@@ -970,7 +1032,7 @@ function registerFundStatus(program2) {
|
|
|
970
1032
|
printKeyValue("Total Saved", formatUsd10(result.supplied));
|
|
971
1033
|
if (savePositions.length > 0) {
|
|
972
1034
|
for (const p of savePositions) {
|
|
973
|
-
printLine(` ${
|
|
1035
|
+
printLine(` ${pc9.dim("\u2022")} ${formatAssetAmount3(p.amount, p.asset)} ${p.asset} (${formatUsd10(p.amountUsd ?? p.amount)}) on ${p.protocol} @ ${p.apy.toFixed(2)}% APY`);
|
|
974
1036
|
}
|
|
975
1037
|
}
|
|
976
1038
|
printKeyValue("Blended APY", `${result.apy.toFixed(2)}%`);
|
|
@@ -1455,7 +1517,7 @@ function isRetryable(code) {
|
|
|
1455
1517
|
}
|
|
1456
1518
|
|
|
1457
1519
|
// src/commands/pay.ts
|
|
1458
|
-
import
|
|
1520
|
+
import pc10 from "picocolors";
|
|
1459
1521
|
import { T2000 as T200019 } from "@t2000/sdk";
|
|
1460
1522
|
function registerPay(program2) {
|
|
1461
1523
|
program2.command("pay <url>").description("Pay for an MPP-protected API resource").option("--key <path>", "Key file path").option("--method <method>", "HTTP method (GET, POST, PUT)", "GET").option("--data <json>", "Request body for POST/PUT").option("--header <key=value>", "Additional HTTP header (repeatable)", collectHeaders, {}).option("--max-price <amount>", "Max USDC price to auto-approve", "1.00").action(async (url, opts) => {
|
|
@@ -1484,7 +1546,7 @@ function registerPay(program2) {
|
|
|
1484
1546
|
if (result.paid && result.receipt) {
|
|
1485
1547
|
printSuccess(`Paid via MPP (tx: ${result.receipt.reference.slice(0, 10)}...)`);
|
|
1486
1548
|
}
|
|
1487
|
-
printInfo(`\u2190 ${result.status} OK ${
|
|
1549
|
+
printInfo(`\u2190 ${result.status} OK ${pc10.dim(`[${elapsed}ms]`)}`);
|
|
1488
1550
|
}
|
|
1489
1551
|
if (isJsonMode()) {
|
|
1490
1552
|
printJson({
|
|
@@ -1597,7 +1659,7 @@ function registerLock(program2) {
|
|
|
1597
1659
|
|
|
1598
1660
|
// src/commands/sentinel.ts
|
|
1599
1661
|
import { T2000 as T200020, MIST_PER_SUI } from "@t2000/sdk";
|
|
1600
|
-
import
|
|
1662
|
+
import pc11 from "picocolors";
|
|
1601
1663
|
function formatSui(mist) {
|
|
1602
1664
|
return (Number(mist) / Number(MIST_PER_SUI)).toFixed(2);
|
|
1603
1665
|
}
|
|
@@ -1627,8 +1689,8 @@ function registerSentinel(program2) {
|
|
|
1627
1689
|
const pool = `${formatSui(s.prizePool)} SUI`.padEnd(12);
|
|
1628
1690
|
const fee = `${formatSui(s.attackFee)} SUI`.padEnd(12);
|
|
1629
1691
|
printLine(` ${s.name}`);
|
|
1630
|
-
printLine(` ${
|
|
1631
|
-
printLine(` ${
|
|
1692
|
+
printLine(` ${pc11.dim(`Pool: ${pool}Fee: ${fee}Attacks: ${s.totalAttacks}`)}`);
|
|
1693
|
+
printLine(` ${pc11.dim(s.objectId)}`);
|
|
1632
1694
|
printBlank();
|
|
1633
1695
|
});
|
|
1634
1696
|
printBlank();
|
|
@@ -1663,7 +1725,7 @@ function registerSentinel(program2) {
|
|
|
1663
1725
|
if (s.systemPrompt) {
|
|
1664
1726
|
printBlank();
|
|
1665
1727
|
printKeyValue("System Prompt", "");
|
|
1666
|
-
printLine(` ${
|
|
1728
|
+
printLine(` ${pc11.dim(s.systemPrompt.slice(0, 500))}`);
|
|
1667
1729
|
}
|
|
1668
1730
|
printBlank();
|
|
1669
1731
|
} catch (error) {
|
|
@@ -1689,7 +1751,7 @@ function registerSentinel(program2) {
|
|
|
1689
1751
|
return;
|
|
1690
1752
|
}
|
|
1691
1753
|
printBlank();
|
|
1692
|
-
printLine(` ${
|
|
1754
|
+
printLine(` ${pc11.dim("\u23F3")} Requesting attack...`);
|
|
1693
1755
|
const result = await agent.sentinelAttack(id, prompt, feeMist);
|
|
1694
1756
|
printBlank();
|
|
1695
1757
|
if (result.won) {
|
|
@@ -1716,7 +1778,7 @@ function registerSentinel(program2) {
|
|
|
1716
1778
|
|
|
1717
1779
|
// src/commands/earn.ts
|
|
1718
1780
|
import { T2000 as T200021, MIST_PER_SUI as MIST_PER_SUI2, listSentinels, formatUsd as formatUsd12 } from "@t2000/sdk";
|
|
1719
|
-
import
|
|
1781
|
+
import pc12 from "picocolors";
|
|
1720
1782
|
function mistToSui(mist) {
|
|
1721
1783
|
return Number(mist) / Number(MIST_PER_SUI2);
|
|
1722
1784
|
}
|
|
@@ -1788,7 +1850,7 @@ function registerEarn(program2) {
|
|
|
1788
1850
|
return;
|
|
1789
1851
|
}
|
|
1790
1852
|
printHeader("Earning Opportunities");
|
|
1791
|
-
printLine(
|
|
1853
|
+
printLine(pc12.bold("SAVINGS") + pc12.dim(" \u2014 Passive Yield"));
|
|
1792
1854
|
printDivider();
|
|
1793
1855
|
if (savePositions.length > 0) {
|
|
1794
1856
|
for (const pos of savePositions) {
|
|
@@ -1797,7 +1859,7 @@ function registerEarn(program2) {
|
|
|
1797
1859
|
if (dailyYield > 1e-4) {
|
|
1798
1860
|
const dailyStr = dailyYield < 0.01 ? `$${dailyYield.toFixed(4)}` : formatUsd12(dailyYield);
|
|
1799
1861
|
const monthlyStr = dailyYield * 30 < 0.01 ? `$${(dailyYield * 30).toFixed(4)}` : formatUsd12(dailyYield * 30);
|
|
1800
|
-
printLine(
|
|
1862
|
+
printLine(pc12.dim(` ~${dailyStr}/day \xB7 ~${monthlyStr}/month`));
|
|
1801
1863
|
}
|
|
1802
1864
|
}
|
|
1803
1865
|
if (savePositions.length > 1) {
|
|
@@ -1812,7 +1874,7 @@ function registerEarn(program2) {
|
|
|
1812
1874
|
const example = 100;
|
|
1813
1875
|
const daily = example * bestSaveApy / 100 / 365;
|
|
1814
1876
|
const monthly = daily * 30;
|
|
1815
|
-
printLine(
|
|
1877
|
+
printLine(pc12.dim(` Save $${example} \u2192 ~$${daily.toFixed(2)}/day \xB7 ~$${monthly.toFixed(2)}/month`));
|
|
1816
1878
|
printBlank();
|
|
1817
1879
|
printInfo("No savings yet \u2014 run `t2000 save <amount>` to start");
|
|
1818
1880
|
} else if (posData) {
|
|
@@ -1822,7 +1884,7 @@ function registerEarn(program2) {
|
|
|
1822
1884
|
}
|
|
1823
1885
|
if (earningInvestments.length > 0) {
|
|
1824
1886
|
printBlank();
|
|
1825
|
-
printLine(
|
|
1887
|
+
printLine(pc12.bold("INVESTMENTS") + pc12.dim(" \u2014 Earning Yield"));
|
|
1826
1888
|
printDivider();
|
|
1827
1889
|
let totalInvestValue = 0;
|
|
1828
1890
|
for (const pos of earningInvestments) {
|
|
@@ -1835,7 +1897,7 @@ function registerEarn(program2) {
|
|
|
1835
1897
|
if (dailyYield > 1e-4) {
|
|
1836
1898
|
const dailyStr = dailyYield < 0.01 ? `$${dailyYield.toFixed(4)}` : formatUsd12(dailyYield);
|
|
1837
1899
|
const monthlyStr = dailyYield * 30 < 0.01 ? `$${(dailyYield * 30).toFixed(4)}` : formatUsd12(dailyYield * 30);
|
|
1838
|
-
printLine(
|
|
1900
|
+
printLine(pc12.dim(` ~${dailyStr}/day \xB7 ~${monthlyStr}/month`));
|
|
1839
1901
|
}
|
|
1840
1902
|
totalInvestValue += pos.currentValue;
|
|
1841
1903
|
}
|
|
@@ -1845,7 +1907,7 @@ function registerEarn(program2) {
|
|
|
1845
1907
|
}
|
|
1846
1908
|
}
|
|
1847
1909
|
printBlank();
|
|
1848
|
-
printLine(
|
|
1910
|
+
printLine(pc12.bold("SENTINEL BOUNTIES") + pc12.dim(" \u2014 Active Red Teaming"));
|
|
1849
1911
|
printDivider();
|
|
1850
1912
|
if (agents && agents.length > 0) {
|
|
1851
1913
|
const totalPool = agents.reduce((sum, s) => sum + mistToSui(s.prizePool), 0);
|
|
@@ -1864,12 +1926,12 @@ function registerEarn(program2) {
|
|
|
1864
1926
|
printInfo("Sentinel data unavailable");
|
|
1865
1927
|
}
|
|
1866
1928
|
printBlank();
|
|
1867
|
-
printLine(
|
|
1929
|
+
printLine(pc12.bold("Quick Actions"));
|
|
1868
1930
|
printDivider();
|
|
1869
|
-
printLine(` ${
|
|
1870
|
-
printLine(` ${
|
|
1871
|
-
printLine(` ${
|
|
1872
|
-
printLine(` ${
|
|
1931
|
+
printLine(` ${pc12.dim("t2000 save <amount> [asset]")} Save stablecoins for yield`);
|
|
1932
|
+
printLine(` ${pc12.dim("t2000 invest earn <asset>")} Earn yield on investments`);
|
|
1933
|
+
printLine(` ${pc12.dim("t2000 sentinel list")} Browse sentinel bounties`);
|
|
1934
|
+
printLine(` ${pc12.dim("t2000 sentinel attack <id>")} Attack a sentinel`);
|
|
1873
1935
|
printBlank();
|
|
1874
1936
|
} catch (error) {
|
|
1875
1937
|
handleError(error);
|
|
@@ -1878,7 +1940,7 @@ function registerEarn(program2) {
|
|
|
1878
1940
|
}
|
|
1879
1941
|
|
|
1880
1942
|
// src/commands/rebalance.ts
|
|
1881
|
-
import
|
|
1943
|
+
import pc13 from "picocolors";
|
|
1882
1944
|
import { T2000 as T200022, formatUsd as formatUsd13, SUPPORTED_ASSETS as SUPPORTED_ASSETS2 } from "@t2000/sdk";
|
|
1883
1945
|
function registerRebalance(program2) {
|
|
1884
1946
|
program2.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) => {
|
|
@@ -1906,24 +1968,24 @@ function registerRebalance(program2) {
|
|
|
1906
1968
|
const diff = plan.newApy - plan.currentApy;
|
|
1907
1969
|
if (diff < minYieldDiff) {
|
|
1908
1970
|
printInfo(`Already optimized \u2014 ${plan.currentApy.toFixed(2)}% APY on ${plan.fromProtocol}`);
|
|
1909
|
-
printLine(
|
|
1910
|
-
printLine(
|
|
1971
|
+
printLine(pc13.dim(` Best available: ${plan.newApy.toFixed(2)}% (${displayAsset(plan.toAsset)} on ${plan.toProtocol})`));
|
|
1972
|
+
printLine(pc13.dim(` Difference: ${diff.toFixed(2)}% (below ${minYieldDiff}% threshold)`));
|
|
1911
1973
|
} else if (plan.breakEvenDays > maxBreakEven && plan.estimatedSwapCost > 0) {
|
|
1912
1974
|
printInfo(`Skipped \u2014 break-even of ${plan.breakEvenDays} days exceeds ${maxBreakEven}-day limit`);
|
|
1913
|
-
printLine(
|
|
1975
|
+
printLine(pc13.dim(` ${displayAsset(plan.fromAsset)} on ${plan.fromProtocol} (${plan.currentApy.toFixed(2)}%) \u2192 ${displayAsset(plan.toAsset)} on ${plan.toProtocol} (${plan.newApy.toFixed(2)}%)`));
|
|
1914
1976
|
} else {
|
|
1915
1977
|
printInfo("Already at the best rate. Nothing to rebalance.");
|
|
1916
1978
|
}
|
|
1917
1979
|
printBlank();
|
|
1918
1980
|
return;
|
|
1919
1981
|
}
|
|
1920
|
-
printLine(
|
|
1982
|
+
printLine(pc13.bold("Rebalance Plan"));
|
|
1921
1983
|
printDivider();
|
|
1922
1984
|
printKeyValue("From", `${displayAsset(plan.fromAsset)} on ${plan.fromProtocol} (${plan.currentApy.toFixed(2)}% APY)`);
|
|
1923
1985
|
printKeyValue("To", `${displayAsset(plan.toAsset)} on ${plan.toProtocol} (${plan.newApy.toFixed(2)}% APY)`);
|
|
1924
1986
|
printKeyValue("Amount", formatUsd13(plan.amount));
|
|
1925
1987
|
printBlank();
|
|
1926
|
-
printLine(
|
|
1988
|
+
printLine(pc13.bold("Economics"));
|
|
1927
1989
|
printDivider();
|
|
1928
1990
|
printKeyValue("APY Gain", `+${(plan.newApy - plan.currentApy).toFixed(2)}%`);
|
|
1929
1991
|
printKeyValue("Annual Gain", `${formatUsd13(plan.annualGain)}/year`);
|
|
@@ -1933,7 +1995,7 @@ function registerRebalance(program2) {
|
|
|
1933
1995
|
}
|
|
1934
1996
|
printBlank();
|
|
1935
1997
|
if (plan.steps.length > 0) {
|
|
1936
|
-
printLine(
|
|
1998
|
+
printLine(pc13.bold("Steps"));
|
|
1937
1999
|
printDivider();
|
|
1938
2000
|
for (let i = 0; i < plan.steps.length; i++) {
|
|
1939
2001
|
const step = plan.steps[i];
|
|
@@ -1949,8 +2011,8 @@ function registerRebalance(program2) {
|
|
|
1949
2011
|
printBlank();
|
|
1950
2012
|
}
|
|
1951
2013
|
if (opts.dryRun) {
|
|
1952
|
-
printLine(
|
|
1953
|
-
printLine(
|
|
2014
|
+
printLine(pc13.bold(pc13.yellow("DRY RUN \u2014 Preview only, no transactions executed")));
|
|
2015
|
+
printLine(pc13.dim(" Run `t2000 rebalance` to execute."));
|
|
1954
2016
|
printBlank();
|
|
1955
2017
|
return;
|
|
1956
2018
|
}
|
|
@@ -2063,7 +2125,7 @@ function registerMcp(program2) {
|
|
|
2063
2125
|
mcp.command("start", { isDefault: true }).description("Start MCP server (stdio transport)").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2064
2126
|
let mod;
|
|
2065
2127
|
try {
|
|
2066
|
-
mod = await import("./dist-
|
|
2128
|
+
mod = await import("./dist-NXFA54RO.js");
|
|
2067
2129
|
} catch {
|
|
2068
2130
|
console.error(
|
|
2069
2131
|
"MCP server not installed. Run:\n npm install -g @t2000/mcp"
|
|
@@ -2215,7 +2277,7 @@ function registerContacts(program2) {
|
|
|
2215
2277
|
}
|
|
2216
2278
|
|
|
2217
2279
|
// src/commands/invest.ts
|
|
2218
|
-
import
|
|
2280
|
+
import pc14 from "picocolors";
|
|
2219
2281
|
import { T2000 as T200024, formatUsd as formatUsd15, formatAssetAmount as formatAssetAmount4, INVESTMENT_ASSETS as INVESTMENT_ASSETS2 } from "@t2000/sdk";
|
|
2220
2282
|
function registerInvest(program2) {
|
|
2221
2283
|
const investCmd = program2.command("invest").description("Buy or sell investment assets");
|
|
@@ -2223,7 +2285,7 @@ function registerInvest(program2) {
|
|
|
2223
2285
|
try {
|
|
2224
2286
|
const parsed = parseFloat(amount);
|
|
2225
2287
|
if (isNaN(parsed) || parsed <= 0 || !isFinite(parsed)) {
|
|
2226
|
-
console.error(
|
|
2288
|
+
console.error(pc14.red(" \u2717 Amount must be greater than $0"));
|
|
2227
2289
|
process.exitCode = 1;
|
|
2228
2290
|
return;
|
|
2229
2291
|
}
|
|
@@ -2255,7 +2317,7 @@ function registerInvest(program2) {
|
|
|
2255
2317
|
if (!isAll) {
|
|
2256
2318
|
const parsed = parseFloat(amount);
|
|
2257
2319
|
if (isNaN(parsed) || parsed <= 0 || !isFinite(parsed)) {
|
|
2258
|
-
console.error(
|
|
2320
|
+
console.error(pc14.red(" \u2717 Amount must be greater than $0"));
|
|
2259
2321
|
process.exitCode = 1;
|
|
2260
2322
|
return;
|
|
2261
2323
|
}
|
|
@@ -2277,7 +2339,7 @@ function registerInvest(program2) {
|
|
|
2277
2339
|
printSuccess(`Sold ${formatAssetAmount4(result.amount, sym)} ${sym} at ${formatUsd15(result.price)}`);
|
|
2278
2340
|
printKeyValue("Proceeds", formatUsd15(result.usdValue));
|
|
2279
2341
|
if (result.realizedPnL !== void 0) {
|
|
2280
|
-
const pnlColor = result.realizedPnL >= 0 ?
|
|
2342
|
+
const pnlColor = result.realizedPnL >= 0 ? pc14.green : pc14.red;
|
|
2281
2343
|
const pnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
2282
2344
|
printKeyValue("Realized P&L", pnlColor(`${pnlSign}${formatUsd15(result.realizedPnL)}`));
|
|
2283
2345
|
}
|
|
@@ -2408,9 +2470,9 @@ function registerInvest(program2) {
|
|
|
2408
2470
|
printSeparator();
|
|
2409
2471
|
for (const [key, def] of Object.entries(all)) {
|
|
2410
2472
|
const allocs = Object.entries(def.allocations).map(([a, p]) => `${a} ${p}%`).join(", ");
|
|
2411
|
-
const tag = def.custom ?
|
|
2473
|
+
const tag = def.custom ? pc14.dim(" (custom)") : "";
|
|
2412
2474
|
printKeyValue(key, `${allocs}${tag}`);
|
|
2413
|
-
printLine(` ${
|
|
2475
|
+
printLine(` ${pc14.dim(def.description)}`);
|
|
2414
2476
|
}
|
|
2415
2477
|
printSeparator();
|
|
2416
2478
|
const hasPositions = Object.keys(all).some((k) => agent.portfolio.hasStrategyPositions(k));
|
|
@@ -2426,7 +2488,7 @@ function registerInvest(program2) {
|
|
|
2426
2488
|
try {
|
|
2427
2489
|
const parsed = parseFloat(amount);
|
|
2428
2490
|
if (isNaN(parsed) || parsed <= 0) {
|
|
2429
|
-
console.error(
|
|
2491
|
+
console.error(pc14.red(" \u2717 Amount must be greater than $0"));
|
|
2430
2492
|
process.exitCode = 1;
|
|
2431
2493
|
return;
|
|
2432
2494
|
}
|
|
@@ -2460,7 +2522,7 @@ function registerInvest(program2) {
|
|
|
2460
2522
|
printKeyValue("Tx", explorerUrl(txDigests[0]));
|
|
2461
2523
|
} else {
|
|
2462
2524
|
for (const buy of result.buys) {
|
|
2463
|
-
printLine(` ${
|
|
2525
|
+
printLine(` ${pc14.dim(`${buy.asset}: ${explorerUrl(buy.tx)}`)}`);
|
|
2464
2526
|
}
|
|
2465
2527
|
}
|
|
2466
2528
|
}
|
|
@@ -2482,18 +2544,18 @@ function registerInvest(program2) {
|
|
|
2482
2544
|
printSuccess(`Sold all ${name} strategy positions`);
|
|
2483
2545
|
printSeparator();
|
|
2484
2546
|
for (const sell of result.sells) {
|
|
2485
|
-
const pnlColor = sell.realizedPnL >= 0 ?
|
|
2547
|
+
const pnlColor = sell.realizedPnL >= 0 ? pc14.green : pc14.red;
|
|
2486
2548
|
const pnlSign = sell.realizedPnL >= 0 ? "+" : "";
|
|
2487
2549
|
printKeyValue(sell.asset, `${formatAssetAmount4(sell.amount, sell.asset)} \u2192 ${formatUsd15(sell.usdValue)} ${pnlColor(`${pnlSign}${formatUsd15(sell.realizedPnL)}`)}`);
|
|
2488
2550
|
}
|
|
2489
2551
|
if (result.failed && result.failed.length > 0) {
|
|
2490
2552
|
for (const f of result.failed) {
|
|
2491
|
-
console.error(
|
|
2553
|
+
console.error(pc14.yellow(` \u26A0 ${f.asset}: ${f.reason}`));
|
|
2492
2554
|
}
|
|
2493
2555
|
}
|
|
2494
2556
|
printSeparator();
|
|
2495
2557
|
printKeyValue("Total proceeds", formatUsd15(result.totalProceeds));
|
|
2496
|
-
const rpnlColor = result.realizedPnL >= 0 ?
|
|
2558
|
+
const rpnlColor = result.realizedPnL >= 0 ? pc14.green : pc14.red;
|
|
2497
2559
|
const rpnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
2498
2560
|
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd15(result.realizedPnL)}`));
|
|
2499
2561
|
printBlank();
|
|
@@ -2520,8 +2582,8 @@ function registerInvest(program2) {
|
|
|
2520
2582
|
const target = status.definition.allocations[pos.asset] ?? 0;
|
|
2521
2583
|
const actual = status.currentWeights[pos.asset] ?? 0;
|
|
2522
2584
|
const drift = actual - target;
|
|
2523
|
-
const driftColor = Math.abs(drift) > 3 ?
|
|
2524
|
-
const pnlColor = pos.unrealizedPnL >= 0 ?
|
|
2585
|
+
const driftColor = Math.abs(drift) > 3 ? pc14.yellow : pc14.dim;
|
|
2586
|
+
const pnlColor = pos.unrealizedPnL >= 0 ? pc14.green : pc14.red;
|
|
2525
2587
|
const pnlSign = pos.unrealizedPnL >= 0 ? "+" : "";
|
|
2526
2588
|
printKeyValue(
|
|
2527
2589
|
pos.asset,
|
|
@@ -2552,7 +2614,7 @@ function registerInvest(program2) {
|
|
|
2552
2614
|
printSuccess(`Rebalanced ${name} strategy`);
|
|
2553
2615
|
printSeparator();
|
|
2554
2616
|
for (const t of result.trades) {
|
|
2555
|
-
const action = t.action === "buy" ?
|
|
2617
|
+
const action = t.action === "buy" ? pc14.green("BUY") : pc14.red("SELL");
|
|
2556
2618
|
printKeyValue(t.asset, `${action} ${formatUsd15(t.usdAmount)} (${formatAssetAmount4(t.amount, t.asset)})`);
|
|
2557
2619
|
}
|
|
2558
2620
|
printSeparator();
|
|
@@ -2569,7 +2631,7 @@ function registerInvest(program2) {
|
|
|
2569
2631
|
for (const pair of opts.alloc) {
|
|
2570
2632
|
const [asset, pctStr] = pair.split(":");
|
|
2571
2633
|
if (!asset || !pctStr) {
|
|
2572
|
-
console.error(
|
|
2634
|
+
console.error(pc14.red(` \u2717 Invalid allocation: '${pair}'. Use ASSET:PCT format (e.g. SUI:60)`));
|
|
2573
2635
|
process.exitCode = 1;
|
|
2574
2636
|
return;
|
|
2575
2637
|
}
|
|
@@ -2596,7 +2658,7 @@ function registerInvest(program2) {
|
|
|
2596
2658
|
const pin = await resolvePin();
|
|
2597
2659
|
const agent = await T200024.create({ pin, keyPath: opts.key });
|
|
2598
2660
|
if (agent.portfolio.hasStrategyPositions(name.toLowerCase())) {
|
|
2599
|
-
console.error(
|
|
2661
|
+
console.error(pc14.red(` \u2717 Strategy '${name}' has open positions. Sell first: t2000 invest strategy sell ${name}`));
|
|
2600
2662
|
process.exitCode = 1;
|
|
2601
2663
|
return;
|
|
2602
2664
|
}
|
|
@@ -2617,12 +2679,12 @@ function registerInvest(program2) {
|
|
|
2617
2679
|
try {
|
|
2618
2680
|
const parsed = parseFloat(amount);
|
|
2619
2681
|
if (isNaN(parsed) || parsed < 1) {
|
|
2620
|
-
console.error(
|
|
2682
|
+
console.error(pc14.red(" \u2717 Amount must be at least $1"));
|
|
2621
2683
|
process.exitCode = 1;
|
|
2622
2684
|
return;
|
|
2623
2685
|
}
|
|
2624
2686
|
if (!["daily", "weekly", "monthly"].includes(frequency)) {
|
|
2625
|
-
console.error(
|
|
2687
|
+
console.error(pc14.red(" \u2717 Frequency must be daily, weekly, or monthly"));
|
|
2626
2688
|
process.exitCode = 1;
|
|
2627
2689
|
return;
|
|
2628
2690
|
}
|
|
@@ -2632,7 +2694,7 @@ function registerInvest(program2) {
|
|
|
2632
2694
|
const isStrategy = target ? target.toLowerCase() in allStrategies : false;
|
|
2633
2695
|
const isAsset = target ? target.toUpperCase() in INVESTMENT_ASSETS2 : false;
|
|
2634
2696
|
if (target && !isStrategy && !isAsset) {
|
|
2635
|
-
console.error(
|
|
2697
|
+
console.error(pc14.red(` \u2717 '${target}' is not a valid strategy or asset`));
|
|
2636
2698
|
process.exitCode = 1;
|
|
2637
2699
|
return;
|
|
2638
2700
|
}
|
|
@@ -2679,9 +2741,9 @@ function registerInvest(program2) {
|
|
|
2679
2741
|
printSeparator();
|
|
2680
2742
|
for (const s of status.schedules) {
|
|
2681
2743
|
const target = s.strategy ?? s.asset ?? "?";
|
|
2682
|
-
const statusTag = s.enabled ?
|
|
2744
|
+
const statusTag = s.enabled ? pc14.green("active") : pc14.dim("paused");
|
|
2683
2745
|
printKeyValue(s.id, `${formatUsd15(s.amount)} ${s.frequency} \u2192 ${target} ${statusTag}`);
|
|
2684
|
-
printLine(` ${
|
|
2746
|
+
printLine(` ${pc14.dim(`Next: ${new Date(s.nextRun).toLocaleDateString()} \xB7 Runs: ${s.runCount} \xB7 Total: ${formatUsd15(s.totalInvested)}`)}`);
|
|
2685
2747
|
}
|
|
2686
2748
|
printSeparator();
|
|
2687
2749
|
if (status.pendingRuns.length > 0) {
|
|
@@ -2724,7 +2786,7 @@ function registerInvest(program2) {
|
|
|
2724
2786
|
}
|
|
2725
2787
|
if (result.skipped.length > 0) {
|
|
2726
2788
|
for (const skip of result.skipped) {
|
|
2727
|
-
printLine(` ${
|
|
2789
|
+
printLine(` ${pc14.yellow("\u26A0")} Skipped ${skip.scheduleId}: ${skip.reason}`);
|
|
2728
2790
|
}
|
|
2729
2791
|
}
|
|
2730
2792
|
printBlank();
|
|
@@ -2751,22 +2813,22 @@ function registerInvest(program2) {
|
|
|
2751
2813
|
}
|
|
2752
2814
|
|
|
2753
2815
|
// src/commands/portfolio.ts
|
|
2754
|
-
import
|
|
2816
|
+
import pc15 from "picocolors";
|
|
2755
2817
|
import { T2000 as T200025, formatUsd as formatUsd16, formatAssetAmount as formatAssetAmount5 } from "@t2000/sdk";
|
|
2756
2818
|
function printPositionLine(pos, rewardKeys) {
|
|
2757
2819
|
if (pos.currentPrice === 0 && pos.totalAmount > 0) {
|
|
2758
2820
|
printKeyValue(
|
|
2759
2821
|
pos.asset,
|
|
2760
|
-
`${formatAssetAmount5(pos.totalAmount, pos.asset)} Avg: ${formatUsd16(pos.avgPrice)} Now: ${
|
|
2822
|
+
`${formatAssetAmount5(pos.totalAmount, pos.asset)} Avg: ${formatUsd16(pos.avgPrice)} Now: ${pc15.yellow("unavailable")}`
|
|
2761
2823
|
);
|
|
2762
2824
|
} else {
|
|
2763
|
-
const pnlColor = pos.unrealizedPnL >= 0 ?
|
|
2825
|
+
const pnlColor = pos.unrealizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2764
2826
|
const pnlSign = pos.unrealizedPnL >= 0 ? "+" : "";
|
|
2765
2827
|
let yieldSuffix = "";
|
|
2766
2828
|
if (pos.earning && pos.earningApy) {
|
|
2767
2829
|
const hasRewards = rewardKeys?.has(`${pos.earningProtocol}:${pos.asset}`);
|
|
2768
|
-
const rewardTag = hasRewards ? ` ${
|
|
2769
|
-
yieldSuffix = ` ${
|
|
2830
|
+
const rewardTag = hasRewards ? ` ${pc15.yellow("+rewards")}` : "";
|
|
2831
|
+
yieldSuffix = ` ${pc15.cyan(`${pos.earningApy.toFixed(1)}% APY (${pos.earningProtocol})`)}${rewardTag}`;
|
|
2770
2832
|
}
|
|
2771
2833
|
printKeyValue(
|
|
2772
2834
|
pos.asset,
|
|
@@ -2807,19 +2869,19 @@ function registerPortfolio(program2) {
|
|
|
2807
2869
|
stratLabel = def.name;
|
|
2808
2870
|
} catch {
|
|
2809
2871
|
}
|
|
2810
|
-
printLine(` ${
|
|
2872
|
+
printLine(` ${pc15.bold(pc15.cyan(`\u25B8 ${stratLabel}`))}`);
|
|
2811
2873
|
printSeparator();
|
|
2812
2874
|
for (const pos of positions) {
|
|
2813
2875
|
printPositionLine(pos, rewardKeys);
|
|
2814
2876
|
}
|
|
2815
2877
|
const stratValue = positions.reduce((s, p) => s + p.currentValue, 0);
|
|
2816
|
-
printLine(` ${
|
|
2878
|
+
printLine(` ${pc15.dim(`Subtotal: ${formatUsd16(stratValue)}`)}`);
|
|
2817
2879
|
printBlank();
|
|
2818
2880
|
}
|
|
2819
2881
|
}
|
|
2820
2882
|
if (hasDirectPositions) {
|
|
2821
2883
|
if (hasStrategyPositions) {
|
|
2822
|
-
printLine(` ${
|
|
2884
|
+
printLine(` ${pc15.bold(pc15.cyan("\u25B8 Direct"))}`);
|
|
2823
2885
|
}
|
|
2824
2886
|
printSeparator();
|
|
2825
2887
|
for (const pos of portfolio.positions) {
|
|
@@ -2827,21 +2889,21 @@ function registerPortfolio(program2) {
|
|
|
2827
2889
|
}
|
|
2828
2890
|
if (hasStrategyPositions) {
|
|
2829
2891
|
const directValue = portfolio.positions.reduce((s, p) => s + p.currentValue, 0);
|
|
2830
|
-
printLine(` ${
|
|
2892
|
+
printLine(` ${pc15.dim(`Subtotal: ${formatUsd16(directValue)}`)}`);
|
|
2831
2893
|
}
|
|
2832
2894
|
}
|
|
2833
2895
|
printSeparator();
|
|
2834
2896
|
const hasPriceUnavailable = portfolio.positions.some((p) => p.currentPrice === 0 && p.totalAmount > 0);
|
|
2835
2897
|
if (hasPriceUnavailable) {
|
|
2836
|
-
printInfo(
|
|
2898
|
+
printInfo(pc15.yellow("\u26A0 Price data unavailable for some assets. Values may be inaccurate."));
|
|
2837
2899
|
}
|
|
2838
2900
|
printKeyValue("Total invested", formatUsd16(portfolio.totalInvested));
|
|
2839
2901
|
printKeyValue("Current value", formatUsd16(portfolio.totalValue));
|
|
2840
|
-
const upnlColor = portfolio.unrealizedPnL >= 0 ?
|
|
2902
|
+
const upnlColor = portfolio.unrealizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2841
2903
|
const upnlSign = portfolio.unrealizedPnL >= 0 ? "+" : "";
|
|
2842
2904
|
printKeyValue("Unrealized P&L", upnlColor(`${upnlSign}${formatUsd16(portfolio.unrealizedPnL)} (${upnlSign}${portfolio.unrealizedPnLPct.toFixed(1)}%)`));
|
|
2843
2905
|
if (portfolio.realizedPnL !== 0) {
|
|
2844
|
-
const rpnlColor = portfolio.realizedPnL >= 0 ?
|
|
2906
|
+
const rpnlColor = portfolio.realizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2845
2907
|
const rpnlSign = portfolio.realizedPnL >= 0 ? "+" : "";
|
|
2846
2908
|
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd16(portfolio.realizedPnL)}`));
|
|
2847
2909
|
}
|
|
@@ -2853,7 +2915,7 @@ function registerPortfolio(program2) {
|
|
|
2853
2915
|
}
|
|
2854
2916
|
|
|
2855
2917
|
// src/commands/claimRewards.ts
|
|
2856
|
-
import
|
|
2918
|
+
import pc16 from "picocolors";
|
|
2857
2919
|
import { T2000 as T200026, formatUsd as formatUsd17 } from "@t2000/sdk";
|
|
2858
2920
|
function registerClaimRewards(program2) {
|
|
2859
2921
|
program2.command("claim-rewards").description("Claim pending protocol rewards").option("--key <path>", "Key file path").action(async (opts) => {
|
|
@@ -2867,20 +2929,20 @@ function registerClaimRewards(program2) {
|
|
|
2867
2929
|
}
|
|
2868
2930
|
printBlank();
|
|
2869
2931
|
if (result.rewards.length === 0) {
|
|
2870
|
-
printLine(` ${
|
|
2932
|
+
printLine(` ${pc16.dim("No rewards to claim")}`);
|
|
2871
2933
|
printBlank();
|
|
2872
2934
|
return;
|
|
2873
2935
|
}
|
|
2874
2936
|
const protocols = [...new Set(result.rewards.map((r) => r.protocol))];
|
|
2875
|
-
printLine(` ${
|
|
2937
|
+
printLine(` ${pc16.green("\u2713")} Claimed and converted rewards to USDC`);
|
|
2876
2938
|
printSeparator();
|
|
2877
2939
|
const received = result.usdcReceived;
|
|
2878
2940
|
if (received >= 0.01) {
|
|
2879
|
-
printKeyValue("Received", `${
|
|
2941
|
+
printKeyValue("Received", `${pc16.green(formatUsd17(received))} USDC`);
|
|
2880
2942
|
} else if (received > 0) {
|
|
2881
|
-
printKeyValue("Received", `${
|
|
2943
|
+
printKeyValue("Received", `${pc16.green("< $0.01")} USDC`);
|
|
2882
2944
|
} else {
|
|
2883
|
-
printKeyValue("Received", `${
|
|
2945
|
+
printKeyValue("Received", `${pc16.dim("< $0.01 USDC (rewards are still accruing)")}`);
|
|
2884
2946
|
}
|
|
2885
2947
|
printKeyValue("Source", protocols.join(", "));
|
|
2886
2948
|
if (result.tx) {
|