@t2000/sdk 1.23.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5101,35 +5101,6 @@ async function vt(e, n) {
5101
5101
  );
5102
5102
  return await De(e, t, n);
5103
5103
  }
5104
- function wt(e) {
5105
- const n = /* @__PURE__ */ new Map();
5106
- e.forEach((r) => {
5107
- const t = r.assetId, a = r.option, s = `${t}-${a}-${r.rewardCoinType}-${r.market}`;
5108
- n.has(s) ? n.get(s).total += r.userClaimableReward : n.set(s, {
5109
- assetId: t,
5110
- rewardType: a,
5111
- coinType: r.rewardCoinType,
5112
- total: Number(r.userClaimableReward),
5113
- market: r.market
5114
- });
5115
- });
5116
- const o = /* @__PURE__ */ new Map();
5117
- for (const { assetId: r, rewardType: t, coinType: a, total: s, market: i } of n.values()) {
5118
- const c = `${r}-${t}-${i}`;
5119
- o.has(c) || o.set(c, { assetId: r, rewardType: t, market: i, rewards: /* @__PURE__ */ new Map() });
5120
- const u = o.get(c);
5121
- u.rewards.set(a, (u.rewards.get(a) || 0) + s);
5122
- }
5123
- return Array.from(o.values()).map((r) => ({
5124
- assetId: r.assetId,
5125
- rewardType: r.rewardType,
5126
- market: r.market,
5127
- rewards: Array.from(r.rewards.entries()).map(([t, a]) => ({
5128
- coinType: t,
5129
- available: a.toFixed(6)
5130
- }))
5131
- }));
5132
- }
5133
5104
  async function Ct(e, n, o) {
5134
5105
  const r = await R({
5135
5106
  ...o,
@@ -5307,6 +5278,7 @@ async function Ct(e, n, o) {
5307
5278
 
5308
5279
  // src/protocols/navi.ts
5309
5280
  init_errors();
5281
+ init_token_registry();
5310
5282
  var MIN_HEALTH_FACTOR = 1.5;
5311
5283
  function sdkOptions(client) {
5312
5284
  return { env: "prod", client, cacheTime: 0, disableCache: true };
@@ -5681,24 +5653,8 @@ async function getPendingRewards(client, address) {
5681
5653
  );
5682
5654
  }
5683
5655
  if (!rewards || rewards.length === 0) return [];
5684
- const summary = wt(rewards);
5685
- const result = [];
5686
- for (const s of summary) {
5687
- for (const rw of s.rewards) {
5688
- const available = Number(rw.available);
5689
- if (available <= 0) continue;
5690
- const symbol = rw.coinType.split("::").pop() ?? "UNKNOWN";
5691
- result.push({
5692
- protocol: "navi",
5693
- asset: String(s.assetId),
5694
- coinType: rw.coinType,
5695
- symbol,
5696
- amount: available,
5697
- estimatedValueUsd: 0
5698
- });
5699
- }
5700
- }
5701
- return result;
5656
+ const claimable = rewards.filter((r) => Number(r.userClaimableReward) > 0);
5657
+ return aggregateClaimableRewards(claimable);
5702
5658
  }
5703
5659
  async function addClaimRewardsToTx(tx, client, address) {
5704
5660
  let rewards;
@@ -5748,7 +5704,8 @@ function aggregateClaimableRewards(claimable) {
5748
5704
  for (const c of claimable) {
5749
5705
  const coinType = c.rewardCoinType;
5750
5706
  if (!coinType) continue;
5751
- const symbol = coinType.split("::").pop() ?? "REWARD";
5707
+ const meta = getCoinMeta(coinType);
5708
+ const symbol = meta?.symbol ?? coinType.split("::").pop() ?? "REWARD";
5752
5709
  const amount = Number(c.userClaimableReward);
5753
5710
  if (!Number.isFinite(amount) || amount <= 0) continue;
5754
5711
  const existing = aggregated.get(coinType);
@@ -7487,6 +7444,183 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
7487
7444
  // src/index.ts
7488
7445
  init_errors();
7489
7446
  init_coinSelection();
7447
+ init_errors();
7448
+ init_token_registry();
7449
+ init_cetus_swap();
7450
+ async function addHarvestToTx(tx, client, address, options = {}) {
7451
+ const slippage = options.slippage ?? 0.01;
7452
+ const minRewardUsd = options.minRewardUsd ?? 0.01;
7453
+ const priceCache = options.priceCache;
7454
+ let rawRewards;
7455
+ try {
7456
+ rawRewards = await vt(address, {
7457
+ env: "prod",
7458
+ client,
7459
+ markets: ["main"]
7460
+ });
7461
+ } catch (err) {
7462
+ const msg = err instanceof Error ? err.message : String(err);
7463
+ throw new exports.T2000Error(
7464
+ "PROTOCOL_UNAVAILABLE",
7465
+ `NAVI rewards lookup failed: ${msg}`,
7466
+ { source: "navi-harvest-read" },
7467
+ true
7468
+ );
7469
+ }
7470
+ const claimable = (rawRewards ?? []).filter((r) => Number(r.userClaimableReward) > 0);
7471
+ if (claimable.length === 0) {
7472
+ throw new exports.T2000Error(
7473
+ "INVALID_AMOUNT",
7474
+ "No pending rewards to harvest.",
7475
+ { source: "navi-harvest" }
7476
+ );
7477
+ }
7478
+ const aggregated = aggregateClaimableRewards(claimable);
7479
+ let claimed;
7480
+ try {
7481
+ const claimResult = await Ct(tx, claimable, {
7482
+ env: "prod",
7483
+ // 'skip' = NAVI doesn't auto-transfer; coin handles stay in the PTB
7484
+ // for downstream consumption. Verified against NAVI lending source
7485
+ // (index.esm.js@1828–1911) — when type !== 'transfer' && type !==
7486
+ // 'depositNAVI', the `else` branch pushes `{ coin, identifier, ... }`
7487
+ // to the return without consuming the handle.
7488
+ customCoinReceive: { type: "skip" }
7489
+ });
7490
+ const grouped = /* @__PURE__ */ new Map();
7491
+ for (const c of claimResult) {
7492
+ const ct2 = c.identifier.suiCoinType ?? "";
7493
+ if (!ct2) continue;
7494
+ const list = grouped.get(ct2) ?? [];
7495
+ list.push(c.coin);
7496
+ grouped.set(ct2, list);
7497
+ }
7498
+ claimed = [];
7499
+ for (const [coinType, handles] of grouped.entries()) {
7500
+ if (handles.length === 1) {
7501
+ claimed.push({ coin: handles[0], coinType });
7502
+ } else {
7503
+ const [dest, ...rest] = handles;
7504
+ tx.mergeCoins(dest, rest);
7505
+ claimed.push({ coin: dest, coinType });
7506
+ }
7507
+ }
7508
+ } catch (err) {
7509
+ const msg = err instanceof Error ? err.message : String(err);
7510
+ throw new exports.T2000Error(
7511
+ "PROTOCOL_UNAVAILABLE",
7512
+ `NAVI claim PTB build failed: ${msg}`,
7513
+ { source: "navi-harvest-claim-ptb" },
7514
+ true
7515
+ );
7516
+ }
7517
+ const usdcHandles = [];
7518
+ const swaps = [];
7519
+ const skipped = [];
7520
+ let expectedUsdcDeposited = 0;
7521
+ for (const { coin, coinType } of claimed) {
7522
+ const aggRow = aggregated.find((r) => r.coinType === coinType);
7523
+ if (!aggRow) {
7524
+ continue;
7525
+ }
7526
+ if (coinType === exports.USDC_TYPE) {
7527
+ usdcHandles.push(coin);
7528
+ expectedUsdcDeposited += aggRow.amount;
7529
+ continue;
7530
+ }
7531
+ const meta = getCoinMeta(coinType);
7532
+ const isTradeable = meta && (meta.tier === 1 || meta.tier === 2);
7533
+ if (!isTradeable) {
7534
+ tx.transferObjects([coin], address);
7535
+ skipped.push({
7536
+ symbol: aggRow.symbol,
7537
+ coinType,
7538
+ amount: aggRow.amount,
7539
+ reason: "untradeable"
7540
+ });
7541
+ continue;
7542
+ }
7543
+ if (priceCache && minRewardUsd > 0) {
7544
+ const px = priceCache.get(aggRow.symbol.toUpperCase());
7545
+ if (px && px > 0 && aggRow.amount * px < minRewardUsd) {
7546
+ tx.transferObjects([coin], address);
7547
+ skipped.push({
7548
+ symbol: aggRow.symbol,
7549
+ coinType,
7550
+ amount: aggRow.amount,
7551
+ reason: "dust"
7552
+ });
7553
+ continue;
7554
+ }
7555
+ }
7556
+ try {
7557
+ const swapResult = await addSwapToTx(tx, client, address, {
7558
+ from: aggRow.symbol,
7559
+ to: "USDC",
7560
+ amount: aggRow.amount,
7561
+ slippage,
7562
+ inputCoin: coin,
7563
+ providers: options.providers
7564
+ });
7565
+ usdcHandles.push(swapResult.coin);
7566
+ expectedUsdcDeposited += swapResult.expectedAmountOut;
7567
+ swaps.push({
7568
+ fromSymbol: aggRow.symbol,
7569
+ fromCoinType: coinType,
7570
+ toSymbol: "USDC",
7571
+ inputAmount: swapResult.effectiveAmountIn,
7572
+ expectedOutputUsdc: swapResult.expectedAmountOut
7573
+ });
7574
+ } catch (err) {
7575
+ const code = err instanceof exports.T2000Error ? err.code : "UNKNOWN";
7576
+ if (code !== "SWAP_NO_ROUTE" && code !== "SWAP_FAILED") {
7577
+ throw err;
7578
+ }
7579
+ tx.transferObjects([coin], address);
7580
+ skipped.push({
7581
+ symbol: aggRow.symbol,
7582
+ coinType,
7583
+ amount: aggRow.amount,
7584
+ reason: "no-route"
7585
+ });
7586
+ }
7587
+ }
7588
+ if (usdcHandles.length > 0) {
7589
+ let depositCoin;
7590
+ if (usdcHandles.length === 1) {
7591
+ depositCoin = usdcHandles[0];
7592
+ } else {
7593
+ const [primary, ...rest] = usdcHandles;
7594
+ tx.mergeCoins(primary, rest);
7595
+ depositCoin = primary;
7596
+ }
7597
+ try {
7598
+ await addSaveToTx(tx, client, address, depositCoin, { asset: "USDC" });
7599
+ } catch (err) {
7600
+ const msg = err instanceof Error ? err.message : String(err);
7601
+ throw new exports.T2000Error(
7602
+ "PROTOCOL_UNAVAILABLE",
7603
+ `NAVI deposit failed during harvest: ${msg}`,
7604
+ { source: "navi-harvest-deposit" },
7605
+ true
7606
+ );
7607
+ }
7608
+ }
7609
+ return {
7610
+ claimed: aggregated,
7611
+ swaps,
7612
+ skipped,
7613
+ expectedUsdcDeposited
7614
+ };
7615
+ }
7616
+ async function buildHarvestRewardsTx(client, address, options = {}) {
7617
+ const tx = new transactions.Transaction();
7618
+ tx.setSender(address);
7619
+ const plan = await addHarvestToTx(tx, client, address, options);
7620
+ return { tx, plan };
7621
+ }
7622
+
7623
+ // src/composeTx.ts
7490
7624
  init_cetus_swap();
7491
7625
  init_volo();
7492
7626
  init_coinSelection();
@@ -7686,6 +7820,29 @@ var WRITE_APPENDER_REGISTRY = {
7686
7820
  const rewards = await addClaimRewardsToTx(tx, ctx.client, ctx.sender);
7687
7821
  return { preview: { toolName: "claim_rewards", rewards } };
7688
7822
  },
7823
+ // [Track B / 2026-05-08] Macro appender — assembles claim → swap(s) →
7824
+ // save inline. The audric host wires `getSponsoredSwapProviders()` into
7825
+ // `options.providers` automatically when `ctx.sponsoredContext === true`
7826
+ // (parity with `swap_execute` below). Slippage + dust-floor pulled from
7827
+ // the input; price cache is forwarded from the host so the dust filter
7828
+ // can compare claimed amounts to USD.
7829
+ harvest_rewards: async (tx, input, ctx) => {
7830
+ const providers = ctx.sponsoredContext ? await getSponsoredSwapProviders() : void 0;
7831
+ const plan = await addHarvestToTx(tx, ctx.client, ctx.sender, {
7832
+ slippage: input.slippage,
7833
+ minRewardUsd: input.minRewardUsd,
7834
+ providers
7835
+ });
7836
+ return {
7837
+ preview: {
7838
+ toolName: "harvest_rewards",
7839
+ claimed: plan.claimed,
7840
+ swaps: plan.swaps,
7841
+ skipped: plan.skipped,
7842
+ expectedUsdcDeposited: plan.expectedUsdcDeposited
7843
+ }
7844
+ };
7845
+ },
7689
7846
  volo_stake: async (tx, input, ctx) => {
7690
7847
  if (input.amountSui <= 0) {
7691
7848
  throw new exports.T2000Error("INVALID_AMOUNT", "Stake amount must be greater than zero");
@@ -8133,15 +8290,18 @@ exports.T2000_OVERLAY_FEE_WALLET = T2000_OVERLAY_FEE_WALLET;
8133
8290
  exports.USDC_DECIMALS = USDC_DECIMALS;
8134
8291
  exports.WRITE_APPENDER_REGISTRY = WRITE_APPENDER_REGISTRY;
8135
8292
  exports.ZkLoginSigner = ZkLoginSigner;
8293
+ exports.addClaimRewardsToTx = addClaimRewardsToTx;
8136
8294
  exports.addFeeTransfer = addFeeTransfer;
8137
8295
  exports.addSendToTx = addSendToTx;
8138
8296
  exports.addStakeVSuiToTx = addStakeVSuiToTx;
8139
8297
  exports.addSwapToTx = addSwapToTx;
8140
8298
  exports.addUnstakeVSuiToTx = addUnstakeVSuiToTx;
8299
+ exports.aggregateClaimableRewards = aggregateClaimableRewards;
8141
8300
  exports.allDescriptors = allDescriptors;
8142
8301
  exports.assertAllowedAsset = assertAllowedAsset;
8143
8302
  exports.buildAddLeafTx = buildAddLeafTx;
8144
8303
  exports.buildClaimRewardsTx = buildClaimRewardsTx;
8304
+ exports.buildHarvestRewardsTx = buildHarvestRewardsTx;
8145
8305
  exports.buildRevokeLeafTx = buildRevokeLeafTx;
8146
8306
  exports.buildSendTx = buildSendTx;
8147
8307
  exports.buildStakeVSuiTx = buildStakeVSuiTx;