@t2000/sdk 0.9.4 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -232,7 +232,7 @@ Every operation (send, save, borrow, repay, withdraw) routes through a 3-step ga
232
232
 
233
233
  Every transaction result includes a `gasMethod` field (`'self-funded'` | `'auto-topup'` | `'sponsored'`) indicating which strategy was used.
234
234
 
235
- **Architecture:** Each protocol operation (NAVI, Suilend, Cetus, send) exposes a `buildXxxTx()` function that returns a `Transaction` without executing it. `executeWithGas()` then handles execution with the fallback chain. This separation ensures gas management is consistent across all operations.
235
+ **Architecture:** Each protocol operation (NAVI, Suilend, Cetus, send) exposes both `buildXxxTx()` (standalone transaction) and `addXxxToTx()` (composable PTB) functions. Multi-step operations (save with auto-convert, withdraw with auto-swap, rebalance) compose multiple protocol calls into a single atomic PTB. `executeWithGas()` handles execution with the gas fallback chain. If any step within a PTB fails, the entire transaction reverts — no funds left in intermediate states.
236
236
 
237
237
  ## Configuration
238
238
 
@@ -275,7 +275,7 @@ Common error codes: `INSUFFICIENT_BALANCE` · `INVALID_ADDRESS` · `INVALID_AMOU
275
275
  ## Testing
276
276
 
277
277
  ```bash
278
- # Run all SDK unit tests (262 tests)
278
+ # Run all SDK unit tests (367 tests)
279
279
  pnpm --filter @t2000/sdk test
280
280
  ```
281
281
 
@@ -291,6 +291,13 @@ pnpm --filter @t2000/sdk test
291
291
  | `send.test.ts` | Send transaction building and validation |
292
292
  | `manager.test.ts` | Gas resolution chain (self-fund, auto-topup, sponsored fallback) |
293
293
  | `autoTopUp.test.ts` | Auto-topup threshold logic and swap execution |
294
+ | `compliance.test.ts` | Adapter contract compliance (49 checks across all adapters) |
295
+ | `registry.test.ts` | Best rates, multi-protocol routing, quote aggregation |
296
+ | `cetus.test.ts` | Cetus swap adapter (metadata, quotes, transaction building) |
297
+ | `suilend.test.ts` | Suilend adapter (rates, positions, obligation lifecycle) |
298
+ | `t2000.integration.test.ts` | End-to-end flows (save, withdraw, borrow, repay, rebalance, auto-swap) |
299
+ | `protocolFee.test.ts` | Protocol fee calculation and collection |
300
+ | `sentinel.test.ts` | Sentinel attack flow, listing, fee parsing |
294
301
  | `serialization.test.ts` | Transaction JSON serialization roundtrip |
295
302
 
296
303
  ## Protocol Fees
@@ -299,7 +306,7 @@ pnpm --filter @t2000/sdk test
299
306
  |-----------|-----|-------|
300
307
  | Save (deposit) | 0.10% | Protocol fee on deposit |
301
308
  | Borrow | 0.05% | Protocol fee on loan |
302
- | Swap | **Free** | Only standard Cetus pool fees |
309
+ | Swap (internal) | **Free** | Cetus pool fees only; used internally by rebalance/auto-convert |
303
310
  | Withdraw | Free | |
304
311
  | Repay | Free | |
305
312
  | Send | Free | |
@@ -392,7 +392,7 @@ function compoundBalance(rawBalance, currentIndex) {
392
392
  const result = (rawBalance * BigInt(currentIndex) + half) / scale;
393
393
  return Number(result) / 10 ** NAVI_BALANCE_DECIMALS;
394
394
  }
395
- async function getUserState(client, address) {
395
+ async function getUserState(client, address, includeZero = false) {
396
396
  const config = await getConfig();
397
397
  const tx = new transactions.Transaction();
398
398
  tx.moveCall({
@@ -405,11 +405,13 @@ async function getUserState(client, address) {
405
405
  });
406
406
  const decoded = decodeDevInspect(result, bcs.bcs.vector(UserStateInfo));
407
407
  if (!decoded) return [];
408
- return decoded.map((s) => ({
408
+ const mapped = decoded.map((s) => ({
409
409
  assetId: s.asset_id,
410
410
  supplyBalance: toBigInt(s.supply_balance),
411
411
  borrowBalance: toBigInt(s.borrow_balance)
412
- })).filter((s) => s.supplyBalance !== 0n || s.borrowBalance !== 0n);
412
+ }));
413
+ if (includeZero) return mapped;
414
+ return mapped.filter((s) => s.supplyBalance !== 0n || s.borrowBalance !== 0n);
413
415
  }
414
416
  async function fetchCoins(client, owner, coinType) {
415
417
  const all = [];
@@ -466,20 +468,20 @@ async function buildSaveTx(client, address, amount, options = {}) {
466
468
  async function buildWithdrawTx(client, address, amount, options = {}) {
467
469
  const asset = options.asset ?? "USDC";
468
470
  const assetInfo = SUPPORTED_ASSETS[asset];
469
- const [config, pool, pools, states] = await Promise.all([
471
+ const [config, pool, pools, allStates] = await Promise.all([
470
472
  getConfig(),
471
473
  getPool(asset),
472
474
  getPools(),
473
- getUserState(client, address)
475
+ getUserState(client, address, true)
474
476
  ]);
475
- const assetState = states.find((s) => s.assetId === pool.id);
477
+ const assetState = allStates.find((s) => s.assetId === pool.id);
476
478
  const deposited = assetState ? compoundBalance(assetState.supplyBalance, pool.currentSupplyIndex) : 0;
477
479
  const effectiveAmount = Math.min(amount, Math.max(0, deposited - WITHDRAW_DUST_BUFFER));
478
480
  if (effectiveAmount <= 0) throw new T2000Error("NO_COLLATERAL", `Nothing to withdraw for ${assetInfo.displayName} on NAVI`);
479
481
  const rawAmount = Number(stableToRaw(effectiveAmount, assetInfo.decimals));
480
482
  const tx = new transactions.Transaction();
481
483
  tx.setSender(address);
482
- addOracleUpdatesForPositions(tx, config, pools, states, pool);
484
+ addOracleUpdatesForPositions(tx, config, pools, allStates, pool);
483
485
  const [balance] = tx.moveCall({
484
486
  target: `${config.package}::incentive_v3::withdraw_v2`,
485
487
  arguments: [
@@ -506,18 +508,18 @@ async function buildWithdrawTx(client, address, amount, options = {}) {
506
508
  async function addWithdrawToTx(tx, client, address, amount, options = {}) {
507
509
  const asset = options.asset ?? "USDC";
508
510
  const assetInfo = SUPPORTED_ASSETS[asset];
509
- const [config, pool, pools, states] = await Promise.all([
511
+ const [config, pool, pools, allStates] = await Promise.all([
510
512
  getConfig(),
511
513
  getPool(asset),
512
514
  getPools(),
513
- getUserState(client, address)
515
+ getUserState(client, address, true)
514
516
  ]);
515
- const assetState = states.find((s) => s.assetId === pool.id);
517
+ const assetState = allStates.find((s) => s.assetId === pool.id);
516
518
  const deposited = assetState ? compoundBalance(assetState.supplyBalance, pool.currentSupplyIndex) : 0;
517
519
  const effectiveAmount = Math.min(amount, Math.max(0, deposited - WITHDRAW_DUST_BUFFER));
518
520
  if (effectiveAmount <= 0) throw new T2000Error("NO_COLLATERAL", `Nothing to withdraw for ${assetInfo.displayName} on NAVI`);
519
521
  const rawAmount = Number(stableToRaw(effectiveAmount, assetInfo.decimals));
520
- addOracleUpdatesForPositions(tx, config, pools, states, pool);
522
+ addOracleUpdatesForPositions(tx, config, pools, allStates, pool);
521
523
  const [balance] = tx.moveCall({
522
524
  target: `${config.package}::incentive_v3::withdraw_v2`,
523
525
  arguments: [
@@ -598,15 +600,15 @@ async function buildBorrowTx(client, address, amount, options = {}) {
598
600
  const asset = options.asset ?? "USDC";
599
601
  const assetInfo = SUPPORTED_ASSETS[asset];
600
602
  const rawAmount = Number(stableToRaw(amount, assetInfo.decimals));
601
- const [config, pool, pools, states] = await Promise.all([
603
+ const [config, pool, pools, allStates] = await Promise.all([
602
604
  getConfig(),
603
605
  getPool(asset),
604
606
  getPools(),
605
- getUserState(client, address)
607
+ getUserState(client, address, true)
606
608
  ]);
607
609
  const tx = new transactions.Transaction();
608
610
  tx.setSender(address);
609
- addOracleUpdatesForPositions(tx, config, pools, states, pool);
611
+ addOracleUpdatesForPositions(tx, config, pools, allStates, pool);
610
612
  const [balance] = tx.moveCall({
611
613
  target: `${config.package}::incentive_v3::borrow_v2`,
612
614
  arguments: [