@t2000/sdk 0.19.20 → 0.19.22

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,7 +11,6 @@ var promises = require('fs/promises');
11
11
  var path = require('path');
12
12
  var os = require('os');
13
13
  var lending = require('@naviprotocol/lending');
14
- var bcs = require('@mysten/sui/bcs');
15
14
  var aggregatorSdk = require('@cetusprotocol/aggregator-sdk');
16
15
  var client = require('@suilend/sdk/client');
17
16
  var initialize = require('@suilend/sdk/lib/initialize');
@@ -135,18 +134,6 @@ var PERPS_MARKETS = ["SUI-PERP"];
135
134
  var DEFAULT_MAX_LEVERAGE = 5;
136
135
  var DEFAULT_MAX_POSITION_SIZE = 1e3;
137
136
  var GAS_RESERVE_MIN = 0.05;
138
- var SENTINEL = {
139
- PACKAGE: "0x88b83f36dafcd5f6dcdcf1d2cb5889b03f61264ab3cee9cae35db7aa940a21b7",
140
- AGENT_REGISTRY: "0xc47564f5f14c12b31e0dfa1a3dc99a6380a1edf8929c28cb0eaa3359c8db36ac",
141
- ENCLAVE: "0xfb1261aeb9583514cb1341a548a5ec12d1231bd96af22215f1792617a93e1213",
142
- PROTOCOL_CONFIG: "0x2fa4fa4a1dd0498612304635ff9334e1b922e78af325000e9d9c0e88adea459f",
143
- TEE_API: "https://app.suisentinel.xyz/api/consume-prompt",
144
- SENTINELS_API: "https://api.suisentinel.xyz/agents/mainnet",
145
- RANDOM: "0x8",
146
- MIN_FEE_MIST: 100000000n,
147
- // 0.1 SUI
148
- MAX_PROMPT_TOKENS: 600
149
- };
150
137
 
151
138
  // src/errors.ts
152
139
  var T2000Error = class extends Error {
@@ -559,7 +546,7 @@ async function queryBalance(client, address) {
559
546
  var SUI_TYPE = "0x2::sui::SUI";
560
547
  var KNOWN_TARGETS = [
561
548
  [/::suilend|::obligation/, "lending"],
562
- [/::navi|::incentive_v2/, "lending"],
549
+ [/::navi|::incentive_v\d+|::oracle_pro/, "lending"],
563
550
  [/::cetus|::pool/, "swap"],
564
551
  [/::deepbook/, "swap"],
565
552
  [/::transfer::public_transfer/, "send"]
@@ -713,6 +700,7 @@ function sdkOptions(client) {
713
700
  return { env: "prod", client, cacheTime: 0, disableCache: true };
714
701
  }
715
702
  async function refreshOracle(tx, client, address, options) {
703
+ if (options?.skipOracle) return;
716
704
  const origInfo = console.info;
717
705
  const origWarn = console.warn;
718
706
  console.info = (...args) => {
@@ -880,13 +868,14 @@ async function buildSaveTx(client, address, amount, options = {}) {
880
868
  const assetInfo = resolveAssetInfo(asset);
881
869
  const coins = await fetchCoins(client, address, assetInfo.type);
882
870
  if (coins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", `No ${assetInfo.displayName} coins found`);
871
+ const totalBalance = coins.reduce((sum, c) => sum + BigInt(c.balance), 0n);
883
872
  const tx = new transactions.Transaction();
884
873
  tx.setSender(address);
885
874
  const coinObj = mergeCoins(tx, coins);
886
875
  if (options.collectFee) {
887
876
  addCollectFeeToTx(tx, coinObj, "save");
888
877
  }
889
- const rawAmount = Number(stableToRaw(amount, assetInfo.decimals));
878
+ const rawAmount = Math.min(Number(stableToRaw(amount, assetInfo.decimals)), Number(totalBalance));
890
879
  try {
891
880
  await lending.depositCoinPTB(tx, assetInfo.type, coinObj, {
892
881
  ...sdkOptions(client),
@@ -927,6 +916,7 @@ async function buildWithdrawTx(client, address, amount, options = {}) {
927
916
  }
928
917
  async function addWithdrawToTx(tx, client, address, amount, options = {}) {
929
918
  const asset = options.asset ?? "USDC";
919
+ const sponsored = options.sponsored ?? true;
930
920
  const assetInfo = resolveAssetInfo(asset);
931
921
  const posResult = await getPositions(client, address);
932
922
  const supply = posResult.positions.find(
@@ -944,7 +934,7 @@ async function addWithdrawToTx(tx, client, address, amount, options = {}) {
944
934
  });
945
935
  return { coin, effectiveAmount: 0 };
946
936
  }
947
- await refreshOracle(tx, client, address);
937
+ await refreshOracle(tx, client, address, { skipPythUpdate: sponsored });
948
938
  try {
949
939
  const coin = await lending.withdrawCoinPTB(tx, assetInfo.type, rawAmount, sdkOptions(client));
950
940
  return { coin, effectiveAmount };
@@ -968,8 +958,9 @@ async function addSaveToTx(tx, _client, _address, coin, options = {}) {
968
958
  }
969
959
  async function addRepayToTx(tx, client, address, coin, options = {}) {
970
960
  const asset = options.asset ?? "USDC";
961
+ const sponsored = options.sponsored ?? true;
971
962
  const assetInfo = resolveAssetInfo(asset);
972
- await refreshOracle(tx, client, address);
963
+ await refreshOracle(tx, client, address, { skipPythUpdate: sponsored });
973
964
  try {
974
965
  await lending.repayCoinPTB(tx, assetInfo.type, coin, { env: "prod" });
975
966
  } catch (err) {
@@ -1007,12 +998,16 @@ async function buildRepayTx(client, address, amount, options = {}) {
1007
998
  const assetInfo = resolveAssetInfo(asset);
1008
999
  const coins = await fetchCoins(client, address, assetInfo.type);
1009
1000
  if (coins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", `No ${assetInfo.displayName} coins to repay with`);
1001
+ const totalBalance = coins.reduce((sum, c) => sum + BigInt(c.balance), 0n);
1010
1002
  const tx = new transactions.Transaction();
1011
1003
  tx.setSender(address);
1012
1004
  const coinObj = mergeCoins(tx, coins);
1013
- const rawAmount = Number(stableToRaw(amount, assetInfo.decimals));
1005
+ const rawAmount = Math.min(Number(stableToRaw(amount, assetInfo.decimals)), Number(totalBalance));
1014
1006
  const [repayCoin] = tx.splitCoins(coinObj, [rawAmount]);
1015
- await refreshOracle(tx, client, address, { skipPythUpdate: options.sponsored });
1007
+ await refreshOracle(tx, client, address, {
1008
+ skipPythUpdate: options.sponsored,
1009
+ skipOracle: options.skipOracle
1010
+ });
1016
1011
  try {
1017
1012
  await lending.repayCoinPTB(tx, assetInfo.type, repayCoin, {
1018
1013
  ...sdkOptions(client),
@@ -1126,206 +1121,6 @@ async function getFundStatus(client, address) {
1126
1121
  projectedMonthly: earnings.dailyEarning * 30
1127
1122
  };
1128
1123
  }
1129
- var descriptor = {
1130
- id: "sentinel",
1131
- name: "Sui Sentinel",
1132
- packages: [SENTINEL.PACKAGE],
1133
- actionMap: {
1134
- "sentinel::request_attack": "sentinel_attack",
1135
- "sentinel::consume_prompt": "sentinel_settle"
1136
- }
1137
- };
1138
- function mapAgent(raw) {
1139
- return {
1140
- id: raw.agent_id,
1141
- objectId: raw.agent_object_id,
1142
- name: raw.agent_name,
1143
- model: raw.model ?? "unknown",
1144
- systemPrompt: raw.prompt,
1145
- attackFee: BigInt(raw.cost_per_message),
1146
- prizePool: BigInt(raw.total_balance),
1147
- totalAttacks: raw.total_attacks,
1148
- successfulBreaches: raw.successful_breaches ?? 0,
1149
- state: raw.state
1150
- };
1151
- }
1152
- async function listSentinels() {
1153
- const res = await fetch(SENTINEL.SENTINELS_API);
1154
- if (!res.ok) {
1155
- throw new T2000Error("SENTINEL_API_ERROR", `Sentinel API returned ${res.status}`);
1156
- }
1157
- const data = await res.json();
1158
- if (!Array.isArray(data.agents)) {
1159
- throw new T2000Error("SENTINEL_API_ERROR", "Unexpected API response shape");
1160
- }
1161
- return data.agents.filter((a) => a.state === "active").map(mapAgent);
1162
- }
1163
- async function getSentinelInfo(client, sentinelObjectId) {
1164
- const agents = await listSentinels();
1165
- const match = agents.find((a) => a.objectId === sentinelObjectId || a.id === sentinelObjectId);
1166
- if (match) return match;
1167
- const obj = await client.getObject({
1168
- id: sentinelObjectId,
1169
- options: { showContent: true, showType: true }
1170
- });
1171
- if (!obj.data) {
1172
- throw new T2000Error("SENTINEL_NOT_FOUND", `Sentinel ${sentinelObjectId} not found on-chain`);
1173
- }
1174
- const content = obj.data.content;
1175
- if (!content || content.dataType !== "moveObject") {
1176
- throw new T2000Error("SENTINEL_NOT_FOUND", `Object ${sentinelObjectId} is not a Move object`);
1177
- }
1178
- const fields = content.fields;
1179
- return {
1180
- id: fields.id?.id ?? sentinelObjectId,
1181
- objectId: sentinelObjectId,
1182
- name: fields.name ?? "Unknown",
1183
- model: fields.model ?? "unknown",
1184
- systemPrompt: fields.system_prompt ?? "",
1185
- attackFee: BigInt(fields.cost_per_message ?? "0"),
1186
- prizePool: BigInt(fields.balance ?? "0"),
1187
- totalAttacks: Number(fields.total_attacks ?? "0"),
1188
- successfulBreaches: Number(fields.successful_breaches ?? "0"),
1189
- state: fields.state ?? "unknown"
1190
- };
1191
- }
1192
- async function requestAttack(client, signer, sentinelObjectId, feeMist) {
1193
- if (feeMist < SENTINEL.MIN_FEE_MIST) {
1194
- throw new T2000Error("INVALID_AMOUNT", `Attack fee must be at least 0.1 SUI (${SENTINEL.MIN_FEE_MIST} MIST)`);
1195
- }
1196
- const address = signer.getAddress();
1197
- const tx = new transactions.Transaction();
1198
- tx.setSender(address);
1199
- const [coin] = tx.splitCoins(tx.gas, [Number(feeMist)]);
1200
- const [attack2] = tx.moveCall({
1201
- target: `${SENTINEL.PACKAGE}::sentinel::request_attack`,
1202
- arguments: [
1203
- tx.object(SENTINEL.AGENT_REGISTRY),
1204
- tx.object(sentinelObjectId),
1205
- tx.object(SENTINEL.PROTOCOL_CONFIG),
1206
- coin,
1207
- tx.object(SENTINEL.RANDOM),
1208
- tx.object(CLOCK_ID)
1209
- ]
1210
- });
1211
- tx.transferObjects([attack2], address);
1212
- const built = await tx.build({ client });
1213
- const { signature } = await signer.signTransaction(built);
1214
- const result = await client.executeTransactionBlock({
1215
- transactionBlock: built,
1216
- signature,
1217
- options: { showObjectChanges: true, showEffects: true }
1218
- });
1219
- await client.waitForTransaction({ digest: result.digest });
1220
- const attackObj = result.objectChanges?.find(
1221
- (c) => c.type === "created" && c.objectType?.includes("::sentinel::Attack")
1222
- );
1223
- const attackObjectId = attackObj && "objectId" in attackObj ? attackObj.objectId : void 0;
1224
- if (!attackObjectId) {
1225
- throw new T2000Error("SENTINEL_TX_FAILED", "Attack object was not created \u2014 transaction may have failed");
1226
- }
1227
- return { attackObjectId, digest: result.digest };
1228
- }
1229
- async function submitPrompt(agentId, attackObjectId, prompt) {
1230
- const res = await fetch(SENTINEL.TEE_API, {
1231
- method: "POST",
1232
- headers: { "Content-Type": "application/json" },
1233
- body: JSON.stringify({
1234
- agent_id: agentId,
1235
- attack_object_id: attackObjectId,
1236
- message: prompt
1237
- })
1238
- });
1239
- if (!res.ok) {
1240
- const body = await res.text().catch(() => "");
1241
- throw new T2000Error("SENTINEL_TEE_ERROR", `TEE returned ${res.status}: ${body.slice(0, 200)}`);
1242
- }
1243
- const raw = await res.json();
1244
- const envelope = raw.response ?? raw;
1245
- const data = envelope.data ?? envelope;
1246
- const signature = raw.signature ?? data.signature;
1247
- const timestampMs = envelope.timestamp_ms ?? data.timestamp_ms;
1248
- if (typeof signature !== "string") {
1249
- throw new T2000Error("SENTINEL_TEE_ERROR", "TEE response missing signature");
1250
- }
1251
- return {
1252
- success: data.success ?? data.is_success,
1253
- score: data.score,
1254
- agentResponse: data.agent_response,
1255
- juryResponse: data.jury_response,
1256
- funResponse: data.fun_response ?? "",
1257
- signature,
1258
- timestampMs
1259
- };
1260
- }
1261
- async function settleAttack(client, signer, sentinelObjectId, attackObjectId, prompt, verdict) {
1262
- const sigBytes = Array.from(Buffer.from(verdict.signature.replace(/^0x/, ""), "hex"));
1263
- const address = signer.getAddress();
1264
- const tx = new transactions.Transaction();
1265
- tx.setSender(address);
1266
- tx.moveCall({
1267
- target: `${SENTINEL.PACKAGE}::sentinel::consume_prompt`,
1268
- arguments: [
1269
- tx.object(SENTINEL.AGENT_REGISTRY),
1270
- tx.object(SENTINEL.PROTOCOL_CONFIG),
1271
- tx.object(sentinelObjectId),
1272
- tx.pure.bool(verdict.success),
1273
- tx.pure.string(verdict.agentResponse),
1274
- tx.pure.string(verdict.juryResponse),
1275
- tx.pure.string(verdict.funResponse),
1276
- tx.pure.string(prompt),
1277
- tx.pure.u8(verdict.score),
1278
- tx.pure.u64(verdict.timestampMs),
1279
- tx.pure(bcs.bcs.vector(bcs.bcs.u8()).serialize(sigBytes)),
1280
- tx.object(SENTINEL.ENCLAVE),
1281
- tx.object(attackObjectId),
1282
- tx.object(CLOCK_ID)
1283
- ]
1284
- });
1285
- const built = await tx.build({ client });
1286
- const { signature } = await signer.signTransaction(built);
1287
- const result = await client.executeTransactionBlock({
1288
- transactionBlock: built,
1289
- signature,
1290
- options: { showEffects: true }
1291
- });
1292
- await client.waitForTransaction({ digest: result.digest });
1293
- const txSuccess = result.effects?.status?.status === "success";
1294
- return { digest: result.digest, success: txSuccess };
1295
- }
1296
- async function attack(client, signer, sentinelId, prompt, feeMist) {
1297
- const sentinel = await getSentinelInfo(client, sentinelId);
1298
- const fee = feeMist ?? sentinel.attackFee;
1299
- if (fee < SENTINEL.MIN_FEE_MIST) {
1300
- throw new T2000Error("INVALID_AMOUNT", `Attack fee must be at least 0.1 SUI`);
1301
- }
1302
- const { attackObjectId, digest: requestTx } = await requestAttack(
1303
- client,
1304
- signer,
1305
- sentinel.objectId,
1306
- fee
1307
- );
1308
- const verdict = await submitPrompt(sentinel.id, attackObjectId, prompt);
1309
- const { digest: settleTx } = await settleAttack(
1310
- client,
1311
- signer,
1312
- sentinel.objectId,
1313
- attackObjectId,
1314
- prompt,
1315
- verdict
1316
- );
1317
- const won = verdict.success && verdict.score >= 70;
1318
- return {
1319
- attackObjectId,
1320
- sentinelId: sentinel.id,
1321
- prompt,
1322
- verdict,
1323
- requestTx,
1324
- settleTx,
1325
- won,
1326
- feePaid: Number(fee) / Number(MIST_PER_SUI)
1327
- };
1328
- }
1329
1124
 
1330
1125
  // src/adapters/registry.ts
1331
1126
  var ProtocolRegistry = class {
@@ -1472,8 +1267,9 @@ var ProtocolRegistry = class {
1472
1267
  }
1473
1268
  };
1474
1269
 
1475
- // src/adapters/navi.ts
1476
- var descriptor2 = {
1270
+ // src/adapters/descriptors.ts
1271
+ var SUILEND_PACKAGE = "0xf95b06141ed4a174f239417323bde3f209b972f5930d8521ea38a52aff3a6ddf";
1272
+ var naviDescriptor = {
1477
1273
  id: "navi",
1478
1274
  name: "NAVI Protocol",
1479
1275
  packages: [],
@@ -1489,6 +1285,42 @@ var descriptor2 = {
1489
1285
  "incentive_v3::repay": "repay"
1490
1286
  }
1491
1287
  };
1288
+ var suilendDescriptor = {
1289
+ id: "suilend",
1290
+ name: "Suilend",
1291
+ packages: [SUILEND_PACKAGE],
1292
+ actionMap: {
1293
+ "lending_market::deposit_liquidity_and_mint_ctokens": "save",
1294
+ "lending_market::deposit_ctokens_into_obligation": "save",
1295
+ "lending_market::create_obligation": "save",
1296
+ "lending_market::withdraw_ctokens": "withdraw",
1297
+ "lending_market::redeem_ctokens_and_withdraw_liquidity": "withdraw",
1298
+ "lending_market::redeem_ctokens_and_withdraw_liquidity_request": "withdraw",
1299
+ "lending_market::fulfill_liquidity_request": "withdraw",
1300
+ "lending_market::unstake_sui_from_staker": "withdraw",
1301
+ "lending_market::borrow": "borrow",
1302
+ "lending_market::repay": "repay"
1303
+ }
1304
+ };
1305
+ var cetusDescriptor = {
1306
+ id: "cetus",
1307
+ name: "Cetus DEX",
1308
+ packages: [CETUS_PACKAGE],
1309
+ actionMap: {
1310
+ "router::swap": "swap",
1311
+ "router::swap_ab_bc": "swap",
1312
+ "router::swap_ab_cb": "swap",
1313
+ "router::swap_ba_bc": "swap",
1314
+ "router::swap_ba_cb": "swap"
1315
+ }
1316
+ };
1317
+ var allDescriptors = [
1318
+ naviDescriptor,
1319
+ suilendDescriptor,
1320
+ cetusDescriptor
1321
+ ];
1322
+
1323
+ // src/adapters/navi.ts
1492
1324
  var NaviAdapter = class {
1493
1325
  id = "navi";
1494
1326
  name = "NAVI Protocol";
@@ -1537,7 +1369,11 @@ var NaviAdapter = class {
1537
1369
  }
1538
1370
  async buildRepayTx(address, amount, asset, options) {
1539
1371
  const normalized = normalizeAsset(asset);
1540
- const tx = await buildRepayTx(this.client, address, amount, { asset: normalized, sponsored: options?.sponsored });
1372
+ const tx = await buildRepayTx(this.client, address, amount, {
1373
+ asset: normalized,
1374
+ sponsored: options?.sponsored,
1375
+ skipOracle: options?.skipOracle
1376
+ });
1541
1377
  return { tx };
1542
1378
  }
1543
1379
  async maxWithdraw(address, _asset) {
@@ -1764,18 +1600,6 @@ function fallbackQuote(fromAsset, amount, poolPrice) {
1764
1600
  }
1765
1601
 
1766
1602
  // src/adapters/cetus.ts
1767
- var descriptor3 = {
1768
- id: "cetus",
1769
- name: "Cetus DEX",
1770
- packages: [CETUS_PACKAGE],
1771
- actionMap: {
1772
- "router::swap": "swap",
1773
- "router::swap_ab_bc": "swap",
1774
- "router::swap_ab_cb": "swap",
1775
- "router::swap_ba_bc": "swap",
1776
- "router::swap_ba_cb": "swap"
1777
- }
1778
- };
1779
1603
  var CetusAdapter = class {
1780
1604
  id = "cetus";
1781
1605
  name = "Cetus";
@@ -1834,7 +1658,6 @@ var CetusAdapter = class {
1834
1658
  });
1835
1659
  }
1836
1660
  };
1837
- var SUILEND_PACKAGE = "0xf95b06141ed4a174f239417323bde3f209b972f5930d8521ea38a52aff3a6ddf";
1838
1661
  var MIN_HEALTH_FACTOR2 = 1.5;
1839
1662
  async function quietSuilend(fn) {
1840
1663
  const origLog = console.log;
@@ -1851,23 +1674,6 @@ async function quietSuilend(fn) {
1851
1674
  console.warn = origWarn;
1852
1675
  });
1853
1676
  }
1854
- var descriptor4 = {
1855
- id: "suilend",
1856
- name: "Suilend",
1857
- packages: [SUILEND_PACKAGE],
1858
- actionMap: {
1859
- "lending_market::deposit_liquidity_and_mint_ctokens": "save",
1860
- "lending_market::deposit_ctokens_into_obligation": "save",
1861
- "lending_market::create_obligation": "save",
1862
- "lending_market::withdraw_ctokens": "withdraw",
1863
- "lending_market::redeem_ctokens_and_withdraw_liquidity": "withdraw",
1864
- "lending_market::redeem_ctokens_and_withdraw_liquidity_request": "withdraw",
1865
- "lending_market::fulfill_liquidity_request": "withdraw",
1866
- "lending_market::unstake_sui_from_staker": "withdraw",
1867
- "lending_market::borrow": "borrow",
1868
- "lending_market::repay": "repay"
1869
- }
1870
- };
1871
1677
  var SuilendAdapter = class {
1872
1678
  id = "suilend";
1873
1679
  name = "Suilend";
@@ -2210,16 +2016,23 @@ var SuilendAdapter = class {
2210
2016
  if (obligationOwnerCaps.length === 0 || obligations.length === 0) return [];
2211
2017
  const ob = obligations[0];
2212
2018
  const rewards = [];
2019
+ const WAD = 1e18;
2213
2020
  for (const dep of ob.deposits) {
2214
- for (const rw of dep.reserve.depositsPoolRewardManager.poolRewards) {
2021
+ const urm = dep.userRewardManager;
2022
+ for (const rw of dep.reserve.depositsPoolRewardManager?.poolRewards ?? []) {
2215
2023
  if (rw.endTimeMs <= Date.now()) continue;
2024
+ let claimableAmount = 0;
2025
+ const userReward = urm?.rewards?.[rw.rewardIndex];
2026
+ if (userReward?.earnedRewards) {
2027
+ claimableAmount = Number(BigInt(userReward.earnedRewards.value.toString())) / WAD / 10 ** rw.mintDecimals;
2028
+ }
2216
2029
  const symbol = rw.symbol || rw.coinType.split("::").pop() || "UNKNOWN";
2217
2030
  rewards.push({
2218
2031
  protocol: "suilend",
2219
2032
  asset: this.resolveSymbol(dep.coinType),
2220
2033
  coinType: rw.coinType,
2221
2034
  symbol,
2222
- amount: 0,
2035
+ amount: claimableAmount,
2223
2036
  estimatedValueUsd: 0
2224
2037
  });
2225
2038
  }
@@ -2668,8 +2481,7 @@ async function resolveGas(client, signer, buildTx) {
2668
2481
  // src/safeguards/types.ts
2669
2482
  var OUTBOUND_OPS = /* @__PURE__ */ new Set([
2670
2483
  "send",
2671
- "pay",
2672
- "sentinel"
2484
+ "pay"
2673
2485
  ]);
2674
2486
  var DEFAULT_SAFEGUARD_CONFIG = {
2675
2487
  locked: false,
@@ -2903,6 +2715,7 @@ var ContactManager = class {
2903
2715
  }
2904
2716
  }
2905
2717
  };
2718
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
2906
2719
  function emptyData() {
2907
2720
  return { positions: {}, strategies: {}, realizedPnL: 0 };
2908
2721
  }
@@ -3058,25 +2871,34 @@ var PortfolioManager = class {
3058
2871
  }
3059
2872
  // --- Strategy position tracking ---
3060
2873
  recordStrategyBuy(strategyKey, trade) {
2874
+ if (UNSAFE_KEYS.has(strategyKey) || UNSAFE_KEYS.has(trade.asset)) {
2875
+ throw new T2000Error("ASSET_NOT_SUPPORTED", "Invalid strategy key or asset name");
2876
+ }
3061
2877
  this.load();
3062
- if (!this.data.strategies[strategyKey]) {
3063
- this.data.strategies[strategyKey] = {};
2878
+ if (!Object.hasOwn(this.data.strategies, strategyKey)) {
2879
+ this.data.strategies[strategyKey] = /* @__PURE__ */ Object.create(null);
3064
2880
  }
3065
2881
  const bucket = this.data.strategies[strategyKey];
3066
- const pos = bucket[trade.asset] ?? { totalAmount: 0, costBasis: 0, avgPrice: 0, trades: [] };
2882
+ const pos = Object.hasOwn(bucket, trade.asset) ? bucket[trade.asset] : { totalAmount: 0, costBasis: 0, avgPrice: 0, trades: [] };
3067
2883
  pos.totalAmount += trade.amount;
3068
2884
  pos.costBasis += trade.usdValue;
3069
2885
  pos.avgPrice = pos.costBasis / pos.totalAmount;
3070
2886
  pos.trades.push(trade);
3071
- bucket[trade.asset] = pos;
2887
+ Object.defineProperty(bucket, trade.asset, { value: pos, writable: true, enumerable: true, configurable: true });
3072
2888
  this.save();
3073
2889
  }
3074
2890
  recordStrategySell(strategyKey, trade) {
2891
+ if (UNSAFE_KEYS.has(strategyKey) || UNSAFE_KEYS.has(trade.asset)) {
2892
+ throw new T2000Error("ASSET_NOT_SUPPORTED", "Invalid strategy key or asset name");
2893
+ }
3075
2894
  this.load();
3076
2895
  const bucket = this.data.strategies[strategyKey];
3077
2896
  if (!bucket) {
3078
2897
  throw new T2000Error("STRATEGY_NOT_FOUND", `No positions for strategy '${strategyKey}'`);
3079
2898
  }
2899
+ if (!Object.hasOwn(bucket, trade.asset)) {
2900
+ throw new T2000Error("INSUFFICIENT_INVESTMENT", `No ${trade.asset} position in strategy '${strategyKey}'`);
2901
+ }
3080
2902
  const pos = bucket[trade.asset];
3081
2903
  if (!pos || pos.totalAmount <= 0) {
3082
2904
  throw new T2000Error("INSUFFICIENT_INVESTMENT", `No ${trade.asset} position in strategy '${strategyKey}'`);
@@ -3093,7 +2915,7 @@ var PortfolioManager = class {
3093
2915
  pos.avgPrice = 0;
3094
2916
  }
3095
2917
  pos.trades.push(trade);
3096
- bucket[trade.asset] = pos;
2918
+ Object.defineProperty(bucket, trade.asset, { value: pos, writable: true, enumerable: true, configurable: true });
3097
2919
  const hasPositions = Object.values(bucket).some((p) => p.totalAmount > 0);
3098
2920
  if (!hasPositions) {
3099
2921
  delete this.data.strategies[strategyKey];
@@ -5927,17 +5749,6 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
5927
5749
  async fundStatus() {
5928
5750
  return getFundStatus(this.client, this._address);
5929
5751
  }
5930
- // -- Sentinel --
5931
- async sentinelList() {
5932
- return listSentinels();
5933
- }
5934
- async sentinelInfo(id) {
5935
- return getSentinelInfo(this.client, id);
5936
- }
5937
- async sentinelAttack(id, prompt, fee) {
5938
- this.enforcer.check({ operation: "sentinel", amount: fee ? Number(fee) / 1e9 : 0.1 });
5939
- return attack(this.client, this._signer, id, prompt, fee);
5940
- }
5941
5752
  // -- Helpers --
5942
5753
  async getFreeBalance(asset) {
5943
5754
  if (!(asset in INVESTMENT_ASSETS)) return Infinity;
@@ -6090,14 +5901,6 @@ function parseMoveAbort(errorStr) {
6090
5901
  return { reason: errorStr };
6091
5902
  }
6092
5903
 
6093
- // src/adapters/index.ts
6094
- var allDescriptors = [
6095
- descriptor2,
6096
- descriptor4,
6097
- descriptor3,
6098
- descriptor
6099
- ];
6100
-
6101
5904
  exports.AutoInvestManager = AutoInvestManager;
6102
5905
  exports.BPS_DENOMINATOR = BPS_DENOMINATOR;
6103
5906
  exports.CLOCK_ID = CLOCK_ID;
@@ -6117,7 +5920,6 @@ exports.OUTBOUND_OPS = OUTBOUND_OPS;
6117
5920
  exports.PERPS_MARKETS = PERPS_MARKETS;
6118
5921
  exports.PortfolioManager = PortfolioManager;
6119
5922
  exports.ProtocolRegistry = ProtocolRegistry;
6120
- exports.SENTINEL = SENTINEL;
6121
5923
  exports.STABLE_ASSETS = STABLE_ASSETS;
6122
5924
  exports.SUI_DECIMALS = SUI_DECIMALS;
6123
5925
  exports.SUPPORTED_ASSETS = SUPPORTED_ASSETS;
@@ -6132,7 +5934,7 @@ exports.ZkLoginSigner = ZkLoginSigner;
6132
5934
  exports.addCollectFeeToTx = addCollectFeeToTx;
6133
5935
  exports.allDescriptors = allDescriptors;
6134
5936
  exports.calculateFee = calculateFee;
6135
- exports.cetusDescriptor = descriptor3;
5937
+ exports.cetusDescriptor = cetusDescriptor;
6136
5938
  exports.executeAutoTopUp = executeAutoTopUp;
6137
5939
  exports.executeWithGas = executeWithGas;
6138
5940
  exports.exportPrivateKey = exportPrivateKey;
@@ -6145,28 +5947,21 @@ exports.getDecimals = getDecimals;
6145
5947
  exports.getGasStatus = getGasStatus;
6146
5948
  exports.getPoolPrice = getPoolPrice;
6147
5949
  exports.getRates = getRates;
6148
- exports.getSentinelInfo = getSentinelInfo;
6149
5950
  exports.keypairFromPrivateKey = keypairFromPrivateKey;
6150
- exports.listSentinels = listSentinels;
6151
5951
  exports.loadKey = loadKey;
6152
5952
  exports.mapMoveAbortCode = mapMoveAbortCode;
6153
5953
  exports.mapWalletError = mapWalletError;
6154
5954
  exports.mistToSui = mistToSui;
6155
- exports.naviDescriptor = descriptor2;
5955
+ exports.naviDescriptor = naviDescriptor;
6156
5956
  exports.rawToStable = rawToStable;
6157
5957
  exports.rawToUsdc = rawToUsdc;
6158
- exports.requestAttack = requestAttack;
6159
5958
  exports.saveKey = saveKey;
6160
- exports.sentinelAttack = attack;
6161
- exports.sentinelDescriptor = descriptor;
6162
- exports.settleAttack = settleAttack;
6163
5959
  exports.shouldAutoTopUp = shouldAutoTopUp;
6164
5960
  exports.simulateTransaction = simulateTransaction;
6165
5961
  exports.solveHashcash = solveHashcash;
6166
5962
  exports.stableToRaw = stableToRaw;
6167
- exports.submitPrompt = submitPrompt;
6168
5963
  exports.suiToMist = suiToMist;
6169
- exports.suilendDescriptor = descriptor4;
5964
+ exports.suilendDescriptor = suilendDescriptor;
6170
5965
  exports.throwIfSimulationFailed = throwIfSimulationFailed;
6171
5966
  exports.truncateAddress = truncateAddress;
6172
5967
  exports.usdcToRaw = usdcToRaw;