@t2000/sdk 0.3.0 → 0.4.1

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
@@ -11,8 +11,8 @@ var path = require('path');
11
11
  var os = require('os');
12
12
  var transactions = require('@mysten/sui/transactions');
13
13
  var lending = require('@naviprotocol/lending');
14
- var suiClmmSdk = require('@cetusprotocol/sui-clmm-sdk');
15
14
  var bcs = require('@mysten/sui/bcs');
15
+ var aggregatorSdk = require('@cetusprotocol/aggregator-sdk');
16
16
 
17
17
  // src/t2000.ts
18
18
 
@@ -524,8 +524,8 @@ async function buildRepayTx(client, address, amount) {
524
524
  await lending.repayCoinPTB(tx, USDC_TYPE, coinObj, { ...ENV, amount: rawAmount });
525
525
  return tx;
526
526
  }
527
- async function getHealthFactor(client, keypair) {
528
- const address = keypair.getPublicKey().toSuiAddress();
527
+ async function getHealthFactor(client, addressOrKeypair) {
528
+ const address = typeof addressOrKeypair === "string" ? addressOrKeypair : addressOrKeypair.getPublicKey().toSuiAddress();
529
529
  const [healthFactor, state, pool] = await Promise.all([
530
530
  lending.getHealthFactor(address, clientOpt(client, true)),
531
531
  lending.getLendingState(address, clientOpt(client, true)),
@@ -557,8 +557,8 @@ async function getRates(client) {
557
557
  return { USDC: { saveApy: 4, borrowApy: 6 } };
558
558
  }
559
559
  }
560
- async function getPositions(client, keypair) {
561
- const address = keypair.getPublicKey().toSuiAddress();
560
+ async function getPositions(client, addressOrKeypair) {
561
+ const address = typeof addressOrKeypair === "string" ? addressOrKeypair : addressOrKeypair.getPublicKey().toSuiAddress();
562
562
  const state = await lending.getLendingState(address, clientOpt(client, true));
563
563
  const positions = [];
564
564
  for (const pos of state) {
@@ -586,8 +586,8 @@ async function getPositions(client, keypair) {
586
586
  }
587
587
  return { positions };
588
588
  }
589
- async function maxWithdrawAmount(client, keypair) {
590
- const hf = await getHealthFactor(client, keypair);
589
+ async function maxWithdrawAmount(client, addressOrKeypair) {
590
+ const hf = await getHealthFactor(client, addressOrKeypair);
591
591
  const ltv = hf.liquidationThreshold > 0 ? hf.liquidationThreshold : 0.75;
592
592
  let maxAmount;
593
593
  if (hf.borrowed === 0) {
@@ -603,8 +603,8 @@ async function maxWithdrawAmount(client, keypair) {
603
603
  currentHF: hf.healthFactor
604
604
  };
605
605
  }
606
- async function maxBorrowAmount(client, keypair) {
607
- const hf = await getHealthFactor(client, keypair);
606
+ async function maxBorrowAmount(client, addressOrKeypair) {
607
+ const hf = await getHealthFactor(client, addressOrKeypair);
608
608
  const ltv = hf.liquidationThreshold > 0 ? hf.liquidationThreshold : 0.75;
609
609
  const maxAmount = Math.max(0, hf.supplied * ltv / MIN_HEALTH_FACTOR - hf.borrowed);
610
610
  return {
@@ -613,108 +613,6 @@ async function maxBorrowAmount(client, keypair) {
613
613
  currentHF: hf.healthFactor
614
614
  };
615
615
  }
616
- var DEFAULT_SLIPPAGE_BPS = 300;
617
- function isA2B(from) {
618
- return from === "USDC";
619
- }
620
- var _cetusSDK = null;
621
- function getCetusSDK() {
622
- if (!_cetusSDK) {
623
- _cetusSDK = suiClmmSdk.CetusClmmSDK.createSDK({ env: "mainnet" });
624
- }
625
- return _cetusSDK;
626
- }
627
- async function buildSwapTx(params) {
628
- const { client, address, fromAsset, toAsset, amount, maxSlippageBps = DEFAULT_SLIPPAGE_BPS } = params;
629
- const a2b = isA2B(fromAsset);
630
- const fromInfo = SUPPORTED_ASSETS[fromAsset];
631
- const toInfo = SUPPORTED_ASSETS[toAsset];
632
- const rawAmount = BigInt(Math.floor(amount * 10 ** fromInfo.decimals));
633
- const sdk = getCetusSDK();
634
- sdk.setSenderAddress(address);
635
- const pool = await sdk.Pool.getPool(CETUS_USDC_SUI_POOL);
636
- const preSwapResult = await sdk.Swap.preSwap({
637
- pool,
638
- current_sqrt_price: pool.current_sqrt_price,
639
- coin_type_a: pool.coin_type_a,
640
- coin_type_b: pool.coin_type_b,
641
- decimals_a: 6,
642
- decimals_b: 9,
643
- a2b,
644
- by_amount_in: true,
645
- amount: rawAmount.toString()
646
- });
647
- const estimatedOut = Number(preSwapResult.estimated_amount_out);
648
- const slippageFactor = (1e4 - maxSlippageBps) / 1e4;
649
- const amountLimit = Math.floor(estimatedOut * slippageFactor);
650
- const swapPayload = await sdk.Swap.createSwapPayload({
651
- pool_id: pool.id,
652
- coin_type_a: pool.coin_type_a,
653
- coin_type_b: pool.coin_type_b,
654
- a2b,
655
- by_amount_in: true,
656
- amount: preSwapResult.amount.toString(),
657
- amount_limit: amountLimit.toString()
658
- });
659
- return {
660
- tx: swapPayload,
661
- estimatedOut,
662
- toDecimals: toInfo.decimals
663
- };
664
- }
665
- async function getPoolPrice(client) {
666
- try {
667
- const pool = await client.getObject({
668
- id: CETUS_USDC_SUI_POOL,
669
- options: { showContent: true }
670
- });
671
- if (pool.data?.content?.dataType === "moveObject") {
672
- const fields = pool.data.content.fields;
673
- const currentSqrtPrice = BigInt(String(fields.current_sqrt_price ?? "0"));
674
- if (currentSqrtPrice > 0n) {
675
- const Q64 = 2n ** 64n;
676
- const sqrtPriceFloat = Number(currentSqrtPrice) / Number(Q64);
677
- const rawPrice = sqrtPriceFloat * sqrtPriceFloat;
678
- const suiPriceUsd = 1e3 / rawPrice;
679
- if (suiPriceUsd > 0.01 && suiPriceUsd < 1e3) return suiPriceUsd;
680
- }
681
- }
682
- } catch {
683
- }
684
- return 3.5;
685
- }
686
- async function getSwapQuote(client, fromAsset, toAsset, amount) {
687
- const a2b = isA2B(fromAsset);
688
- const fromInfo = SUPPORTED_ASSETS[fromAsset];
689
- const toInfo = SUPPORTED_ASSETS[toAsset];
690
- const rawAmount = BigInt(Math.floor(amount * 10 ** fromInfo.decimals));
691
- const poolPrice = await getPoolPrice(client);
692
- try {
693
- const sdk = getCetusSDK();
694
- const pool = await sdk.Pool.getPool(CETUS_USDC_SUI_POOL);
695
- const preSwapResult = await sdk.Swap.preSwap({
696
- pool,
697
- current_sqrt_price: pool.current_sqrt_price,
698
- coin_type_a: pool.coin_type_a,
699
- coin_type_b: pool.coin_type_b,
700
- decimals_a: 6,
701
- decimals_b: 9,
702
- a2b,
703
- by_amount_in: true,
704
- amount: rawAmount.toString()
705
- });
706
- const expectedOutput = Number(preSwapResult.estimated_amount_out) / 10 ** toInfo.decimals;
707
- return { expectedOutput, priceImpact: 0, poolPrice };
708
- } catch {
709
- let expectedOutput;
710
- if (fromAsset === "USDC") {
711
- expectedOutput = amount / poolPrice;
712
- } else {
713
- expectedOutput = amount * poolPrice;
714
- }
715
- return { expectedOutput, priceImpact: 0, poolPrice };
716
- }
717
- }
718
616
 
719
617
  // src/protocols/yieldTracker.ts
720
618
  async function getEarnings(client, keypair) {
@@ -926,6 +824,298 @@ async function attack(client, signer, sentinelId, prompt, feeMist) {
926
824
  feePaid: Number(fee) / Number(MIST_PER_SUI)
927
825
  };
928
826
  }
827
+
828
+ // src/adapters/registry.ts
829
+ var ProtocolRegistry = class {
830
+ lending = /* @__PURE__ */ new Map();
831
+ swap = /* @__PURE__ */ new Map();
832
+ registerLending(adapter) {
833
+ this.lending.set(adapter.id, adapter);
834
+ }
835
+ registerSwap(adapter) {
836
+ this.swap.set(adapter.id, adapter);
837
+ }
838
+ async bestSaveRate(asset) {
839
+ const candidates = [];
840
+ for (const adapter of this.lending.values()) {
841
+ if (!adapter.supportedAssets.includes(asset)) continue;
842
+ if (!adapter.capabilities.includes("save")) continue;
843
+ try {
844
+ const rate = await adapter.getRates(asset);
845
+ candidates.push({ adapter, rate });
846
+ } catch {
847
+ }
848
+ }
849
+ if (candidates.length === 0) {
850
+ throw new Error(`No lending adapter supports saving ${asset}`);
851
+ }
852
+ candidates.sort((a, b) => b.rate.saveApy - a.rate.saveApy);
853
+ return candidates[0];
854
+ }
855
+ async bestBorrowRate(asset, opts) {
856
+ const candidates = [];
857
+ for (const adapter of this.lending.values()) {
858
+ if (!adapter.supportedAssets.includes(asset)) continue;
859
+ if (!adapter.capabilities.includes("borrow")) continue;
860
+ if (opts?.requireSameAssetBorrow && !adapter.supportsSameAssetBorrow) continue;
861
+ try {
862
+ const rate = await adapter.getRates(asset);
863
+ candidates.push({ adapter, rate });
864
+ } catch {
865
+ }
866
+ }
867
+ if (candidates.length === 0) {
868
+ throw new Error(`No lending adapter supports borrowing ${asset}`);
869
+ }
870
+ candidates.sort((a, b) => a.rate.borrowApy - b.rate.borrowApy);
871
+ return candidates[0];
872
+ }
873
+ async bestSwapQuote(from, to, amount) {
874
+ const candidates = [];
875
+ for (const adapter of this.swap.values()) {
876
+ const pairs = adapter.getSupportedPairs();
877
+ if (!pairs.some((p) => p.from === from && p.to === to)) continue;
878
+ try {
879
+ const quote = await adapter.getQuote(from, to, amount);
880
+ candidates.push({ adapter, quote });
881
+ } catch {
882
+ }
883
+ }
884
+ if (candidates.length === 0) {
885
+ throw new Error(`No swap adapter supports ${from} \u2192 ${to}`);
886
+ }
887
+ candidates.sort((a, b) => b.quote.expectedOutput - a.quote.expectedOutput);
888
+ return candidates[0];
889
+ }
890
+ async allRates(asset) {
891
+ const results = [];
892
+ for (const adapter of this.lending.values()) {
893
+ if (!adapter.supportedAssets.includes(asset)) continue;
894
+ try {
895
+ const rates = await adapter.getRates(asset);
896
+ results.push({ protocol: adapter.name, protocolId: adapter.id, rates });
897
+ } catch {
898
+ }
899
+ }
900
+ return results;
901
+ }
902
+ async allPositions(address) {
903
+ const results = [];
904
+ for (const adapter of this.lending.values()) {
905
+ try {
906
+ const positions = await adapter.getPositions(address);
907
+ if (positions.supplies.length > 0 || positions.borrows.length > 0) {
908
+ results.push({ protocol: adapter.name, protocolId: adapter.id, positions });
909
+ }
910
+ } catch {
911
+ }
912
+ }
913
+ return results;
914
+ }
915
+ getLending(id) {
916
+ return this.lending.get(id);
917
+ }
918
+ getSwap(id) {
919
+ return this.swap.get(id);
920
+ }
921
+ listLending() {
922
+ return [...this.lending.values()];
923
+ }
924
+ listSwap() {
925
+ return [...this.swap.values()];
926
+ }
927
+ };
928
+
929
+ // src/adapters/navi.ts
930
+ var NaviAdapter = class {
931
+ id = "navi";
932
+ name = "NAVI Protocol";
933
+ version = "1.0.0";
934
+ capabilities = ["save", "withdraw", "borrow", "repay"];
935
+ supportedAssets = ["USDC"];
936
+ supportsSameAssetBorrow = true;
937
+ client;
938
+ async init(client) {
939
+ this.client = client;
940
+ }
941
+ initSync(client) {
942
+ this.client = client;
943
+ }
944
+ async getRates(asset) {
945
+ const rates = await getRates(this.client);
946
+ const key = asset.toUpperCase();
947
+ const r = rates[key];
948
+ if (!r) throw new Error(`NAVI does not support ${asset}`);
949
+ return { asset, saveApy: r.saveApy, borrowApy: r.borrowApy };
950
+ }
951
+ async getPositions(address) {
952
+ const result = await getPositions(this.client, address);
953
+ return {
954
+ supplies: result.positions.filter((p) => p.type === "save").map((p) => ({ asset: p.asset, amount: p.amount, apy: p.apy })),
955
+ borrows: result.positions.filter((p) => p.type === "borrow").map((p) => ({ asset: p.asset, amount: p.amount, apy: p.apy }))
956
+ };
957
+ }
958
+ async getHealth(address) {
959
+ return getHealthFactor(this.client, address);
960
+ }
961
+ async buildSaveTx(address, amount, _asset, options) {
962
+ const tx = await buildSaveTx(this.client, address, amount, options);
963
+ return { tx };
964
+ }
965
+ async buildWithdrawTx(address, amount, _asset) {
966
+ const result = await buildWithdrawTx(this.client, address, amount);
967
+ return { tx: result.tx, effectiveAmount: result.effectiveAmount };
968
+ }
969
+ async buildBorrowTx(address, amount, _asset, options) {
970
+ const tx = await buildBorrowTx(this.client, address, amount, options);
971
+ return { tx };
972
+ }
973
+ async buildRepayTx(address, amount, _asset) {
974
+ const tx = await buildRepayTx(this.client, address, amount);
975
+ return { tx };
976
+ }
977
+ async maxWithdraw(address, _asset) {
978
+ return maxWithdrawAmount(this.client, address);
979
+ }
980
+ async maxBorrow(address, _asset) {
981
+ return maxBorrowAmount(this.client, address);
982
+ }
983
+ };
984
+ var DEFAULT_SLIPPAGE_BPS = 300;
985
+ function createAggregatorClient(client, signer) {
986
+ return new aggregatorSdk.AggregatorClient({
987
+ client,
988
+ signer,
989
+ env: aggregatorSdk.Env.Mainnet
990
+ });
991
+ }
992
+ async function buildSwapTx(params) {
993
+ const { client, address, fromAsset, toAsset, amount, maxSlippageBps = DEFAULT_SLIPPAGE_BPS } = params;
994
+ const fromInfo = SUPPORTED_ASSETS[fromAsset];
995
+ const toInfo = SUPPORTED_ASSETS[toAsset];
996
+ const rawAmount = BigInt(Math.floor(amount * 10 ** fromInfo.decimals));
997
+ const aggClient = createAggregatorClient(client, address);
998
+ const result = await aggClient.findRouters({
999
+ from: fromInfo.type,
1000
+ target: toInfo.type,
1001
+ amount: rawAmount,
1002
+ byAmountIn: true
1003
+ });
1004
+ if (!result || result.insufficientLiquidity) {
1005
+ throw new T2000Error(
1006
+ "ASSET_NOT_SUPPORTED",
1007
+ `No swap route found for ${fromAsset} \u2192 ${toAsset}`
1008
+ );
1009
+ }
1010
+ const tx = new transactions.Transaction();
1011
+ const slippage = maxSlippageBps / 1e4;
1012
+ await aggClient.fastRouterSwap({
1013
+ router: result,
1014
+ txb: tx,
1015
+ slippage
1016
+ });
1017
+ const estimatedOut = Number(result.amountOut.toString());
1018
+ return {
1019
+ tx,
1020
+ estimatedOut,
1021
+ toDecimals: toInfo.decimals
1022
+ };
1023
+ }
1024
+ async function getPoolPrice(client) {
1025
+ try {
1026
+ const pool = await client.getObject({
1027
+ id: CETUS_USDC_SUI_POOL,
1028
+ options: { showContent: true }
1029
+ });
1030
+ if (pool.data?.content?.dataType === "moveObject") {
1031
+ const fields = pool.data.content.fields;
1032
+ const currentSqrtPrice = BigInt(String(fields.current_sqrt_price ?? "0"));
1033
+ if (currentSqrtPrice > 0n) {
1034
+ const Q64 = 2n ** 64n;
1035
+ const sqrtPriceFloat = Number(currentSqrtPrice) / Number(Q64);
1036
+ const rawPrice = sqrtPriceFloat * sqrtPriceFloat;
1037
+ const suiPriceUsd = 1e3 / rawPrice;
1038
+ if (suiPriceUsd > 0.01 && suiPriceUsd < 1e3) return suiPriceUsd;
1039
+ }
1040
+ }
1041
+ } catch {
1042
+ }
1043
+ return 3.5;
1044
+ }
1045
+ async function getSwapQuote(client, fromAsset, toAsset, amount) {
1046
+ const fromInfo = SUPPORTED_ASSETS[fromAsset];
1047
+ const toInfo = SUPPORTED_ASSETS[toAsset];
1048
+ const rawAmount = BigInt(Math.floor(amount * 10 ** fromInfo.decimals));
1049
+ const poolPrice = await getPoolPrice(client);
1050
+ try {
1051
+ const aggClient = createAggregatorClient(client);
1052
+ const result = await aggClient.findRouters({
1053
+ from: fromInfo.type,
1054
+ target: toInfo.type,
1055
+ amount: rawAmount,
1056
+ byAmountIn: true
1057
+ });
1058
+ if (!result || result.insufficientLiquidity) {
1059
+ return fallbackQuote(fromAsset, amount, poolPrice);
1060
+ }
1061
+ const expectedOutput = Number(result.amountOut.toString()) / 10 ** toInfo.decimals;
1062
+ const priceImpact = result.deviationRatio ?? 0;
1063
+ return { expectedOutput, priceImpact, poolPrice };
1064
+ } catch {
1065
+ return fallbackQuote(fromAsset, amount, poolPrice);
1066
+ }
1067
+ }
1068
+ function fallbackQuote(fromAsset, amount, poolPrice) {
1069
+ const expectedOutput = fromAsset === "USDC" ? amount / poolPrice : amount * poolPrice;
1070
+ return { expectedOutput, priceImpact: 0, poolPrice };
1071
+ }
1072
+
1073
+ // src/adapters/cetus.ts
1074
+ var CetusAdapter = class {
1075
+ id = "cetus";
1076
+ name = "Cetus";
1077
+ version = "1.0.0";
1078
+ capabilities = ["swap"];
1079
+ client;
1080
+ async init(client) {
1081
+ this.client = client;
1082
+ }
1083
+ initSync(client) {
1084
+ this.client = client;
1085
+ }
1086
+ async getQuote(from, to, amount) {
1087
+ return getSwapQuote(
1088
+ this.client,
1089
+ from.toUpperCase(),
1090
+ to.toUpperCase(),
1091
+ amount
1092
+ );
1093
+ }
1094
+ async buildSwapTx(address, from, to, amount, maxSlippageBps) {
1095
+ const result = await buildSwapTx({
1096
+ client: this.client,
1097
+ address,
1098
+ fromAsset: from.toUpperCase(),
1099
+ toAsset: to.toUpperCase(),
1100
+ amount,
1101
+ maxSlippageBps
1102
+ });
1103
+ return {
1104
+ tx: result.tx,
1105
+ estimatedOut: result.estimatedOut,
1106
+ toDecimals: result.toDecimals
1107
+ };
1108
+ }
1109
+ getSupportedPairs() {
1110
+ return [
1111
+ { from: "USDC", to: "SUI" },
1112
+ { from: "SUI", to: "USDC" }
1113
+ ];
1114
+ }
1115
+ async getPoolPrice() {
1116
+ return getPoolPrice(this.client);
1117
+ }
1118
+ };
929
1119
  function hasLeadingZeroBits(hash, bits) {
930
1120
  const fullBytes = Math.floor(bits / 8);
931
1121
  const remainingBits = bits % 8;
@@ -1158,11 +1348,23 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1158
1348
  keypair;
1159
1349
  client;
1160
1350
  _address;
1161
- constructor(keypair, client) {
1351
+ registry;
1352
+ constructor(keypair, client, registry) {
1162
1353
  super();
1163
1354
  this.keypair = keypair;
1164
1355
  this.client = client;
1165
1356
  this._address = getAddress(keypair);
1357
+ this.registry = registry ?? _T2000.createDefaultRegistry(client);
1358
+ }
1359
+ static createDefaultRegistry(client) {
1360
+ const registry = new ProtocolRegistry();
1361
+ const naviAdapter = new NaviAdapter();
1362
+ naviAdapter.initSync(client);
1363
+ registry.registerLending(naviAdapter);
1364
+ const cetusAdapter = new CetusAdapter();
1365
+ cetusAdapter.initSync(client);
1366
+ registry.registerSwap(cetusAdapter);
1367
+ return registry;
1166
1368
  }
1167
1369
  static async create(options = {}) {
1168
1370
  const { keyPath, pin, passphrase, network = DEFAULT_NETWORK, rpcUrl, sponsored, name } = options;
@@ -1283,6 +1485,11 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1283
1485
  exportKey() {
1284
1486
  return exportPrivateKey(this.keypair);
1285
1487
  }
1488
+ async registerAdapter(adapter) {
1489
+ await adapter.init(this.client);
1490
+ if ("buildSaveTx" in adapter) this.registry.registerLending(adapter);
1491
+ if ("buildSwapTx" in adapter) this.registry.registerSwap(adapter);
1492
+ }
1286
1493
  // -- Savings --
1287
1494
  async save(params) {
1288
1495
  const asset = (params.asset ?? "USDC").toUpperCase();
@@ -1305,12 +1512,12 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1305
1512
  }
1306
1513
  const fee = calculateFee("save", amount);
1307
1514
  const saveAmount = amount;
1308
- const gasResult = await executeWithGas(
1309
- this.client,
1310
- this.keypair,
1311
- () => buildSaveTx(this.client, this._address, saveAmount, { collectFee: true })
1312
- );
1313
- const rates = await getRates(this.client);
1515
+ const adapter = await this.resolveLending(params.protocol, asset, "save");
1516
+ const gasResult = await executeWithGas(this.client, this.keypair, async () => {
1517
+ const { tx } = await adapter.buildSaveTx(this._address, saveAmount, asset, { collectFee: true });
1518
+ return tx;
1519
+ });
1520
+ const rates = await adapter.getRates(asset);
1314
1521
  reportFee(this._address, "save", fee.amount, fee.rate, gasResult.digest);
1315
1522
  this.emitBalanceChange("USDC", saveAmount, "save", gasResult.digest);
1316
1523
  let savingsBalance = saveAmount;
@@ -1323,7 +1530,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1323
1530
  success: true,
1324
1531
  tx: gasResult.digest,
1325
1532
  amount: saveAmount,
1326
- apy: rates.USDC.saveApy,
1533
+ apy: rates.saveApy,
1327
1534
  fee: fee.amount,
1328
1535
  gasCost: gasResult.gasCostSui,
1329
1536
  gasMethod: gasResult.gasMethod,
@@ -1335,18 +1542,19 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1335
1542
  if (asset !== "USDC") {
1336
1543
  throw new T2000Error("ASSET_NOT_SUPPORTED", `Only USDC is supported for withdraw. Got: ${asset}`);
1337
1544
  }
1545
+ const adapter = await this.resolveLending(params.protocol, asset, "withdraw");
1338
1546
  let amount;
1339
1547
  if (params.amount === "all") {
1340
- const maxResult = await this.maxWithdraw();
1548
+ const maxResult = await adapter.maxWithdraw(this._address, asset);
1341
1549
  amount = maxResult.maxAmount;
1342
1550
  if (amount <= 0) {
1343
1551
  throw new T2000Error("NO_COLLATERAL", "No savings to withdraw");
1344
1552
  }
1345
1553
  } else {
1346
1554
  amount = params.amount;
1347
- const hf = await this.healthFactor();
1555
+ const hf = await adapter.getHealth(this._address);
1348
1556
  if (hf.borrowed > 0) {
1349
- const maxResult = await this.maxWithdraw();
1557
+ const maxResult = await adapter.maxWithdraw(this._address, asset);
1350
1558
  if (amount > maxResult.maxAmount) {
1351
1559
  throw new T2000Error(
1352
1560
  "WITHDRAW_WOULD_LIQUIDATE",
@@ -1363,7 +1571,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1363
1571
  const withdrawAmount = amount;
1364
1572
  let effectiveAmount = withdrawAmount;
1365
1573
  const gasResult = await executeWithGas(this.client, this.keypair, async () => {
1366
- const built = await buildWithdrawTx(this.client, this._address, withdrawAmount);
1574
+ const built = await adapter.buildWithdrawTx(this._address, withdrawAmount, asset);
1367
1575
  effectiveAmount = built.effectiveAmount;
1368
1576
  return built.tx;
1369
1577
  });
@@ -1377,7 +1585,8 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1377
1585
  };
1378
1586
  }
1379
1587
  async maxWithdraw() {
1380
- return maxWithdrawAmount(this.client, this.keypair);
1588
+ const adapter = await this.resolveLending(void 0, "USDC", "withdraw");
1589
+ return adapter.maxWithdraw(this._address, "USDC");
1381
1590
  }
1382
1591
  // -- Borrowing --
1383
1592
  async borrow(params) {
@@ -1385,7 +1594,8 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1385
1594
  if (asset !== "USDC") {
1386
1595
  throw new T2000Error("ASSET_NOT_SUPPORTED", `Only USDC is supported for borrow. Got: ${asset}`);
1387
1596
  }
1388
- const maxResult = await this.maxBorrow();
1597
+ const adapter = await this.resolveLending(params.protocol, asset, "borrow");
1598
+ const maxResult = await adapter.maxBorrow(this._address, asset);
1389
1599
  if (params.amount > maxResult.maxAmount) {
1390
1600
  throw new T2000Error("HEALTH_FACTOR_TOO_LOW", `Max safe borrow: $${maxResult.maxAmount.toFixed(2)}`, {
1391
1601
  maxBorrow: maxResult.maxAmount,
@@ -1394,12 +1604,11 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1394
1604
  }
1395
1605
  const fee = calculateFee("borrow", params.amount);
1396
1606
  const borrowAmount = params.amount;
1397
- const gasResult = await executeWithGas(
1398
- this.client,
1399
- this.keypair,
1400
- () => buildBorrowTx(this.client, this._address, borrowAmount, { collectFee: true })
1401
- );
1402
- const hf = await getHealthFactor(this.client, this.keypair);
1607
+ const gasResult = await executeWithGas(this.client, this.keypair, async () => {
1608
+ const { tx } = await adapter.buildBorrowTx(this._address, borrowAmount, asset, { collectFee: true });
1609
+ return tx;
1610
+ });
1611
+ const hf = await adapter.getHealth(this._address);
1403
1612
  reportFee(this._address, "borrow", fee.amount, fee.rate, gasResult.digest);
1404
1613
  this.emitBalanceChange("USDC", borrowAmount, "borrow", gasResult.digest);
1405
1614
  return {
@@ -1417,9 +1626,10 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1417
1626
  if (asset !== "USDC") {
1418
1627
  throw new T2000Error("ASSET_NOT_SUPPORTED", `Only USDC is supported for repay. Got: ${asset}`);
1419
1628
  }
1629
+ const adapter = await this.resolveLending(params.protocol, asset, "repay");
1420
1630
  let amount;
1421
1631
  if (params.amount === "all") {
1422
- const hf2 = await this.healthFactor();
1632
+ const hf2 = await adapter.getHealth(this._address);
1423
1633
  amount = hf2.borrowed;
1424
1634
  if (amount <= 0) {
1425
1635
  throw new T2000Error("NO_COLLATERAL", "No outstanding borrow to repay");
@@ -1428,12 +1638,11 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1428
1638
  amount = params.amount;
1429
1639
  }
1430
1640
  const repayAmount = amount;
1431
- const gasResult = await executeWithGas(
1432
- this.client,
1433
- this.keypair,
1434
- () => buildRepayTx(this.client, this._address, repayAmount)
1435
- );
1436
- const hf = await getHealthFactor(this.client, this.keypair);
1641
+ const gasResult = await executeWithGas(this.client, this.keypair, async () => {
1642
+ const { tx } = await adapter.buildRepayTx(this._address, repayAmount, asset);
1643
+ return tx;
1644
+ });
1645
+ const hf = await adapter.getHealth(this._address);
1437
1646
  this.emitBalanceChange("USDC", repayAmount, "repay", gasResult.digest);
1438
1647
  return {
1439
1648
  success: true,
@@ -1445,10 +1654,12 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1445
1654
  };
1446
1655
  }
1447
1656
  async maxBorrow() {
1448
- return maxBorrowAmount(this.client, this.keypair);
1657
+ const adapter = await this.resolveLending(void 0, "USDC", "borrow");
1658
+ return adapter.maxBorrow(this._address, "USDC");
1449
1659
  }
1450
1660
  async healthFactor() {
1451
- const hf = await getHealthFactor(this.client, this.keypair);
1661
+ const adapter = await this.resolveLending(void 0, "USDC", "save");
1662
+ const hf = await adapter.getHealth(this._address);
1452
1663
  if (hf.healthFactor < 1.2) {
1453
1664
  this.emit("healthCritical", { healthFactor: hf.healthFactor, threshold: 1.5, severity: "critical" });
1454
1665
  } else if (hf.healthFactor < 2) {
@@ -1466,23 +1677,26 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1466
1677
  if (fromAsset === toAsset) {
1467
1678
  throw new T2000Error("INVALID_AMOUNT", "Cannot swap same asset");
1468
1679
  }
1680
+ let adapter;
1681
+ if (params.protocol) {
1682
+ const found = this.registry.getSwap(params.protocol);
1683
+ if (!found) throw new T2000Error("ASSET_NOT_SUPPORTED", `Swap adapter '${params.protocol}' not found`);
1684
+ adapter = found;
1685
+ } else {
1686
+ const best = await this.registry.bestSwapQuote(fromAsset, toAsset, params.amount);
1687
+ adapter = best.adapter;
1688
+ }
1469
1689
  const fee = calculateFee("swap", params.amount);
1470
1690
  const swapAmount = params.amount;
1471
1691
  const slippageBps = params.maxSlippage ? params.maxSlippage * 100 : void 0;
1472
1692
  let swapMeta = { estimatedOut: 0, toDecimals: 0 };
1473
1693
  const gasResult = await executeWithGas(this.client, this.keypair, async () => {
1474
- const built = await buildSwapTx({
1475
- client: this.client,
1476
- address: this._address,
1477
- fromAsset,
1478
- toAsset,
1479
- amount: swapAmount,
1480
- maxSlippageBps: slippageBps
1481
- });
1694
+ const built = await adapter.buildSwapTx(this._address, fromAsset, toAsset, swapAmount, slippageBps);
1482
1695
  swapMeta = { estimatedOut: built.estimatedOut, toDecimals: built.toDecimals };
1483
1696
  return built.tx;
1484
1697
  });
1485
1698
  const toInfo = SUPPORTED_ASSETS[toAsset];
1699
+ await this.client.waitForTransaction({ digest: gasResult.digest });
1486
1700
  const txDetail = await this.client.getTransactionBlock({
1487
1701
  digest: gasResult.digest,
1488
1702
  options: { showBalanceChanges: true }
@@ -1517,17 +1731,39 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1517
1731
  async swapQuote(params) {
1518
1732
  const fromAsset = params.from.toUpperCase();
1519
1733
  const toAsset = params.to.toUpperCase();
1520
- const quote = await getSwapQuote(this.client, fromAsset, toAsset, params.amount);
1734
+ const best = await this.registry.bestSwapQuote(fromAsset, toAsset, params.amount);
1521
1735
  const fee = calculateFee("swap", params.amount);
1522
- return { ...quote, fee: { amount: fee.amount, rate: fee.rate } };
1736
+ return { ...best.quote, fee: { amount: fee.amount, rate: fee.rate } };
1523
1737
  }
1524
1738
  // -- Info --
1525
1739
  async positions() {
1526
- return getPositions(this.client, this.keypair);
1740
+ const allPositions = await this.registry.allPositions(this._address);
1741
+ const positions = allPositions.flatMap(
1742
+ (p) => [
1743
+ ...p.positions.supplies.map((s) => ({
1744
+ protocol: p.protocolId,
1745
+ asset: s.asset,
1746
+ type: "save",
1747
+ amount: s.amount,
1748
+ apy: s.apy
1749
+ })),
1750
+ ...p.positions.borrows.map((b) => ({
1751
+ protocol: p.protocolId,
1752
+ asset: b.asset,
1753
+ type: "borrow",
1754
+ amount: b.amount,
1755
+ apy: b.apy
1756
+ }))
1757
+ ]
1758
+ );
1759
+ return { positions };
1527
1760
  }
1528
1761
  async rates() {
1529
1762
  return getRates(this.client);
1530
1763
  }
1764
+ async allRates(asset = "USDC") {
1765
+ return this.registry.allRates(asset);
1766
+ }
1531
1767
  async earnings() {
1532
1768
  const result = await getEarnings(this.client, this.keypair);
1533
1769
  if (result.totalYieldEarned > 0) {
@@ -1554,6 +1790,29 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
1554
1790
  return attack(this.client, this.keypair, id, prompt, fee);
1555
1791
  }
1556
1792
  // -- Helpers --
1793
+ async resolveLending(protocol, asset, capability) {
1794
+ if (protocol) {
1795
+ const adapter = this.registry.getLending(protocol);
1796
+ if (!adapter) throw new T2000Error("ASSET_NOT_SUPPORTED", `Lending adapter '${protocol}' not found`);
1797
+ return adapter;
1798
+ }
1799
+ if (capability === "save") {
1800
+ const { adapter } = await this.registry.bestSaveRate(asset);
1801
+ return adapter;
1802
+ }
1803
+ if (capability === "borrow" || capability === "repay") {
1804
+ const adapters2 = this.registry.listLending().filter(
1805
+ (a) => a.supportedAssets.includes(asset) && a.capabilities.includes(capability) && (capability !== "borrow" || a.supportsSameAssetBorrow)
1806
+ );
1807
+ if (adapters2.length === 0) throw new T2000Error("ASSET_NOT_SUPPORTED", `No adapter supports ${capability} ${asset}`);
1808
+ return adapters2[0];
1809
+ }
1810
+ const adapters = this.registry.listLending().filter(
1811
+ (a) => a.supportedAssets.includes(asset) && a.capabilities.includes(capability)
1812
+ );
1813
+ if (adapters.length === 0) throw new T2000Error("ASSET_NOT_SUPPORTED", `No adapter supports ${capability} ${asset}`);
1814
+ return adapters[0];
1815
+ }
1557
1816
  emitBalanceChange(asset, amount, cause, tx) {
1558
1817
  this.emit("balanceChange", { asset, previous: 0, current: 0, cause, tx });
1559
1818
  }
@@ -1651,14 +1910,308 @@ function parseMoveAbort(errorStr) {
1651
1910
  }
1652
1911
  return { reason: errorStr };
1653
1912
  }
1913
+ var USDC_TYPE2 = SUPPORTED_ASSETS.USDC.type;
1914
+ SUPPORTED_ASSETS.USDC.decimals;
1915
+ var WAD = 1e18;
1916
+ var MIN_HEALTH_FACTOR2 = 1.5;
1917
+ function interpolateRate(utilBreakpoints, aprBreakpoints, utilizationPct) {
1918
+ if (utilBreakpoints.length === 0) return 0;
1919
+ if (utilizationPct <= utilBreakpoints[0]) return aprBreakpoints[0];
1920
+ if (utilizationPct >= utilBreakpoints[utilBreakpoints.length - 1]) {
1921
+ return aprBreakpoints[aprBreakpoints.length - 1];
1922
+ }
1923
+ for (let i = 1; i < utilBreakpoints.length; i++) {
1924
+ if (utilizationPct <= utilBreakpoints[i]) {
1925
+ const t = (utilizationPct - utilBreakpoints[i - 1]) / (utilBreakpoints[i] - utilBreakpoints[i - 1]);
1926
+ return aprBreakpoints[i - 1] + t * (aprBreakpoints[i] - aprBreakpoints[i - 1]);
1927
+ }
1928
+ }
1929
+ return aprBreakpoints[aprBreakpoints.length - 1];
1930
+ }
1931
+ function computeRatesFromReserve(reserve) {
1932
+ const decimals = reserve.mintDecimals;
1933
+ const available = Number(reserve.availableAmount) / 10 ** decimals;
1934
+ const borrowed = Number(reserve.borrowedAmount.value) / WAD / 10 ** decimals;
1935
+ const totalDeposited = available + borrowed;
1936
+ const utilizationPct = totalDeposited > 0 ? borrowed / totalDeposited * 100 : 0;
1937
+ const config = reserve.config.element;
1938
+ if (!config) return { borrowAprPct: 0, depositAprPct: 0, utilizationPct: 0 };
1939
+ const utils = config.interestRateUtils.map(Number);
1940
+ const aprs = config.interestRateAprs.map((a) => Number(a) / 100);
1941
+ const borrowAprPct = interpolateRate(utils, aprs, utilizationPct);
1942
+ const spreadFeeBps = Number(config.spreadFeeBps);
1943
+ const depositAprPct = utilizationPct / 100 * (borrowAprPct / 100) * (1 - spreadFeeBps / 1e4) * 100;
1944
+ return { borrowAprPct, depositAprPct, utilizationPct };
1945
+ }
1946
+ function cTokenRatio(reserve) {
1947
+ if (reserve.ctokenSupply === 0n) return 1;
1948
+ const available = Number(reserve.availableAmount);
1949
+ const borrowed = Number(reserve.borrowedAmount.value) / WAD;
1950
+ const spreadFees = Number(reserve.unclaimedSpreadFees.value) / WAD;
1951
+ const totalSupply = available + borrowed - spreadFees;
1952
+ return totalSupply / Number(reserve.ctokenSupply);
1953
+ }
1954
+ var SuilendAdapter = class {
1955
+ id = "suilend";
1956
+ name = "Suilend";
1957
+ version = "1.0.0";
1958
+ capabilities = ["save", "withdraw"];
1959
+ supportedAssets = ["USDC"];
1960
+ supportsSameAssetBorrow = false;
1961
+ client;
1962
+ suilend;
1963
+ lendingMarketType;
1964
+ initialized = false;
1965
+ async init(client) {
1966
+ let sdk;
1967
+ try {
1968
+ sdk = await import('@suilend/sdk');
1969
+ } catch {
1970
+ throw new T2000Error(
1971
+ "PROTOCOL_UNAVAILABLE",
1972
+ "Suilend SDK not installed. Run: npm install @suilend/sdk@^1"
1973
+ );
1974
+ }
1975
+ this.client = client;
1976
+ this.lendingMarketType = sdk.LENDING_MARKET_TYPE;
1977
+ try {
1978
+ this.suilend = await sdk.SuilendClient.initialize(
1979
+ sdk.LENDING_MARKET_ID,
1980
+ sdk.LENDING_MARKET_TYPE,
1981
+ client
1982
+ );
1983
+ } catch (err) {
1984
+ throw new T2000Error(
1985
+ "PROTOCOL_UNAVAILABLE",
1986
+ `Failed to initialize Suilend: ${err instanceof Error ? err.message : String(err)}`
1987
+ );
1988
+ }
1989
+ this.initialized = true;
1990
+ }
1991
+ ensureInit() {
1992
+ if (!this.initialized) {
1993
+ throw new T2000Error(
1994
+ "PROTOCOL_UNAVAILABLE",
1995
+ "SuilendAdapter not initialized. Call init() first."
1996
+ );
1997
+ }
1998
+ }
1999
+ findReserve(asset) {
2000
+ const upper = asset.toUpperCase();
2001
+ let coinType;
2002
+ if (upper === "USDC") coinType = USDC_TYPE2;
2003
+ else if (upper === "SUI") coinType = "0x2::sui::SUI";
2004
+ else if (asset.includes("::")) coinType = asset;
2005
+ else return void 0;
2006
+ try {
2007
+ const normalized = utils.normalizeStructTag(coinType);
2008
+ return this.suilend.lendingMarket.reserves.find(
2009
+ (r) => utils.normalizeStructTag(r.coinType.name) === normalized
2010
+ );
2011
+ } catch {
2012
+ return void 0;
2013
+ }
2014
+ }
2015
+ async getObligationCaps(address) {
2016
+ const SuilendClientStatic = (await import('@suilend/sdk')).SuilendClient;
2017
+ return SuilendClientStatic.getObligationOwnerCaps(
2018
+ address,
2019
+ [this.lendingMarketType],
2020
+ this.client
2021
+ );
2022
+ }
2023
+ resolveSymbol(coinType) {
2024
+ const normalized = utils.normalizeStructTag(coinType);
2025
+ if (normalized === utils.normalizeStructTag(USDC_TYPE2)) return "USDC";
2026
+ if (normalized === utils.normalizeStructTag("0x2::sui::SUI")) return "SUI";
2027
+ const parts = coinType.split("::");
2028
+ return parts[parts.length - 1] || "UNKNOWN";
2029
+ }
2030
+ async getRates(asset) {
2031
+ this.ensureInit();
2032
+ const reserve = this.findReserve(asset);
2033
+ if (!reserve) {
2034
+ throw new T2000Error("ASSET_NOT_SUPPORTED", `Suilend does not support ${asset}`);
2035
+ }
2036
+ const { borrowAprPct, depositAprPct } = computeRatesFromReserve(reserve);
2037
+ return {
2038
+ asset,
2039
+ saveApy: depositAprPct,
2040
+ borrowApy: borrowAprPct
2041
+ };
2042
+ }
2043
+ async getPositions(address) {
2044
+ this.ensureInit();
2045
+ const supplies = [];
2046
+ const borrows = [];
2047
+ const caps = await this.getObligationCaps(address);
2048
+ if (caps.length === 0) return { supplies, borrows };
2049
+ const obligation = await this.suilend.getObligation(caps[0].obligationId);
2050
+ for (const deposit of obligation.deposits) {
2051
+ const coinType = utils.normalizeStructTag(deposit.coinType.name);
2052
+ const reserve = this.suilend.lendingMarket.reserves.find(
2053
+ (r) => utils.normalizeStructTag(r.coinType.name) === coinType
2054
+ );
2055
+ if (!reserve) continue;
2056
+ const ctokenAmount = Number(deposit.depositedCtokenAmount.toString());
2057
+ const ratio = cTokenRatio(reserve);
2058
+ const amount = ctokenAmount * ratio / 10 ** reserve.mintDecimals;
2059
+ const { depositAprPct } = computeRatesFromReserve(reserve);
2060
+ supplies.push({ asset: this.resolveSymbol(coinType), amount, apy: depositAprPct });
2061
+ }
2062
+ for (const borrow of obligation.borrows) {
2063
+ const coinType = utils.normalizeStructTag(borrow.coinType.name);
2064
+ const reserve = this.suilend.lendingMarket.reserves.find(
2065
+ (r) => utils.normalizeStructTag(r.coinType.name) === coinType
2066
+ );
2067
+ if (!reserve) continue;
2068
+ const rawBorrowed = Number(borrow.borrowedAmount.value.toString()) / WAD;
2069
+ const amount = rawBorrowed / 10 ** reserve.mintDecimals;
2070
+ const reserveRate = Number(reserve.cumulativeBorrowRate.value.toString()) / WAD;
2071
+ const posRate = Number(borrow.cumulativeBorrowRate.value.toString()) / WAD;
2072
+ const compounded = posRate > 0 ? amount * (reserveRate / posRate) : amount;
2073
+ const { borrowAprPct } = computeRatesFromReserve(reserve);
2074
+ borrows.push({ asset: this.resolveSymbol(coinType), amount: compounded, apy: borrowAprPct });
2075
+ }
2076
+ return { supplies, borrows };
2077
+ }
2078
+ async getHealth(address) {
2079
+ this.ensureInit();
2080
+ const caps = await this.getObligationCaps(address);
2081
+ if (caps.length === 0) {
2082
+ return { healthFactor: Infinity, supplied: 0, borrowed: 0, maxBorrow: 0, liquidationThreshold: 0 };
2083
+ }
2084
+ const positions = await this.getPositions(address);
2085
+ const supplied = positions.supplies.reduce((s, p) => s + p.amount, 0);
2086
+ const borrowed = positions.borrows.reduce((s, p) => s + p.amount, 0);
2087
+ const reserve = this.findReserve("USDC");
2088
+ const closeLtv = reserve?.config?.element?.closeLtvPct ?? 75;
2089
+ const openLtv = reserve?.config?.element?.openLtvPct ?? 70;
2090
+ const liqThreshold = closeLtv / 100;
2091
+ const healthFactor = borrowed > 0 ? supplied * liqThreshold / borrowed : Infinity;
2092
+ const maxBorrow = Math.max(0, supplied * (openLtv / 100) - borrowed);
2093
+ return { healthFactor, supplied, borrowed, maxBorrow, liquidationThreshold: liqThreshold };
2094
+ }
2095
+ async buildSaveTx(address, amount, _asset, options) {
2096
+ this.ensureInit();
2097
+ const rawAmount = usdcToRaw(amount).toString();
2098
+ const tx = new transactions.Transaction();
2099
+ tx.setSender(address);
2100
+ const caps = await this.getObligationCaps(address);
2101
+ let capRef;
2102
+ if (caps.length === 0) {
2103
+ const [newCap] = this.suilend.createObligation(tx);
2104
+ capRef = newCap;
2105
+ } else {
2106
+ capRef = caps[0].id;
2107
+ }
2108
+ const allCoins = await this.fetchAllCoins(address, USDC_TYPE2);
2109
+ if (allCoins.length === 0) {
2110
+ throw new T2000Error("INSUFFICIENT_BALANCE", "No USDC coins found");
2111
+ }
2112
+ const primaryCoinId = allCoins[0].coinObjectId;
2113
+ if (allCoins.length > 1) {
2114
+ tx.mergeCoins(
2115
+ tx.object(primaryCoinId),
2116
+ allCoins.slice(1).map((c) => tx.object(c.coinObjectId))
2117
+ );
2118
+ }
2119
+ const [depositCoin] = tx.splitCoins(tx.object(primaryCoinId), [rawAmount]);
2120
+ if (options?.collectFee) {
2121
+ addCollectFeeToTx(tx, depositCoin, "save");
2122
+ }
2123
+ this.suilend.deposit(depositCoin, USDC_TYPE2, capRef, tx);
2124
+ return { tx };
2125
+ }
2126
+ async buildWithdrawTx(address, amount, _asset) {
2127
+ this.ensureInit();
2128
+ const caps = await this.getObligationCaps(address);
2129
+ if (caps.length === 0) {
2130
+ throw new T2000Error("NO_COLLATERAL", "No Suilend position found");
2131
+ }
2132
+ const positions = await this.getPositions(address);
2133
+ const usdcSupply = positions.supplies.find((s) => s.asset === "USDC");
2134
+ const deposited = usdcSupply?.amount ?? 0;
2135
+ const effectiveAmount = Math.min(amount, deposited);
2136
+ if (effectiveAmount <= 0) {
2137
+ throw new T2000Error("NO_COLLATERAL", "Nothing to withdraw from Suilend");
2138
+ }
2139
+ const rawAmount = usdcToRaw(effectiveAmount).toString();
2140
+ const tx = new transactions.Transaction();
2141
+ tx.setSender(address);
2142
+ await this.suilend.withdrawAndSendToUser(
2143
+ address,
2144
+ caps[0].id,
2145
+ caps[0].obligationId,
2146
+ USDC_TYPE2,
2147
+ rawAmount,
2148
+ tx
2149
+ );
2150
+ return { tx, effectiveAmount };
2151
+ }
2152
+ async buildBorrowTx(_address, _amount, _asset, _options) {
2153
+ throw new T2000Error(
2154
+ "ASSET_NOT_SUPPORTED",
2155
+ "SuilendAdapter.buildBorrowTx() not available \u2014 Suilend requires different collateral/borrow assets. Deferred to Phase 10."
2156
+ );
2157
+ }
2158
+ async buildRepayTx(_address, _amount, _asset) {
2159
+ throw new T2000Error(
2160
+ "ASSET_NOT_SUPPORTED",
2161
+ "SuilendAdapter.buildRepayTx() not available \u2014 deferred to Phase 10."
2162
+ );
2163
+ }
2164
+ async maxWithdraw(address, _asset) {
2165
+ this.ensureInit();
2166
+ const health = await this.getHealth(address);
2167
+ let maxAmount;
2168
+ if (health.borrowed === 0) {
2169
+ maxAmount = health.supplied;
2170
+ } else {
2171
+ maxAmount = Math.max(
2172
+ 0,
2173
+ health.supplied - health.borrowed * MIN_HEALTH_FACTOR2 / health.liquidationThreshold
2174
+ );
2175
+ }
2176
+ const remainingSupply = health.supplied - maxAmount;
2177
+ const hfAfter = health.borrowed > 0 ? remainingSupply * health.liquidationThreshold / health.borrowed : Infinity;
2178
+ return {
2179
+ maxAmount,
2180
+ healthFactorAfter: hfAfter,
2181
+ currentHF: health.healthFactor
2182
+ };
2183
+ }
2184
+ async maxBorrow(_address, _asset) {
2185
+ throw new T2000Error(
2186
+ "ASSET_NOT_SUPPORTED",
2187
+ "SuilendAdapter.maxBorrow() not available \u2014 deferred to Phase 10."
2188
+ );
2189
+ }
2190
+ async fetchAllCoins(owner, coinType) {
2191
+ const all = [];
2192
+ let cursor = null;
2193
+ let hasNext = true;
2194
+ while (hasNext) {
2195
+ const page = await this.client.getCoins({ owner, coinType, cursor: cursor ?? void 0 });
2196
+ all.push(...page.data.map((c) => ({ coinObjectId: c.coinObjectId, balance: c.balance })));
2197
+ cursor = page.nextCursor;
2198
+ hasNext = page.hasNextPage;
2199
+ }
2200
+ return all;
2201
+ }
2202
+ };
1654
2203
 
1655
2204
  exports.BPS_DENOMINATOR = BPS_DENOMINATOR;
1656
2205
  exports.CLOCK_ID = CLOCK_ID;
2206
+ exports.CetusAdapter = CetusAdapter;
1657
2207
  exports.DEFAULT_NETWORK = DEFAULT_NETWORK;
1658
2208
  exports.MIST_PER_SUI = MIST_PER_SUI;
2209
+ exports.NaviAdapter = NaviAdapter;
2210
+ exports.ProtocolRegistry = ProtocolRegistry;
1659
2211
  exports.SENTINEL = SENTINEL;
1660
2212
  exports.SUI_DECIMALS = SUI_DECIMALS;
1661
2213
  exports.SUPPORTED_ASSETS = SUPPORTED_ASSETS;
2214
+ exports.SuilendAdapter = SuilendAdapter;
1662
2215
  exports.T2000 = T2000;
1663
2216
  exports.T2000Error = T2000Error;
1664
2217
  exports.USDC_DECIMALS = USDC_DECIMALS;