@t2000/cli 0.22.4 → 0.22.5
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,7 +497,27 @@ 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
|
+
split: "\u2702 split",
|
|
508
|
+
transaction: "\u{1F4E6} tx"
|
|
509
|
+
};
|
|
510
|
+
function relativeTime(ts) {
|
|
511
|
+
const diff = Date.now() - ts;
|
|
512
|
+
const mins = Math.floor(diff / 6e4);
|
|
513
|
+
if (mins < 1) return "just now";
|
|
514
|
+
if (mins < 60) return `${mins}m ago`;
|
|
515
|
+
const hours = Math.floor(mins / 60);
|
|
516
|
+
if (hours < 24) return `${hours}h ago`;
|
|
517
|
+
const days = Math.floor(hours / 24);
|
|
518
|
+
if (days < 7) return `${days}d ago`;
|
|
519
|
+
return new Date(ts).toLocaleDateString();
|
|
520
|
+
}
|
|
501
521
|
function registerHistory(program2) {
|
|
502
522
|
program2.command("history").description("Show transaction history").option("--limit <n>", "Number of transactions", "20").option("--key <path>", "Key file path").action(async (opts) => {
|
|
503
523
|
try {
|
|
@@ -513,11 +533,19 @@ function registerHistory(program2) {
|
|
|
513
533
|
printInfo("No transactions yet.");
|
|
514
534
|
} else {
|
|
515
535
|
for (const tx of txns) {
|
|
516
|
-
const
|
|
517
|
-
const
|
|
518
|
-
|
|
536
|
+
const label = ACTION_LABELS[tx.action] ?? `\u{1F4E6} ${tx.action}`;
|
|
537
|
+
const time = tx.timestamp ? relativeTime(tx.timestamp) : "";
|
|
538
|
+
const amount = tx.amount ? pc4.bold(`${tx.amount.toFixed(tx.amount < 0.01 ? 4 : 2)} ${tx.asset ?? ""}`) : "";
|
|
539
|
+
const recipient = tx.recipient ? pc4.dim(`\u2192 ${truncateAddress2(tx.recipient)}`) : "";
|
|
540
|
+
const link = pc4.dim(explorerUrl(tx.digest));
|
|
541
|
+
printLine(`${label} ${amount} ${recipient}`);
|
|
542
|
+
printLine(` ${pc4.dim(truncateAddress2(tx.digest))} ${pc4.dim(time)}`);
|
|
543
|
+
printLine(` ${link}`);
|
|
544
|
+
printBlank();
|
|
519
545
|
}
|
|
520
546
|
}
|
|
547
|
+
printDivider();
|
|
548
|
+
printInfo(`${txns.length} transaction${txns.length === 1 ? "" : "s"} shown`);
|
|
521
549
|
printBlank();
|
|
522
550
|
} catch (error) {
|
|
523
551
|
handleError(error);
|
|
@@ -629,7 +657,7 @@ function registerImport(program2) {
|
|
|
629
657
|
}
|
|
630
658
|
|
|
631
659
|
// src/commands/save.ts
|
|
632
|
-
import
|
|
660
|
+
import pc5 from "picocolors";
|
|
633
661
|
import { T2000 as T20009, formatUsd as formatUsd3 } from "@t2000/sdk";
|
|
634
662
|
function registerSave(program2) {
|
|
635
663
|
const action = async (amountStr, opts) => {
|
|
@@ -651,16 +679,16 @@ function registerSave(program2) {
|
|
|
651
679
|
}
|
|
652
680
|
printBlank();
|
|
653
681
|
if (gasManagerUsdc > 0) {
|
|
654
|
-
printSuccess(`Gas manager: ${
|
|
682
|
+
printSuccess(`Gas manager: ${pc5.yellow(formatUsd3(gasManagerUsdc))} USDC \u2192 SUI`);
|
|
655
683
|
}
|
|
656
684
|
const protocolName = opts.protocol ?? "best rate";
|
|
657
|
-
printSuccess(`Saved ${
|
|
685
|
+
printSuccess(`Saved ${pc5.yellow(formatUsd3(result.amount))} USDC to ${protocolName}`);
|
|
658
686
|
if (result.fee > 0) {
|
|
659
687
|
const feeRate = (result.fee / result.amount * 100).toFixed(1);
|
|
660
|
-
printSuccess(`Protocol fee: ${
|
|
688
|
+
printSuccess(`Protocol fee: ${pc5.dim(`${formatUsd3(result.fee)} USDC (${feeRate}%)`)}`);
|
|
661
689
|
}
|
|
662
|
-
printSuccess(`Current APY: ${
|
|
663
|
-
printSuccess(`Savings balance: ${
|
|
690
|
+
printSuccess(`Current APY: ${pc5.green(`${result.apy.toFixed(2)}%`)}`);
|
|
691
|
+
printSuccess(`Savings balance: ${pc5.yellow(formatUsd3(result.savingsBalance))} USDC`);
|
|
664
692
|
printKeyValue("Tx", explorerUrl(result.tx));
|
|
665
693
|
printBlank();
|
|
666
694
|
} catch (error) {
|
|
@@ -792,7 +820,7 @@ function registerHealth(program2) {
|
|
|
792
820
|
}
|
|
793
821
|
|
|
794
822
|
// src/commands/rates.ts
|
|
795
|
-
import
|
|
823
|
+
import pc6 from "picocolors";
|
|
796
824
|
import { T2000 as T200014, SUPPORTED_ASSETS, INVESTMENT_ASSETS, STABLE_ASSETS } from "@t2000/sdk";
|
|
797
825
|
var INVEST_ASSETS = Object.keys(INVESTMENT_ASSETS);
|
|
798
826
|
function registerRates(program2) {
|
|
@@ -809,14 +837,14 @@ function registerRates(program2) {
|
|
|
809
837
|
if (allRates.length > 0) {
|
|
810
838
|
const best = allRates.reduce((a, b) => b.rates.saveApy > a.rates.saveApy ? b : a);
|
|
811
839
|
const bestDisplay = SUPPORTED_ASSETS[best.asset]?.displayName ?? best.asset;
|
|
812
|
-
printLine(
|
|
840
|
+
printLine(pc6.bold(pc6.green(`Best yield: ${best.rates.saveApy.toFixed(2)}% APY`)) + pc6.dim(` (${bestDisplay} on ${best.protocol})`));
|
|
813
841
|
printBlank();
|
|
814
842
|
}
|
|
815
843
|
for (const asset of STABLE_ASSETS) {
|
|
816
844
|
const assetRates = allRates.filter((r) => r.asset === asset);
|
|
817
845
|
if (assetRates.length === 0) continue;
|
|
818
846
|
const display = SUPPORTED_ASSETS[asset]?.displayName ?? asset;
|
|
819
|
-
printLine(
|
|
847
|
+
printLine(pc6.bold(display));
|
|
820
848
|
printDivider();
|
|
821
849
|
for (const entry of assetRates) {
|
|
822
850
|
printKeyValue(entry.protocol, `Save ${entry.rates.saveApy.toFixed(2)}% Borrow ${entry.rates.borrowApy.toFixed(2)}%`);
|
|
@@ -825,7 +853,7 @@ function registerRates(program2) {
|
|
|
825
853
|
}
|
|
826
854
|
const investRates = allRates.filter((r) => INVEST_ASSETS.includes(r.asset));
|
|
827
855
|
if (investRates.length > 0) {
|
|
828
|
-
printLine(
|
|
856
|
+
printLine(pc6.bold("Investment Assets"));
|
|
829
857
|
printDivider();
|
|
830
858
|
for (const asset of INVEST_ASSETS) {
|
|
831
859
|
const assetRates = investRates.filter((r) => r.asset === asset);
|
|
@@ -848,7 +876,7 @@ function registerRates(program2) {
|
|
|
848
876
|
}
|
|
849
877
|
|
|
850
878
|
// src/commands/positions.ts
|
|
851
|
-
import
|
|
879
|
+
import pc7 from "picocolors";
|
|
852
880
|
import { T2000 as T200015, formatUsd as formatUsd8, formatAssetAmount } from "@t2000/sdk";
|
|
853
881
|
function registerPositions(program2) {
|
|
854
882
|
program2.command("positions").description("Show savings & borrow positions across all protocols and assets").option("--key <path>", "Key file path").action(async (opts) => {
|
|
@@ -877,10 +905,10 @@ function registerPositions(program2) {
|
|
|
877
905
|
const saves = result.positions.filter((p) => p.type === "save");
|
|
878
906
|
const borrows = result.positions.filter((p) => p.type === "borrow");
|
|
879
907
|
if (saves.length > 0) {
|
|
880
|
-
printLine(
|
|
908
|
+
printLine(pc7.bold("Savings"));
|
|
881
909
|
printDivider();
|
|
882
910
|
for (const pos of saves) {
|
|
883
|
-
const earning = rewardsByKey.has(`${pos.protocol}:${pos.asset}`) ? ` ${
|
|
911
|
+
const earning = rewardsByKey.has(`${pos.protocol}:${pos.asset}`) ? ` ${pc7.yellow("+rewards")}` : "";
|
|
884
912
|
const usd = formatUsd8(pos.amountUsd ?? pos.amount);
|
|
885
913
|
printKeyValue(pos.protocol, `${formatAssetAmount(pos.amount, pos.asset)} ${pos.asset} (${usd}) @ ${pos.apy.toFixed(2)}% APY${earning}`);
|
|
886
914
|
}
|
|
@@ -889,12 +917,12 @@ function registerPositions(program2) {
|
|
|
889
917
|
printKeyValue("Total", formatUsd8(totalSaved));
|
|
890
918
|
}
|
|
891
919
|
if (hasRewards) {
|
|
892
|
-
printLine(` ${
|
|
920
|
+
printLine(` ${pc7.dim("Run claim-rewards to collect and convert to USDC")}`);
|
|
893
921
|
}
|
|
894
922
|
printBlank();
|
|
895
923
|
}
|
|
896
924
|
if (borrows.length > 0) {
|
|
897
|
-
printLine(
|
|
925
|
+
printLine(pc7.bold("Borrows"));
|
|
898
926
|
printDivider();
|
|
899
927
|
for (const pos of borrows) {
|
|
900
928
|
const usd = formatUsd8(pos.amountUsd ?? pos.amount);
|
|
@@ -914,7 +942,7 @@ function registerPositions(program2) {
|
|
|
914
942
|
}
|
|
915
943
|
|
|
916
944
|
// src/commands/earnings.ts
|
|
917
|
-
import
|
|
945
|
+
import pc8 from "picocolors";
|
|
918
946
|
import { T2000 as T200016, formatUsd as formatUsd9, formatAssetAmount as formatAssetAmount2 } from "@t2000/sdk";
|
|
919
947
|
function registerEarnings(program2) {
|
|
920
948
|
program2.command("earnings").description("Show yield earned to date").option("--key <path>", "Key file path").action(async (opts) => {
|
|
@@ -932,7 +960,7 @@ function registerEarnings(program2) {
|
|
|
932
960
|
printKeyValue("Total Saved", formatUsd9(result.supplied));
|
|
933
961
|
if (savePositions.length > 0) {
|
|
934
962
|
for (const p of savePositions) {
|
|
935
|
-
printLine(` ${
|
|
963
|
+
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
964
|
}
|
|
937
965
|
}
|
|
938
966
|
printKeyValue("Blended APY", `${result.currentApy.toFixed(2)}%`);
|
|
@@ -946,7 +974,7 @@ function registerEarnings(program2) {
|
|
|
946
974
|
}
|
|
947
975
|
|
|
948
976
|
// src/commands/fundStatus.ts
|
|
949
|
-
import
|
|
977
|
+
import pc9 from "picocolors";
|
|
950
978
|
import { T2000 as T200017, formatUsd as formatUsd10, formatAssetAmount as formatAssetAmount3 } from "@t2000/sdk";
|
|
951
979
|
function registerFundStatus(program2) {
|
|
952
980
|
program2.command("fund-status").description("Full savings summary").option("--key <path>", "Key file path").action(async (opts) => {
|
|
@@ -970,7 +998,7 @@ function registerFundStatus(program2) {
|
|
|
970
998
|
printKeyValue("Total Saved", formatUsd10(result.supplied));
|
|
971
999
|
if (savePositions.length > 0) {
|
|
972
1000
|
for (const p of savePositions) {
|
|
973
|
-
printLine(` ${
|
|
1001
|
+
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
1002
|
}
|
|
975
1003
|
}
|
|
976
1004
|
printKeyValue("Blended APY", `${result.apy.toFixed(2)}%`);
|
|
@@ -1455,7 +1483,7 @@ function isRetryable(code) {
|
|
|
1455
1483
|
}
|
|
1456
1484
|
|
|
1457
1485
|
// src/commands/pay.ts
|
|
1458
|
-
import
|
|
1486
|
+
import pc10 from "picocolors";
|
|
1459
1487
|
import { T2000 as T200019 } from "@t2000/sdk";
|
|
1460
1488
|
function registerPay(program2) {
|
|
1461
1489
|
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 +1512,7 @@ function registerPay(program2) {
|
|
|
1484
1512
|
if (result.paid && result.receipt) {
|
|
1485
1513
|
printSuccess(`Paid via MPP (tx: ${result.receipt.reference.slice(0, 10)}...)`);
|
|
1486
1514
|
}
|
|
1487
|
-
printInfo(`\u2190 ${result.status} OK ${
|
|
1515
|
+
printInfo(`\u2190 ${result.status} OK ${pc10.dim(`[${elapsed}ms]`)}`);
|
|
1488
1516
|
}
|
|
1489
1517
|
if (isJsonMode()) {
|
|
1490
1518
|
printJson({
|
|
@@ -1597,7 +1625,7 @@ function registerLock(program2) {
|
|
|
1597
1625
|
|
|
1598
1626
|
// src/commands/sentinel.ts
|
|
1599
1627
|
import { T2000 as T200020, MIST_PER_SUI } from "@t2000/sdk";
|
|
1600
|
-
import
|
|
1628
|
+
import pc11 from "picocolors";
|
|
1601
1629
|
function formatSui(mist) {
|
|
1602
1630
|
return (Number(mist) / Number(MIST_PER_SUI)).toFixed(2);
|
|
1603
1631
|
}
|
|
@@ -1627,8 +1655,8 @@ function registerSentinel(program2) {
|
|
|
1627
1655
|
const pool = `${formatSui(s.prizePool)} SUI`.padEnd(12);
|
|
1628
1656
|
const fee = `${formatSui(s.attackFee)} SUI`.padEnd(12);
|
|
1629
1657
|
printLine(` ${s.name}`);
|
|
1630
|
-
printLine(` ${
|
|
1631
|
-
printLine(` ${
|
|
1658
|
+
printLine(` ${pc11.dim(`Pool: ${pool}Fee: ${fee}Attacks: ${s.totalAttacks}`)}`);
|
|
1659
|
+
printLine(` ${pc11.dim(s.objectId)}`);
|
|
1632
1660
|
printBlank();
|
|
1633
1661
|
});
|
|
1634
1662
|
printBlank();
|
|
@@ -1663,7 +1691,7 @@ function registerSentinel(program2) {
|
|
|
1663
1691
|
if (s.systemPrompt) {
|
|
1664
1692
|
printBlank();
|
|
1665
1693
|
printKeyValue("System Prompt", "");
|
|
1666
|
-
printLine(` ${
|
|
1694
|
+
printLine(` ${pc11.dim(s.systemPrompt.slice(0, 500))}`);
|
|
1667
1695
|
}
|
|
1668
1696
|
printBlank();
|
|
1669
1697
|
} catch (error) {
|
|
@@ -1689,7 +1717,7 @@ function registerSentinel(program2) {
|
|
|
1689
1717
|
return;
|
|
1690
1718
|
}
|
|
1691
1719
|
printBlank();
|
|
1692
|
-
printLine(` ${
|
|
1720
|
+
printLine(` ${pc11.dim("\u23F3")} Requesting attack...`);
|
|
1693
1721
|
const result = await agent.sentinelAttack(id, prompt, feeMist);
|
|
1694
1722
|
printBlank();
|
|
1695
1723
|
if (result.won) {
|
|
@@ -1716,7 +1744,7 @@ function registerSentinel(program2) {
|
|
|
1716
1744
|
|
|
1717
1745
|
// src/commands/earn.ts
|
|
1718
1746
|
import { T2000 as T200021, MIST_PER_SUI as MIST_PER_SUI2, listSentinels, formatUsd as formatUsd12 } from "@t2000/sdk";
|
|
1719
|
-
import
|
|
1747
|
+
import pc12 from "picocolors";
|
|
1720
1748
|
function mistToSui(mist) {
|
|
1721
1749
|
return Number(mist) / Number(MIST_PER_SUI2);
|
|
1722
1750
|
}
|
|
@@ -1788,7 +1816,7 @@ function registerEarn(program2) {
|
|
|
1788
1816
|
return;
|
|
1789
1817
|
}
|
|
1790
1818
|
printHeader("Earning Opportunities");
|
|
1791
|
-
printLine(
|
|
1819
|
+
printLine(pc12.bold("SAVINGS") + pc12.dim(" \u2014 Passive Yield"));
|
|
1792
1820
|
printDivider();
|
|
1793
1821
|
if (savePositions.length > 0) {
|
|
1794
1822
|
for (const pos of savePositions) {
|
|
@@ -1797,7 +1825,7 @@ function registerEarn(program2) {
|
|
|
1797
1825
|
if (dailyYield > 1e-4) {
|
|
1798
1826
|
const dailyStr = dailyYield < 0.01 ? `$${dailyYield.toFixed(4)}` : formatUsd12(dailyYield);
|
|
1799
1827
|
const monthlyStr = dailyYield * 30 < 0.01 ? `$${(dailyYield * 30).toFixed(4)}` : formatUsd12(dailyYield * 30);
|
|
1800
|
-
printLine(
|
|
1828
|
+
printLine(pc12.dim(` ~${dailyStr}/day \xB7 ~${monthlyStr}/month`));
|
|
1801
1829
|
}
|
|
1802
1830
|
}
|
|
1803
1831
|
if (savePositions.length > 1) {
|
|
@@ -1812,7 +1840,7 @@ function registerEarn(program2) {
|
|
|
1812
1840
|
const example = 100;
|
|
1813
1841
|
const daily = example * bestSaveApy / 100 / 365;
|
|
1814
1842
|
const monthly = daily * 30;
|
|
1815
|
-
printLine(
|
|
1843
|
+
printLine(pc12.dim(` Save $${example} \u2192 ~$${daily.toFixed(2)}/day \xB7 ~$${monthly.toFixed(2)}/month`));
|
|
1816
1844
|
printBlank();
|
|
1817
1845
|
printInfo("No savings yet \u2014 run `t2000 save <amount>` to start");
|
|
1818
1846
|
} else if (posData) {
|
|
@@ -1822,7 +1850,7 @@ function registerEarn(program2) {
|
|
|
1822
1850
|
}
|
|
1823
1851
|
if (earningInvestments.length > 0) {
|
|
1824
1852
|
printBlank();
|
|
1825
|
-
printLine(
|
|
1853
|
+
printLine(pc12.bold("INVESTMENTS") + pc12.dim(" \u2014 Earning Yield"));
|
|
1826
1854
|
printDivider();
|
|
1827
1855
|
let totalInvestValue = 0;
|
|
1828
1856
|
for (const pos of earningInvestments) {
|
|
@@ -1835,7 +1863,7 @@ function registerEarn(program2) {
|
|
|
1835
1863
|
if (dailyYield > 1e-4) {
|
|
1836
1864
|
const dailyStr = dailyYield < 0.01 ? `$${dailyYield.toFixed(4)}` : formatUsd12(dailyYield);
|
|
1837
1865
|
const monthlyStr = dailyYield * 30 < 0.01 ? `$${(dailyYield * 30).toFixed(4)}` : formatUsd12(dailyYield * 30);
|
|
1838
|
-
printLine(
|
|
1866
|
+
printLine(pc12.dim(` ~${dailyStr}/day \xB7 ~${monthlyStr}/month`));
|
|
1839
1867
|
}
|
|
1840
1868
|
totalInvestValue += pos.currentValue;
|
|
1841
1869
|
}
|
|
@@ -1845,7 +1873,7 @@ function registerEarn(program2) {
|
|
|
1845
1873
|
}
|
|
1846
1874
|
}
|
|
1847
1875
|
printBlank();
|
|
1848
|
-
printLine(
|
|
1876
|
+
printLine(pc12.bold("SENTINEL BOUNTIES") + pc12.dim(" \u2014 Active Red Teaming"));
|
|
1849
1877
|
printDivider();
|
|
1850
1878
|
if (agents && agents.length > 0) {
|
|
1851
1879
|
const totalPool = agents.reduce((sum, s) => sum + mistToSui(s.prizePool), 0);
|
|
@@ -1864,12 +1892,12 @@ function registerEarn(program2) {
|
|
|
1864
1892
|
printInfo("Sentinel data unavailable");
|
|
1865
1893
|
}
|
|
1866
1894
|
printBlank();
|
|
1867
|
-
printLine(
|
|
1895
|
+
printLine(pc12.bold("Quick Actions"));
|
|
1868
1896
|
printDivider();
|
|
1869
|
-
printLine(` ${
|
|
1870
|
-
printLine(` ${
|
|
1871
|
-
printLine(` ${
|
|
1872
|
-
printLine(` ${
|
|
1897
|
+
printLine(` ${pc12.dim("t2000 save <amount> [asset]")} Save stablecoins for yield`);
|
|
1898
|
+
printLine(` ${pc12.dim("t2000 invest earn <asset>")} Earn yield on investments`);
|
|
1899
|
+
printLine(` ${pc12.dim("t2000 sentinel list")} Browse sentinel bounties`);
|
|
1900
|
+
printLine(` ${pc12.dim("t2000 sentinel attack <id>")} Attack a sentinel`);
|
|
1873
1901
|
printBlank();
|
|
1874
1902
|
} catch (error) {
|
|
1875
1903
|
handleError(error);
|
|
@@ -1878,7 +1906,7 @@ function registerEarn(program2) {
|
|
|
1878
1906
|
}
|
|
1879
1907
|
|
|
1880
1908
|
// src/commands/rebalance.ts
|
|
1881
|
-
import
|
|
1909
|
+
import pc13 from "picocolors";
|
|
1882
1910
|
import { T2000 as T200022, formatUsd as formatUsd13, SUPPORTED_ASSETS as SUPPORTED_ASSETS2 } from "@t2000/sdk";
|
|
1883
1911
|
function registerRebalance(program2) {
|
|
1884
1912
|
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 +1934,24 @@ function registerRebalance(program2) {
|
|
|
1906
1934
|
const diff = plan.newApy - plan.currentApy;
|
|
1907
1935
|
if (diff < minYieldDiff) {
|
|
1908
1936
|
printInfo(`Already optimized \u2014 ${plan.currentApy.toFixed(2)}% APY on ${plan.fromProtocol}`);
|
|
1909
|
-
printLine(
|
|
1910
|
-
printLine(
|
|
1937
|
+
printLine(pc13.dim(` Best available: ${plan.newApy.toFixed(2)}% (${displayAsset(plan.toAsset)} on ${plan.toProtocol})`));
|
|
1938
|
+
printLine(pc13.dim(` Difference: ${diff.toFixed(2)}% (below ${minYieldDiff}% threshold)`));
|
|
1911
1939
|
} else if (plan.breakEvenDays > maxBreakEven && plan.estimatedSwapCost > 0) {
|
|
1912
1940
|
printInfo(`Skipped \u2014 break-even of ${plan.breakEvenDays} days exceeds ${maxBreakEven}-day limit`);
|
|
1913
|
-
printLine(
|
|
1941
|
+
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
1942
|
} else {
|
|
1915
1943
|
printInfo("Already at the best rate. Nothing to rebalance.");
|
|
1916
1944
|
}
|
|
1917
1945
|
printBlank();
|
|
1918
1946
|
return;
|
|
1919
1947
|
}
|
|
1920
|
-
printLine(
|
|
1948
|
+
printLine(pc13.bold("Rebalance Plan"));
|
|
1921
1949
|
printDivider();
|
|
1922
1950
|
printKeyValue("From", `${displayAsset(plan.fromAsset)} on ${plan.fromProtocol} (${plan.currentApy.toFixed(2)}% APY)`);
|
|
1923
1951
|
printKeyValue("To", `${displayAsset(plan.toAsset)} on ${plan.toProtocol} (${plan.newApy.toFixed(2)}% APY)`);
|
|
1924
1952
|
printKeyValue("Amount", formatUsd13(plan.amount));
|
|
1925
1953
|
printBlank();
|
|
1926
|
-
printLine(
|
|
1954
|
+
printLine(pc13.bold("Economics"));
|
|
1927
1955
|
printDivider();
|
|
1928
1956
|
printKeyValue("APY Gain", `+${(plan.newApy - plan.currentApy).toFixed(2)}%`);
|
|
1929
1957
|
printKeyValue("Annual Gain", `${formatUsd13(plan.annualGain)}/year`);
|
|
@@ -1933,7 +1961,7 @@ function registerRebalance(program2) {
|
|
|
1933
1961
|
}
|
|
1934
1962
|
printBlank();
|
|
1935
1963
|
if (plan.steps.length > 0) {
|
|
1936
|
-
printLine(
|
|
1964
|
+
printLine(pc13.bold("Steps"));
|
|
1937
1965
|
printDivider();
|
|
1938
1966
|
for (let i = 0; i < plan.steps.length; i++) {
|
|
1939
1967
|
const step = plan.steps[i];
|
|
@@ -1949,8 +1977,8 @@ function registerRebalance(program2) {
|
|
|
1949
1977
|
printBlank();
|
|
1950
1978
|
}
|
|
1951
1979
|
if (opts.dryRun) {
|
|
1952
|
-
printLine(
|
|
1953
|
-
printLine(
|
|
1980
|
+
printLine(pc13.bold(pc13.yellow("DRY RUN \u2014 Preview only, no transactions executed")));
|
|
1981
|
+
printLine(pc13.dim(" Run `t2000 rebalance` to execute."));
|
|
1954
1982
|
printBlank();
|
|
1955
1983
|
return;
|
|
1956
1984
|
}
|
|
@@ -2063,7 +2091,7 @@ function registerMcp(program2) {
|
|
|
2063
2091
|
mcp.command("start", { isDefault: true }).description("Start MCP server (stdio transport)").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2064
2092
|
let mod;
|
|
2065
2093
|
try {
|
|
2066
|
-
mod = await import("./dist-
|
|
2094
|
+
mod = await import("./dist-NXFA54RO.js");
|
|
2067
2095
|
} catch {
|
|
2068
2096
|
console.error(
|
|
2069
2097
|
"MCP server not installed. Run:\n npm install -g @t2000/mcp"
|
|
@@ -2215,7 +2243,7 @@ function registerContacts(program2) {
|
|
|
2215
2243
|
}
|
|
2216
2244
|
|
|
2217
2245
|
// src/commands/invest.ts
|
|
2218
|
-
import
|
|
2246
|
+
import pc14 from "picocolors";
|
|
2219
2247
|
import { T2000 as T200024, formatUsd as formatUsd15, formatAssetAmount as formatAssetAmount4, INVESTMENT_ASSETS as INVESTMENT_ASSETS2 } from "@t2000/sdk";
|
|
2220
2248
|
function registerInvest(program2) {
|
|
2221
2249
|
const investCmd = program2.command("invest").description("Buy or sell investment assets");
|
|
@@ -2223,7 +2251,7 @@ function registerInvest(program2) {
|
|
|
2223
2251
|
try {
|
|
2224
2252
|
const parsed = parseFloat(amount);
|
|
2225
2253
|
if (isNaN(parsed) || parsed <= 0 || !isFinite(parsed)) {
|
|
2226
|
-
console.error(
|
|
2254
|
+
console.error(pc14.red(" \u2717 Amount must be greater than $0"));
|
|
2227
2255
|
process.exitCode = 1;
|
|
2228
2256
|
return;
|
|
2229
2257
|
}
|
|
@@ -2255,7 +2283,7 @@ function registerInvest(program2) {
|
|
|
2255
2283
|
if (!isAll) {
|
|
2256
2284
|
const parsed = parseFloat(amount);
|
|
2257
2285
|
if (isNaN(parsed) || parsed <= 0 || !isFinite(parsed)) {
|
|
2258
|
-
console.error(
|
|
2286
|
+
console.error(pc14.red(" \u2717 Amount must be greater than $0"));
|
|
2259
2287
|
process.exitCode = 1;
|
|
2260
2288
|
return;
|
|
2261
2289
|
}
|
|
@@ -2277,7 +2305,7 @@ function registerInvest(program2) {
|
|
|
2277
2305
|
printSuccess(`Sold ${formatAssetAmount4(result.amount, sym)} ${sym} at ${formatUsd15(result.price)}`);
|
|
2278
2306
|
printKeyValue("Proceeds", formatUsd15(result.usdValue));
|
|
2279
2307
|
if (result.realizedPnL !== void 0) {
|
|
2280
|
-
const pnlColor = result.realizedPnL >= 0 ?
|
|
2308
|
+
const pnlColor = result.realizedPnL >= 0 ? pc14.green : pc14.red;
|
|
2281
2309
|
const pnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
2282
2310
|
printKeyValue("Realized P&L", pnlColor(`${pnlSign}${formatUsd15(result.realizedPnL)}`));
|
|
2283
2311
|
}
|
|
@@ -2408,9 +2436,9 @@ function registerInvest(program2) {
|
|
|
2408
2436
|
printSeparator();
|
|
2409
2437
|
for (const [key, def] of Object.entries(all)) {
|
|
2410
2438
|
const allocs = Object.entries(def.allocations).map(([a, p]) => `${a} ${p}%`).join(", ");
|
|
2411
|
-
const tag = def.custom ?
|
|
2439
|
+
const tag = def.custom ? pc14.dim(" (custom)") : "";
|
|
2412
2440
|
printKeyValue(key, `${allocs}${tag}`);
|
|
2413
|
-
printLine(` ${
|
|
2441
|
+
printLine(` ${pc14.dim(def.description)}`);
|
|
2414
2442
|
}
|
|
2415
2443
|
printSeparator();
|
|
2416
2444
|
const hasPositions = Object.keys(all).some((k) => agent.portfolio.hasStrategyPositions(k));
|
|
@@ -2426,7 +2454,7 @@ function registerInvest(program2) {
|
|
|
2426
2454
|
try {
|
|
2427
2455
|
const parsed = parseFloat(amount);
|
|
2428
2456
|
if (isNaN(parsed) || parsed <= 0) {
|
|
2429
|
-
console.error(
|
|
2457
|
+
console.error(pc14.red(" \u2717 Amount must be greater than $0"));
|
|
2430
2458
|
process.exitCode = 1;
|
|
2431
2459
|
return;
|
|
2432
2460
|
}
|
|
@@ -2460,7 +2488,7 @@ function registerInvest(program2) {
|
|
|
2460
2488
|
printKeyValue("Tx", explorerUrl(txDigests[0]));
|
|
2461
2489
|
} else {
|
|
2462
2490
|
for (const buy of result.buys) {
|
|
2463
|
-
printLine(` ${
|
|
2491
|
+
printLine(` ${pc14.dim(`${buy.asset}: ${explorerUrl(buy.tx)}`)}`);
|
|
2464
2492
|
}
|
|
2465
2493
|
}
|
|
2466
2494
|
}
|
|
@@ -2482,18 +2510,18 @@ function registerInvest(program2) {
|
|
|
2482
2510
|
printSuccess(`Sold all ${name} strategy positions`);
|
|
2483
2511
|
printSeparator();
|
|
2484
2512
|
for (const sell of result.sells) {
|
|
2485
|
-
const pnlColor = sell.realizedPnL >= 0 ?
|
|
2513
|
+
const pnlColor = sell.realizedPnL >= 0 ? pc14.green : pc14.red;
|
|
2486
2514
|
const pnlSign = sell.realizedPnL >= 0 ? "+" : "";
|
|
2487
2515
|
printKeyValue(sell.asset, `${formatAssetAmount4(sell.amount, sell.asset)} \u2192 ${formatUsd15(sell.usdValue)} ${pnlColor(`${pnlSign}${formatUsd15(sell.realizedPnL)}`)}`);
|
|
2488
2516
|
}
|
|
2489
2517
|
if (result.failed && result.failed.length > 0) {
|
|
2490
2518
|
for (const f of result.failed) {
|
|
2491
|
-
console.error(
|
|
2519
|
+
console.error(pc14.yellow(` \u26A0 ${f.asset}: ${f.reason}`));
|
|
2492
2520
|
}
|
|
2493
2521
|
}
|
|
2494
2522
|
printSeparator();
|
|
2495
2523
|
printKeyValue("Total proceeds", formatUsd15(result.totalProceeds));
|
|
2496
|
-
const rpnlColor = result.realizedPnL >= 0 ?
|
|
2524
|
+
const rpnlColor = result.realizedPnL >= 0 ? pc14.green : pc14.red;
|
|
2497
2525
|
const rpnlSign = result.realizedPnL >= 0 ? "+" : "";
|
|
2498
2526
|
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd15(result.realizedPnL)}`));
|
|
2499
2527
|
printBlank();
|
|
@@ -2520,8 +2548,8 @@ function registerInvest(program2) {
|
|
|
2520
2548
|
const target = status.definition.allocations[pos.asset] ?? 0;
|
|
2521
2549
|
const actual = status.currentWeights[pos.asset] ?? 0;
|
|
2522
2550
|
const drift = actual - target;
|
|
2523
|
-
const driftColor = Math.abs(drift) > 3 ?
|
|
2524
|
-
const pnlColor = pos.unrealizedPnL >= 0 ?
|
|
2551
|
+
const driftColor = Math.abs(drift) > 3 ? pc14.yellow : pc14.dim;
|
|
2552
|
+
const pnlColor = pos.unrealizedPnL >= 0 ? pc14.green : pc14.red;
|
|
2525
2553
|
const pnlSign = pos.unrealizedPnL >= 0 ? "+" : "";
|
|
2526
2554
|
printKeyValue(
|
|
2527
2555
|
pos.asset,
|
|
@@ -2552,7 +2580,7 @@ function registerInvest(program2) {
|
|
|
2552
2580
|
printSuccess(`Rebalanced ${name} strategy`);
|
|
2553
2581
|
printSeparator();
|
|
2554
2582
|
for (const t of result.trades) {
|
|
2555
|
-
const action = t.action === "buy" ?
|
|
2583
|
+
const action = t.action === "buy" ? pc14.green("BUY") : pc14.red("SELL");
|
|
2556
2584
|
printKeyValue(t.asset, `${action} ${formatUsd15(t.usdAmount)} (${formatAssetAmount4(t.amount, t.asset)})`);
|
|
2557
2585
|
}
|
|
2558
2586
|
printSeparator();
|
|
@@ -2569,7 +2597,7 @@ function registerInvest(program2) {
|
|
|
2569
2597
|
for (const pair of opts.alloc) {
|
|
2570
2598
|
const [asset, pctStr] = pair.split(":");
|
|
2571
2599
|
if (!asset || !pctStr) {
|
|
2572
|
-
console.error(
|
|
2600
|
+
console.error(pc14.red(` \u2717 Invalid allocation: '${pair}'. Use ASSET:PCT format (e.g. SUI:60)`));
|
|
2573
2601
|
process.exitCode = 1;
|
|
2574
2602
|
return;
|
|
2575
2603
|
}
|
|
@@ -2596,7 +2624,7 @@ function registerInvest(program2) {
|
|
|
2596
2624
|
const pin = await resolvePin();
|
|
2597
2625
|
const agent = await T200024.create({ pin, keyPath: opts.key });
|
|
2598
2626
|
if (agent.portfolio.hasStrategyPositions(name.toLowerCase())) {
|
|
2599
|
-
console.error(
|
|
2627
|
+
console.error(pc14.red(` \u2717 Strategy '${name}' has open positions. Sell first: t2000 invest strategy sell ${name}`));
|
|
2600
2628
|
process.exitCode = 1;
|
|
2601
2629
|
return;
|
|
2602
2630
|
}
|
|
@@ -2617,12 +2645,12 @@ function registerInvest(program2) {
|
|
|
2617
2645
|
try {
|
|
2618
2646
|
const parsed = parseFloat(amount);
|
|
2619
2647
|
if (isNaN(parsed) || parsed < 1) {
|
|
2620
|
-
console.error(
|
|
2648
|
+
console.error(pc14.red(" \u2717 Amount must be at least $1"));
|
|
2621
2649
|
process.exitCode = 1;
|
|
2622
2650
|
return;
|
|
2623
2651
|
}
|
|
2624
2652
|
if (!["daily", "weekly", "monthly"].includes(frequency)) {
|
|
2625
|
-
console.error(
|
|
2653
|
+
console.error(pc14.red(" \u2717 Frequency must be daily, weekly, or monthly"));
|
|
2626
2654
|
process.exitCode = 1;
|
|
2627
2655
|
return;
|
|
2628
2656
|
}
|
|
@@ -2632,7 +2660,7 @@ function registerInvest(program2) {
|
|
|
2632
2660
|
const isStrategy = target ? target.toLowerCase() in allStrategies : false;
|
|
2633
2661
|
const isAsset = target ? target.toUpperCase() in INVESTMENT_ASSETS2 : false;
|
|
2634
2662
|
if (target && !isStrategy && !isAsset) {
|
|
2635
|
-
console.error(
|
|
2663
|
+
console.error(pc14.red(` \u2717 '${target}' is not a valid strategy or asset`));
|
|
2636
2664
|
process.exitCode = 1;
|
|
2637
2665
|
return;
|
|
2638
2666
|
}
|
|
@@ -2679,9 +2707,9 @@ function registerInvest(program2) {
|
|
|
2679
2707
|
printSeparator();
|
|
2680
2708
|
for (const s of status.schedules) {
|
|
2681
2709
|
const target = s.strategy ?? s.asset ?? "?";
|
|
2682
|
-
const statusTag = s.enabled ?
|
|
2710
|
+
const statusTag = s.enabled ? pc14.green("active") : pc14.dim("paused");
|
|
2683
2711
|
printKeyValue(s.id, `${formatUsd15(s.amount)} ${s.frequency} \u2192 ${target} ${statusTag}`);
|
|
2684
|
-
printLine(` ${
|
|
2712
|
+
printLine(` ${pc14.dim(`Next: ${new Date(s.nextRun).toLocaleDateString()} \xB7 Runs: ${s.runCount} \xB7 Total: ${formatUsd15(s.totalInvested)}`)}`);
|
|
2685
2713
|
}
|
|
2686
2714
|
printSeparator();
|
|
2687
2715
|
if (status.pendingRuns.length > 0) {
|
|
@@ -2724,7 +2752,7 @@ function registerInvest(program2) {
|
|
|
2724
2752
|
}
|
|
2725
2753
|
if (result.skipped.length > 0) {
|
|
2726
2754
|
for (const skip of result.skipped) {
|
|
2727
|
-
printLine(` ${
|
|
2755
|
+
printLine(` ${pc14.yellow("\u26A0")} Skipped ${skip.scheduleId}: ${skip.reason}`);
|
|
2728
2756
|
}
|
|
2729
2757
|
}
|
|
2730
2758
|
printBlank();
|
|
@@ -2751,22 +2779,22 @@ function registerInvest(program2) {
|
|
|
2751
2779
|
}
|
|
2752
2780
|
|
|
2753
2781
|
// src/commands/portfolio.ts
|
|
2754
|
-
import
|
|
2782
|
+
import pc15 from "picocolors";
|
|
2755
2783
|
import { T2000 as T200025, formatUsd as formatUsd16, formatAssetAmount as formatAssetAmount5 } from "@t2000/sdk";
|
|
2756
2784
|
function printPositionLine(pos, rewardKeys) {
|
|
2757
2785
|
if (pos.currentPrice === 0 && pos.totalAmount > 0) {
|
|
2758
2786
|
printKeyValue(
|
|
2759
2787
|
pos.asset,
|
|
2760
|
-
`${formatAssetAmount5(pos.totalAmount, pos.asset)} Avg: ${formatUsd16(pos.avgPrice)} Now: ${
|
|
2788
|
+
`${formatAssetAmount5(pos.totalAmount, pos.asset)} Avg: ${formatUsd16(pos.avgPrice)} Now: ${pc15.yellow("unavailable")}`
|
|
2761
2789
|
);
|
|
2762
2790
|
} else {
|
|
2763
|
-
const pnlColor = pos.unrealizedPnL >= 0 ?
|
|
2791
|
+
const pnlColor = pos.unrealizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2764
2792
|
const pnlSign = pos.unrealizedPnL >= 0 ? "+" : "";
|
|
2765
2793
|
let yieldSuffix = "";
|
|
2766
2794
|
if (pos.earning && pos.earningApy) {
|
|
2767
2795
|
const hasRewards = rewardKeys?.has(`${pos.earningProtocol}:${pos.asset}`);
|
|
2768
|
-
const rewardTag = hasRewards ? ` ${
|
|
2769
|
-
yieldSuffix = ` ${
|
|
2796
|
+
const rewardTag = hasRewards ? ` ${pc15.yellow("+rewards")}` : "";
|
|
2797
|
+
yieldSuffix = ` ${pc15.cyan(`${pos.earningApy.toFixed(1)}% APY (${pos.earningProtocol})`)}${rewardTag}`;
|
|
2770
2798
|
}
|
|
2771
2799
|
printKeyValue(
|
|
2772
2800
|
pos.asset,
|
|
@@ -2807,19 +2835,19 @@ function registerPortfolio(program2) {
|
|
|
2807
2835
|
stratLabel = def.name;
|
|
2808
2836
|
} catch {
|
|
2809
2837
|
}
|
|
2810
|
-
printLine(` ${
|
|
2838
|
+
printLine(` ${pc15.bold(pc15.cyan(`\u25B8 ${stratLabel}`))}`);
|
|
2811
2839
|
printSeparator();
|
|
2812
2840
|
for (const pos of positions) {
|
|
2813
2841
|
printPositionLine(pos, rewardKeys);
|
|
2814
2842
|
}
|
|
2815
2843
|
const stratValue = positions.reduce((s, p) => s + p.currentValue, 0);
|
|
2816
|
-
printLine(` ${
|
|
2844
|
+
printLine(` ${pc15.dim(`Subtotal: ${formatUsd16(stratValue)}`)}`);
|
|
2817
2845
|
printBlank();
|
|
2818
2846
|
}
|
|
2819
2847
|
}
|
|
2820
2848
|
if (hasDirectPositions) {
|
|
2821
2849
|
if (hasStrategyPositions) {
|
|
2822
|
-
printLine(` ${
|
|
2850
|
+
printLine(` ${pc15.bold(pc15.cyan("\u25B8 Direct"))}`);
|
|
2823
2851
|
}
|
|
2824
2852
|
printSeparator();
|
|
2825
2853
|
for (const pos of portfolio.positions) {
|
|
@@ -2827,21 +2855,21 @@ function registerPortfolio(program2) {
|
|
|
2827
2855
|
}
|
|
2828
2856
|
if (hasStrategyPositions) {
|
|
2829
2857
|
const directValue = portfolio.positions.reduce((s, p) => s + p.currentValue, 0);
|
|
2830
|
-
printLine(` ${
|
|
2858
|
+
printLine(` ${pc15.dim(`Subtotal: ${formatUsd16(directValue)}`)}`);
|
|
2831
2859
|
}
|
|
2832
2860
|
}
|
|
2833
2861
|
printSeparator();
|
|
2834
2862
|
const hasPriceUnavailable = portfolio.positions.some((p) => p.currentPrice === 0 && p.totalAmount > 0);
|
|
2835
2863
|
if (hasPriceUnavailable) {
|
|
2836
|
-
printInfo(
|
|
2864
|
+
printInfo(pc15.yellow("\u26A0 Price data unavailable for some assets. Values may be inaccurate."));
|
|
2837
2865
|
}
|
|
2838
2866
|
printKeyValue("Total invested", formatUsd16(portfolio.totalInvested));
|
|
2839
2867
|
printKeyValue("Current value", formatUsd16(portfolio.totalValue));
|
|
2840
|
-
const upnlColor = portfolio.unrealizedPnL >= 0 ?
|
|
2868
|
+
const upnlColor = portfolio.unrealizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2841
2869
|
const upnlSign = portfolio.unrealizedPnL >= 0 ? "+" : "";
|
|
2842
2870
|
printKeyValue("Unrealized P&L", upnlColor(`${upnlSign}${formatUsd16(portfolio.unrealizedPnL)} (${upnlSign}${portfolio.unrealizedPnLPct.toFixed(1)}%)`));
|
|
2843
2871
|
if (portfolio.realizedPnL !== 0) {
|
|
2844
|
-
const rpnlColor = portfolio.realizedPnL >= 0 ?
|
|
2872
|
+
const rpnlColor = portfolio.realizedPnL >= 0 ? pc15.green : pc15.red;
|
|
2845
2873
|
const rpnlSign = portfolio.realizedPnL >= 0 ? "+" : "";
|
|
2846
2874
|
printKeyValue("Realized P&L", rpnlColor(`${rpnlSign}${formatUsd16(portfolio.realizedPnL)}`));
|
|
2847
2875
|
}
|
|
@@ -2853,7 +2881,7 @@ function registerPortfolio(program2) {
|
|
|
2853
2881
|
}
|
|
2854
2882
|
|
|
2855
2883
|
// src/commands/claimRewards.ts
|
|
2856
|
-
import
|
|
2884
|
+
import pc16 from "picocolors";
|
|
2857
2885
|
import { T2000 as T200026, formatUsd as formatUsd17 } from "@t2000/sdk";
|
|
2858
2886
|
function registerClaimRewards(program2) {
|
|
2859
2887
|
program2.command("claim-rewards").description("Claim pending protocol rewards").option("--key <path>", "Key file path").action(async (opts) => {
|
|
@@ -2867,20 +2895,20 @@ function registerClaimRewards(program2) {
|
|
|
2867
2895
|
}
|
|
2868
2896
|
printBlank();
|
|
2869
2897
|
if (result.rewards.length === 0) {
|
|
2870
|
-
printLine(` ${
|
|
2898
|
+
printLine(` ${pc16.dim("No rewards to claim")}`);
|
|
2871
2899
|
printBlank();
|
|
2872
2900
|
return;
|
|
2873
2901
|
}
|
|
2874
2902
|
const protocols = [...new Set(result.rewards.map((r) => r.protocol))];
|
|
2875
|
-
printLine(` ${
|
|
2903
|
+
printLine(` ${pc16.green("\u2713")} Claimed and converted rewards to USDC`);
|
|
2876
2904
|
printSeparator();
|
|
2877
2905
|
const received = result.usdcReceived;
|
|
2878
2906
|
if (received >= 0.01) {
|
|
2879
|
-
printKeyValue("Received", `${
|
|
2907
|
+
printKeyValue("Received", `${pc16.green(formatUsd17(received))} USDC`);
|
|
2880
2908
|
} else if (received > 0) {
|
|
2881
|
-
printKeyValue("Received", `${
|
|
2909
|
+
printKeyValue("Received", `${pc16.green("< $0.01")} USDC`);
|
|
2882
2910
|
} else {
|
|
2883
|
-
printKeyValue("Received", `${
|
|
2911
|
+
printKeyValue("Received", `${pc16.dim("< $0.01 USDC (rewards are still accruing)")}`);
|
|
2884
2912
|
}
|
|
2885
2913
|
printKeyValue("Source", protocols.join(", "));
|
|
2886
2914
|
if (result.tx) {
|