@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.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { I as InvestmentTrade, S as StrategyDefinition, A as AutoInvestSchedule, a as AutoInvestStatus, T as T2000Options, b as SendResult, B as BalanceResponse, c as TransactionRecord, D as DepositInfo, L as LendingAdapter, d as SwapAdapter, e as SaveResult, W as WithdrawResult, M as MaxWithdrawResult, f as BorrowResult, R as RepayResult, g as MaxBorrowResult, H as HealthFactorResult, h as SwapResult, i as InvestResult, j as InvestEarnResult, k as StrategyBuyResult, l as StrategySellResult, m as StrategyRebalanceResult, n as StrategyStatusResult, o as AutoInvestRunResult, P as PortfolioResult, p as InvestmentPosition, q as PositionsResult, r as RatesResult, s as LendingRates, t as RebalanceResult, E as EarningsResult, F as FundStatusResult, u as SentinelAgent, v as SentinelAttackResult, G as GasMethod } from './index-D4cFY__D.cjs';
2
- export { w as AdapterCapability, x as AdapterPositions, y as AdapterTxResult, z as AssetRates, C as CetusAdapter, J as GasReserve, K as HealthInfo, N as NaviAdapter, O as PerpsAdapter, Q as PerpsPosition, U as PositionEntry, V as PositionSide, X as ProtocolDescriptor, Y as ProtocolRegistry, Z as RebalanceStep, _ as SentinelVerdict, $ as SuilendAdapter, a0 as SwapQuote, a1 as TradePositionsResult, a2 as TradeResult, a3 as allDescriptors, a4 as cetusDescriptor, a5 as getSentinelInfo, a6 as listSentinels, a7 as naviDescriptor, a8 as requestAttack, a9 as sentinelAttack, aa as sentinelDescriptor, ab as settleAttack, ac as submitPrompt, ad as suilendDescriptor } from './index-D4cFY__D.cjs';
1
+ import { I as InvestmentTrade, S as StrategyDefinition, A as AutoInvestSchedule, a as AutoInvestStatus, T as T2000Options, b as SendResult, B as BalanceResponse, c as TransactionRecord, D as DepositInfo, L as LendingAdapter, d as SwapAdapter, e as SaveResult, W as WithdrawResult, M as MaxWithdrawResult, f as BorrowResult, R as RepayResult, g as MaxBorrowResult, H as HealthFactorResult, h as SwapResult, i as InvestResult, j as InvestEarnResult, P as PendingReward, C as ClaimRewardsResult, k as StrategyBuyResult, l as StrategySellResult, m as StrategyRebalanceResult, n as StrategyStatusResult, o as AutoInvestRunResult, p as PortfolioResult, q as InvestmentPosition, r as PositionsResult, s as RatesResult, t as LendingRates, u as RebalanceResult, E as EarningsResult, F as FundStatusResult, v as SentinelAgent, w as SentinelAttackResult, G as GasMethod } from './index-xQEri-Eu.cjs';
2
+ export { x as AdapterCapability, y as AdapterPositions, z as AdapterTxResult, J as AssetRates, K as CetusAdapter, N as GasReserve, O as HealthInfo, Q as NaviAdapter, U as PerpsAdapter, V as PerpsPosition, X as PositionEntry, Y as PositionSide, Z as ProtocolDescriptor, _ as ProtocolRegistry, $ as RebalanceStep, a0 as SentinelVerdict, a1 as SuilendAdapter, a2 as SwapQuote, a3 as TradePositionsResult, a4 as TradeResult, a5 as allDescriptors, a6 as cetusDescriptor, a7 as getSentinelInfo, a8 as listSentinels, a9 as naviDescriptor, aa as requestAttack, ab as sentinelAttack, ac as sentinelDescriptor, ad as settleAttack, ae as submitPrompt, af as suilendDescriptor } from './index-xQEri-Eu.cjs';
3
3
  import { EventEmitter } from 'eventemitter3';
4
4
  import { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';
5
5
  import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
@@ -461,6 +461,8 @@ declare class T2000 extends EventEmitter<T2000Events> {
461
461
  investUnearn(params: {
462
462
  asset: InvestmentAsset;
463
463
  }): Promise<InvestEarnResult>;
464
+ getPendingRewards(): Promise<PendingReward[]>;
465
+ claimRewards(): Promise<ClaimRewardsResult>;
464
466
  investStrategy(params: {
465
467
  strategy: string;
466
468
  usdAmount: number;
@@ -643,4 +645,4 @@ interface GasStatusResponse {
643
645
  }
644
646
  declare function getGasStatus(address?: string): Promise<GasStatusResponse>;
645
647
 
646
- export { AutoInvestManager, AutoInvestRunResult, AutoInvestSchedule, AutoInvestStatus, type AutoTopUpResult, BPS_DENOMINATOR, BalanceResponse, BorrowResult, CLOCK_ID, type Contact, ContactManager, type ContactMap, DEFAULT_MAX_LEVERAGE, DEFAULT_MAX_POSITION_SIZE, DEFAULT_NETWORK, DEFAULT_SAFEGUARD_CONFIG, DEFAULT_STRATEGIES, DepositInfo, EarningsResult, type FeeOperation, FundStatusResult, GAS_RESERVE_MIN, type GasExecutionResult, GasMethod, type GasRequestType, type GasSponsorResponse, type GasStatusResponse, HealthFactorResult, INVESTMENT_ASSETS, InvestEarnResult, InvestResult, type InvestmentAsset, InvestmentPosition, InvestmentTrade, LendingAdapter, LendingRates, MIST_PER_SUI, MaxBorrowResult, MaxWithdrawResult, OUTBOUND_OPS, PERPS_MARKETS, type PerpsMarket, PortfolioManager, PortfolioResult, PositionsResult, type ProtocolFeeInfo, RatesResult, RebalanceResult, RepayResult, SENTINEL, STABLE_ASSETS, SUI_DECIMALS, SUPPORTED_ASSETS, type SafeguardConfig, SafeguardEnforcer, SafeguardError, type SafeguardErrorDetails, type SafeguardRule, SaveResult, SendResult, SentinelAgent, SentinelAttackResult, type SimulationResult, type StableAsset, StrategyBuyResult, StrategyDefinition, StrategyManager, StrategyRebalanceResult, StrategySellResult, StrategyStatusResult, type SupportedAsset, SwapAdapter, SwapResult, T2000, T2000Error, type T2000ErrorCode, type T2000ErrorData, T2000Options, TransactionRecord, type TxMetadata, USDC_DECIMALS, WithdrawResult, addCollectFeeToTx, calculateFee, executeAutoTopUp, executeWithGas, exportPrivateKey, formatAssetAmount, formatSui, formatUsd, generateKeypair, getAddress, getDecimals, getGasStatus, getPoolPrice, getRates, keypairFromPrivateKey, loadKey, mapMoveAbortCode, mapWalletError, mistToSui, rawToStable, rawToUsdc, saveKey, shouldAutoTopUp, simulateTransaction, solveHashcash, stableToRaw, suiToMist, throwIfSimulationFailed, truncateAddress, usdcToRaw, validateAddress, walletExists };
648
+ export { AutoInvestManager, AutoInvestRunResult, AutoInvestSchedule, AutoInvestStatus, type AutoTopUpResult, BPS_DENOMINATOR, BalanceResponse, BorrowResult, CLOCK_ID, ClaimRewardsResult, type Contact, ContactManager, type ContactMap, DEFAULT_MAX_LEVERAGE, DEFAULT_MAX_POSITION_SIZE, DEFAULT_NETWORK, DEFAULT_SAFEGUARD_CONFIG, DEFAULT_STRATEGIES, DepositInfo, EarningsResult, type FeeOperation, FundStatusResult, GAS_RESERVE_MIN, type GasExecutionResult, GasMethod, type GasRequestType, type GasSponsorResponse, type GasStatusResponse, HealthFactorResult, INVESTMENT_ASSETS, InvestEarnResult, InvestResult, type InvestmentAsset, InvestmentPosition, InvestmentTrade, LendingAdapter, LendingRates, MIST_PER_SUI, MaxBorrowResult, MaxWithdrawResult, OUTBOUND_OPS, PERPS_MARKETS, PendingReward, type PerpsMarket, PortfolioManager, PortfolioResult, PositionsResult, type ProtocolFeeInfo, RatesResult, RebalanceResult, RepayResult, SENTINEL, STABLE_ASSETS, SUI_DECIMALS, SUPPORTED_ASSETS, type SafeguardConfig, SafeguardEnforcer, SafeguardError, type SafeguardErrorDetails, type SafeguardRule, SaveResult, SendResult, SentinelAgent, SentinelAttackResult, type SimulationResult, type StableAsset, StrategyBuyResult, StrategyDefinition, StrategyManager, StrategyRebalanceResult, StrategySellResult, StrategyStatusResult, type SupportedAsset, SwapAdapter, SwapResult, T2000, T2000Error, type T2000ErrorCode, type T2000ErrorData, T2000Options, TransactionRecord, type TxMetadata, USDC_DECIMALS, WithdrawResult, addCollectFeeToTx, calculateFee, executeAutoTopUp, executeWithGas, exportPrivateKey, formatAssetAmount, formatSui, formatUsd, generateKeypair, getAddress, getDecimals, getGasStatus, getPoolPrice, getRates, keypairFromPrivateKey, loadKey, mapMoveAbortCode, mapWalletError, mistToSui, rawToStable, rawToUsdc, saveKey, shouldAutoTopUp, simulateTransaction, solveHashcash, stableToRaw, suiToMist, throwIfSimulationFailed, truncateAddress, usdcToRaw, validateAddress, walletExists };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { I as InvestmentTrade, S as StrategyDefinition, A as AutoInvestSchedule, a as AutoInvestStatus, T as T2000Options, b as SendResult, B as BalanceResponse, c as TransactionRecord, D as DepositInfo, L as LendingAdapter, d as SwapAdapter, e as SaveResult, W as WithdrawResult, M as MaxWithdrawResult, f as BorrowResult, R as RepayResult, g as MaxBorrowResult, H as HealthFactorResult, h as SwapResult, i as InvestResult, j as InvestEarnResult, k as StrategyBuyResult, l as StrategySellResult, m as StrategyRebalanceResult, n as StrategyStatusResult, o as AutoInvestRunResult, P as PortfolioResult, p as InvestmentPosition, q as PositionsResult, r as RatesResult, s as LendingRates, t as RebalanceResult, E as EarningsResult, F as FundStatusResult, u as SentinelAgent, v as SentinelAttackResult, G as GasMethod } from './index-D4cFY__D.js';
2
- export { w as AdapterCapability, x as AdapterPositions, y as AdapterTxResult, z as AssetRates, C as CetusAdapter, J as GasReserve, K as HealthInfo, N as NaviAdapter, O as PerpsAdapter, Q as PerpsPosition, U as PositionEntry, V as PositionSide, X as ProtocolDescriptor, Y as ProtocolRegistry, Z as RebalanceStep, _ as SentinelVerdict, $ as SuilendAdapter, a0 as SwapQuote, a1 as TradePositionsResult, a2 as TradeResult, a3 as allDescriptors, a4 as cetusDescriptor, a5 as getSentinelInfo, a6 as listSentinels, a7 as naviDescriptor, a8 as requestAttack, a9 as sentinelAttack, aa as sentinelDescriptor, ab as settleAttack, ac as submitPrompt, ad as suilendDescriptor } from './index-D4cFY__D.js';
1
+ import { I as InvestmentTrade, S as StrategyDefinition, A as AutoInvestSchedule, a as AutoInvestStatus, T as T2000Options, b as SendResult, B as BalanceResponse, c as TransactionRecord, D as DepositInfo, L as LendingAdapter, d as SwapAdapter, e as SaveResult, W as WithdrawResult, M as MaxWithdrawResult, f as BorrowResult, R as RepayResult, g as MaxBorrowResult, H as HealthFactorResult, h as SwapResult, i as InvestResult, j as InvestEarnResult, P as PendingReward, C as ClaimRewardsResult, k as StrategyBuyResult, l as StrategySellResult, m as StrategyRebalanceResult, n as StrategyStatusResult, o as AutoInvestRunResult, p as PortfolioResult, q as InvestmentPosition, r as PositionsResult, s as RatesResult, t as LendingRates, u as RebalanceResult, E as EarningsResult, F as FundStatusResult, v as SentinelAgent, w as SentinelAttackResult, G as GasMethod } from './index-xQEri-Eu.js';
2
+ export { x as AdapterCapability, y as AdapterPositions, z as AdapterTxResult, J as AssetRates, K as CetusAdapter, N as GasReserve, O as HealthInfo, Q as NaviAdapter, U as PerpsAdapter, V as PerpsPosition, X as PositionEntry, Y as PositionSide, Z as ProtocolDescriptor, _ as ProtocolRegistry, $ as RebalanceStep, a0 as SentinelVerdict, a1 as SuilendAdapter, a2 as SwapQuote, a3 as TradePositionsResult, a4 as TradeResult, a5 as allDescriptors, a6 as cetusDescriptor, a7 as getSentinelInfo, a8 as listSentinels, a9 as naviDescriptor, aa as requestAttack, ab as sentinelAttack, ac as sentinelDescriptor, ad as settleAttack, ae as submitPrompt, af as suilendDescriptor } from './index-xQEri-Eu.js';
3
3
  import { EventEmitter } from 'eventemitter3';
4
4
  import { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';
5
5
  import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
@@ -461,6 +461,8 @@ declare class T2000 extends EventEmitter<T2000Events> {
461
461
  investUnearn(params: {
462
462
  asset: InvestmentAsset;
463
463
  }): Promise<InvestEarnResult>;
464
+ getPendingRewards(): Promise<PendingReward[]>;
465
+ claimRewards(): Promise<ClaimRewardsResult>;
464
466
  investStrategy(params: {
465
467
  strategy: string;
466
468
  usdAmount: number;
@@ -643,4 +645,4 @@ interface GasStatusResponse {
643
645
  }
644
646
  declare function getGasStatus(address?: string): Promise<GasStatusResponse>;
645
647
 
646
- export { AutoInvestManager, AutoInvestRunResult, AutoInvestSchedule, AutoInvestStatus, type AutoTopUpResult, BPS_DENOMINATOR, BalanceResponse, BorrowResult, CLOCK_ID, type Contact, ContactManager, type ContactMap, DEFAULT_MAX_LEVERAGE, DEFAULT_MAX_POSITION_SIZE, DEFAULT_NETWORK, DEFAULT_SAFEGUARD_CONFIG, DEFAULT_STRATEGIES, DepositInfo, EarningsResult, type FeeOperation, FundStatusResult, GAS_RESERVE_MIN, type GasExecutionResult, GasMethod, type GasRequestType, type GasSponsorResponse, type GasStatusResponse, HealthFactorResult, INVESTMENT_ASSETS, InvestEarnResult, InvestResult, type InvestmentAsset, InvestmentPosition, InvestmentTrade, LendingAdapter, LendingRates, MIST_PER_SUI, MaxBorrowResult, MaxWithdrawResult, OUTBOUND_OPS, PERPS_MARKETS, type PerpsMarket, PortfolioManager, PortfolioResult, PositionsResult, type ProtocolFeeInfo, RatesResult, RebalanceResult, RepayResult, SENTINEL, STABLE_ASSETS, SUI_DECIMALS, SUPPORTED_ASSETS, type SafeguardConfig, SafeguardEnforcer, SafeguardError, type SafeguardErrorDetails, type SafeguardRule, SaveResult, SendResult, SentinelAgent, SentinelAttackResult, type SimulationResult, type StableAsset, StrategyBuyResult, StrategyDefinition, StrategyManager, StrategyRebalanceResult, StrategySellResult, StrategyStatusResult, type SupportedAsset, SwapAdapter, SwapResult, T2000, T2000Error, type T2000ErrorCode, type T2000ErrorData, T2000Options, TransactionRecord, type TxMetadata, USDC_DECIMALS, WithdrawResult, addCollectFeeToTx, calculateFee, executeAutoTopUp, executeWithGas, exportPrivateKey, formatAssetAmount, formatSui, formatUsd, generateKeypair, getAddress, getDecimals, getGasStatus, getPoolPrice, getRates, keypairFromPrivateKey, loadKey, mapMoveAbortCode, mapWalletError, mistToSui, rawToStable, rawToUsdc, saveKey, shouldAutoTopUp, simulateTransaction, solveHashcash, stableToRaw, suiToMist, throwIfSimulationFailed, truncateAddress, usdcToRaw, validateAddress, walletExists };
648
+ export { AutoInvestManager, AutoInvestRunResult, AutoInvestSchedule, AutoInvestStatus, type AutoTopUpResult, BPS_DENOMINATOR, BalanceResponse, BorrowResult, CLOCK_ID, ClaimRewardsResult, type Contact, ContactManager, type ContactMap, DEFAULT_MAX_LEVERAGE, DEFAULT_MAX_POSITION_SIZE, DEFAULT_NETWORK, DEFAULT_SAFEGUARD_CONFIG, DEFAULT_STRATEGIES, DepositInfo, EarningsResult, type FeeOperation, FundStatusResult, GAS_RESERVE_MIN, type GasExecutionResult, GasMethod, type GasRequestType, type GasSponsorResponse, type GasStatusResponse, HealthFactorResult, INVESTMENT_ASSETS, InvestEarnResult, InvestResult, type InvestmentAsset, InvestmentPosition, InvestmentTrade, LendingAdapter, LendingRates, MIST_PER_SUI, MaxBorrowResult, MaxWithdrawResult, OUTBOUND_OPS, PERPS_MARKETS, PendingReward, type PerpsMarket, PortfolioManager, PortfolioResult, PositionsResult, type ProtocolFeeInfo, RatesResult, RebalanceResult, RepayResult, SENTINEL, STABLE_ASSETS, SUI_DECIMALS, SUPPORTED_ASSETS, type SafeguardConfig, SafeguardEnforcer, SafeguardError, type SafeguardErrorDetails, type SafeguardRule, SaveResult, SendResult, SentinelAgent, SentinelAttackResult, type SimulationResult, type StableAsset, StrategyBuyResult, StrategyDefinition, StrategyManager, StrategyRebalanceResult, StrategySellResult, StrategyStatusResult, type SupportedAsset, SwapAdapter, SwapResult, T2000, T2000Error, type T2000ErrorCode, type T2000ErrorData, T2000Options, TransactionRecord, type TxMetadata, USDC_DECIMALS, WithdrawResult, addCollectFeeToTx, calculateFee, executeAutoTopUp, executeWithGas, exportPrivateKey, formatAssetAmount, formatSui, formatUsd, generateKeypair, getAddress, getDecimals, getGasStatus, getPoolPrice, getRates, keypairFromPrivateKey, loadKey, mapMoveAbortCode, mapWalletError, mistToSui, rawToStable, rawToUsdc, saveKey, shouldAutoTopUp, simulateTransaction, solveHashcash, stableToRaw, suiToMist, throwIfSimulationFailed, truncateAddress, usdcToRaw, validateAddress, walletExists };
package/dist/index.js CHANGED
@@ -493,6 +493,7 @@ async function queryBalance(client, address) {
493
493
  debt: 0,
494
494
  investment: 0,
495
495
  investmentPnL: 0,
496
+ pendingRewards: 0,
496
497
  gasReserve: {
497
498
  sui: suiAmount,
498
499
  usdEquiv
@@ -1176,6 +1177,173 @@ async function maxBorrowAmount(client, addressOrKeypair) {
1176
1177
  const maxAmount = Math.max(0, hf.supplied * ltv / MIN_HEALTH_FACTOR - hf.borrowed);
1177
1178
  return { maxAmount, healthFactorAfter: MIN_HEALTH_FACTOR, currentHF: hf.healthFactor };
1178
1179
  }
1180
+ var CERT_TYPE = "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT";
1181
+ var DEEP_TYPE = "0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP";
1182
+ var REWARD_FUNDS = {
1183
+ [CERT_TYPE]: "0x7093cf7549d5e5b35bfde2177223d1050f71655c7f676a5e610ee70eb4d93b5c",
1184
+ [DEEP_TYPE]: "0xc889d78b634f954979e80e622a2ae0fece824c0f6d9590044378a2563035f32f"
1185
+ };
1186
+ var REWARD_SYMBOLS = {
1187
+ [CERT_TYPE]: "vSUI",
1188
+ [DEEP_TYPE]: "DEEP"
1189
+ };
1190
+ var incentiveRulesCache = null;
1191
+ async function getIncentiveRules(client) {
1192
+ if (incentiveRulesCache && Date.now() - incentiveRulesCache.ts < CACHE_TTL) {
1193
+ return incentiveRulesCache.data;
1194
+ }
1195
+ const [pools, obj] = await Promise.all([
1196
+ getPools(),
1197
+ client.getObject({
1198
+ id: "0x62982dad27fb10bb314b3384d5de8d2ac2d72ab2dbeae5d801dbdb9efa816c80",
1199
+ options: { showContent: true }
1200
+ })
1201
+ ]);
1202
+ const rewardCoinMap = /* @__PURE__ */ new Map();
1203
+ for (const pool of pools) {
1204
+ const ct = (pool.suiCoinType || pool.coinType || "").toLowerCase();
1205
+ const suffix = ct.split("::").slice(1).join("::");
1206
+ const coins = pool.supplyIncentiveApyInfo?.rewardCoin;
1207
+ if (Array.isArray(coins) && coins.length > 0) {
1208
+ rewardCoinMap.set(suffix, coins[0]);
1209
+ }
1210
+ }
1211
+ const result = /* @__PURE__ */ new Map();
1212
+ if (obj.data?.content?.dataType !== "moveObject") {
1213
+ incentiveRulesCache = { data: result, ts: Date.now() };
1214
+ return result;
1215
+ }
1216
+ const fields = obj.data.content.fields;
1217
+ const poolsObj = fields.pools;
1218
+ const entries = poolsObj?.fields?.contents;
1219
+ if (!Array.isArray(entries)) {
1220
+ incentiveRulesCache = { data: result, ts: Date.now() };
1221
+ return result;
1222
+ }
1223
+ for (const entry of entries) {
1224
+ const ef = entry?.fields;
1225
+ if (!ef) continue;
1226
+ const key = String(ef.key ?? "");
1227
+ const value = ef.value;
1228
+ const rules = value?.fields?.rules;
1229
+ const ruleEntries = rules?.fields?.contents;
1230
+ if (!Array.isArray(ruleEntries)) continue;
1231
+ const ruleIds = ruleEntries.map((re) => {
1232
+ const rf = re?.fields;
1233
+ return String(rf?.key ?? "");
1234
+ }).filter(Boolean);
1235
+ const suffix = key.split("::").slice(1).join("::").toLowerCase();
1236
+ const full = key.toLowerCase();
1237
+ const rewardCoin = rewardCoinMap.get(suffix) ?? rewardCoinMap.get(full) ?? null;
1238
+ result.set(key, { ruleIds, rewardCoinType: rewardCoin });
1239
+ }
1240
+ incentiveRulesCache = { data: result, ts: Date.now() };
1241
+ return result;
1242
+ }
1243
+ function stripPrefix(coinType) {
1244
+ return coinType.replace(/^0x0*/, "");
1245
+ }
1246
+ async function getPendingRewards(client, address) {
1247
+ const [pools, states, rules] = await Promise.all([
1248
+ getPools(),
1249
+ getUserState(client, address),
1250
+ getIncentiveRules(client)
1251
+ ]);
1252
+ const rewards = [];
1253
+ const deposited = states.filter((s) => s.supplyBalance > 0n);
1254
+ if (deposited.length === 0) return rewards;
1255
+ const rewardTotals = /* @__PURE__ */ new Map();
1256
+ for (const state of deposited) {
1257
+ const pool = pools.find((p) => p.id === state.assetId);
1258
+ if (!pool) continue;
1259
+ const boostedApr = parseFloat(pool.supplyIncentiveApyInfo?.boostedApr ?? "0");
1260
+ if (boostedApr <= 0) continue;
1261
+ const rewardCoins = pool.supplyIncentiveApyInfo?.rewardCoin;
1262
+ if (!Array.isArray(rewardCoins) || rewardCoins.length === 0) continue;
1263
+ const rewardType = rewardCoins[0];
1264
+ const supplyBal = compoundBalance(state.supplyBalance, pool.currentSupplyIndex, pool);
1265
+ const price = pool.token?.price ?? 0;
1266
+ const depositUsd = supplyBal * price;
1267
+ const annualRewardUsd = depositUsd * (boostedApr / 100);
1268
+ const estimatedUsd = annualRewardUsd / 365;
1269
+ rewardTotals.set(rewardType, (rewardTotals.get(rewardType) ?? 0) + estimatedUsd);
1270
+ }
1271
+ for (const [coinType, dailyUsd] of rewardTotals) {
1272
+ if (dailyUsd < 1e-3) continue;
1273
+ rewards.push({
1274
+ protocol: "navi",
1275
+ coinType,
1276
+ symbol: REWARD_SYMBOLS[coinType] ?? coinType.split("::").pop() ?? "UNKNOWN",
1277
+ amount: 0,
1278
+ estimatedValueUsd: dailyUsd
1279
+ });
1280
+ }
1281
+ return rewards;
1282
+ }
1283
+ async function addClaimRewardsToTx(tx, client, address) {
1284
+ const [config, pools, states, rules] = await Promise.all([
1285
+ getConfig(),
1286
+ getPools(),
1287
+ getUserState(client, address),
1288
+ getIncentiveRules(client)
1289
+ ]);
1290
+ const deposited = states.filter((s) => s.supplyBalance > 0n);
1291
+ if (deposited.length === 0) return [];
1292
+ const claimGroups = /* @__PURE__ */ new Map();
1293
+ for (const state of deposited) {
1294
+ const pool = pools.find((p) => p.id === state.assetId);
1295
+ if (!pool) continue;
1296
+ const boostedApr = parseFloat(pool.supplyIncentiveApyInfo?.boostedApr ?? "0");
1297
+ if (boostedApr <= 0) continue;
1298
+ const rewardCoins = pool.supplyIncentiveApyInfo?.rewardCoin;
1299
+ if (!Array.isArray(rewardCoins) || rewardCoins.length === 0) continue;
1300
+ const rewardType = rewardCoins[0];
1301
+ const fundId = REWARD_FUNDS[rewardType];
1302
+ if (!fundId) continue;
1303
+ const coinType = pool.suiCoinType || pool.coinType || "";
1304
+ const strippedType = stripPrefix(coinType);
1305
+ const ruleData = Array.from(rules.entries()).find(
1306
+ ([key]) => stripPrefix(key) === strippedType || key.split("::").slice(1).join("::").toLowerCase() === coinType.split("::").slice(1).join("::").toLowerCase()
1307
+ );
1308
+ if (!ruleData || ruleData[1].ruleIds.length === 0) continue;
1309
+ const group = claimGroups.get(rewardType) ?? { assets: [], ruleIds: [] };
1310
+ for (const ruleId of ruleData[1].ruleIds) {
1311
+ group.assets.push(strippedType);
1312
+ group.ruleIds.push(ruleId);
1313
+ }
1314
+ claimGroups.set(rewardType, group);
1315
+ }
1316
+ const claimed = [];
1317
+ for (const [rewardType, { assets, ruleIds }] of claimGroups) {
1318
+ const fundId = REWARD_FUNDS[rewardType];
1319
+ const [balance] = tx.moveCall({
1320
+ target: `${config.package}::incentive_v3::claim_reward`,
1321
+ typeArguments: [rewardType],
1322
+ arguments: [
1323
+ tx.object(CLOCK),
1324
+ tx.object(config.incentiveV3),
1325
+ tx.object(config.storage),
1326
+ tx.object(fundId),
1327
+ tx.pure(bcs.vector(bcs.string()).serialize(assets)),
1328
+ tx.pure(bcs.vector(bcs.Address).serialize(ruleIds))
1329
+ ]
1330
+ });
1331
+ const [coin] = tx.moveCall({
1332
+ target: "0x2::coin::from_balance",
1333
+ typeArguments: [rewardType],
1334
+ arguments: [balance]
1335
+ });
1336
+ tx.transferObjects([coin], address);
1337
+ claimed.push({
1338
+ protocol: "navi",
1339
+ coinType: rewardType,
1340
+ symbol: REWARD_SYMBOLS[rewardType] ?? "UNKNOWN",
1341
+ amount: 0,
1342
+ estimatedValueUsd: 0
1343
+ });
1344
+ }
1345
+ return claimed;
1346
+ }
1179
1347
 
1180
1348
  // src/protocols/yieldTracker.ts
1181
1349
  async function getEarnings(client, keypair) {
@@ -1623,6 +1791,12 @@ var NaviAdapter = class {
1623
1791
  const normalized = normalizeAsset(asset);
1624
1792
  return addRepayToTx(tx, this.client, address, coin, { asset: normalized });
1625
1793
  }
1794
+ async getPendingRewards(address) {
1795
+ return getPendingRewards(this.client, address);
1796
+ }
1797
+ async addClaimRewardsToTx(tx, address) {
1798
+ return addClaimRewardsToTx(tx, this.client, address);
1799
+ }
1626
1800
  };
1627
1801
  var DEFAULT_SLIPPAGE_BPS = 300;
1628
1802
  function createAggregatorClient(client, signer) {
@@ -1948,15 +2122,17 @@ function parseReserve(raw, index) {
1948
2122
  const dMgr = f(r.deposits_pool_reward_manager);
1949
2123
  const rawRewards = Array.isArray(dMgr?.pool_rewards) ? dMgr.pool_rewards : [];
1950
2124
  const now = Date.now();
1951
- const depositPoolRewards = rawRewards.filter((rw) => rw !== null).map((rw) => {
2125
+ const depositPoolRewards = rawRewards.map((rw, idx) => {
2126
+ if (rw === null) return null;
1952
2127
  const rwf = f(rw);
1953
2128
  return {
1954
2129
  coinType: str(f(rwf.coin_type)?.name),
1955
2130
  totalRewards: num(rwf.total_rewards),
1956
2131
  startTimeMs: num(rwf.start_time_ms),
1957
- endTimeMs: num(rwf.end_time_ms)
2132
+ endTimeMs: num(rwf.end_time_ms),
2133
+ rewardIndex: idx
1958
2134
  };
1959
- }).filter((rw) => rw.endTimeMs > now && rw.totalRewards > 0);
2135
+ }).filter((rw) => rw !== null && rw.endTimeMs > now && rw.totalRewards > 0);
1960
2136
  return {
1961
2137
  coinType: str(coinTypeField?.name),
1962
2138
  mintDecimals: num(r.mint_decimals),
@@ -2507,6 +2683,109 @@ var SuilendAdapter = class {
2507
2683
  }
2508
2684
  return all;
2509
2685
  }
2686
+ // -- Claim Rewards --------------------------------------------------------
2687
+ isClaimableReward(coinType) {
2688
+ const ct = coinType.toLowerCase();
2689
+ return ct.includes("spring_sui") || ct.includes("deep::deep") || ct.includes("cert::cert");
2690
+ }
2691
+ async getPendingRewards(address) {
2692
+ const caps = await this.fetchObligationCaps(address);
2693
+ if (caps.length === 0) return [];
2694
+ const [reserves, obligation] = await Promise.all([
2695
+ this.loadReserves(true),
2696
+ this.fetchObligation(caps[0].obligationId)
2697
+ ]);
2698
+ const rewards = [];
2699
+ const rewardEstimates = /* @__PURE__ */ new Map();
2700
+ for (const dep of obligation.deposits) {
2701
+ const reserve = reserves[dep.reserveIdx];
2702
+ if (!reserve) continue;
2703
+ const ratio = cTokenRatio(reserve);
2704
+ const amount = dep.ctokenAmount * ratio / 10 ** reserve.mintDecimals;
2705
+ const price = reserve.price;
2706
+ const depositUsd = amount * price;
2707
+ for (const rw of reserve.depositPoolRewards) {
2708
+ if (!this.isClaimableReward(rw.coinType)) continue;
2709
+ const rewardReserve = reserves.find((r) => {
2710
+ try {
2711
+ return normalizeStructTag(r.coinType) === normalizeStructTag(rw.coinType);
2712
+ } catch {
2713
+ return false;
2714
+ }
2715
+ });
2716
+ const rewardPrice = rewardReserve?.price ?? 0;
2717
+ const rewardDecimals = rewardReserve?.mintDecimals ?? 9;
2718
+ const durationMs = rw.endTimeMs - rw.startTimeMs;
2719
+ if (durationMs <= 0) continue;
2720
+ const annualTokens = rw.totalRewards / 10 ** rewardDecimals * (MS_PER_YEAR / durationMs);
2721
+ const totalDepositValue = reserve.depositTotalShares / 10 ** reserve.mintDecimals * price;
2722
+ if (totalDepositValue <= 0) continue;
2723
+ const userShare = depositUsd / totalDepositValue;
2724
+ const dailyRewardUsd = annualTokens * rewardPrice / 365 * userShare;
2725
+ rewardEstimates.set(rw.coinType, (rewardEstimates.get(rw.coinType) ?? 0) + dailyRewardUsd);
2726
+ }
2727
+ }
2728
+ for (const [coinType, dailyUsd] of rewardEstimates) {
2729
+ if (dailyUsd < 1e-3) continue;
2730
+ const symbol = coinType.includes("spring_sui") ? "SPRING_SUI" : coinType.includes("deep::") ? "DEEP" : coinType.split("::").pop() ?? "UNKNOWN";
2731
+ rewards.push({
2732
+ protocol: "suilend",
2733
+ coinType,
2734
+ symbol,
2735
+ amount: 0,
2736
+ estimatedValueUsd: dailyUsd
2737
+ });
2738
+ }
2739
+ return rewards;
2740
+ }
2741
+ async addClaimRewardsToTx(tx, address) {
2742
+ const caps = await this.fetchObligationCaps(address);
2743
+ if (caps.length === 0) return [];
2744
+ const [pkg, reserves, obligation] = await Promise.all([
2745
+ this.resolvePackage(),
2746
+ this.loadReserves(true),
2747
+ this.fetchObligation(caps[0].obligationId)
2748
+ ]);
2749
+ const claimsByToken = /* @__PURE__ */ new Map();
2750
+ const claimed = [];
2751
+ for (const dep of obligation.deposits) {
2752
+ const reserve = reserves[dep.reserveIdx];
2753
+ if (!reserve) continue;
2754
+ for (const rw of reserve.depositPoolRewards) {
2755
+ if (!this.isClaimableReward(rw.coinType)) continue;
2756
+ const [coin] = tx.moveCall({
2757
+ target: `${pkg}::lending_market::claim_rewards`,
2758
+ typeArguments: [LENDING_MARKET_TYPE, rw.coinType],
2759
+ arguments: [
2760
+ tx.object(LENDING_MARKET_ID),
2761
+ tx.object(caps[0].id),
2762
+ tx.object(CLOCK2),
2763
+ tx.pure.u64(reserve.arrayIndex),
2764
+ tx.pure.u64(rw.rewardIndex),
2765
+ tx.pure.bool(true)
2766
+ ]
2767
+ });
2768
+ const existing = claimsByToken.get(rw.coinType) ?? [];
2769
+ existing.push(coin);
2770
+ claimsByToken.set(rw.coinType, existing);
2771
+ }
2772
+ }
2773
+ for (const [coinType, coins] of claimsByToken) {
2774
+ if (coins.length > 1) {
2775
+ tx.mergeCoins(coins[0], coins.slice(1));
2776
+ }
2777
+ tx.transferObjects([coins[0]], address);
2778
+ const symbol = coinType.includes("spring_sui") ? "SPRING_SUI" : coinType.includes("deep::") ? "DEEP" : coinType.split("::").pop() ?? "UNKNOWN";
2779
+ claimed.push({
2780
+ protocol: "suilend",
2781
+ coinType,
2782
+ symbol,
2783
+ amount: 0,
2784
+ estimatedValueUsd: 0
2785
+ });
2786
+ }
2787
+ return claimed;
2788
+ }
2510
2789
  };
2511
2790
  function hasLeadingZeroBits(hash, bits) {
2512
2791
  const fullBytes = Math.floor(bits / 8);
@@ -3632,6 +3911,12 @@ To access invested funds: t2000 invest sell ${params.amount} ${asset}`,
3632
3911
  bal.investment = 0;
3633
3912
  bal.investmentPnL = 0;
3634
3913
  }
3914
+ try {
3915
+ const pendingRewards = await this.getPendingRewards();
3916
+ bal.pendingRewards = pendingRewards.reduce((s, r) => s + r.estimatedValueUsd, 0);
3917
+ } catch {
3918
+ bal.pendingRewards = 0;
3919
+ }
3635
3920
  bal.total = bal.available + bal.savings - bal.debt + bal.investment + bal.gasReserve.usdEquiv;
3636
3921
  return bal;
3637
3922
  }
@@ -4581,6 +4866,47 @@ To sell investment: t2000 invest sell ${params.amount} ${fromAsset}`,
4581
4866
  gasMethod: gasResult.gasMethod
4582
4867
  };
4583
4868
  }
4869
+ // -- Claim Rewards --
4870
+ async getPendingRewards() {
4871
+ const adapters = this.registry.listLending();
4872
+ const results = await Promise.allSettled(
4873
+ adapters.filter((a) => a.getPendingRewards).map((a) => a.getPendingRewards(this._address))
4874
+ );
4875
+ const all = [];
4876
+ for (const r of results) {
4877
+ if (r.status === "fulfilled") all.push(...r.value);
4878
+ }
4879
+ return all;
4880
+ }
4881
+ async claimRewards() {
4882
+ this.enforcer.assertNotLocked();
4883
+ const adapters = this.registry.listLending().filter((a) => a.addClaimRewardsToTx);
4884
+ if (adapters.length === 0) {
4885
+ return { success: true, tx: "", rewards: [], totalValueUsd: 0, gasCost: 0, gasMethod: "none" };
4886
+ }
4887
+ const tx = new Transaction();
4888
+ tx.setSender(this._address);
4889
+ const allRewards = [];
4890
+ for (const adapter of adapters) {
4891
+ try {
4892
+ const claimed = await adapter.addClaimRewardsToTx(tx, this._address);
4893
+ allRewards.push(...claimed);
4894
+ } catch {
4895
+ }
4896
+ }
4897
+ if (allRewards.length === 0) {
4898
+ return { success: true, tx: "", rewards: [], totalValueUsd: 0, gasCost: 0, gasMethod: "none" };
4899
+ }
4900
+ const gasResult = await executeWithGas(this.client, this.keypair, async () => tx);
4901
+ return {
4902
+ success: true,
4903
+ tx: gasResult.digest,
4904
+ rewards: allRewards,
4905
+ totalValueUsd: allRewards.reduce((s, r) => s + r.estimatedValueUsd, 0),
4906
+ gasCost: gasResult.gasCostSui,
4907
+ gasMethod: gasResult.gasMethod
4908
+ };
4909
+ }
4584
4910
  // -- Strategies --
4585
4911
  async investStrategy(params) {
4586
4912
  this.enforcer.assertNotLocked();