@t2000/sdk 0.17.12 → 0.17.14

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.cjs CHANGED
@@ -1908,6 +1908,26 @@ function computeRates(reserve) {
1908
1908
  const depositAprPct = utilizationPct / 100 * (borrowAprPct / 100) * (1 - reserve.spreadFeeBps / 1e4) * 100;
1909
1909
  return { borrowAprPct, depositAprPct };
1910
1910
  }
1911
+ var MS_PER_YEAR = 365.25 * 24 * 3600 * 1e3;
1912
+ function computeDepositRewardApr(reserve, allReserves) {
1913
+ if (reserve.depositTotalShares <= 0 || reserve.price <= 0) return 0;
1914
+ const totalDepositValue = reserve.depositTotalShares / 10 ** reserve.mintDecimals * reserve.price;
1915
+ if (totalDepositValue <= 0) return 0;
1916
+ const priceMap = /* @__PURE__ */ new Map();
1917
+ for (const r of allReserves) {
1918
+ if (r.price > 0) priceMap.set(r.coinType, { price: r.price, decimals: r.mintDecimals });
1919
+ }
1920
+ let rewardApr = 0;
1921
+ for (const rw of reserve.depositPoolRewards) {
1922
+ const info = priceMap.get(rw.coinType);
1923
+ if (!info || info.price <= 0) continue;
1924
+ const durationMs = rw.endTimeMs - rw.startTimeMs;
1925
+ if (durationMs <= 0) continue;
1926
+ const annualTokens = rw.totalRewards / 10 ** info.decimals * (MS_PER_YEAR / durationMs);
1927
+ rewardApr += annualTokens * info.price / totalDepositValue * 100;
1928
+ }
1929
+ return rewardApr;
1930
+ }
1911
1931
  function cTokenRatio(reserve) {
1912
1932
  if (reserve.ctokenSupply === 0) return 1;
1913
1933
  const totalSupply = reserve.availableAmount + reserve.borrowedAmountWad / WAD - reserve.unclaimedSpreadFeesWad / WAD;
@@ -1927,6 +1947,18 @@ function parseReserve(raw, index) {
1927
1947
  const r = f(raw);
1928
1948
  const coinTypeField = f(r.coin_type);
1929
1949
  const config = f(f(r.config)?.element);
1950
+ const dMgr = f(r.deposits_pool_reward_manager);
1951
+ const rawRewards = Array.isArray(dMgr?.pool_rewards) ? dMgr.pool_rewards : [];
1952
+ const now = Date.now();
1953
+ const depositPoolRewards = rawRewards.filter((rw) => rw !== null).map((rw) => {
1954
+ const rwf = f(rw);
1955
+ return {
1956
+ coinType: str(f(rwf.coin_type)?.name),
1957
+ totalRewards: num(rwf.total_rewards),
1958
+ startTimeMs: num(rwf.start_time_ms),
1959
+ endTimeMs: num(rwf.end_time_ms)
1960
+ };
1961
+ }).filter((rw) => rw.endTimeMs > now && rw.totalRewards > 0);
1930
1962
  return {
1931
1963
  coinType: str(coinTypeField?.name),
1932
1964
  mintDecimals: num(r.mint_decimals),
@@ -1940,7 +1972,10 @@ function parseReserve(raw, index) {
1940
1972
  spreadFeeBps: num(config?.spread_fee_bps),
1941
1973
  interestRateUtils: Array.isArray(config?.interest_rate_utils) ? config.interest_rate_utils.map(num) : [],
1942
1974
  interestRateAprs: Array.isArray(config?.interest_rate_aprs) ? config.interest_rate_aprs.map(num) : [],
1943
- arrayIndex: index
1975
+ arrayIndex: index,
1976
+ price: num(f(r.price)?.value) / WAD,
1977
+ depositTotalShares: num(dMgr?.total_shares),
1978
+ depositPoolRewards
1944
1979
  };
1945
1980
  }
1946
1981
  function parseObligation(raw) {
@@ -2085,7 +2120,8 @@ var SuilendAdapter = class {
2085
2120
  const reserve = this.findReserve(reserves, asset);
2086
2121
  if (!reserve) throw new T2000Error("ASSET_NOT_SUPPORTED", `Suilend does not support ${asset}`);
2087
2122
  const { borrowAprPct, depositAprPct } = computeRates(reserve);
2088
- return { asset, saveApy: depositAprPct, borrowApy: borrowAprPct };
2123
+ const rewardApr = computeDepositRewardApr(reserve, reserves);
2124
+ return { asset, saveApy: depositAprPct + rewardApr, borrowApy: borrowAprPct };
2089
2125
  }
2090
2126
  async getPositions(address) {
2091
2127
  const supplies = [];
@@ -2102,7 +2138,8 @@ var SuilendAdapter = class {
2102
2138
  const ratio = cTokenRatio(reserve);
2103
2139
  const amount = dep.ctokenAmount * ratio / 10 ** reserve.mintDecimals;
2104
2140
  const { depositAprPct } = computeRates(reserve);
2105
- supplies.push({ asset: this.resolveSymbol(dep.coinType), amount, apy: depositAprPct });
2141
+ const rewardApr = computeDepositRewardApr(reserve, reserves);
2142
+ supplies.push({ asset: this.resolveSymbol(dep.coinType), amount, apy: depositAprPct + rewardApr });
2106
2143
  }
2107
2144
  for (const bor of obligation.borrows) {
2108
2145
  const reserve = reserves[bor.reserveIdx];
@@ -4281,13 +4318,28 @@ To sell investment: t2000 invest sell ${params.amount} ${fromAsset}`,
4281
4318
  if (bal.available < params.usdAmount) {
4282
4319
  throw new T2000Error("INSUFFICIENT_BALANCE", `Insufficient checking balance. Available: $${bal.available.toFixed(2)}, requested: $${params.usdAmount.toFixed(2)}`);
4283
4320
  }
4284
- const swapResult = await this.exchange({
4285
- from: "USDC",
4286
- to: params.asset,
4287
- amount: params.usdAmount,
4288
- maxSlippage: params.maxSlippage ?? defaultSlippage(params.asset),
4289
- _bypassInvestmentGuard: true
4290
- });
4321
+ let swapResult;
4322
+ const maxRetries = 3;
4323
+ for (let attempt = 0; ; attempt++) {
4324
+ try {
4325
+ swapResult = await this.exchange({
4326
+ from: "USDC",
4327
+ to: params.asset,
4328
+ amount: params.usdAmount,
4329
+ maxSlippage: params.maxSlippage ?? defaultSlippage(params.asset),
4330
+ _bypassInvestmentGuard: true
4331
+ });
4332
+ break;
4333
+ } catch (err) {
4334
+ const msg = err instanceof Error ? err.message : String(err);
4335
+ const isSlippage = msg.includes("slippage") || msg.includes("amount_out_slippage");
4336
+ if (isSlippage && attempt < maxRetries) {
4337
+ await new Promise((r) => setTimeout(r, 2e3 * (attempt + 1)));
4338
+ continue;
4339
+ }
4340
+ throw err;
4341
+ }
4342
+ }
4291
4343
  if (swapResult.toAmount === 0) {
4292
4344
  throw new T2000Error("SWAP_FAILED", "Swap returned zero tokens \u2014 try a different amount or check liquidity");
4293
4345
  }
@@ -4385,13 +4437,28 @@ To sell investment: t2000 invest sell ${params.amount} ${fromAsset}`,
4385
4437
  if (sellAmountAsset <= 0) {
4386
4438
  throw new T2000Error("INSUFFICIENT_INVESTMENT", "Nothing to sell after gas reserve");
4387
4439
  }
4388
- const swapResult = await this.exchange({
4389
- from: params.asset,
4390
- to: "USDC",
4391
- amount: sellAmountAsset,
4392
- maxSlippage: params.maxSlippage ?? defaultSlippage(params.asset),
4393
- _bypassInvestmentGuard: true
4394
- });
4440
+ let swapResult;
4441
+ const maxRetries = 3;
4442
+ for (let attempt = 0; ; attempt++) {
4443
+ try {
4444
+ swapResult = await this.exchange({
4445
+ from: params.asset,
4446
+ to: "USDC",
4447
+ amount: sellAmountAsset,
4448
+ maxSlippage: params.maxSlippage ?? defaultSlippage(params.asset),
4449
+ _bypassInvestmentGuard: true
4450
+ });
4451
+ break;
4452
+ } catch (err) {
4453
+ const msg = err instanceof Error ? err.message : String(err);
4454
+ const isSlippage = msg.includes("slippage") || msg.includes("amount_out_slippage");
4455
+ if (isSlippage && attempt < maxRetries) {
4456
+ await new Promise((r) => setTimeout(r, 2e3 * (attempt + 1)));
4457
+ continue;
4458
+ }
4459
+ throw err;
4460
+ }
4461
+ }
4395
4462
  const price = swapResult.toAmount / sellAmountAsset;
4396
4463
  const realizedPnL = this.portfolio.recordSell({
4397
4464
  id: `inv_${Date.now()}`,