@t2000/sdk 0.9.2 → 0.9.5

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.
@@ -1,4 +1,4 @@
1
- export { A as AdapterCapability, k as AdapterPositions, l as AdapterTxResult, C as CetusAdapter, o as HealthInfo, L as LendingAdapter, g as LendingRates, N as NaviAdapter, q as ProtocolDescriptor, r as ProtocolRegistry, u as SuilendAdapter, b as SwapAdapter, v as SwapQuote, x as allDescriptors, y as cetusDescriptor, J as naviDescriptor, Q as sentinelDescriptor, X as suilendDescriptor } from '../index-C7W686z2.cjs';
1
+ export { A as AdapterCapability, k as AdapterPositions, l as AdapterTxResult, C as CetusAdapter, o as HealthInfo, L as LendingAdapter, g as LendingRates, N as NaviAdapter, q as ProtocolDescriptor, r as ProtocolRegistry, u as SuilendAdapter, b as SwapAdapter, v as SwapQuote, x as allDescriptors, y as cetusDescriptor, J as naviDescriptor, Q as sentinelDescriptor, X as suilendDescriptor } from '../index-CrLRqDFL.cjs';
2
2
  import '@mysten/sui/transactions';
3
3
  import '@mysten/sui/jsonRpc';
4
4
  import '@mysten/sui/keypairs/ed25519';
@@ -1,4 +1,4 @@
1
- export { A as AdapterCapability, k as AdapterPositions, l as AdapterTxResult, C as CetusAdapter, o as HealthInfo, L as LendingAdapter, g as LendingRates, N as NaviAdapter, q as ProtocolDescriptor, r as ProtocolRegistry, u as SuilendAdapter, b as SwapAdapter, v as SwapQuote, x as allDescriptors, y as cetusDescriptor, J as naviDescriptor, Q as sentinelDescriptor, X as suilendDescriptor } from '../index-C7W686z2.js';
1
+ export { A as AdapterCapability, k as AdapterPositions, l as AdapterTxResult, C as CetusAdapter, o as HealthInfo, L as LendingAdapter, g as LendingRates, N as NaviAdapter, q as ProtocolDescriptor, r as ProtocolRegistry, u as SuilendAdapter, b as SwapAdapter, v as SwapQuote, x as allDescriptors, y as cetusDescriptor, J as naviDescriptor, Q as sentinelDescriptor, X as suilendDescriptor } from '../index-CrLRqDFL.js';
2
2
  import '@mysten/sui/transactions';
3
3
  import '@mysten/sui/jsonRpc';
4
4
  import '@mysten/sui/keypairs/ed25519';
@@ -390,7 +390,7 @@ function compoundBalance(rawBalance, currentIndex) {
390
390
  const result = (rawBalance * BigInt(currentIndex) + half) / scale;
391
391
  return Number(result) / 10 ** NAVI_BALANCE_DECIMALS;
392
392
  }
393
- async function getUserState(client, address) {
393
+ async function getUserState(client, address, includeZero = false) {
394
394
  const config = await getConfig();
395
395
  const tx = new Transaction();
396
396
  tx.moveCall({
@@ -403,11 +403,13 @@ async function getUserState(client, address) {
403
403
  });
404
404
  const decoded = decodeDevInspect(result, bcs.vector(UserStateInfo));
405
405
  if (!decoded) return [];
406
- return decoded.map((s) => ({
406
+ const mapped = decoded.map((s) => ({
407
407
  assetId: s.asset_id,
408
408
  supplyBalance: toBigInt(s.supply_balance),
409
409
  borrowBalance: toBigInt(s.borrow_balance)
410
- })).filter((s) => s.supplyBalance !== 0n || s.borrowBalance !== 0n);
410
+ }));
411
+ if (includeZero) return mapped;
412
+ return mapped.filter((s) => s.supplyBalance !== 0n || s.borrowBalance !== 0n);
411
413
  }
412
414
  async function fetchCoins(client, owner, coinType) {
413
415
  const all = [];
@@ -464,20 +466,20 @@ async function buildSaveTx(client, address, amount, options = {}) {
464
466
  async function buildWithdrawTx(client, address, amount, options = {}) {
465
467
  const asset = options.asset ?? "USDC";
466
468
  const assetInfo = SUPPORTED_ASSETS[asset];
467
- const [config, pool, pools, states] = await Promise.all([
469
+ const [config, pool, pools, allStates] = await Promise.all([
468
470
  getConfig(),
469
471
  getPool(asset),
470
472
  getPools(),
471
- getUserState(client, address)
473
+ getUserState(client, address, true)
472
474
  ]);
473
- const assetState = states.find((s) => s.assetId === pool.id);
475
+ const assetState = allStates.find((s) => s.assetId === pool.id);
474
476
  const deposited = assetState ? compoundBalance(assetState.supplyBalance, pool.currentSupplyIndex) : 0;
475
477
  const effectiveAmount = Math.min(amount, Math.max(0, deposited - WITHDRAW_DUST_BUFFER));
476
478
  if (effectiveAmount <= 0) throw new T2000Error("NO_COLLATERAL", `Nothing to withdraw for ${assetInfo.displayName} on NAVI`);
477
479
  const rawAmount = Number(stableToRaw(effectiveAmount, assetInfo.decimals));
478
480
  const tx = new Transaction();
479
481
  tx.setSender(address);
480
- addOracleUpdatesForPositions(tx, config, pools, states, pool);
482
+ addOracleUpdatesForPositions(tx, config, pools, allStates, pool);
481
483
  const [balance] = tx.moveCall({
482
484
  target: `${config.package}::incentive_v3::withdraw_v2`,
483
485
  arguments: [
@@ -501,6 +503,94 @@ async function buildWithdrawTx(client, address, amount, options = {}) {
501
503
  tx.transferObjects([coin], address);
502
504
  return { tx, effectiveAmount };
503
505
  }
506
+ async function addWithdrawToTx(tx, client, address, amount, options = {}) {
507
+ const asset = options.asset ?? "USDC";
508
+ const assetInfo = SUPPORTED_ASSETS[asset];
509
+ const [config, pool, pools, allStates] = await Promise.all([
510
+ getConfig(),
511
+ getPool(asset),
512
+ getPools(),
513
+ getUserState(client, address, true)
514
+ ]);
515
+ const assetState = allStates.find((s) => s.assetId === pool.id);
516
+ const deposited = assetState ? compoundBalance(assetState.supplyBalance, pool.currentSupplyIndex) : 0;
517
+ const effectiveAmount = Math.min(amount, Math.max(0, deposited - WITHDRAW_DUST_BUFFER));
518
+ if (effectiveAmount <= 0) throw new T2000Error("NO_COLLATERAL", `Nothing to withdraw for ${assetInfo.displayName} on NAVI`);
519
+ const rawAmount = Number(stableToRaw(effectiveAmount, assetInfo.decimals));
520
+ addOracleUpdatesForPositions(tx, config, pools, allStates, pool);
521
+ const [balance] = tx.moveCall({
522
+ target: `${config.package}::incentive_v3::withdraw_v2`,
523
+ arguments: [
524
+ tx.object(CLOCK),
525
+ tx.object(config.oracle.priceOracle),
526
+ tx.object(config.storage),
527
+ tx.object(pool.contract.pool),
528
+ tx.pure.u8(pool.id),
529
+ tx.pure.u64(rawAmount),
530
+ tx.object(config.incentiveV2),
531
+ tx.object(config.incentiveV3),
532
+ tx.object(SUI_SYSTEM_STATE)
533
+ ],
534
+ typeArguments: [pool.suiCoinType]
535
+ });
536
+ const [coin] = tx.moveCall({
537
+ target: "0x2::coin::from_balance",
538
+ arguments: [balance],
539
+ typeArguments: [pool.suiCoinType]
540
+ });
541
+ return { coin, effectiveAmount };
542
+ }
543
+ async function addSaveToTx(tx, _client, _address, coin, options = {}) {
544
+ const asset = options.asset ?? "USDC";
545
+ const [config, pool] = await Promise.all([getConfig(), getPool(asset)]);
546
+ if (options.collectFee) {
547
+ addCollectFeeToTx(tx, coin, "save");
548
+ }
549
+ const [coinValue] = tx.moveCall({
550
+ target: "0x2::coin::value",
551
+ typeArguments: [pool.suiCoinType],
552
+ arguments: [coin]
553
+ });
554
+ tx.moveCall({
555
+ target: `${config.package}::incentive_v3::entry_deposit`,
556
+ arguments: [
557
+ tx.object(CLOCK),
558
+ tx.object(config.storage),
559
+ tx.object(pool.contract.pool),
560
+ tx.pure.u8(pool.id),
561
+ coin,
562
+ coinValue,
563
+ tx.object(config.incentiveV2),
564
+ tx.object(config.incentiveV3)
565
+ ],
566
+ typeArguments: [pool.suiCoinType]
567
+ });
568
+ }
569
+ async function addRepayToTx(tx, client, _address, coin, options = {}) {
570
+ const asset = options.asset ?? "USDC";
571
+ const [config, pool] = await Promise.all([getConfig(), getPool(asset)]);
572
+ addOracleUpdate(tx, config, pool);
573
+ const [coinValue] = tx.moveCall({
574
+ target: "0x2::coin::value",
575
+ typeArguments: [pool.suiCoinType],
576
+ arguments: [coin]
577
+ });
578
+ tx.moveCall({
579
+ target: `${config.package}::incentive_v3::entry_repay`,
580
+ arguments: [
581
+ tx.object(CLOCK),
582
+ tx.object(config.oracle.priceOracle),
583
+ tx.object(config.storage),
584
+ tx.object(pool.contract.pool),
585
+ tx.pure.u8(pool.id),
586
+ coin,
587
+ coinValue,
588
+ tx.object(config.incentiveV2),
589
+ tx.object(config.incentiveV3)
590
+ ],
591
+ typeArguments: [pool.suiCoinType]
592
+ });
593
+ }
504
594
  async function buildBorrowTx(client, address, amount, options = {}) {
505
595
  if (!amount || amount <= 0 || !Number.isFinite(amount)) {
506
596
  throw new T2000Error("INVALID_AMOUNT", "Borrow amount must be a positive number");
@@ -508,15 +598,15 @@ async function buildBorrowTx(client, address, amount, options = {}) {
508
598
  const asset = options.asset ?? "USDC";
509
599
  const assetInfo = SUPPORTED_ASSETS[asset];
510
600
  const rawAmount = Number(stableToRaw(amount, assetInfo.decimals));
511
- const [config, pool, pools, states] = await Promise.all([
601
+ const [config, pool, pools, allStates] = await Promise.all([
512
602
  getConfig(),
513
603
  getPool(asset),
514
604
  getPools(),
515
- getUserState(client, address)
605
+ getUserState(client, address, true)
516
606
  ]);
517
607
  const tx = new Transaction();
518
608
  tx.setSender(address);
519
- addOracleUpdatesForPositions(tx, config, pools, states, pool);
609
+ addOracleUpdatesForPositions(tx, config, pools, allStates, pool);
520
610
  const [balance] = tx.moveCall({
521
611
  target: `${config.package}::incentive_v3::borrow_v2`,
522
612
  arguments: [
@@ -792,6 +882,18 @@ var NaviAdapter = class {
792
882
  async maxBorrow(address, _asset) {
793
883
  return maxBorrowAmount(this.client, address);
794
884
  }
885
+ async addWithdrawToTx(tx, address, amount, asset) {
886
+ const stableAsset = normalizeAsset(asset);
887
+ return addWithdrawToTx(tx, this.client, address, amount, { asset: stableAsset });
888
+ }
889
+ async addSaveToTx(tx, address, coin, asset, options) {
890
+ const stableAsset = normalizeAsset(asset);
891
+ return addSaveToTx(tx, this.client, address, coin, { ...options, asset: stableAsset });
892
+ }
893
+ async addRepayToTx(tx, address, coin, asset) {
894
+ const stableAsset = normalizeAsset(asset);
895
+ return addRepayToTx(tx, this.client, address, coin, { asset: stableAsset });
896
+ }
795
897
  };
796
898
  var DEFAULT_SLIPPAGE_BPS = 300;
797
899
  function createAggregatorClient(client, signer) {
@@ -836,6 +938,41 @@ async function buildSwapTx(params) {
836
938
  toDecimals: toInfo.decimals
837
939
  };
838
940
  }
941
+ async function addSwapToTx(params) {
942
+ const { tx, client, address, inputCoin, fromAsset, toAsset, amount, maxSlippageBps = DEFAULT_SLIPPAGE_BPS } = params;
943
+ const fromInfo = SUPPORTED_ASSETS[fromAsset];
944
+ const toInfo = SUPPORTED_ASSETS[toAsset];
945
+ if (!fromInfo || !toInfo) {
946
+ throw new T2000Error("ASSET_NOT_SUPPORTED", `Swap pair ${fromAsset}/${toAsset} is not supported`);
947
+ }
948
+ const rawAmount = BigInt(Math.floor(amount * 10 ** fromInfo.decimals));
949
+ const aggClient = createAggregatorClient(client, address);
950
+ const result = await aggClient.findRouters({
951
+ from: fromInfo.type,
952
+ target: toInfo.type,
953
+ amount: rawAmount,
954
+ byAmountIn: true
955
+ });
956
+ if (!result || result.insufficientLiquidity) {
957
+ throw new T2000Error(
958
+ "ASSET_NOT_SUPPORTED",
959
+ `No swap route found for ${fromAsset} \u2192 ${toAsset}`
960
+ );
961
+ }
962
+ const slippage = maxSlippageBps / 1e4;
963
+ const outputCoin = await aggClient.routerSwap({
964
+ router: result,
965
+ txb: tx,
966
+ inputCoin,
967
+ slippage
968
+ });
969
+ const estimatedOut = Number(result.amountOut.toString());
970
+ return {
971
+ outputCoin,
972
+ estimatedOut,
973
+ toDecimals: toInfo.decimals
974
+ };
975
+ }
839
976
  async function getPoolPrice(client) {
840
977
  try {
841
978
  const pool = await client.getObject({
@@ -946,6 +1083,18 @@ var CetusAdapter = class {
946
1083
  async getPoolPrice() {
947
1084
  return getPoolPrice(this.client);
948
1085
  }
1086
+ async addSwapToTx(tx, address, inputCoin, from, to, amount, maxSlippageBps) {
1087
+ return addSwapToTx({
1088
+ tx,
1089
+ client: this.client,
1090
+ address,
1091
+ inputCoin,
1092
+ fromAsset: from,
1093
+ toAsset: to,
1094
+ amount,
1095
+ maxSlippageBps
1096
+ });
1097
+ }
949
1098
  };
950
1099
  var WAD = 1e18;
951
1100
  var MIN_HEALTH_FACTOR2 = 1.5;
@@ -1341,6 +1490,95 @@ var SuilendAdapter = class {
1341
1490
  tx.transferObjects([coin], address);
1342
1491
  return { tx, effectiveAmount };
1343
1492
  }
1493
+ async addWithdrawToTx(tx, address, amount, asset) {
1494
+ const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1495
+ const assetInfo = SUPPORTED_ASSETS[assetKey];
1496
+ const [pkg, reserves] = await Promise.all([this.resolvePackage(), this.loadReserves(true)]);
1497
+ const reserve = this.findReserve(reserves, assetKey);
1498
+ if (!reserve) throw new T2000Error("ASSET_NOT_SUPPORTED", `${assetInfo.displayName} reserve not found on Suilend`);
1499
+ const caps = await this.fetchObligationCaps(address);
1500
+ if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend position found");
1501
+ const positions = await this.getPositions(address);
1502
+ const deposited = positions.supplies.find((s) => s.asset === assetKey)?.amount ?? 0;
1503
+ const effectiveAmount = Math.min(amount, deposited);
1504
+ if (effectiveAmount <= 0) throw new T2000Error("NO_COLLATERAL", `Nothing to withdraw for ${assetInfo.displayName} on Suilend`);
1505
+ const ratio = cTokenRatio(reserve);
1506
+ const ctokenAmount = Math.ceil(effectiveAmount * 10 ** reserve.mintDecimals / ratio);
1507
+ const [ctokens] = tx.moveCall({
1508
+ target: `${pkg}::lending_market::withdraw_ctokens`,
1509
+ typeArguments: [LENDING_MARKET_TYPE, assetInfo.type],
1510
+ arguments: [
1511
+ tx.object(LENDING_MARKET_ID),
1512
+ tx.pure.u64(reserve.arrayIndex),
1513
+ tx.object(caps[0].id),
1514
+ tx.object(CLOCK2),
1515
+ tx.pure.u64(ctokenAmount)
1516
+ ]
1517
+ });
1518
+ const exemptionType = `${SUILEND_PACKAGE}::lending_market::RateLimiterExemption<${LENDING_MARKET_TYPE}, ${assetInfo.type}>`;
1519
+ const [none] = tx.moveCall({
1520
+ target: "0x1::option::none",
1521
+ typeArguments: [exemptionType]
1522
+ });
1523
+ const [coin] = tx.moveCall({
1524
+ target: `${pkg}::lending_market::redeem_ctokens_and_withdraw_liquidity`,
1525
+ typeArguments: [LENDING_MARKET_TYPE, assetInfo.type],
1526
+ arguments: [
1527
+ tx.object(LENDING_MARKET_ID),
1528
+ tx.pure.u64(reserve.arrayIndex),
1529
+ tx.object(CLOCK2),
1530
+ ctokens,
1531
+ none
1532
+ ]
1533
+ });
1534
+ return { coin, effectiveAmount };
1535
+ }
1536
+ async addSaveToTx(tx, address, coin, asset, options) {
1537
+ const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1538
+ const assetInfo = SUPPORTED_ASSETS[assetKey];
1539
+ const [pkg, reserves] = await Promise.all([this.resolvePackage(), this.loadReserves()]);
1540
+ const reserve = this.findReserve(reserves, assetKey);
1541
+ if (!reserve) throw new T2000Error("ASSET_NOT_SUPPORTED", `${assetInfo.displayName} reserve not found on Suilend`);
1542
+ const caps = await this.fetchObligationCaps(address);
1543
+ let capRef;
1544
+ if (caps.length === 0) {
1545
+ const [newCap] = tx.moveCall({
1546
+ target: `${pkg}::lending_market::create_obligation`,
1547
+ typeArguments: [LENDING_MARKET_TYPE],
1548
+ arguments: [tx.object(LENDING_MARKET_ID)]
1549
+ });
1550
+ capRef = newCap;
1551
+ } else {
1552
+ capRef = caps[0].id;
1553
+ }
1554
+ if (options?.collectFee) {
1555
+ addCollectFeeToTx(tx, coin, "save");
1556
+ }
1557
+ const [ctokens] = tx.moveCall({
1558
+ target: `${pkg}::lending_market::deposit_liquidity_and_mint_ctokens`,
1559
+ typeArguments: [LENDING_MARKET_TYPE, assetInfo.type],
1560
+ arguments: [
1561
+ tx.object(LENDING_MARKET_ID),
1562
+ tx.pure.u64(reserve.arrayIndex),
1563
+ tx.object(CLOCK2),
1564
+ coin
1565
+ ]
1566
+ });
1567
+ tx.moveCall({
1568
+ target: `${pkg}::lending_market::deposit_ctokens_into_obligation`,
1569
+ typeArguments: [LENDING_MARKET_TYPE, assetInfo.type],
1570
+ arguments: [
1571
+ tx.object(LENDING_MARKET_ID),
1572
+ tx.pure.u64(reserve.arrayIndex),
1573
+ typeof capRef === "string" ? tx.object(capRef) : capRef,
1574
+ tx.object(CLOCK2),
1575
+ ctokens
1576
+ ]
1577
+ });
1578
+ if (typeof capRef !== "string") {
1579
+ tx.transferObjects([capRef], address);
1580
+ }
1581
+ }
1344
1582
  async buildBorrowTx(address, amount, asset, options) {
1345
1583
  const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1346
1584
  const assetInfo = SUPPORTED_ASSETS[assetKey];
@@ -1400,6 +1638,26 @@ var SuilendAdapter = class {
1400
1638
  });
1401
1639
  return { tx };
1402
1640
  }
1641
+ async addRepayToTx(tx, address, coin, asset) {
1642
+ const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1643
+ const assetInfo = SUPPORTED_ASSETS[assetKey];
1644
+ const [pkg, reserves] = await Promise.all([this.resolvePackage(), this.loadReserves()]);
1645
+ const reserve = this.findReserve(reserves, assetKey);
1646
+ if (!reserve) throw new T2000Error("ASSET_NOT_SUPPORTED", `${assetInfo.displayName} reserve not found on Suilend`);
1647
+ const caps = await this.fetchObligationCaps(address);
1648
+ if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend obligation found");
1649
+ tx.moveCall({
1650
+ target: `${pkg}::lending_market::repay`,
1651
+ typeArguments: [LENDING_MARKET_TYPE, assetInfo.type],
1652
+ arguments: [
1653
+ tx.object(LENDING_MARKET_ID),
1654
+ tx.pure.u64(reserve.arrayIndex),
1655
+ tx.object(caps[0].id),
1656
+ tx.object(CLOCK2),
1657
+ coin
1658
+ ]
1659
+ });
1660
+ }
1403
1661
  async maxWithdraw(address, _asset) {
1404
1662
  const health = await this.getHealth(address);
1405
1663
  let maxAmount;