@t2000/sdk 0.19.24 → 0.20.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.
@@ -1,14 +1,8 @@
1
1
  import { Transaction } from '@mysten/sui/transactions';
2
2
  import { getPools, getLendingPositions, getHealthFactor as getHealthFactor$1, depositCoinPTB, withdrawCoinPTB, borrowCoinPTB, repayCoinPTB, getUserAvailableLendingRewards, summaryLendingRewards, claimLendingRewardsPTB, updateOraclePriceBeforeUserOperationPTB } from '@naviprotocol/lending';
3
- import { AggregatorClient, Env } from '@cetusprotocol/aggregator-sdk';
4
- import { normalizeStructTag } from '@mysten/sui/utils';
5
- import { SuilendClient, LENDING_MARKET_ID, LENDING_MARKET_TYPE } from '@suilend/sdk/client';
6
- import { initializeSuilend, initializeObligations } from '@suilend/sdk/lib/initialize';
7
- import { Side } from '@suilend/sdk/lib/types';
8
3
 
9
4
  // src/constants.ts
10
5
  var SAVE_FEE_BPS = 10n;
11
- var SWAP_FEE_BPS = 0n;
12
6
  var BORROW_FEE_BPS = 5n;
13
7
  var SUPPORTED_ASSETS = {
14
8
  USDC: {
@@ -40,39 +34,13 @@ var SUPPORTED_ASSETS = {
40
34
  decimals: 9,
41
35
  symbol: "SUI",
42
36
  displayName: "SUI"
43
- },
44
- BTC: {
45
- type: "0x0041f9f9344cac094454cd574e333c4fdb132d7bcc9379bcd4aab485b2a63942::wbtc::WBTC",
46
- decimals: 8,
47
- symbol: "BTC",
48
- displayName: "Bitcoin"
49
- },
50
- ETH: {
51
- type: "0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH",
52
- decimals: 8,
53
- symbol: "ETH",
54
- displayName: "Ethereum"
55
- },
56
- GOLD: {
57
- type: "0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM",
58
- decimals: 9,
59
- symbol: "GOLD",
60
- displayName: "Gold"
61
37
  }
62
38
  };
63
- var STABLE_ASSETS = ["USDC", "USDT", "USDe", "USDsui"];
39
+ var STABLE_ASSETS = ["USDC"];
64
40
  var T2000_PACKAGE_ID = process.env.T2000_PACKAGE_ID ?? "0xab92e9f1fe549ad3d6a52924a73181b45791e76120b975138fac9ec9b75db9f3";
65
41
  var T2000_CONFIG_ID = process.env.T2000_CONFIG_ID ?? "0x408add9aa9322f93cfd87523d8f603006eb8713894f4c460283c58a6888dae8a";
66
42
  var T2000_TREASURY_ID = process.env.T2000_TREASURY_ID ?? "0x3bb501b8300125dca59019247941a42af6b292a150ce3cfcce9449456be2ec91";
67
43
  process.env.T2000_API_URL ?? "https://api.t2000.ai";
68
- var CETUS_USDC_SUI_POOL = "0x51e883ba7c0b566a26cbc8a94cd33eb0abd418a77cc1e60ad22fd9b1f29cd2ab";
69
- var CETUS_PACKAGE = "0x1eabed72c53feb3805120a081dc15963c204dc8d091542592abaf7a35689b2fb";
70
- var INVESTMENT_ASSETS = {
71
- SUI: SUPPORTED_ASSETS.SUI,
72
- BTC: SUPPORTED_ASSETS.BTC,
73
- ETH: SUPPORTED_ASSETS.ETH,
74
- GOLD: SUPPORTED_ASSETS.GOLD
75
- };
76
44
 
77
45
  // src/errors.ts
78
46
  var T2000Error = class extends Error {
@@ -99,13 +67,9 @@ var T2000Error = class extends Error {
99
67
  // src/adapters/registry.ts
100
68
  var ProtocolRegistry = class {
101
69
  lending = /* @__PURE__ */ new Map();
102
- swap = /* @__PURE__ */ new Map();
103
70
  registerLending(adapter) {
104
71
  this.lending.set(adapter.id, adapter);
105
72
  }
106
- registerSwap(adapter) {
107
- this.swap.set(adapter.id, adapter);
108
- }
109
73
  async bestSaveRate(asset) {
110
74
  const candidates = [];
111
75
  for (const adapter of this.lending.values()) {
@@ -141,23 +105,6 @@ var ProtocolRegistry = class {
141
105
  candidates.sort((a, b) => a.rate.borrowApy - b.rate.borrowApy);
142
106
  return candidates[0];
143
107
  }
144
- async bestSwapQuote(from, to, amount) {
145
- const candidates = [];
146
- for (const adapter of this.swap.values()) {
147
- const pairs = adapter.getSupportedPairs();
148
- if (!pairs.some((p) => p.from === from && p.to === to)) continue;
149
- try {
150
- const quote = await adapter.getQuote(from, to, amount);
151
- candidates.push({ adapter, quote });
152
- } catch {
153
- }
154
- }
155
- if (candidates.length === 0) {
156
- throw new T2000Error("ASSET_NOT_SUPPORTED", `No swap adapter supports ${from} \u2192 ${to}`);
157
- }
158
- candidates.sort((a, b) => b.quote.expectedOutput - a.quote.expectedOutput);
159
- return candidates[0];
160
- }
161
108
  async bestSaveRateAcrossAssets() {
162
109
  const candidates = [];
163
110
  for (const asset of STABLE_ASSETS) {
@@ -179,9 +126,8 @@ var ProtocolRegistry = class {
179
126
  }
180
127
  async allRatesAcrossAssets() {
181
128
  const results = [];
182
- const allAssets = [...STABLE_ASSETS, ...Object.keys(INVESTMENT_ASSETS)];
183
129
  const seen = /* @__PURE__ */ new Set();
184
- for (const asset of allAssets) {
130
+ for (const asset of STABLE_ASSETS) {
185
131
  if (seen.has(asset)) continue;
186
132
  seen.add(asset);
187
133
  for (const adapter of this.lending.values()) {
@@ -230,15 +176,9 @@ var ProtocolRegistry = class {
230
176
  getLending(id) {
231
177
  return this.lending.get(id);
232
178
  }
233
- getSwap(id) {
234
- return this.swap.get(id);
235
- }
236
179
  listLending() {
237
180
  return [...this.lending.values()];
238
181
  }
239
- listSwap() {
240
- return [...this.swap.values()];
241
- }
242
182
  };
243
183
 
244
184
  // src/utils/format.ts
@@ -259,12 +199,10 @@ function normalizeAsset(input) {
259
199
  // src/protocols/protocolFee.ts
260
200
  var FEE_RATES = {
261
201
  save: SAVE_FEE_BPS,
262
- swap: SWAP_FEE_BPS,
263
202
  borrow: BORROW_FEE_BPS
264
203
  };
265
204
  var OP_CODES = {
266
205
  save: 0,
267
- swap: 1,
268
206
  borrow: 2
269
207
  };
270
208
  function addCollectFeeToTx(tx, paymentCoin, operation) {
@@ -689,7 +627,6 @@ async function addClaimRewardsToTx(tx, client, address) {
689
627
  }
690
628
 
691
629
  // src/adapters/descriptors.ts
692
- var SUILEND_PACKAGE = "0xf95b06141ed4a174f239417323bde3f209b972f5930d8521ea38a52aff3a6ddf";
693
630
  var naviDescriptor = {
694
631
  id: "navi",
695
632
  name: "NAVI Protocol",
@@ -706,39 +643,8 @@ var naviDescriptor = {
706
643
  "incentive_v3::repay": "repay"
707
644
  }
708
645
  };
709
- var suilendDescriptor = {
710
- id: "suilend",
711
- name: "Suilend",
712
- packages: [SUILEND_PACKAGE],
713
- actionMap: {
714
- "lending_market::deposit_liquidity_and_mint_ctokens": "save",
715
- "lending_market::deposit_ctokens_into_obligation": "save",
716
- "lending_market::create_obligation": "save",
717
- "lending_market::withdraw_ctokens": "withdraw",
718
- "lending_market::redeem_ctokens_and_withdraw_liquidity": "withdraw",
719
- "lending_market::redeem_ctokens_and_withdraw_liquidity_request": "withdraw",
720
- "lending_market::fulfill_liquidity_request": "withdraw",
721
- "lending_market::unstake_sui_from_staker": "withdraw",
722
- "lending_market::borrow": "borrow",
723
- "lending_market::repay": "repay"
724
- }
725
- };
726
- var cetusDescriptor = {
727
- id: "cetus",
728
- name: "Cetus DEX",
729
- packages: [CETUS_PACKAGE],
730
- actionMap: {
731
- "router::swap": "swap",
732
- "router::swap_ab_bc": "swap",
733
- "router::swap_ab_cb": "swap",
734
- "router::swap_ba_bc": "swap",
735
- "router::swap_ba_cb": "swap"
736
- }
737
- };
738
646
  var allDescriptors = [
739
- naviDescriptor,
740
- suilendDescriptor,
741
- cetusDescriptor
647
+ naviDescriptor
742
648
  ];
743
649
 
744
650
  // src/adapters/navi.ts
@@ -822,651 +728,7 @@ var NaviAdapter = class {
822
728
  return addClaimRewardsToTx(tx, this.client, address);
823
729
  }
824
730
  };
825
- var DEFAULT_SLIPPAGE_BPS = 300;
826
- function createAggregatorClient(client, signer) {
827
- return new AggregatorClient({
828
- client,
829
- signer,
830
- env: Env.Mainnet
831
- });
832
- }
833
- async function buildSwapTx(params) {
834
- const { client, address, fromAsset, toAsset, amount, maxSlippageBps = DEFAULT_SLIPPAGE_BPS } = params;
835
- const fromInfo = SUPPORTED_ASSETS[fromAsset];
836
- const toInfo = SUPPORTED_ASSETS[toAsset];
837
- if (!fromInfo || !toInfo) {
838
- throw new T2000Error("ASSET_NOT_SUPPORTED", `Swap pair ${fromAsset}/${toAsset} is not supported`);
839
- }
840
- const rawAmount = BigInt(Math.floor(amount * 10 ** fromInfo.decimals));
841
- const aggClient = createAggregatorClient(client, address);
842
- const _origLog = console.log;
843
- console.log = () => {
844
- };
845
- let result;
846
- try {
847
- result = await aggClient.findRouters({
848
- from: fromInfo.type,
849
- target: toInfo.type,
850
- amount: rawAmount,
851
- byAmountIn: true
852
- });
853
- } finally {
854
- console.log = _origLog;
855
- }
856
- if (!result || result.insufficientLiquidity) {
857
- throw new T2000Error(
858
- "ASSET_NOT_SUPPORTED",
859
- `No swap route found for ${fromAsset} \u2192 ${toAsset}`
860
- );
861
- }
862
- const tx = new Transaction();
863
- const slippage = maxSlippageBps / 1e4;
864
- console.log = () => {
865
- };
866
- try {
867
- await aggClient.fastRouterSwap({
868
- router: result,
869
- txb: tx,
870
- slippage
871
- });
872
- } finally {
873
- console.log = _origLog;
874
- }
875
- const estimatedOut = Number(result.amountOut.toString());
876
- return {
877
- tx,
878
- estimatedOut,
879
- toDecimals: toInfo.decimals
880
- };
881
- }
882
- async function addSwapToTx(params) {
883
- const { tx, client, address, inputCoin, fromAsset, toAsset, amount, maxSlippageBps = DEFAULT_SLIPPAGE_BPS } = params;
884
- const fromInfo = SUPPORTED_ASSETS[fromAsset];
885
- const toInfo = SUPPORTED_ASSETS[toAsset];
886
- if (!fromInfo || !toInfo) {
887
- throw new T2000Error("ASSET_NOT_SUPPORTED", `Swap pair ${fromAsset}/${toAsset} is not supported`);
888
- }
889
- const rawAmount = BigInt(Math.floor(amount * 10 ** fromInfo.decimals));
890
- const aggClient = createAggregatorClient(client, address);
891
- const _origLog = console.log;
892
- console.log = () => {
893
- };
894
- let result;
895
- try {
896
- result = await aggClient.findRouters({
897
- from: fromInfo.type,
898
- target: toInfo.type,
899
- amount: rawAmount,
900
- byAmountIn: true
901
- });
902
- } finally {
903
- console.log = _origLog;
904
- }
905
- if (!result || result.insufficientLiquidity) {
906
- throw new T2000Error(
907
- "ASSET_NOT_SUPPORTED",
908
- `No swap route found for ${fromAsset} \u2192 ${toAsset}`
909
- );
910
- }
911
- const slippage = maxSlippageBps / 1e4;
912
- console.log = () => {
913
- };
914
- let outputCoin;
915
- try {
916
- outputCoin = await aggClient.routerSwap({
917
- router: result,
918
- txb: tx,
919
- inputCoin,
920
- slippage
921
- });
922
- } finally {
923
- console.log = _origLog;
924
- }
925
- const estimatedOut = Number(result.amountOut.toString());
926
- return {
927
- outputCoin,
928
- estimatedOut,
929
- toDecimals: toInfo.decimals
930
- };
931
- }
932
- async function getPoolPrice(client) {
933
- try {
934
- const pool = await client.getObject({
935
- id: CETUS_USDC_SUI_POOL,
936
- options: { showContent: true }
937
- });
938
- if (pool.data?.content?.dataType === "moveObject") {
939
- const fields = pool.data.content.fields;
940
- const currentSqrtPrice = BigInt(String(fields.current_sqrt_price ?? "0"));
941
- if (currentSqrtPrice > 0n) {
942
- const Q64 = 2n ** 64n;
943
- const sqrtPriceFloat = Number(currentSqrtPrice) / Number(Q64);
944
- const rawPrice = sqrtPriceFloat * sqrtPriceFloat;
945
- const suiPriceUsd = 1e3 / rawPrice;
946
- if (suiPriceUsd > 0.01 && suiPriceUsd < 1e3) return suiPriceUsd;
947
- }
948
- }
949
- } catch {
950
- }
951
- return 3.5;
952
- }
953
- async function getSwapQuote(client, fromAsset, toAsset, amount) {
954
- const fromInfo = SUPPORTED_ASSETS[fromAsset];
955
- const toInfo = SUPPORTED_ASSETS[toAsset];
956
- if (!fromInfo || !toInfo) {
957
- throw new T2000Error("ASSET_NOT_SUPPORTED", `Swap pair ${fromAsset}/${toAsset} is not supported`);
958
- }
959
- const rawAmount = BigInt(Math.floor(amount * 10 ** fromInfo.decimals));
960
- const poolPrice = await getPoolPrice(client);
961
- try {
962
- const aggClient = createAggregatorClient(client);
963
- const result = await aggClient.findRouters({
964
- from: fromInfo.type,
965
- target: toInfo.type,
966
- amount: rawAmount,
967
- byAmountIn: true
968
- });
969
- if (!result || result.insufficientLiquidity) {
970
- return fallbackQuote(fromAsset, amount, poolPrice);
971
- }
972
- const expectedOutput = Number(result.amountOut.toString()) / 10 ** toInfo.decimals;
973
- const priceImpact = result.deviationRatio ?? 0;
974
- return { expectedOutput, priceImpact, poolPrice };
975
- } catch {
976
- return fallbackQuote(fromAsset, amount, poolPrice);
977
- }
978
- }
979
- function fallbackQuote(fromAsset, amount, poolPrice) {
980
- const expectedOutput = fromAsset === "USDC" ? amount / poolPrice : amount * poolPrice;
981
- return { expectedOutput, priceImpact: 0, poolPrice };
982
- }
983
-
984
- // src/adapters/cetus.ts
985
- var CetusAdapter = class {
986
- id = "cetus";
987
- name = "Cetus";
988
- version = "1.0.0";
989
- capabilities = ["swap"];
990
- client;
991
- async init(client) {
992
- this.client = client;
993
- }
994
- initSync(client) {
995
- this.client = client;
996
- }
997
- async getQuote(from, to, amount) {
998
- return getSwapQuote(this.client, from, to, amount);
999
- }
1000
- async buildSwapTx(address, from, to, amount, maxSlippageBps) {
1001
- const result = await buildSwapTx({
1002
- client: this.client,
1003
- address,
1004
- fromAsset: from,
1005
- toAsset: to,
1006
- amount,
1007
- maxSlippageBps
1008
- });
1009
- return {
1010
- tx: result.tx,
1011
- estimatedOut: result.estimatedOut,
1012
- toDecimals: result.toDecimals
1013
- };
1014
- }
1015
- getSupportedPairs() {
1016
- const pairs = [];
1017
- for (const asset of Object.keys(INVESTMENT_ASSETS)) {
1018
- pairs.push({ from: "USDC", to: asset }, { from: asset, to: "USDC" });
1019
- }
1020
- for (const a of STABLE_ASSETS) {
1021
- for (const b of STABLE_ASSETS) {
1022
- if (a !== b) pairs.push({ from: a, to: b });
1023
- }
1024
- }
1025
- return pairs;
1026
- }
1027
- async getPoolPrice() {
1028
- return getPoolPrice(this.client);
1029
- }
1030
- async addSwapToTx(tx, address, inputCoin, from, to, amount, maxSlippageBps) {
1031
- return addSwapToTx({
1032
- tx,
1033
- client: this.client,
1034
- address,
1035
- inputCoin,
1036
- fromAsset: from,
1037
- toAsset: to,
1038
- amount,
1039
- maxSlippageBps
1040
- });
1041
- }
1042
- };
1043
- var MIN_HEALTH_FACTOR2 = 1.5;
1044
- async function quietSuilend(fn) {
1045
- const origLog = console.log;
1046
- const origWarn = console.warn;
1047
- const filter = (...args) => typeof args[0] === "string" && (args[0].includes("PythEndpoint") || args[0].includes("PythConnection"));
1048
- console.log = (...args) => {
1049
- if (!filter(...args)) origLog.apply(console, args);
1050
- };
1051
- console.warn = (...args) => {
1052
- if (!filter(...args)) origWarn.apply(console, args);
1053
- };
1054
- return fn().finally(() => {
1055
- console.log = origLog;
1056
- console.warn = origWarn;
1057
- });
1058
- }
1059
- var SuilendAdapter = class {
1060
- id = "suilend";
1061
- name = "Suilend";
1062
- version = "3.0.0";
1063
- capabilities = ["save", "withdraw", "borrow", "repay"];
1064
- supportedAssets = [...STABLE_ASSETS, "SUI", "ETH", "BTC", "GOLD"];
1065
- supportsSameAssetBorrow = false;
1066
- client;
1067
- sdkClient = null;
1068
- async init(client) {
1069
- this.client = client;
1070
- }
1071
- initSync(client) {
1072
- this.client = client;
1073
- }
1074
- async getSdkClient() {
1075
- if (!this.sdkClient) {
1076
- this.sdkClient = await SuilendClient.initialize(
1077
- LENDING_MARKET_ID,
1078
- LENDING_MARKET_TYPE,
1079
- this.client,
1080
- false
1081
- );
1082
- }
1083
- return this.sdkClient;
1084
- }
1085
- resolveSymbol(coinType) {
1086
- try {
1087
- const normalized = normalizeStructTag(coinType);
1088
- for (const [key, info] of Object.entries(SUPPORTED_ASSETS)) {
1089
- try {
1090
- if (normalizeStructTag(info.type) === normalized) return key;
1091
- } catch {
1092
- }
1093
- }
1094
- } catch {
1095
- }
1096
- const parts = coinType.split("::");
1097
- return parts[parts.length - 1] || "UNKNOWN";
1098
- }
1099
- async getRates(asset) {
1100
- try {
1101
- const sdk = await this.getSdkClient();
1102
- const { reserveMap } = await quietSuilend(() => initializeSuilend(this.client, sdk));
1103
- const assetInfo = SUPPORTED_ASSETS[asset];
1104
- if (!assetInfo) throw new T2000Error("ASSET_NOT_SUPPORTED", `Suilend does not support ${asset}`);
1105
- const normalized = normalizeStructTag(assetInfo.type);
1106
- const reserve = Object.values(reserveMap).find((r) => {
1107
- try {
1108
- return normalizeStructTag(r.coinType) === normalized;
1109
- } catch {
1110
- return false;
1111
- }
1112
- });
1113
- if (!reserve) throw new T2000Error("ASSET_NOT_SUPPORTED", `Suilend does not support ${asset}`);
1114
- return {
1115
- asset,
1116
- saveApy: reserve.depositAprPercent.toNumber(),
1117
- borrowApy: reserve.borrowAprPercent.toNumber()
1118
- };
1119
- } catch (err) {
1120
- if (err instanceof T2000Error) throw err;
1121
- const msg = err instanceof Error ? err.message : String(err);
1122
- throw new T2000Error("PROTOCOL_UNAVAILABLE", `Suilend getRates failed: ${msg}`);
1123
- }
1124
- }
1125
- async getPositions(address) {
1126
- const supplies = [];
1127
- const borrows = [];
1128
- try {
1129
- const sdk = await this.getSdkClient();
1130
- const { reserveMap, refreshedRawReserves } = await quietSuilend(() => initializeSuilend(this.client, sdk));
1131
- const { obligations, obligationOwnerCaps } = await initializeObligations(
1132
- this.client,
1133
- sdk,
1134
- refreshedRawReserves,
1135
- reserveMap,
1136
- address
1137
- );
1138
- if (obligationOwnerCaps.length === 0 || obligations.length === 0) {
1139
- return { supplies, borrows };
1140
- }
1141
- const obligation = obligations[0];
1142
- for (const dep of obligation.deposits) {
1143
- const symbol = this.resolveSymbol(dep.coinType);
1144
- const amount = dep.depositedAmount.toNumber();
1145
- const amountUsd = dep.depositedAmountUsd.toNumber();
1146
- const apy = dep.reserve.depositAprPercent.toNumber();
1147
- if (amountUsd > 0.01) {
1148
- supplies.push({ asset: symbol, amount, amountUsd, apy });
1149
- }
1150
- }
1151
- for (const bor of obligation.borrows) {
1152
- const symbol = this.resolveSymbol(bor.coinType);
1153
- const amount = bor.borrowedAmount.toNumber();
1154
- const amountUsd = bor.borrowedAmountUsd.toNumber();
1155
- const apy = bor.reserve.borrowAprPercent.toNumber();
1156
- if (amountUsd > 0.01) {
1157
- borrows.push({ asset: symbol, amount, amountUsd, apy });
1158
- }
1159
- }
1160
- } catch (err) {
1161
- if (err instanceof T2000Error) throw err;
1162
- const msg = err instanceof Error ? err.message : String(err);
1163
- throw new T2000Error("PROTOCOL_UNAVAILABLE", `Suilend getPositions failed: ${msg}`);
1164
- }
1165
- return { supplies, borrows };
1166
- }
1167
- async getHealth(address) {
1168
- try {
1169
- const sdk = await this.getSdkClient();
1170
- const { reserveMap, refreshedRawReserves } = await quietSuilend(() => initializeSuilend(this.client, sdk));
1171
- const { obligations, obligationOwnerCaps } = await initializeObligations(
1172
- this.client,
1173
- sdk,
1174
- refreshedRawReserves,
1175
- reserveMap,
1176
- address
1177
- );
1178
- if (obligationOwnerCaps.length === 0 || obligations.length === 0) {
1179
- return { healthFactor: Infinity, supplied: 0, borrowed: 0, maxBorrow: 0, liquidationThreshold: 0 };
1180
- }
1181
- const ob = obligations[0];
1182
- const supplied = ob.depositedAmountUsd.toNumber();
1183
- const borrowed = ob.borrowedAmountUsd.toNumber();
1184
- const borrowLimit = ob.borrowLimitUsd.toNumber();
1185
- const unhealthy = ob.unhealthyBorrowValueUsd.toNumber();
1186
- const liqThreshold = supplied > 0 ? unhealthy / supplied : 0.75;
1187
- const healthFactor = borrowed > 0 ? unhealthy / borrowed : Infinity;
1188
- const maxBorrow = Math.max(0, borrowLimit - borrowed);
1189
- return { healthFactor, supplied, borrowed, maxBorrow, liquidationThreshold: liqThreshold };
1190
- } catch {
1191
- return { healthFactor: Infinity, supplied: 0, borrowed: 0, maxBorrow: 0, liquidationThreshold: 0 };
1192
- }
1193
- }
1194
- async buildSaveTx(address, amount, asset, options) {
1195
- const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1196
- const assetInfo = SUPPORTED_ASSETS[assetKey];
1197
- const sdk = await this.getSdkClient();
1198
- const caps = await SuilendClient.getObligationOwnerCaps(address, [LENDING_MARKET_TYPE], this.client);
1199
- const tx = new Transaction();
1200
- tx.setSender(address);
1201
- const rawValue = stableToRaw(amount, assetInfo.decimals).toString();
1202
- if (caps.length > 0) {
1203
- if (options?.collectFee) {
1204
- const allCoins = await this.fetchAllCoins(address, assetInfo.type);
1205
- if (allCoins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", `No ${assetInfo.displayName} coins found`);
1206
- const primaryCoinId = allCoins[0].coinObjectId;
1207
- if (allCoins.length > 1) {
1208
- tx.mergeCoins(tx.object(primaryCoinId), allCoins.slice(1).map((c) => tx.object(c.coinObjectId)));
1209
- }
1210
- const [depositCoin] = tx.splitCoins(tx.object(primaryCoinId), [rawValue]);
1211
- addCollectFeeToTx(tx, depositCoin, "save");
1212
- }
1213
- await sdk.depositIntoObligation(address, assetInfo.type, rawValue, tx, caps[0].id);
1214
- } else {
1215
- const newCap = sdk.createObligation(tx);
1216
- let depositCoin;
1217
- if (assetKey === "SUI") {
1218
- [depositCoin] = tx.splitCoins(tx.gas, [rawValue]);
1219
- } else {
1220
- const allCoins = await this.fetchAllCoins(address, assetInfo.type);
1221
- if (allCoins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", `No ${assetInfo.displayName} coins found`);
1222
- const primaryCoin = tx.object(allCoins[0].coinObjectId);
1223
- if (allCoins.length > 1) {
1224
- tx.mergeCoins(primaryCoin, allCoins.slice(1).map((c) => tx.object(c.coinObjectId)));
1225
- }
1226
- [depositCoin] = tx.splitCoins(primaryCoin, [rawValue]);
1227
- }
1228
- if (options?.collectFee) {
1229
- addCollectFeeToTx(tx, depositCoin, "save");
1230
- }
1231
- sdk.deposit(depositCoin, assetInfo.type, newCap, tx);
1232
- tx.transferObjects([newCap], address);
1233
- }
1234
- return { tx };
1235
- }
1236
- async buildWithdrawTx(address, amount, asset) {
1237
- const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1238
- const assetInfo = SUPPORTED_ASSETS[assetKey];
1239
- const sdk = await this.getSdkClient();
1240
- const caps = await SuilendClient.getObligationOwnerCaps(address, [LENDING_MARKET_TYPE], this.client);
1241
- if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend position found");
1242
- const { ctokenRaw, effectiveAmount, obligationIndex } = await this.resolveWithdrawCTokens(sdk, address, assetKey, assetInfo, amount);
1243
- const cap = caps[obligationIndex] ?? caps[0];
1244
- const tx = new Transaction();
1245
- tx.setSender(address);
1246
- await sdk.withdrawAndSendToUser(address, cap.id, cap.obligationId, assetInfo.type, ctokenRaw, tx);
1247
- return { tx, effectiveAmount };
1248
- }
1249
- async addWithdrawToTx(tx, address, amount, asset) {
1250
- const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1251
- const assetInfo = SUPPORTED_ASSETS[assetKey];
1252
- const sdk = await this.getSdkClient();
1253
- const caps = await SuilendClient.getObligationOwnerCaps(address, [LENDING_MARKET_TYPE], this.client);
1254
- if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend position found");
1255
- const { ctokenRaw, effectiveAmount, obligationIndex } = await this.resolveWithdrawCTokens(sdk, address, assetKey, assetInfo, amount);
1256
- const cap = caps[obligationIndex] ?? caps[0];
1257
- const coin = await sdk.withdraw(cap.id, cap.obligationId, assetInfo.type, ctokenRaw, tx);
1258
- return { coin, effectiveAmount };
1259
- }
1260
- async addSaveToTx(tx, address, coin, asset, options) {
1261
- const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1262
- const assetInfo = SUPPORTED_ASSETS[assetKey];
1263
- const sdk = await this.getSdkClient();
1264
- const caps = await SuilendClient.getObligationOwnerCaps(address, [LENDING_MARKET_TYPE], this.client);
1265
- let capRef;
1266
- if (caps.length === 0) {
1267
- const newCap = sdk.createObligation(tx);
1268
- capRef = newCap;
1269
- tx.transferObjects([newCap], address);
1270
- } else {
1271
- capRef = caps[0].id;
1272
- }
1273
- if (options?.collectFee) {
1274
- addCollectFeeToTx(tx, coin, "save");
1275
- }
1276
- sdk.deposit(coin, assetInfo.type, capRef, tx);
1277
- }
1278
- async buildBorrowTx(address, amount, asset, options) {
1279
- const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1280
- const assetInfo = SUPPORTED_ASSETS[assetKey];
1281
- const sdk = await this.getSdkClient();
1282
- const caps = await SuilendClient.getObligationOwnerCaps(address, [LENDING_MARKET_TYPE], this.client);
1283
- if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend position found. Deposit collateral first with: t2000 save <amount>");
1284
- const rawValue = stableToRaw(amount, assetInfo.decimals).toString();
1285
- const tx = new Transaction();
1286
- tx.setSender(address);
1287
- if (options?.collectFee) {
1288
- const coin = await sdk.borrow(caps[0].id, caps[0].obligationId, assetInfo.type, rawValue, tx);
1289
- addCollectFeeToTx(tx, coin, "borrow");
1290
- tx.transferObjects([coin], address);
1291
- } else {
1292
- await sdk.borrowAndSendToUser(address, caps[0].id, caps[0].obligationId, assetInfo.type, rawValue, tx);
1293
- }
1294
- return { tx };
1295
- }
1296
- async buildRepayTx(address, amount, asset) {
1297
- const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1298
- const assetInfo = SUPPORTED_ASSETS[assetKey];
1299
- const sdk = await this.getSdkClient();
1300
- const caps = await SuilendClient.getObligationOwnerCaps(address, [LENDING_MARKET_TYPE], this.client);
1301
- if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend obligation found");
1302
- const rawValue = stableToRaw(amount, assetInfo.decimals).toString();
1303
- const tx = new Transaction();
1304
- tx.setSender(address);
1305
- await sdk.repayIntoObligation(address, caps[0].obligationId, assetInfo.type, rawValue, tx);
1306
- return { tx };
1307
- }
1308
- async addRepayToTx(tx, address, coin, asset) {
1309
- const assetKey = asset in SUPPORTED_ASSETS ? asset : "USDC";
1310
- const assetInfo = SUPPORTED_ASSETS[assetKey];
1311
- const sdk = await this.getSdkClient();
1312
- const caps = await SuilendClient.getObligationOwnerCaps(address, [LENDING_MARKET_TYPE], this.client);
1313
- if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend obligation found");
1314
- sdk.repay(caps[0].obligationId, assetInfo.type, coin, tx);
1315
- }
1316
- async resolveWithdrawCTokens(sdk, address, assetKey, assetInfo, amount) {
1317
- const { reserveMap, refreshedRawReserves } = await quietSuilend(() => initializeSuilend(this.client, sdk));
1318
- const { obligations } = await initializeObligations(
1319
- this.client,
1320
- sdk,
1321
- refreshedRawReserves,
1322
- reserveMap,
1323
- address
1324
- );
1325
- if (obligations.length === 0) throw new T2000Error("NO_COLLATERAL", `Nothing to withdraw for ${assetInfo.displayName} on Suilend \u2014 no obligations found`);
1326
- let dep;
1327
- let matchedObligation = 0;
1328
- for (let oi = 0; oi < obligations.length; oi++) {
1329
- dep = obligations[oi].deposits.find((d) => {
1330
- const resolved = this.resolveSymbol(d.coinType);
1331
- if (resolved === assetKey) return true;
1332
- try {
1333
- return normalizeStructTag(d.coinType) === normalizeStructTag(assetInfo.type);
1334
- } catch {
1335
- return false;
1336
- }
1337
- });
1338
- if (dep && dep.depositedAmount.toNumber() > 1e-10) {
1339
- matchedObligation = oi;
1340
- break;
1341
- }
1342
- dep = void 0;
1343
- }
1344
- if (!dep) {
1345
- const foundDeposits = obligations.flatMap(
1346
- (o, i) => o.deposits.map((d) => `ob${i}:${this.resolveSymbol(d.coinType)}=${d.depositedAmount.toFixed(8)}`)
1347
- );
1348
- throw new T2000Error(
1349
- "NO_COLLATERAL",
1350
- `Nothing to withdraw for ${assetInfo.displayName} (${assetKey}) on Suilend. Found deposits: [${foundDeposits.join(", ")}]`
1351
- );
1352
- }
1353
- const deposited = dep.depositedAmount.toNumber();
1354
- const effectiveAmount = Math.min(amount, deposited);
1355
- const proportion = effectiveAmount / deposited;
1356
- const ctokenRaw = proportion >= 0.999 ? dep.depositedCtokenAmount.toFixed(0) : dep.depositedCtokenAmount.times(proportion).integerValue(1).toFixed(0);
1357
- return { ctokenRaw, effectiveAmount, obligationIndex: matchedObligation };
1358
- }
1359
- async maxWithdraw(address, _asset) {
1360
- const health = await this.getHealth(address);
1361
- let maxAmount;
1362
- if (health.borrowed === 0) {
1363
- maxAmount = health.supplied;
1364
- } else {
1365
- maxAmount = Math.max(0, health.supplied - health.borrowed * MIN_HEALTH_FACTOR2 / health.liquidationThreshold);
1366
- }
1367
- const remainingSupply = health.supplied - maxAmount;
1368
- const hfAfter = health.borrowed > 0 ? remainingSupply * health.liquidationThreshold / health.borrowed : Infinity;
1369
- return { maxAmount, healthFactorAfter: hfAfter, currentHF: health.healthFactor };
1370
- }
1371
- async maxBorrow(address, _asset) {
1372
- const health = await this.getHealth(address);
1373
- return { maxAmount: health.maxBorrow, healthFactorAfter: MIN_HEALTH_FACTOR2, currentHF: health.healthFactor };
1374
- }
1375
- async fetchAllCoins(owner, coinType) {
1376
- const all = [];
1377
- let cursor = null;
1378
- let hasNext = true;
1379
- while (hasNext) {
1380
- const page = await this.client.getCoins({ owner, coinType, cursor: cursor ?? void 0 });
1381
- all.push(...page.data.map((c) => ({ coinObjectId: c.coinObjectId, balance: c.balance })));
1382
- cursor = page.nextCursor;
1383
- hasNext = page.hasNextPage;
1384
- }
1385
- return all;
1386
- }
1387
- async getPendingRewards(address) {
1388
- try {
1389
- const sdk = await this.getSdkClient();
1390
- const { reserveMap, refreshedRawReserves } = await quietSuilend(() => initializeSuilend(this.client, sdk));
1391
- const { obligations, obligationOwnerCaps } = await initializeObligations(
1392
- this.client,
1393
- sdk,
1394
- refreshedRawReserves,
1395
- reserveMap,
1396
- address
1397
- );
1398
- if (obligationOwnerCaps.length === 0 || obligations.length === 0) return [];
1399
- const ob = obligations[0];
1400
- const rewards = [];
1401
- const WAD = 1e18;
1402
- for (const dep of ob.deposits) {
1403
- const urm = dep.userRewardManager;
1404
- for (const rw of dep.reserve.depositsPoolRewardManager?.poolRewards ?? []) {
1405
- if (rw.endTimeMs <= Date.now()) continue;
1406
- let claimableAmount = 0;
1407
- const userReward = urm?.rewards?.[rw.rewardIndex];
1408
- if (userReward?.earnedRewards) {
1409
- claimableAmount = Number(BigInt(userReward.earnedRewards.value.toString())) / WAD / 10 ** rw.mintDecimals;
1410
- }
1411
- const symbol = rw.symbol || rw.coinType.split("::").pop() || "UNKNOWN";
1412
- rewards.push({
1413
- protocol: "suilend",
1414
- asset: this.resolveSymbol(dep.coinType),
1415
- coinType: rw.coinType,
1416
- symbol,
1417
- amount: claimableAmount,
1418
- estimatedValueUsd: 0
1419
- });
1420
- }
1421
- }
1422
- return rewards;
1423
- } catch {
1424
- return [];
1425
- }
1426
- }
1427
- async addClaimRewardsToTx(tx, address) {
1428
- try {
1429
- const sdk = await this.getSdkClient();
1430
- const caps = await SuilendClient.getObligationOwnerCaps(address, [LENDING_MARKET_TYPE], this.client);
1431
- if (caps.length === 0) return [];
1432
- const { reserveMap, refreshedRawReserves } = await quietSuilend(() => initializeSuilend(this.client, sdk));
1433
- const { obligations } = await initializeObligations(
1434
- this.client,
1435
- sdk,
1436
- refreshedRawReserves,
1437
- reserveMap,
1438
- address
1439
- );
1440
- if (obligations.length === 0) return [];
1441
- const ob = obligations[0];
1442
- const claimRewards = [];
1443
- for (const dep of ob.deposits) {
1444
- for (const rw of dep.reserve.depositsPoolRewardManager.poolRewards) {
1445
- if (rw.endTimeMs <= Date.now()) continue;
1446
- claimRewards.push({
1447
- reserveArrayIndex: dep.reserveArrayIndex,
1448
- rewardIndex: BigInt(rw.rewardIndex),
1449
- rewardCoinType: rw.coinType,
1450
- side: Side.DEPOSIT
1451
- });
1452
- }
1453
- }
1454
- if (claimRewards.length === 0) return [];
1455
- sdk.claimRewardsAndSendToUser(address, caps[0].id, claimRewards, tx);
1456
- return claimRewards.map((r) => ({
1457
- protocol: "suilend",
1458
- asset: "",
1459
- coinType: r.rewardCoinType,
1460
- symbol: r.rewardCoinType.split("::").pop() ?? "UNKNOWN",
1461
- amount: 0,
1462
- estimatedValueUsd: 0
1463
- }));
1464
- } catch {
1465
- return [];
1466
- }
1467
- }
1468
- };
1469
731
 
1470
- export { CetusAdapter, NaviAdapter, ProtocolRegistry, SuilendAdapter, allDescriptors, cetusDescriptor, naviDescriptor, suilendDescriptor };
732
+ export { NaviAdapter, ProtocolRegistry, allDescriptors, naviDescriptor };
1471
733
  //# sourceMappingURL=index.js.map
1472
734
  //# sourceMappingURL=index.js.map