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