@t2000/engine 0.7.1 → 0.7.3

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.d.ts CHANGED
@@ -823,6 +823,7 @@ declare const transactionHistoryTool: Tool<{
823
823
 
824
824
  declare const saveDepositTool: Tool<{
825
825
  amount: number;
826
+ asset?: string | undefined;
826
827
  }, {
827
828
  success: boolean;
828
829
  tx: string;
@@ -861,6 +862,7 @@ declare const sendTransferTool: Tool<{
861
862
 
862
863
  declare const borrowTool: Tool<{
863
864
  amount: number;
865
+ asset?: string | undefined;
864
866
  }, {
865
867
  success: boolean;
866
868
  tx: string;
package/dist/index.js CHANGED
@@ -701,9 +701,10 @@ async function fetchProtocolStats(manager, opts) {
701
701
  }
702
702
 
703
703
  // src/tools/savings.ts
704
+ var DUST_THRESHOLD_USD = 0.01;
704
705
  function buildSavingsFromPositions(sp) {
705
706
  const positions = [
706
- ...sp.supplies.map((s) => ({
707
+ ...sp.supplies.filter((s) => s.amountUsd >= DUST_THRESHOLD_USD).map((s) => ({
707
708
  protocol: s.protocol,
708
709
  type: "supply",
709
710
  symbol: s.asset,
@@ -712,7 +713,7 @@ function buildSavingsFromPositions(sp) {
712
713
  apy: s.apy,
713
714
  liquidationThreshold: 0
714
715
  })),
715
- ...sp.borrows_detail.map((b) => ({
716
+ ...sp.borrows_detail.filter((b) => b.amountUsd >= DUST_THRESHOLD_USD).map((b) => ({
716
717
  protocol: b.protocol,
717
718
  type: "borrow",
718
719
  symbol: b.asset,
@@ -742,6 +743,27 @@ function buildSavingsFromPositions(sp) {
742
743
  }
743
744
  };
744
745
  }
746
+ function formatSavingsDisplay(result) {
747
+ const { positions, earnings, fundStatus } = result;
748
+ const supplies = positions.filter((p) => p.type === "supply");
749
+ const borrows = positions.filter((p) => p.type === "borrow");
750
+ const lines = [];
751
+ if (supplies.length > 0) {
752
+ lines.push(`Savings: $${fundStatus.supplied.toFixed(2)} at ${(earnings.currentApy * 100).toFixed(2)}% blended APY`);
753
+ for (const s of supplies) {
754
+ lines.push(` ${s.symbol}: ${s.amount.toFixed(s.amount < 1 ? 6 : 2)} ($${s.valueUsd.toFixed(2)}) at ${(s.apy * 100).toFixed(2)}% APY`);
755
+ }
756
+ } else {
757
+ lines.push("No savings positions.");
758
+ }
759
+ if (borrows.length > 0) {
760
+ const totalDebt = borrows.reduce((s, b) => s + b.valueUsd, 0);
761
+ lines.push(`Debt: $${totalDebt.toFixed(2)}`);
762
+ }
763
+ lines.push(`Daily earnings: $${fundStatus.earnedToday.toFixed(4)}`);
764
+ lines.push(`Monthly projected: $${fundStatus.projectedMonthly.toFixed(4)}`);
765
+ return lines.join("\n");
766
+ }
745
767
  var savingsInfoTool = buildTool({
746
768
  name: "savings_info",
747
769
  description: "Get detailed savings positions and earnings: current deposits by protocol, APY, total yield earned, daily earning rate, and projected monthly returns.",
@@ -751,14 +773,16 @@ var savingsInfoTool = buildTool({
751
773
  async call(_input, context) {
752
774
  if (context.positionFetcher && context.walletAddress) {
753
775
  const sp = await context.positionFetcher(context.walletAddress);
754
- return { data: buildSavingsFromPositions(sp) };
776
+ const result2 = buildSavingsFromPositions(sp);
777
+ return { data: result2, displayText: formatSavingsDisplay(result2) };
755
778
  }
756
779
  if (hasNaviMcp(context)) {
757
780
  const savings = await fetchSavings(
758
781
  getMcpManager(context),
759
782
  getWalletAddress(context)
760
783
  );
761
- return { data: savings };
784
+ savings.positions = savings.positions.filter((p) => p.valueUsd >= DUST_THRESHOLD_USD);
785
+ return { data: savings, displayText: formatSavingsDisplay(savings) };
762
786
  }
763
787
  const agent = requireAgent(context);
764
788
  const [posResult, earnings, fundStatus] = await Promise.all([
@@ -774,25 +798,24 @@ var savingsInfoTool = buildTool({
774
798
  valueUsd: p.amountUsd ?? p.valueUsd ?? 0,
775
799
  apy: p.apy ?? 0,
776
800
  liquidationThreshold: p.liquidationThreshold ?? 0
777
- }));
778
- return {
779
- data: {
780
- positions,
781
- earnings: {
782
- totalYieldEarned: earnings.totalYieldEarned,
783
- currentApy: earnings.currentApy,
784
- dailyEarning: earnings.dailyEarning,
785
- supplied: earnings.supplied
786
- },
787
- fundStatus: {
788
- supplied: fundStatus.supplied,
789
- apy: fundStatus.apy,
790
- earnedToday: fundStatus.earnedToday,
791
- earnedAllTime: fundStatus.earnedAllTime,
792
- projectedMonthly: fundStatus.projectedMonthly
793
- }
801
+ })).filter((p) => p.valueUsd >= DUST_THRESHOLD_USD);
802
+ const result = {
803
+ positions,
804
+ earnings: {
805
+ totalYieldEarned: earnings.totalYieldEarned,
806
+ currentApy: earnings.currentApy,
807
+ dailyEarning: earnings.dailyEarning,
808
+ supplied: earnings.supplied
809
+ },
810
+ fundStatus: {
811
+ supplied: fundStatus.supplied,
812
+ apy: fundStatus.apy,
813
+ earnedToday: fundStatus.earnedToday,
814
+ earnedAllTime: fundStatus.earnedAllTime,
815
+ projectedMonthly: fundStatus.projectedMonthly
794
816
  }
795
817
  };
818
+ return { data: result, displayText: formatSavingsDisplay(result) };
796
819
  }
797
820
  });
798
821
  function hfStatus(hf) {
@@ -1020,15 +1043,20 @@ var transactionHistoryTool = buildTool({
1020
1043
  });
1021
1044
  var saveDepositTool = buildTool({
1022
1045
  name: "save_deposit",
1023
- description: "Deposit USDC into NAVI lending to earn yield. Amount is in USDC.",
1046
+ description: "Deposit USDC into NAVI savings to earn yield. ONLY USDC is accepted \u2014 if the user asks to save any other token (USDT, SUI, USDe, etc.), do NOT call this tool. Instead tell them to swap to USDC first, then deposit.",
1024
1047
  inputSchema: z.object({
1025
- amount: z.number().positive()
1048
+ amount: z.number().positive(),
1049
+ asset: z.string().optional().describe("Must be USDC or omitted. Any other asset is rejected.")
1026
1050
  }),
1027
1051
  jsonSchema: {
1028
1052
  type: "object",
1029
1053
  properties: {
1030
1054
  amount: {
1031
1055
  description: "Exact amount of USDC to deposit"
1056
+ },
1057
+ asset: {
1058
+ type: "string",
1059
+ description: "Must be USDC or omitted. Any other asset is rejected."
1032
1060
  }
1033
1061
  },
1034
1062
  required: ["amount"]
@@ -1036,6 +1064,9 @@ var saveDepositTool = buildTool({
1036
1064
  isReadOnly: false,
1037
1065
  permissionLevel: "confirm",
1038
1066
  async call(input, context) {
1067
+ if (input.asset && input.asset.toUpperCase() !== "USDC") {
1068
+ throw new Error(`Only USDC deposits are supported. Cannot deposit ${input.asset}. Swap to USDC first, then deposit.`);
1069
+ }
1039
1070
  const agent = requireAgent(context);
1040
1071
  const result = await agent.save({ amount: input.amount });
1041
1072
  return {
@@ -1137,16 +1168,21 @@ var sendTransferTool = buildTool({
1137
1168
  });
1138
1169
  var borrowTool = buildTool({
1139
1170
  name: "borrow",
1140
- description: "Borrow USDC against savings collateral. Requires existing savings deposits. Checks max safe borrow and health factor. Returns tx hash, fee, and post-borrow health factor.",
1171
+ description: "Borrow USDC against savings collateral. ONLY USDC borrows are supported. Requires existing savings deposits. Checks max safe borrow and health factor. Returns tx hash, fee, and post-borrow health factor.",
1141
1172
  inputSchema: z.object({
1142
- amount: z.number().positive()
1173
+ amount: z.number().positive(),
1174
+ asset: z.string().optional().describe("Must be USDC or omitted. Any other asset is rejected.")
1143
1175
  }),
1144
1176
  jsonSchema: {
1145
1177
  type: "object",
1146
1178
  properties: {
1147
1179
  amount: {
1148
1180
  type: "number",
1149
- description: "Amount in USD to borrow"
1181
+ description: "Amount in USDC to borrow"
1182
+ },
1183
+ asset: {
1184
+ type: "string",
1185
+ description: "Must be USDC or omitted. Any other asset is rejected."
1150
1186
  }
1151
1187
  },
1152
1188
  required: ["amount"]
@@ -1154,6 +1190,9 @@ var borrowTool = buildTool({
1154
1190
  isReadOnly: false,
1155
1191
  permissionLevel: "confirm",
1156
1192
  async call(input, context) {
1193
+ if (input.asset && input.asset.toUpperCase() !== "USDC") {
1194
+ throw new Error(`Only USDC borrows are supported. Cannot borrow ${input.asset}.`);
1195
+ }
1157
1196
  const agent = requireAgent(context);
1158
1197
  const result = await agent.borrow({ amount: input.amount });
1159
1198
  return {
@@ -1729,18 +1768,20 @@ var portfolioAnalysisTool = buildTool({
1729
1768
  throw new Error("No wallet address provided. Sign in first.");
1730
1769
  }
1731
1770
  const rpcUrl = context.suiRpcUrl ?? "https://fullnode.mainnet.sui.io:443";
1771
+ const DUST_USD = 0.01;
1732
1772
  const coins = await fetchWalletCoins(address, rpcUrl);
1733
1773
  const nonZero = coins.filter((c) => Number(c.totalBalance) > 0);
1734
1774
  const prices = await fetchTokenPrices(nonZero.map((c) => c.coinType)).catch(() => ({}));
1735
1775
  let walletValue = 0;
1736
- const allocations = [];
1776
+ const allAllocations = [];
1737
1777
  for (const coin of nonZero) {
1738
1778
  const amount = Number(coin.totalBalance) / 10 ** coin.decimals;
1739
1779
  const price = prices[coin.coinType] ?? 0;
1740
1780
  const usdValue = amount * price;
1741
1781
  walletValue += usdValue;
1742
- allocations.push({ symbol: coin.symbol, amount, usdValue, percentage: 0 });
1782
+ allAllocations.push({ symbol: coin.symbol, amount, usdValue, percentage: 0 });
1743
1783
  }
1784
+ const allocations = allAllocations.filter((a) => a.usdValue >= DUST_USD);
1744
1785
  let savingsValue = 0;
1745
1786
  let debtValue = 0;
1746
1787
  let healthFactor = null;