@t2000/sdk 0.19.20 → 0.19.21

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.
@@ -544,6 +544,7 @@ interface LendingAdapter {
544
544
  }): Promise<AdapterTxResult>;
545
545
  buildRepayTx(address: string, amount: number, asset: string, options?: {
546
546
  sponsored?: boolean;
547
+ skipOracle?: boolean;
547
548
  }): Promise<AdapterTxResult>;
548
549
  maxWithdraw(address: string, asset: string): Promise<{
549
550
  maxAmount: number;
@@ -692,6 +693,7 @@ declare class NaviAdapter implements LendingAdapter {
692
693
  }): Promise<AdapterTxResult>;
693
694
  buildRepayTx(address: string, amount: number, asset: string, options?: {
694
695
  sponsored?: boolean;
696
+ skipOracle?: boolean;
695
697
  }): Promise<AdapterTxResult>;
696
698
  maxWithdraw(address: string, _asset: string): Promise<MaxWithdrawResult>;
697
699
  maxBorrow(address: string, _asset: string): Promise<MaxBorrowResult>;
@@ -544,6 +544,7 @@ interface LendingAdapter {
544
544
  }): Promise<AdapterTxResult>;
545
545
  buildRepayTx(address: string, amount: number, asset: string, options?: {
546
546
  sponsored?: boolean;
547
+ skipOracle?: boolean;
547
548
  }): Promise<AdapterTxResult>;
548
549
  maxWithdraw(address: string, asset: string): Promise<{
549
550
  maxAmount: number;
@@ -692,6 +693,7 @@ declare class NaviAdapter implements LendingAdapter {
692
693
  }): Promise<AdapterTxResult>;
693
694
  buildRepayTx(address: string, amount: number, asset: string, options?: {
694
695
  sponsored?: boolean;
696
+ skipOracle?: boolean;
695
697
  }): Promise<AdapterTxResult>;
696
698
  maxWithdraw(address: string, _asset: string): Promise<MaxWithdrawResult>;
697
699
  maxBorrow(address: string, _asset: string): Promise<MaxBorrowResult>;
package/dist/index.cjs CHANGED
@@ -559,7 +559,7 @@ async function queryBalance(client, address) {
559
559
  var SUI_TYPE = "0x2::sui::SUI";
560
560
  var KNOWN_TARGETS = [
561
561
  [/::suilend|::obligation/, "lending"],
562
- [/::navi|::incentive_v2/, "lending"],
562
+ [/::navi|::incentive_v\d+|::oracle_pro/, "lending"],
563
563
  [/::cetus|::pool/, "swap"],
564
564
  [/::deepbook/, "swap"],
565
565
  [/::transfer::public_transfer/, "send"]
@@ -713,6 +713,7 @@ function sdkOptions(client) {
713
713
  return { env: "prod", client, cacheTime: 0, disableCache: true };
714
714
  }
715
715
  async function refreshOracle(tx, client, address, options) {
716
+ if (options?.skipOracle) return;
716
717
  const origInfo = console.info;
717
718
  const origWarn = console.warn;
718
719
  console.info = (...args) => {
@@ -880,13 +881,14 @@ async function buildSaveTx(client, address, amount, options = {}) {
880
881
  const assetInfo = resolveAssetInfo(asset);
881
882
  const coins = await fetchCoins(client, address, assetInfo.type);
882
883
  if (coins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", `No ${assetInfo.displayName} coins found`);
884
+ const totalBalance = coins.reduce((sum, c) => sum + BigInt(c.balance), 0n);
883
885
  const tx = new transactions.Transaction();
884
886
  tx.setSender(address);
885
887
  const coinObj = mergeCoins(tx, coins);
886
888
  if (options.collectFee) {
887
889
  addCollectFeeToTx(tx, coinObj, "save");
888
890
  }
889
- const rawAmount = Number(stableToRaw(amount, assetInfo.decimals));
891
+ const rawAmount = Math.min(Number(stableToRaw(amount, assetInfo.decimals)), Number(totalBalance));
890
892
  try {
891
893
  await lending.depositCoinPTB(tx, assetInfo.type, coinObj, {
892
894
  ...sdkOptions(client),
@@ -1007,12 +1009,16 @@ async function buildRepayTx(client, address, amount, options = {}) {
1007
1009
  const assetInfo = resolveAssetInfo(asset);
1008
1010
  const coins = await fetchCoins(client, address, assetInfo.type);
1009
1011
  if (coins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", `No ${assetInfo.displayName} coins to repay with`);
1012
+ const totalBalance = coins.reduce((sum, c) => sum + BigInt(c.balance), 0n);
1010
1013
  const tx = new transactions.Transaction();
1011
1014
  tx.setSender(address);
1012
1015
  const coinObj = mergeCoins(tx, coins);
1013
- const rawAmount = Number(stableToRaw(amount, assetInfo.decimals));
1016
+ const rawAmount = Math.min(Number(stableToRaw(amount, assetInfo.decimals)), Number(totalBalance));
1014
1017
  const [repayCoin] = tx.splitCoins(coinObj, [rawAmount]);
1015
- await refreshOracle(tx, client, address, { skipPythUpdate: options.sponsored });
1018
+ await refreshOracle(tx, client, address, {
1019
+ skipPythUpdate: options.sponsored,
1020
+ skipOracle: options.skipOracle
1021
+ });
1016
1022
  try {
1017
1023
  await lending.repayCoinPTB(tx, assetInfo.type, repayCoin, {
1018
1024
  ...sdkOptions(client),
@@ -1537,7 +1543,11 @@ var NaviAdapter = class {
1537
1543
  }
1538
1544
  async buildRepayTx(address, amount, asset, options) {
1539
1545
  const normalized = normalizeAsset(asset);
1540
- const tx = await buildRepayTx(this.client, address, amount, { asset: normalized, sponsored: options?.sponsored });
1546
+ const tx = await buildRepayTx(this.client, address, amount, {
1547
+ asset: normalized,
1548
+ sponsored: options?.sponsored,
1549
+ skipOracle: options?.skipOracle
1550
+ });
1541
1551
  return { tx };
1542
1552
  }
1543
1553
  async maxWithdraw(address, _asset) {
@@ -2210,16 +2220,23 @@ var SuilendAdapter = class {
2210
2220
  if (obligationOwnerCaps.length === 0 || obligations.length === 0) return [];
2211
2221
  const ob = obligations[0];
2212
2222
  const rewards = [];
2223
+ const WAD = 1e18;
2213
2224
  for (const dep of ob.deposits) {
2214
- for (const rw of dep.reserve.depositsPoolRewardManager.poolRewards) {
2225
+ const urm = dep.userRewardManager;
2226
+ for (const rw of dep.reserve.depositsPoolRewardManager?.poolRewards ?? []) {
2215
2227
  if (rw.endTimeMs <= Date.now()) continue;
2228
+ let claimableAmount = 0;
2229
+ const userReward = urm?.rewards?.[rw.rewardIndex];
2230
+ if (userReward?.earnedRewards) {
2231
+ claimableAmount = Number(BigInt(userReward.earnedRewards.value.toString())) / WAD / 10 ** rw.mintDecimals;
2232
+ }
2216
2233
  const symbol = rw.symbol || rw.coinType.split("::").pop() || "UNKNOWN";
2217
2234
  rewards.push({
2218
2235
  protocol: "suilend",
2219
2236
  asset: this.resolveSymbol(dep.coinType),
2220
2237
  coinType: rw.coinType,
2221
2238
  symbol,
2222
- amount: 0,
2239
+ amount: claimableAmount,
2223
2240
  estimatedValueUsd: 0
2224
2241
  });
2225
2242
  }
@@ -2903,6 +2920,7 @@ var ContactManager = class {
2903
2920
  }
2904
2921
  }
2905
2922
  };
2923
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
2906
2924
  function emptyData() {
2907
2925
  return { positions: {}, strategies: {}, realizedPnL: 0 };
2908
2926
  }
@@ -3058,25 +3076,34 @@ var PortfolioManager = class {
3058
3076
  }
3059
3077
  // --- Strategy position tracking ---
3060
3078
  recordStrategyBuy(strategyKey, trade) {
3079
+ if (UNSAFE_KEYS.has(strategyKey) || UNSAFE_KEYS.has(trade.asset)) {
3080
+ throw new T2000Error("ASSET_NOT_SUPPORTED", "Invalid strategy key or asset name");
3081
+ }
3061
3082
  this.load();
3062
- if (!this.data.strategies[strategyKey]) {
3063
- this.data.strategies[strategyKey] = {};
3083
+ if (!Object.hasOwn(this.data.strategies, strategyKey)) {
3084
+ this.data.strategies[strategyKey] = /* @__PURE__ */ Object.create(null);
3064
3085
  }
3065
3086
  const bucket = this.data.strategies[strategyKey];
3066
- const pos = bucket[trade.asset] ?? { totalAmount: 0, costBasis: 0, avgPrice: 0, trades: [] };
3087
+ const pos = Object.hasOwn(bucket, trade.asset) ? bucket[trade.asset] : { totalAmount: 0, costBasis: 0, avgPrice: 0, trades: [] };
3067
3088
  pos.totalAmount += trade.amount;
3068
3089
  pos.costBasis += trade.usdValue;
3069
3090
  pos.avgPrice = pos.costBasis / pos.totalAmount;
3070
3091
  pos.trades.push(trade);
3071
- bucket[trade.asset] = pos;
3092
+ Object.defineProperty(bucket, trade.asset, { value: pos, writable: true, enumerable: true, configurable: true });
3072
3093
  this.save();
3073
3094
  }
3074
3095
  recordStrategySell(strategyKey, trade) {
3096
+ if (UNSAFE_KEYS.has(strategyKey) || UNSAFE_KEYS.has(trade.asset)) {
3097
+ throw new T2000Error("ASSET_NOT_SUPPORTED", "Invalid strategy key or asset name");
3098
+ }
3075
3099
  this.load();
3076
3100
  const bucket = this.data.strategies[strategyKey];
3077
3101
  if (!bucket) {
3078
3102
  throw new T2000Error("STRATEGY_NOT_FOUND", `No positions for strategy '${strategyKey}'`);
3079
3103
  }
3104
+ if (!Object.hasOwn(bucket, trade.asset)) {
3105
+ throw new T2000Error("INSUFFICIENT_INVESTMENT", `No ${trade.asset} position in strategy '${strategyKey}'`);
3106
+ }
3080
3107
  const pos = bucket[trade.asset];
3081
3108
  if (!pos || pos.totalAmount <= 0) {
3082
3109
  throw new T2000Error("INSUFFICIENT_INVESTMENT", `No ${trade.asset} position in strategy '${strategyKey}'`);
@@ -3093,7 +3120,7 @@ var PortfolioManager = class {
3093
3120
  pos.avgPrice = 0;
3094
3121
  }
3095
3122
  pos.trades.push(trade);
3096
- bucket[trade.asset] = pos;
3123
+ Object.defineProperty(bucket, trade.asset, { value: pos, writable: true, enumerable: true, configurable: true });
3097
3124
  const hasPositions = Object.values(bucket).some((p) => p.totalAmount > 0);
3098
3125
  if (!hasPositions) {
3099
3126
  delete this.data.strategies[strategyKey];