@t2000/sdk 0.17.14 → 0.17.16
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/adapters/index.cjs +279 -3
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.d.cts +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +279 -3
- package/dist/adapters/index.js.map +1 -1
- package/dist/{index-D4cFY__D.d.cts → index-xQEri-Eu.d.cts} +31 -1
- package/dist/{index-D4cFY__D.d.ts → index-xQEri-Eu.d.ts} +31 -1
- package/dist/index.cjs +327 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +327 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -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 {
|
|
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 {
|
|
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,172 @@ 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
|
+
rewards.push({
|
|
1275
|
+
protocol: "navi",
|
|
1276
|
+
coinType,
|
|
1277
|
+
symbol: REWARD_SYMBOLS[coinType] ?? coinType.split("::").pop() ?? "UNKNOWN",
|
|
1278
|
+
amount: 0,
|
|
1279
|
+
estimatedValueUsd: dailyUsd
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
return rewards;
|
|
1283
|
+
}
|
|
1284
|
+
async function addClaimRewardsToTx(tx, client, address) {
|
|
1285
|
+
const [config, pools, states, rules] = await Promise.all([
|
|
1286
|
+
getConfig(),
|
|
1287
|
+
getPools(),
|
|
1288
|
+
getUserState(client, address),
|
|
1289
|
+
getIncentiveRules(client)
|
|
1290
|
+
]);
|
|
1291
|
+
const deposited = states.filter((s) => s.supplyBalance > 0n);
|
|
1292
|
+
if (deposited.length === 0) return [];
|
|
1293
|
+
const claimGroups = /* @__PURE__ */ new Map();
|
|
1294
|
+
for (const state of deposited) {
|
|
1295
|
+
const pool = pools.find((p) => p.id === state.assetId);
|
|
1296
|
+
if (!pool) continue;
|
|
1297
|
+
const boostedApr = parseFloat(pool.supplyIncentiveApyInfo?.boostedApr ?? "0");
|
|
1298
|
+
if (boostedApr <= 0) continue;
|
|
1299
|
+
const rewardCoins = pool.supplyIncentiveApyInfo?.rewardCoin;
|
|
1300
|
+
if (!Array.isArray(rewardCoins) || rewardCoins.length === 0) continue;
|
|
1301
|
+
const rewardType = rewardCoins[0];
|
|
1302
|
+
const fundId = REWARD_FUNDS[rewardType];
|
|
1303
|
+
if (!fundId) continue;
|
|
1304
|
+
const coinType = pool.suiCoinType || pool.coinType || "";
|
|
1305
|
+
const strippedType = stripPrefix(coinType);
|
|
1306
|
+
const ruleData = Array.from(rules.entries()).find(
|
|
1307
|
+
([key]) => stripPrefix(key) === strippedType || key.split("::").slice(1).join("::").toLowerCase() === coinType.split("::").slice(1).join("::").toLowerCase()
|
|
1308
|
+
);
|
|
1309
|
+
if (!ruleData || ruleData[1].ruleIds.length === 0) continue;
|
|
1310
|
+
const group = claimGroups.get(rewardType) ?? { assets: [], ruleIds: [] };
|
|
1311
|
+
for (const ruleId of ruleData[1].ruleIds) {
|
|
1312
|
+
group.assets.push(strippedType);
|
|
1313
|
+
group.ruleIds.push(ruleId);
|
|
1314
|
+
}
|
|
1315
|
+
claimGroups.set(rewardType, group);
|
|
1316
|
+
}
|
|
1317
|
+
const claimed = [];
|
|
1318
|
+
for (const [rewardType, { assets, ruleIds }] of claimGroups) {
|
|
1319
|
+
const fundId = REWARD_FUNDS[rewardType];
|
|
1320
|
+
const [balance] = tx.moveCall({
|
|
1321
|
+
target: `${config.package}::incentive_v3::claim_reward`,
|
|
1322
|
+
typeArguments: [rewardType],
|
|
1323
|
+
arguments: [
|
|
1324
|
+
tx.object(CLOCK),
|
|
1325
|
+
tx.object(config.incentiveV3),
|
|
1326
|
+
tx.object(config.storage),
|
|
1327
|
+
tx.object(fundId),
|
|
1328
|
+
tx.pure(bcs.bcs.vector(bcs.bcs.string()).serialize(assets)),
|
|
1329
|
+
tx.pure(bcs.bcs.vector(bcs.bcs.Address).serialize(ruleIds))
|
|
1330
|
+
]
|
|
1331
|
+
});
|
|
1332
|
+
const [coin] = tx.moveCall({
|
|
1333
|
+
target: "0x2::coin::from_balance",
|
|
1334
|
+
typeArguments: [rewardType],
|
|
1335
|
+
arguments: [balance]
|
|
1336
|
+
});
|
|
1337
|
+
tx.transferObjects([coin], address);
|
|
1338
|
+
claimed.push({
|
|
1339
|
+
protocol: "navi",
|
|
1340
|
+
coinType: rewardType,
|
|
1341
|
+
symbol: REWARD_SYMBOLS[rewardType] ?? "UNKNOWN",
|
|
1342
|
+
amount: 0,
|
|
1343
|
+
estimatedValueUsd: 0
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
return claimed;
|
|
1347
|
+
}
|
|
1181
1348
|
|
|
1182
1349
|
// src/protocols/yieldTracker.ts
|
|
1183
1350
|
async function getEarnings(client, keypair) {
|
|
@@ -1625,6 +1792,12 @@ var NaviAdapter = class {
|
|
|
1625
1792
|
const normalized = normalizeAsset(asset);
|
|
1626
1793
|
return addRepayToTx(tx, this.client, address, coin, { asset: normalized });
|
|
1627
1794
|
}
|
|
1795
|
+
async getPendingRewards(address) {
|
|
1796
|
+
return getPendingRewards(this.client, address);
|
|
1797
|
+
}
|
|
1798
|
+
async addClaimRewardsToTx(tx, address) {
|
|
1799
|
+
return addClaimRewardsToTx(tx, this.client, address);
|
|
1800
|
+
}
|
|
1628
1801
|
};
|
|
1629
1802
|
var DEFAULT_SLIPPAGE_BPS = 300;
|
|
1630
1803
|
function createAggregatorClient(client, signer) {
|
|
@@ -1950,15 +2123,17 @@ function parseReserve(raw, index) {
|
|
|
1950
2123
|
const dMgr = f(r.deposits_pool_reward_manager);
|
|
1951
2124
|
const rawRewards = Array.isArray(dMgr?.pool_rewards) ? dMgr.pool_rewards : [];
|
|
1952
2125
|
const now = Date.now();
|
|
1953
|
-
const depositPoolRewards = rawRewards.
|
|
2126
|
+
const depositPoolRewards = rawRewards.map((rw, idx) => {
|
|
2127
|
+
if (rw === null) return null;
|
|
1954
2128
|
const rwf = f(rw);
|
|
1955
2129
|
return {
|
|
1956
2130
|
coinType: str(f(rwf.coin_type)?.name),
|
|
1957
2131
|
totalRewards: num(rwf.total_rewards),
|
|
1958
2132
|
startTimeMs: num(rwf.start_time_ms),
|
|
1959
|
-
endTimeMs: num(rwf.end_time_ms)
|
|
2133
|
+
endTimeMs: num(rwf.end_time_ms),
|
|
2134
|
+
rewardIndex: idx
|
|
1960
2135
|
};
|
|
1961
|
-
}).filter((rw) => rw.endTimeMs > now && rw.totalRewards > 0);
|
|
2136
|
+
}).filter((rw) => rw !== null && rw.endTimeMs > now && rw.totalRewards > 0);
|
|
1962
2137
|
return {
|
|
1963
2138
|
coinType: str(coinTypeField?.name),
|
|
1964
2139
|
mintDecimals: num(r.mint_decimals),
|
|
@@ -2509,6 +2684,108 @@ var SuilendAdapter = class {
|
|
|
2509
2684
|
}
|
|
2510
2685
|
return all;
|
|
2511
2686
|
}
|
|
2687
|
+
// -- Claim Rewards --------------------------------------------------------
|
|
2688
|
+
isClaimableReward(coinType) {
|
|
2689
|
+
const ct = coinType.toLowerCase();
|
|
2690
|
+
return ct.includes("spring_sui") || ct.includes("deep::deep") || ct.includes("cert::cert");
|
|
2691
|
+
}
|
|
2692
|
+
async getPendingRewards(address) {
|
|
2693
|
+
const caps = await this.fetchObligationCaps(address);
|
|
2694
|
+
if (caps.length === 0) return [];
|
|
2695
|
+
const [reserves, obligation] = await Promise.all([
|
|
2696
|
+
this.loadReserves(true),
|
|
2697
|
+
this.fetchObligation(caps[0].obligationId)
|
|
2698
|
+
]);
|
|
2699
|
+
const rewards = [];
|
|
2700
|
+
const rewardEstimates = /* @__PURE__ */ new Map();
|
|
2701
|
+
for (const dep of obligation.deposits) {
|
|
2702
|
+
const reserve = reserves[dep.reserveIdx];
|
|
2703
|
+
if (!reserve) continue;
|
|
2704
|
+
const ratio = cTokenRatio(reserve);
|
|
2705
|
+
const amount = dep.ctokenAmount * ratio / 10 ** reserve.mintDecimals;
|
|
2706
|
+
const price = reserve.price;
|
|
2707
|
+
const depositUsd = amount * price;
|
|
2708
|
+
for (const rw of reserve.depositPoolRewards) {
|
|
2709
|
+
if (!this.isClaimableReward(rw.coinType)) continue;
|
|
2710
|
+
const rewardReserve = reserves.find((r) => {
|
|
2711
|
+
try {
|
|
2712
|
+
return utils.normalizeStructTag(r.coinType) === utils.normalizeStructTag(rw.coinType);
|
|
2713
|
+
} catch {
|
|
2714
|
+
return false;
|
|
2715
|
+
}
|
|
2716
|
+
});
|
|
2717
|
+
const rewardPrice = rewardReserve?.price ?? 0;
|
|
2718
|
+
const rewardDecimals = rewardReserve?.mintDecimals ?? 9;
|
|
2719
|
+
const durationMs = rw.endTimeMs - rw.startTimeMs;
|
|
2720
|
+
if (durationMs <= 0) continue;
|
|
2721
|
+
const annualTokens = rw.totalRewards / 10 ** rewardDecimals * (MS_PER_YEAR / durationMs);
|
|
2722
|
+
const totalDepositValue = reserve.depositTotalShares / 10 ** reserve.mintDecimals * price;
|
|
2723
|
+
if (totalDepositValue <= 0) continue;
|
|
2724
|
+
const userShare = depositUsd / totalDepositValue;
|
|
2725
|
+
const dailyRewardUsd = annualTokens * rewardPrice / 365 * userShare;
|
|
2726
|
+
rewardEstimates.set(rw.coinType, (rewardEstimates.get(rw.coinType) ?? 0) + dailyRewardUsd);
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
for (const [coinType, dailyUsd] of rewardEstimates) {
|
|
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
|
+
}
|
|
2512
2789
|
};
|
|
2513
2790
|
function hasLeadingZeroBits(hash, bits) {
|
|
2514
2791
|
const fullBytes = Math.floor(bits / 8);
|
|
@@ -3634,6 +3911,12 @@ To access invested funds: t2000 invest sell ${params.amount} ${asset}`,
|
|
|
3634
3911
|
bal.investment = 0;
|
|
3635
3912
|
bal.investmentPnL = 0;
|
|
3636
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
|
+
}
|
|
3637
3920
|
bal.total = bal.available + bal.savings - bal.debt + bal.investment + bal.gasReserve.usdEquiv;
|
|
3638
3921
|
return bal;
|
|
3639
3922
|
}
|
|
@@ -4583,6 +4866,47 @@ To sell investment: t2000 invest sell ${params.amount} ${fromAsset}`,
|
|
|
4583
4866
|
gasMethod: gasResult.gasMethod
|
|
4584
4867
|
};
|
|
4585
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 transactions.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
|
+
}
|
|
4586
4910
|
// -- Strategies --
|
|
4587
4911
|
async investStrategy(params) {
|
|
4588
4912
|
this.enforcer.assertNotLocked();
|