@t2000/sdk 0.6.0 → 0.6.2

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.
@@ -3,6 +3,28 @@ import { bcs } from '@mysten/sui/bcs';
3
3
  import { AggregatorClient, Env } from '@cetusprotocol/aggregator-sdk';
4
4
  import { normalizeStructTag } from '@mysten/sui/utils';
5
5
 
6
+ // src/errors.ts
7
+ var T2000Error = class extends Error {
8
+ code;
9
+ data;
10
+ retryable;
11
+ constructor(code, message, data, retryable = false) {
12
+ super(message);
13
+ this.name = "T2000Error";
14
+ this.code = code;
15
+ this.data = data;
16
+ this.retryable = retryable;
17
+ }
18
+ toJSON() {
19
+ return {
20
+ error: this.code,
21
+ message: this.message,
22
+ ...this.data && { data: this.data },
23
+ retryable: this.retryable
24
+ };
25
+ }
26
+ };
27
+
6
28
  // src/adapters/registry.ts
7
29
  var ProtocolRegistry = class {
8
30
  lending = /* @__PURE__ */ new Map();
@@ -25,7 +47,7 @@ var ProtocolRegistry = class {
25
47
  }
26
48
  }
27
49
  if (candidates.length === 0) {
28
- throw new Error(`No lending adapter supports saving ${asset}`);
50
+ throw new T2000Error("ASSET_NOT_SUPPORTED", `No lending adapter supports saving ${asset}`);
29
51
  }
30
52
  candidates.sort((a, b) => b.rate.saveApy - a.rate.saveApy);
31
53
  return candidates[0];
@@ -43,7 +65,7 @@ var ProtocolRegistry = class {
43
65
  }
44
66
  }
45
67
  if (candidates.length === 0) {
46
- throw new Error(`No lending adapter supports borrowing ${asset}`);
68
+ throw new T2000Error("ASSET_NOT_SUPPORTED", `No lending adapter supports borrowing ${asset}`);
47
69
  }
48
70
  candidates.sort((a, b) => a.rate.borrowApy - b.rate.borrowApy);
49
71
  return candidates[0];
@@ -60,7 +82,7 @@ var ProtocolRegistry = class {
60
82
  }
61
83
  }
62
84
  if (candidates.length === 0) {
63
- throw new Error(`No swap adapter supports ${from} \u2192 ${to}`);
85
+ throw new T2000Error("ASSET_NOT_SUPPORTED", `No swap adapter supports ${from} \u2192 ${to}`);
64
86
  }
65
87
  candidates.sort((a, b) => b.quote.expectedOutput - a.quote.expectedOutput);
66
88
  return candidates[0];
@@ -127,28 +149,6 @@ var T2000_TREASURY_ID = process.env.T2000_TREASURY_ID ?? "0x3bb501b8300125dca590
127
149
  process.env.T2000_API_URL ?? "https://api.t2000.ai";
128
150
  var CETUS_USDC_SUI_POOL = "0x51e883ba7c0b566a26cbc8a94cd33eb0abd418a77cc1e60ad22fd9b1f29cd2ab";
129
151
 
130
- // src/errors.ts
131
- var T2000Error = class extends Error {
132
- code;
133
- data;
134
- retryable;
135
- constructor(code, message, data, retryable = false) {
136
- super(message);
137
- this.name = "T2000Error";
138
- this.code = code;
139
- this.data = data;
140
- this.retryable = retryable;
141
- }
142
- toJSON() {
143
- return {
144
- error: this.code,
145
- message: this.message,
146
- ...this.data && { data: this.data },
147
- retryable: this.retryable
148
- };
149
- }
150
- };
151
-
152
152
  // src/utils/format.ts
153
153
  function usdcToRaw(amount) {
154
154
  return BigInt(Math.round(amount * 10 ** USDC_DECIMALS));
@@ -250,6 +250,24 @@ async function getUsdcPool() {
250
250
  if (!usdc) throw new T2000Error("PROTOCOL_UNAVAILABLE", "USDC pool not found on NAVI");
251
251
  return usdc;
252
252
  }
253
+ function addOracleUpdate(tx, config, pool) {
254
+ const feed = config.oracle.feeds?.find((f2) => f2.assetId === pool.id);
255
+ if (!feed) {
256
+ throw new T2000Error("PROTOCOL_UNAVAILABLE", `Oracle feed not found for asset ${pool.token?.symbol ?? pool.id}`);
257
+ }
258
+ tx.moveCall({
259
+ target: `${config.oracle.packageId}::oracle_pro::update_single_price_v2`,
260
+ arguments: [
261
+ tx.object(CLOCK),
262
+ tx.object(config.oracle.oracleConfig),
263
+ tx.object(config.oracle.priceOracle),
264
+ tx.object(config.oracle.supraOracleHolder),
265
+ tx.object(feed.pythPriceInfoObject),
266
+ tx.object(config.oracle.switchboardAggregator),
267
+ tx.pure.address(feed.feedId)
268
+ ]
269
+ });
270
+ }
253
271
  function rateToApy(rawRate) {
254
272
  if (!rawRate || rawRate === "0") return 0;
255
273
  return Number(BigInt(rawRate)) / 10 ** RATE_DECIMALS * 100;
@@ -272,7 +290,7 @@ function compoundBalance(rawBalance, currentIndex) {
272
290
  if (!rawBalance || !currentIndex || currentIndex === "0") return 0;
273
291
  const scale = BigInt("1" + "0".repeat(RATE_DECIMALS));
274
292
  const half = scale / 2n;
275
- const result = (rawBalance * scale + half) / BigInt(currentIndex);
293
+ const result = (rawBalance * BigInt(currentIndex) + half) / scale;
276
294
  return Number(result) / 10 ** NAVI_BALANCE_DECIMALS;
277
295
  }
278
296
  async function getUserState(client, address) {
@@ -315,6 +333,9 @@ function mergeCoins(tx, coins) {
315
333
  return primary;
316
334
  }
317
335
  async function buildSaveTx(client, address, amount, options = {}) {
336
+ if (!amount || amount <= 0 || !Number.isFinite(amount)) {
337
+ throw new T2000Error("INVALID_AMOUNT", "Save amount must be a positive number");
338
+ }
318
339
  const rawAmount = Number(usdcToRaw(amount));
319
340
  const [config, pool] = await Promise.all([getConfig(), getUsdcPool()]);
320
341
  const coins = await fetchCoins(client, address, USDC_TYPE);
@@ -355,6 +376,7 @@ async function buildWithdrawTx(client, address, amount) {
355
376
  const rawAmount = Number(usdcToRaw(effectiveAmount));
356
377
  const tx = new Transaction();
357
378
  tx.setSender(address);
379
+ addOracleUpdate(tx, config, pool);
358
380
  const [balance] = tx.moveCall({
359
381
  target: `${config.package}::incentive_v3::withdraw_v2`,
360
382
  arguments: [
@@ -379,10 +401,14 @@ async function buildWithdrawTx(client, address, amount) {
379
401
  return { tx, effectiveAmount };
380
402
  }
381
403
  async function buildBorrowTx(client, address, amount, options = {}) {
404
+ if (!amount || amount <= 0 || !Number.isFinite(amount)) {
405
+ throw new T2000Error("INVALID_AMOUNT", "Borrow amount must be a positive number");
406
+ }
382
407
  const rawAmount = Number(usdcToRaw(amount));
383
408
  const [config, pool] = await Promise.all([getConfig(), getUsdcPool()]);
384
409
  const tx = new Transaction();
385
410
  tx.setSender(address);
411
+ addOracleUpdate(tx, config, pool);
386
412
  const [balance] = tx.moveCall({
387
413
  target: `${config.package}::incentive_v3::borrow_v2`,
388
414
  arguments: [
@@ -403,16 +429,23 @@ async function buildBorrowTx(client, address, amount, options = {}) {
403
429
  arguments: [balance],
404
430
  typeArguments: [pool.suiCoinType]
405
431
  });
432
+ if (options.collectFee) {
433
+ addCollectFeeToTx(tx, borrowedCoin, "borrow");
434
+ }
406
435
  tx.transferObjects([borrowedCoin], address);
407
436
  return tx;
408
437
  }
409
438
  async function buildRepayTx(client, address, amount) {
439
+ if (!amount || amount <= 0 || !Number.isFinite(amount)) {
440
+ throw new T2000Error("INVALID_AMOUNT", "Repay amount must be a positive number");
441
+ }
410
442
  const rawAmount = Number(usdcToRaw(amount));
411
443
  const [config, pool] = await Promise.all([getConfig(), getUsdcPool()]);
412
444
  const coins = await fetchCoins(client, address, USDC_TYPE);
413
445
  if (coins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", "No USDC coins to repay with");
414
446
  const tx = new Transaction();
415
447
  tx.setSender(address);
448
+ addOracleUpdate(tx, config, pool);
416
449
  const coinObj = mergeCoins(tx, coins);
417
450
  tx.moveCall({
418
451
  target: `${config.package}::incentive_v3::entry_repay`,
@@ -569,7 +602,7 @@ var NaviAdapter = class {
569
602
  const rates = await getRates(this.client);
570
603
  const key = asset.toUpperCase();
571
604
  const r = rates[key];
572
- if (!r) throw new Error(`NAVI does not support ${asset}`);
605
+ if (!r) throw new T2000Error("ASSET_NOT_SUPPORTED", `NAVI does not support ${asset}`);
573
606
  return { asset, saveApy: r.saveApy, borrowApy: r.borrowApy };
574
607
  }
575
608
  async getPositions(address) {