@t2000/sdk 0.17.14 → 0.17.15

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.
@@ -23,6 +23,7 @@ interface BalanceResponse {
23
23
  debt: number;
24
24
  investment: number;
25
25
  investmentPnL: number;
26
+ pendingRewards: number;
26
27
  gasReserve: GasReserve;
27
28
  total: number;
28
29
  assets: Record<string, number>;
@@ -349,6 +350,21 @@ interface AutoInvestRunResult {
349
350
  reason: string;
350
351
  }>;
351
352
  }
353
+ interface PendingReward$1 {
354
+ protocol: string;
355
+ coinType: string;
356
+ symbol: string;
357
+ amount: number;
358
+ estimatedValueUsd: number;
359
+ }
360
+ interface ClaimRewardsResult {
361
+ success: boolean;
362
+ tx: string;
363
+ rewards: PendingReward$1[];
364
+ totalValueUsd: number;
365
+ gasCost: number;
366
+ gasMethod: GasMethod;
367
+ }
352
368
  type PositionSide = 'long' | 'short';
353
369
  interface PerpsPosition {
354
370
  market: string;
@@ -485,6 +501,15 @@ interface LendingAdapter {
485
501
  collectFee?: boolean;
486
502
  }): Promise<void>;
487
503
  addRepayToTx?(tx: Transaction, address: string, coin: TransactionObjectArgument, asset: string): Promise<void>;
504
+ getPendingRewards?(address: string): Promise<PendingReward[]>;
505
+ addClaimRewardsToTx?(tx: Transaction, address: string): Promise<PendingReward[]>;
506
+ }
507
+ interface PendingReward {
508
+ protocol: string;
509
+ coinType: string;
510
+ symbol: string;
511
+ amount: number;
512
+ estimatedValueUsd: number;
488
513
  }
489
514
  interface SwapAdapter {
490
515
  readonly id: string;
@@ -609,6 +634,8 @@ declare class NaviAdapter implements LendingAdapter {
609
634
  collectFee?: boolean;
610
635
  }): Promise<void>;
611
636
  addRepayToTx(tx: Transaction, address: string, coin: TransactionObjectArgument, asset: string): Promise<void>;
637
+ getPendingRewards(address: string): Promise<PendingReward[]>;
638
+ addClaimRewardsToTx(tx: Transaction, address: string): Promise<PendingReward[]>;
612
639
  }
613
640
 
614
641
  declare const descriptor$2: ProtocolDescriptor;
@@ -699,6 +726,9 @@ declare class SuilendAdapter implements LendingAdapter {
699
726
  currentHF: number;
700
727
  }>;
701
728
  private fetchAllCoins;
729
+ private isClaimableReward;
730
+ getPendingRewards(address: string): Promise<PendingReward[]>;
731
+ addClaimRewardsToTx(tx: Transaction, address: string): Promise<PendingReward[]>;
702
732
  }
703
733
 
704
734
  declare const descriptor: ProtocolDescriptor;
@@ -718,4 +748,4 @@ declare function attack(client: SuiJsonRpcClient, signer: Ed25519Keypair, sentin
718
748
  /** All registered protocol descriptors — used by the indexer for event classification */
719
749
  declare const allDescriptors: ProtocolDescriptor[];
720
750
 
721
- export { SuilendAdapter as $, type AutoInvestSchedule as A, type BalanceResponse as B, CetusAdapter as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasMethod as G, type HealthFactorResult as H, type InvestmentTrade as I, type GasReserve as J, type HealthInfo as K, type LendingAdapter as L, type MaxWithdrawResult as M, NaviAdapter as N, type PerpsAdapter as O, type PortfolioResult as P, type PerpsPosition as Q, type RepayResult as R, type StrategyDefinition as S, type T2000Options as T, type PositionEntry as U, type PositionSide as V, type WithdrawResult as W, type ProtocolDescriptor as X, ProtocolRegistry as Y, type RebalanceStep as Z, type SentinelVerdict as _, type AutoInvestStatus as a, type SwapQuote as a0, type TradePositionsResult as a1, type TradeResult as a2, allDescriptors as a3, descriptor$2 as a4, getSentinelInfo as a5, listSentinels as a6, descriptor$3 as a7, requestAttack as a8, attack as a9, descriptor as aa, settleAttack as ab, submitPrompt as ac, descriptor$1 as ad, type SendResult as b, type TransactionRecord as c, type SwapAdapter as d, type SaveResult as e, type BorrowResult as f, type MaxBorrowResult as g, type SwapResult as h, type InvestResult as i, type InvestEarnResult as j, type StrategyBuyResult as k, type StrategySellResult as l, type StrategyRebalanceResult as m, type StrategyStatusResult as n, type AutoInvestRunResult as o, type InvestmentPosition as p, type PositionsResult as q, type RatesResult as r, type LendingRates as s, type RebalanceResult as t, type SentinelAgent as u, type SentinelAttackResult as v, type AdapterCapability as w, type AdapterPositions as x, type AdapterTxResult as y, type AssetRates as z };
751
+ export { type RebalanceStep as $, type AutoInvestSchedule as A, type BalanceResponse as B, type ClaimRewardsResult as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasMethod as G, type HealthFactorResult as H, type InvestmentTrade as I, type AssetRates as J, CetusAdapter as K, type LendingAdapter as L, type MaxWithdrawResult as M, type GasReserve as N, type HealthInfo as O, type PendingReward$1 as P, NaviAdapter as Q, type RepayResult as R, type StrategyDefinition as S, type T2000Options as T, type PerpsAdapter as U, type PerpsPosition as V, type WithdrawResult as W, type PositionEntry as X, type PositionSide as Y, type ProtocolDescriptor as Z, ProtocolRegistry as _, type AutoInvestStatus as a, type SentinelVerdict as a0, SuilendAdapter as a1, type SwapQuote as a2, type TradePositionsResult as a3, type TradeResult as a4, allDescriptors as a5, descriptor$2 as a6, getSentinelInfo as a7, listSentinels as a8, descriptor$3 as a9, requestAttack as aa, attack as ab, descriptor as ac, settleAttack as ad, submitPrompt as ae, descriptor$1 as af, type SendResult as b, type TransactionRecord as c, type SwapAdapter as d, type SaveResult as e, type BorrowResult as f, type MaxBorrowResult as g, type SwapResult as h, type InvestResult as i, type InvestEarnResult as j, type StrategyBuyResult as k, type StrategySellResult as l, type StrategyRebalanceResult as m, type StrategyStatusResult as n, type AutoInvestRunResult as o, type PortfolioResult as p, type InvestmentPosition as q, type PositionsResult as r, type RatesResult as s, type LendingRates as t, type RebalanceResult as u, type SentinelAgent as v, type SentinelAttackResult as w, type AdapterCapability as x, type AdapterPositions as y, type AdapterTxResult as z };
@@ -23,6 +23,7 @@ interface BalanceResponse {
23
23
  debt: number;
24
24
  investment: number;
25
25
  investmentPnL: number;
26
+ pendingRewards: number;
26
27
  gasReserve: GasReserve;
27
28
  total: number;
28
29
  assets: Record<string, number>;
@@ -349,6 +350,21 @@ interface AutoInvestRunResult {
349
350
  reason: string;
350
351
  }>;
351
352
  }
353
+ interface PendingReward$1 {
354
+ protocol: string;
355
+ coinType: string;
356
+ symbol: string;
357
+ amount: number;
358
+ estimatedValueUsd: number;
359
+ }
360
+ interface ClaimRewardsResult {
361
+ success: boolean;
362
+ tx: string;
363
+ rewards: PendingReward$1[];
364
+ totalValueUsd: number;
365
+ gasCost: number;
366
+ gasMethod: GasMethod;
367
+ }
352
368
  type PositionSide = 'long' | 'short';
353
369
  interface PerpsPosition {
354
370
  market: string;
@@ -485,6 +501,15 @@ interface LendingAdapter {
485
501
  collectFee?: boolean;
486
502
  }): Promise<void>;
487
503
  addRepayToTx?(tx: Transaction, address: string, coin: TransactionObjectArgument, asset: string): Promise<void>;
504
+ getPendingRewards?(address: string): Promise<PendingReward[]>;
505
+ addClaimRewardsToTx?(tx: Transaction, address: string): Promise<PendingReward[]>;
506
+ }
507
+ interface PendingReward {
508
+ protocol: string;
509
+ coinType: string;
510
+ symbol: string;
511
+ amount: number;
512
+ estimatedValueUsd: number;
488
513
  }
489
514
  interface SwapAdapter {
490
515
  readonly id: string;
@@ -609,6 +634,8 @@ declare class NaviAdapter implements LendingAdapter {
609
634
  collectFee?: boolean;
610
635
  }): Promise<void>;
611
636
  addRepayToTx(tx: Transaction, address: string, coin: TransactionObjectArgument, asset: string): Promise<void>;
637
+ getPendingRewards(address: string): Promise<PendingReward[]>;
638
+ addClaimRewardsToTx(tx: Transaction, address: string): Promise<PendingReward[]>;
612
639
  }
613
640
 
614
641
  declare const descriptor$2: ProtocolDescriptor;
@@ -699,6 +726,9 @@ declare class SuilendAdapter implements LendingAdapter {
699
726
  currentHF: number;
700
727
  }>;
701
728
  private fetchAllCoins;
729
+ private isClaimableReward;
730
+ getPendingRewards(address: string): Promise<PendingReward[]>;
731
+ addClaimRewardsToTx(tx: Transaction, address: string): Promise<PendingReward[]>;
702
732
  }
703
733
 
704
734
  declare const descriptor: ProtocolDescriptor;
@@ -718,4 +748,4 @@ declare function attack(client: SuiJsonRpcClient, signer: Ed25519Keypair, sentin
718
748
  /** All registered protocol descriptors — used by the indexer for event classification */
719
749
  declare const allDescriptors: ProtocolDescriptor[];
720
750
 
721
- export { SuilendAdapter as $, type AutoInvestSchedule as A, type BalanceResponse as B, CetusAdapter as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasMethod as G, type HealthFactorResult as H, type InvestmentTrade as I, type GasReserve as J, type HealthInfo as K, type LendingAdapter as L, type MaxWithdrawResult as M, NaviAdapter as N, type PerpsAdapter as O, type PortfolioResult as P, type PerpsPosition as Q, type RepayResult as R, type StrategyDefinition as S, type T2000Options as T, type PositionEntry as U, type PositionSide as V, type WithdrawResult as W, type ProtocolDescriptor as X, ProtocolRegistry as Y, type RebalanceStep as Z, type SentinelVerdict as _, type AutoInvestStatus as a, type SwapQuote as a0, type TradePositionsResult as a1, type TradeResult as a2, allDescriptors as a3, descriptor$2 as a4, getSentinelInfo as a5, listSentinels as a6, descriptor$3 as a7, requestAttack as a8, attack as a9, descriptor as aa, settleAttack as ab, submitPrompt as ac, descriptor$1 as ad, type SendResult as b, type TransactionRecord as c, type SwapAdapter as d, type SaveResult as e, type BorrowResult as f, type MaxBorrowResult as g, type SwapResult as h, type InvestResult as i, type InvestEarnResult as j, type StrategyBuyResult as k, type StrategySellResult as l, type StrategyRebalanceResult as m, type StrategyStatusResult as n, type AutoInvestRunResult as o, type InvestmentPosition as p, type PositionsResult as q, type RatesResult as r, type LendingRates as s, type RebalanceResult as t, type SentinelAgent as u, type SentinelAttackResult as v, type AdapterCapability as w, type AdapterPositions as x, type AdapterTxResult as y, type AssetRates as z };
751
+ export { type RebalanceStep as $, type AutoInvestSchedule as A, type BalanceResponse as B, type ClaimRewardsResult as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasMethod as G, type HealthFactorResult as H, type InvestmentTrade as I, type AssetRates as J, CetusAdapter as K, type LendingAdapter as L, type MaxWithdrawResult as M, type GasReserve as N, type HealthInfo as O, type PendingReward$1 as P, NaviAdapter as Q, type RepayResult as R, type StrategyDefinition as S, type T2000Options as T, type PerpsAdapter as U, type PerpsPosition as V, type WithdrawResult as W, type PositionEntry as X, type PositionSide as Y, type ProtocolDescriptor as Z, ProtocolRegistry as _, type AutoInvestStatus as a, type SentinelVerdict as a0, SuilendAdapter as a1, type SwapQuote as a2, type TradePositionsResult as a3, type TradeResult as a4, allDescriptors as a5, descriptor$2 as a6, getSentinelInfo as a7, listSentinels as a8, descriptor$3 as a9, requestAttack as aa, attack as ab, descriptor as ac, settleAttack as ad, submitPrompt as ae, descriptor$1 as af, type SendResult as b, type TransactionRecord as c, type SwapAdapter as d, type SaveResult as e, type BorrowResult as f, type MaxBorrowResult as g, type SwapResult as h, type InvestResult as i, type InvestEarnResult as j, type StrategyBuyResult as k, type StrategySellResult as l, type StrategyRebalanceResult as m, type StrategyStatusResult as n, type AutoInvestRunResult as o, type PortfolioResult as p, type InvestmentPosition as q, type PositionsResult as r, type RatesResult as s, type LendingRates as t, type RebalanceResult as u, type SentinelAgent as v, type SentinelAttackResult as w, type AdapterCapability as x, type AdapterPositions as y, type AdapterTxResult as z };
package/dist/index.cjs CHANGED
@@ -495,6 +495,7 @@ async function queryBalance(client, address) {
495
495
  debt: 0,
496
496
  investment: 0,
497
497
  investmentPnL: 0,
498
+ pendingRewards: 0,
498
499
  gasReserve: {
499
500
  sui: suiAmount,
500
501
  usdEquiv
@@ -1178,6 +1179,173 @@ async function maxBorrowAmount(client, addressOrKeypair) {
1178
1179
  const maxAmount = Math.max(0, hf.supplied * ltv / MIN_HEALTH_FACTOR - hf.borrowed);
1179
1180
  return { maxAmount, healthFactorAfter: MIN_HEALTH_FACTOR, currentHF: hf.healthFactor };
1180
1181
  }
1182
+ var CERT_TYPE = "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT";
1183
+ var DEEP_TYPE = "0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP";
1184
+ var REWARD_FUNDS = {
1185
+ [CERT_TYPE]: "0x7093cf7549d5e5b35bfde2177223d1050f71655c7f676a5e610ee70eb4d93b5c",
1186
+ [DEEP_TYPE]: "0xc889d78b634f954979e80e622a2ae0fece824c0f6d9590044378a2563035f32f"
1187
+ };
1188
+ var REWARD_SYMBOLS = {
1189
+ [CERT_TYPE]: "vSUI",
1190
+ [DEEP_TYPE]: "DEEP"
1191
+ };
1192
+ var incentiveRulesCache = null;
1193
+ async function getIncentiveRules(client) {
1194
+ if (incentiveRulesCache && Date.now() - incentiveRulesCache.ts < CACHE_TTL) {
1195
+ return incentiveRulesCache.data;
1196
+ }
1197
+ const [pools, obj] = await Promise.all([
1198
+ getPools(),
1199
+ client.getObject({
1200
+ id: "0x62982dad27fb10bb314b3384d5de8d2ac2d72ab2dbeae5d801dbdb9efa816c80",
1201
+ options: { showContent: true }
1202
+ })
1203
+ ]);
1204
+ const rewardCoinMap = /* @__PURE__ */ new Map();
1205
+ for (const pool of pools) {
1206
+ const ct = (pool.suiCoinType || pool.coinType || "").toLowerCase();
1207
+ const suffix = ct.split("::").slice(1).join("::");
1208
+ const coins = pool.supplyIncentiveApyInfo?.rewardCoin;
1209
+ if (Array.isArray(coins) && coins.length > 0) {
1210
+ rewardCoinMap.set(suffix, coins[0]);
1211
+ }
1212
+ }
1213
+ const result = /* @__PURE__ */ new Map();
1214
+ if (obj.data?.content?.dataType !== "moveObject") {
1215
+ incentiveRulesCache = { data: result, ts: Date.now() };
1216
+ return result;
1217
+ }
1218
+ const fields = obj.data.content.fields;
1219
+ const poolsObj = fields.pools;
1220
+ const entries = poolsObj?.fields?.contents;
1221
+ if (!Array.isArray(entries)) {
1222
+ incentiveRulesCache = { data: result, ts: Date.now() };
1223
+ return result;
1224
+ }
1225
+ for (const entry of entries) {
1226
+ const ef = entry?.fields;
1227
+ if (!ef) continue;
1228
+ const key = String(ef.key ?? "");
1229
+ const value = ef.value;
1230
+ const rules = value?.fields?.rules;
1231
+ const ruleEntries = rules?.fields?.contents;
1232
+ if (!Array.isArray(ruleEntries)) continue;
1233
+ const ruleIds = ruleEntries.map((re) => {
1234
+ const rf = re?.fields;
1235
+ return String(rf?.key ?? "");
1236
+ }).filter(Boolean);
1237
+ const suffix = key.split("::").slice(1).join("::").toLowerCase();
1238
+ const full = key.toLowerCase();
1239
+ const rewardCoin = rewardCoinMap.get(suffix) ?? rewardCoinMap.get(full) ?? null;
1240
+ result.set(key, { ruleIds, rewardCoinType: rewardCoin });
1241
+ }
1242
+ incentiveRulesCache = { data: result, ts: Date.now() };
1243
+ return result;
1244
+ }
1245
+ function stripPrefix(coinType) {
1246
+ return coinType.replace(/^0x0*/, "");
1247
+ }
1248
+ async function getPendingRewards(client, address) {
1249
+ const [pools, states, rules] = await Promise.all([
1250
+ getPools(),
1251
+ getUserState(client, address),
1252
+ getIncentiveRules(client)
1253
+ ]);
1254
+ const rewards = [];
1255
+ const deposited = states.filter((s) => s.supplyBalance > 0n);
1256
+ if (deposited.length === 0) return rewards;
1257
+ const rewardTotals = /* @__PURE__ */ new Map();
1258
+ for (const state of deposited) {
1259
+ const pool = pools.find((p) => p.id === state.assetId);
1260
+ if (!pool) continue;
1261
+ const boostedApr = parseFloat(pool.supplyIncentiveApyInfo?.boostedApr ?? "0");
1262
+ if (boostedApr <= 0) continue;
1263
+ const rewardCoins = pool.supplyIncentiveApyInfo?.rewardCoin;
1264
+ if (!Array.isArray(rewardCoins) || rewardCoins.length === 0) continue;
1265
+ const rewardType = rewardCoins[0];
1266
+ const supplyBal = compoundBalance(state.supplyBalance, pool.currentSupplyIndex, pool);
1267
+ const price = pool.token?.price ?? 0;
1268
+ const depositUsd = supplyBal * price;
1269
+ const annualRewardUsd = depositUsd * (boostedApr / 100);
1270
+ const estimatedUsd = annualRewardUsd / 365;
1271
+ rewardTotals.set(rewardType, (rewardTotals.get(rewardType) ?? 0) + estimatedUsd);
1272
+ }
1273
+ for (const [coinType, dailyUsd] of rewardTotals) {
1274
+ if (dailyUsd < 1e-3) continue;
1275
+ rewards.push({
1276
+ protocol: "navi",
1277
+ coinType,
1278
+ symbol: REWARD_SYMBOLS[coinType] ?? coinType.split("::").pop() ?? "UNKNOWN",
1279
+ amount: 0,
1280
+ estimatedValueUsd: dailyUsd
1281
+ });
1282
+ }
1283
+ return rewards;
1284
+ }
1285
+ async function addClaimRewardsToTx(tx, client, address) {
1286
+ const [config, pools, states, rules] = await Promise.all([
1287
+ getConfig(),
1288
+ getPools(),
1289
+ getUserState(client, address),
1290
+ getIncentiveRules(client)
1291
+ ]);
1292
+ const deposited = states.filter((s) => s.supplyBalance > 0n);
1293
+ if (deposited.length === 0) return [];
1294
+ const claimGroups = /* @__PURE__ */ new Map();
1295
+ for (const state of deposited) {
1296
+ const pool = pools.find((p) => p.id === state.assetId);
1297
+ if (!pool) continue;
1298
+ const boostedApr = parseFloat(pool.supplyIncentiveApyInfo?.boostedApr ?? "0");
1299
+ if (boostedApr <= 0) continue;
1300
+ const rewardCoins = pool.supplyIncentiveApyInfo?.rewardCoin;
1301
+ if (!Array.isArray(rewardCoins) || rewardCoins.length === 0) continue;
1302
+ const rewardType = rewardCoins[0];
1303
+ const fundId = REWARD_FUNDS[rewardType];
1304
+ if (!fundId) continue;
1305
+ const coinType = pool.suiCoinType || pool.coinType || "";
1306
+ const strippedType = stripPrefix(coinType);
1307
+ const ruleData = Array.from(rules.entries()).find(
1308
+ ([key]) => stripPrefix(key) === strippedType || key.split("::").slice(1).join("::").toLowerCase() === coinType.split("::").slice(1).join("::").toLowerCase()
1309
+ );
1310
+ if (!ruleData || ruleData[1].ruleIds.length === 0) continue;
1311
+ const group = claimGroups.get(rewardType) ?? { assets: [], ruleIds: [] };
1312
+ for (const ruleId of ruleData[1].ruleIds) {
1313
+ group.assets.push(strippedType);
1314
+ group.ruleIds.push(ruleId);
1315
+ }
1316
+ claimGroups.set(rewardType, group);
1317
+ }
1318
+ const claimed = [];
1319
+ for (const [rewardType, { assets, ruleIds }] of claimGroups) {
1320
+ const fundId = REWARD_FUNDS[rewardType];
1321
+ const [balance] = tx.moveCall({
1322
+ target: `${config.package}::incentive_v3::claim_reward`,
1323
+ typeArguments: [rewardType],
1324
+ arguments: [
1325
+ tx.object(CLOCK),
1326
+ tx.object(config.incentiveV3),
1327
+ tx.object(config.storage),
1328
+ tx.object(fundId),
1329
+ tx.pure(bcs.bcs.vector(bcs.bcs.string()).serialize(assets)),
1330
+ tx.pure(bcs.bcs.vector(bcs.bcs.Address).serialize(ruleIds))
1331
+ ]
1332
+ });
1333
+ const [coin] = tx.moveCall({
1334
+ target: "0x2::coin::from_balance",
1335
+ typeArguments: [rewardType],
1336
+ arguments: [balance]
1337
+ });
1338
+ tx.transferObjects([coin], address);
1339
+ claimed.push({
1340
+ protocol: "navi",
1341
+ coinType: rewardType,
1342
+ symbol: REWARD_SYMBOLS[rewardType] ?? "UNKNOWN",
1343
+ amount: 0,
1344
+ estimatedValueUsd: 0
1345
+ });
1346
+ }
1347
+ return claimed;
1348
+ }
1181
1349
 
1182
1350
  // src/protocols/yieldTracker.ts
1183
1351
  async function getEarnings(client, keypair) {
@@ -1625,6 +1793,12 @@ var NaviAdapter = class {
1625
1793
  const normalized = normalizeAsset(asset);
1626
1794
  return addRepayToTx(tx, this.client, address, coin, { asset: normalized });
1627
1795
  }
1796
+ async getPendingRewards(address) {
1797
+ return getPendingRewards(this.client, address);
1798
+ }
1799
+ async addClaimRewardsToTx(tx, address) {
1800
+ return addClaimRewardsToTx(tx, this.client, address);
1801
+ }
1628
1802
  };
1629
1803
  var DEFAULT_SLIPPAGE_BPS = 300;
1630
1804
  function createAggregatorClient(client, signer) {
@@ -1950,15 +2124,17 @@ function parseReserve(raw, index) {
1950
2124
  const dMgr = f(r.deposits_pool_reward_manager);
1951
2125
  const rawRewards = Array.isArray(dMgr?.pool_rewards) ? dMgr.pool_rewards : [];
1952
2126
  const now = Date.now();
1953
- const depositPoolRewards = rawRewards.filter((rw) => rw !== null).map((rw) => {
2127
+ const depositPoolRewards = rawRewards.map((rw, idx) => {
2128
+ if (rw === null) return null;
1954
2129
  const rwf = f(rw);
1955
2130
  return {
1956
2131
  coinType: str(f(rwf.coin_type)?.name),
1957
2132
  totalRewards: num(rwf.total_rewards),
1958
2133
  startTimeMs: num(rwf.start_time_ms),
1959
- endTimeMs: num(rwf.end_time_ms)
2134
+ endTimeMs: num(rwf.end_time_ms),
2135
+ rewardIndex: idx
1960
2136
  };
1961
- }).filter((rw) => rw.endTimeMs > now && rw.totalRewards > 0);
2137
+ }).filter((rw) => rw !== null && rw.endTimeMs > now && rw.totalRewards > 0);
1962
2138
  return {
1963
2139
  coinType: str(coinTypeField?.name),
1964
2140
  mintDecimals: num(r.mint_decimals),
@@ -2509,6 +2685,109 @@ var SuilendAdapter = class {
2509
2685
  }
2510
2686
  return all;
2511
2687
  }
2688
+ // -- Claim Rewards --------------------------------------------------------
2689
+ isClaimableReward(coinType) {
2690
+ const ct = coinType.toLowerCase();
2691
+ return ct.includes("spring_sui") || ct.includes("deep::deep") || ct.includes("cert::cert");
2692
+ }
2693
+ async getPendingRewards(address) {
2694
+ const caps = await this.fetchObligationCaps(address);
2695
+ if (caps.length === 0) return [];
2696
+ const [reserves, obligation] = await Promise.all([
2697
+ this.loadReserves(true),
2698
+ this.fetchObligation(caps[0].obligationId)
2699
+ ]);
2700
+ const rewards = [];
2701
+ const rewardEstimates = /* @__PURE__ */ new Map();
2702
+ for (const dep of obligation.deposits) {
2703
+ const reserve = reserves[dep.reserveIdx];
2704
+ if (!reserve) continue;
2705
+ const ratio = cTokenRatio(reserve);
2706
+ const amount = dep.ctokenAmount * ratio / 10 ** reserve.mintDecimals;
2707
+ const price = reserve.price;
2708
+ const depositUsd = amount * price;
2709
+ for (const rw of reserve.depositPoolRewards) {
2710
+ if (!this.isClaimableReward(rw.coinType)) continue;
2711
+ const rewardReserve = reserves.find((r) => {
2712
+ try {
2713
+ return utils.normalizeStructTag(r.coinType) === utils.normalizeStructTag(rw.coinType);
2714
+ } catch {
2715
+ return false;
2716
+ }
2717
+ });
2718
+ const rewardPrice = rewardReserve?.price ?? 0;
2719
+ const rewardDecimals = rewardReserve?.mintDecimals ?? 9;
2720
+ const durationMs = rw.endTimeMs - rw.startTimeMs;
2721
+ if (durationMs <= 0) continue;
2722
+ const annualTokens = rw.totalRewards / 10 ** rewardDecimals * (MS_PER_YEAR / durationMs);
2723
+ const totalDepositValue = reserve.depositTotalShares / 10 ** reserve.mintDecimals * price;
2724
+ if (totalDepositValue <= 0) continue;
2725
+ const userShare = depositUsd / totalDepositValue;
2726
+ const dailyRewardUsd = annualTokens * rewardPrice / 365 * userShare;
2727
+ rewardEstimates.set(rw.coinType, (rewardEstimates.get(rw.coinType) ?? 0) + dailyRewardUsd);
2728
+ }
2729
+ }
2730
+ for (const [coinType, dailyUsd] of rewardEstimates) {
2731
+ if (dailyUsd < 1e-3) continue;
2732
+ const symbol = coinType.includes("spring_sui") ? "SPRING_SUI" : coinType.includes("deep::") ? "DEEP" : coinType.split("::").pop() ?? "UNKNOWN";
2733
+ rewards.push({
2734
+ protocol: "suilend",
2735
+ coinType,
2736
+ symbol,
2737
+ amount: 0,
2738
+ estimatedValueUsd: dailyUsd
2739
+ });
2740
+ }
2741
+ return rewards;
2742
+ }
2743
+ async addClaimRewardsToTx(tx, address) {
2744
+ const caps = await this.fetchObligationCaps(address);
2745
+ if (caps.length === 0) return [];
2746
+ const [pkg, reserves, obligation] = await Promise.all([
2747
+ this.resolvePackage(),
2748
+ this.loadReserves(true),
2749
+ this.fetchObligation(caps[0].obligationId)
2750
+ ]);
2751
+ const claimsByToken = /* @__PURE__ */ new Map();
2752
+ const claimed = [];
2753
+ for (const dep of obligation.deposits) {
2754
+ const reserve = reserves[dep.reserveIdx];
2755
+ if (!reserve) continue;
2756
+ for (const rw of reserve.depositPoolRewards) {
2757
+ if (!this.isClaimableReward(rw.coinType)) continue;
2758
+ const [coin] = tx.moveCall({
2759
+ target: `${pkg}::lending_market::claim_rewards`,
2760
+ typeArguments: [LENDING_MARKET_TYPE, rw.coinType],
2761
+ arguments: [
2762
+ tx.object(LENDING_MARKET_ID),
2763
+ tx.object(caps[0].id),
2764
+ tx.object(CLOCK2),
2765
+ tx.pure.u64(reserve.arrayIndex),
2766
+ tx.pure.u64(rw.rewardIndex),
2767
+ tx.pure.bool(true)
2768
+ ]
2769
+ });
2770
+ const existing = claimsByToken.get(rw.coinType) ?? [];
2771
+ existing.push(coin);
2772
+ claimsByToken.set(rw.coinType, existing);
2773
+ }
2774
+ }
2775
+ for (const [coinType, coins] of claimsByToken) {
2776
+ if (coins.length > 1) {
2777
+ tx.mergeCoins(coins[0], coins.slice(1));
2778
+ }
2779
+ tx.transferObjects([coins[0]], address);
2780
+ const symbol = coinType.includes("spring_sui") ? "SPRING_SUI" : coinType.includes("deep::") ? "DEEP" : coinType.split("::").pop() ?? "UNKNOWN";
2781
+ claimed.push({
2782
+ protocol: "suilend",
2783
+ coinType,
2784
+ symbol,
2785
+ amount: 0,
2786
+ estimatedValueUsd: 0
2787
+ });
2788
+ }
2789
+ return claimed;
2790
+ }
2512
2791
  };
2513
2792
  function hasLeadingZeroBits(hash, bits) {
2514
2793
  const fullBytes = Math.floor(bits / 8);
@@ -3634,6 +3913,12 @@ To access invested funds: t2000 invest sell ${params.amount} ${asset}`,
3634
3913
  bal.investment = 0;
3635
3914
  bal.investmentPnL = 0;
3636
3915
  }
3916
+ try {
3917
+ const pendingRewards = await this.getPendingRewards();
3918
+ bal.pendingRewards = pendingRewards.reduce((s, r) => s + r.estimatedValueUsd, 0);
3919
+ } catch {
3920
+ bal.pendingRewards = 0;
3921
+ }
3637
3922
  bal.total = bal.available + bal.savings - bal.debt + bal.investment + bal.gasReserve.usdEquiv;
3638
3923
  return bal;
3639
3924
  }
@@ -4583,6 +4868,47 @@ To sell investment: t2000 invest sell ${params.amount} ${fromAsset}`,
4583
4868
  gasMethod: gasResult.gasMethod
4584
4869
  };
4585
4870
  }
4871
+ // -- Claim Rewards --
4872
+ async getPendingRewards() {
4873
+ const adapters = this.registry.listLending();
4874
+ const results = await Promise.allSettled(
4875
+ adapters.filter((a) => a.getPendingRewards).map((a) => a.getPendingRewards(this._address))
4876
+ );
4877
+ const all = [];
4878
+ for (const r of results) {
4879
+ if (r.status === "fulfilled") all.push(...r.value);
4880
+ }
4881
+ return all;
4882
+ }
4883
+ async claimRewards() {
4884
+ this.enforcer.assertNotLocked();
4885
+ const adapters = this.registry.listLending().filter((a) => a.addClaimRewardsToTx);
4886
+ if (adapters.length === 0) {
4887
+ return { success: true, tx: "", rewards: [], totalValueUsd: 0, gasCost: 0, gasMethod: "none" };
4888
+ }
4889
+ const tx = new transactions.Transaction();
4890
+ tx.setSender(this._address);
4891
+ const allRewards = [];
4892
+ for (const adapter of adapters) {
4893
+ try {
4894
+ const claimed = await adapter.addClaimRewardsToTx(tx, this._address);
4895
+ allRewards.push(...claimed);
4896
+ } catch {
4897
+ }
4898
+ }
4899
+ if (allRewards.length === 0) {
4900
+ return { success: true, tx: "", rewards: [], totalValueUsd: 0, gasCost: 0, gasMethod: "none" };
4901
+ }
4902
+ const gasResult = await executeWithGas(this.client, this.keypair, async () => tx);
4903
+ return {
4904
+ success: true,
4905
+ tx: gasResult.digest,
4906
+ rewards: allRewards,
4907
+ totalValueUsd: allRewards.reduce((s, r) => s + r.estimatedValueUsd, 0),
4908
+ gasCost: gasResult.gasCostSui,
4909
+ gasMethod: gasResult.gasMethod
4910
+ };
4911
+ }
4586
4912
  // -- Strategies --
4587
4913
  async investStrategy(params) {
4588
4914
  this.enforcer.assertNotLocked();