@t2000/sdk 1.24.14 → 1.25.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.
@@ -0,0 +1,509 @@
1
+ import { RouterDataV3 } from '@cetusprotocol/aggregator-sdk';
2
+ import { Transaction, TransactionObjectArgument } from '@mysten/sui/transactions';
3
+ import { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';
4
+
5
+ /**
6
+ * Cetus Aggregator V3 SDK wrapper — the ONLY file that imports @cetusprotocol/aggregator-sdk.
7
+ * Documented CLAUDE.md exception: multi-DEX routing cannot be feasibly replaced by thin tx builders.
8
+ *
9
+ * [B5 v2 / @t2000/sdk@1.1.0 / 2026-04-30]
10
+ * Overlay fee config is now per-call instead of a module-level singleton. CLI / direct
11
+ * SDK callers (`T2000.swap()`) DON'T pass `overlayFee` → fee-free swap. Audric's
12
+ * prepare/route.ts ALWAYS passes `overlayFee = { rate: OVERLAY_FEE_RATE, receiver:
13
+ * T2000_OVERLAY_FEE_WALLET }` → fee charged. Structural inclusion (Audric's code can't
14
+ * forget to pass it because it IS the code), not a toggle that defaults to safe.
15
+ *
16
+ * Pre-1.1.0: a module-level `OVERLAY_FEE_RECEIVER` constant defaulted to a Move object
17
+ * ID. USDC sent there became OwnedObjects keyed to the object and was inaccessible.
18
+ * Fixed by making the receiver a regular wallet address (T2000_OVERLAY_FEE_WALLET) AND
19
+ * by removing the singleton pattern that hid the misconfig.
20
+ */
21
+
22
+ interface OverlayFeeConfig {
23
+ /** Fee rate as a fraction (e.g. 0.001 = 0.1%). Pass 0 to disable. */
24
+ rate: number;
25
+ /** Wallet address that receives the overlay fee. */
26
+ receiver: string;
27
+ }
28
+ interface SwapRouteResult {
29
+ routerData: RouterDataV3;
30
+ amountIn: string;
31
+ amountOut: string;
32
+ byAmountIn: boolean;
33
+ priceImpact: number;
34
+ insufficientLiquidity: boolean;
35
+ }
36
+ interface SerializedCetusRoutePath {
37
+ id: string;
38
+ direction: boolean;
39
+ provider: string;
40
+ from: string;
41
+ target: string;
42
+ feeRate: number;
43
+ amountIn: string;
44
+ amountOut: string;
45
+ version?: string;
46
+ publishedAt?: string;
47
+ extendedDetails?: Record<string, unknown>;
48
+ }
49
+ interface SerializedRouterDataV3 {
50
+ quoteID?: string;
51
+ /** RouterDataV3.amountIn (BN) → decimal string */
52
+ amountIn: string;
53
+ /** RouterDataV3.amountOut (BN) → decimal string */
54
+ amountOut: string;
55
+ byAmountIn: boolean;
56
+ paths: SerializedCetusRoutePath[];
57
+ insufficientLiquidity: boolean;
58
+ deviationRatio: number;
59
+ /** RouterDataV3.packages (Map) → Record */
60
+ packages?: Record<string, string>;
61
+ totalDeepFee?: number;
62
+ error?: {
63
+ code: number;
64
+ msg: string;
65
+ };
66
+ overlayFee?: number;
67
+ }
68
+ interface SerializedCetusRoute {
69
+ routerData: SerializedRouterDataV3;
70
+ amountIn: string;
71
+ amountOut: string;
72
+ byAmountIn: boolean;
73
+ priceImpact: number;
74
+ insufficientLiquidity: boolean;
75
+ /**
76
+ * Wall-clock timestamp (ms since epoch) at which the route was discovered.
77
+ * Used by audric's prepare-route for SPEC 20.2 D-3 TTL re-validation: if
78
+ * the route is older than the threshold AND price impact has shifted
79
+ * beyond tolerance, fall back to a fresh `findSwapRoute()` call.
80
+ */
81
+ discoveredAt: number;
82
+ /**
83
+ * Snapshot of the input/output coin types the route was discovered for.
84
+ * SPEC 20.2 D-2 (b) structural verification: prepare-route asserts
85
+ * input/output coins match before using the fast-path; mismatch falls
86
+ * back to fresh discovery (defense against client-side tampering and
87
+ * against legitimate token-type drift in the request).
88
+ */
89
+ fromCoinType: string;
90
+ toCoinType: string;
91
+ }
92
+ declare function serializeCetusRoute(route: SwapRouteResult, context: {
93
+ fromCoinType: string;
94
+ toCoinType: string;
95
+ }): SerializedCetusRoute;
96
+ declare function deserializeCetusRoute(serialized: SerializedCetusRoute): SwapRouteResult;
97
+ /**
98
+ * SPEC 20.2 D-2 (b) structural verification helper. Returns true when the
99
+ * serialized route matches the requested coin types (i.e. it's safe to use
100
+ * as the prepare-route fast-path), false otherwise (tampered, or input
101
+ * mismatch from a legitimate but stale pending action). Caller falls back
102
+ * to a fresh `findSwapRoute()` call when verification fails.
103
+ */
104
+ declare function verifyCetusRouteCoinMatch(serialized: SerializedCetusRoute, expected: {
105
+ fromCoinType: string;
106
+ toCoinType: string;
107
+ }): boolean;
108
+ /**
109
+ * SPEC 20.2 D-3 (b) TTL helper. Returns true when the serialized route is
110
+ * fresh enough to use as the fast-path (< `maxAgeMs` old). Returns false
111
+ * for stale routes — caller falls back to fresh `findSwapRoute()` to pick
112
+ * up any pool-price drift since route discovery.
113
+ *
114
+ * Default 30s aligns with the existing quote-freshness contract surfaced
115
+ * to users via `pending_action.quoteAge` (the PermissionCard "QUOTE Ns OLD"
116
+ * badge starts warning the user past 30s).
117
+ */
118
+ declare function isCetusRouteFresh(serialized: SerializedCetusRoute, maxAgeMs?: number): boolean;
119
+ /**
120
+ * Default Audric swap overlay fee — 0.1%. Exported for consumers that want to use
121
+ * the canonical Audric rate (the Audric prepare-route does this). Changing this
122
+ * rate requires a coordinated SDK + audric release.
123
+ */
124
+ declare const OVERLAY_FEE_RATE = 0.001;
125
+ /**
126
+ * Find the optimal swap route via Cetus Aggregator REST API.
127
+ *
128
+ * Pass `overlayFee` to charge an overlay fee on the output (Audric's pattern).
129
+ * Omit it for a fee-free swap (CLI / direct SDK pattern).
130
+ */
131
+ declare function findSwapRoute(params: {
132
+ walletAddress: string;
133
+ from: string;
134
+ to: string;
135
+ amount: bigint;
136
+ byAmountIn: boolean;
137
+ overlayFee?: OverlayFeeConfig;
138
+ /**
139
+ * Optional Cetus provider allow-list. When omitted, all 30+ DEXes
140
+ * are eligible. Sponsored flows (Enoki) MUST pass an exclusion list
141
+ * computed via `getProvidersExcluding([...])` from the Cetus SDK to
142
+ * remove Pyth-dependent providers (HAEDALPMM, METASTABLE, OBRIC,
143
+ * STEAMM_OMM, STEAMM_OMM_V2, SEVENK, HAEDALHMMV2) — those reference
144
+ * `tx.gas` for oracle fees, which Enoki rejects in sponsored txs.
145
+ * Non-sponsored callers (CLI, direct SDK) leave this undefined.
146
+ */
147
+ providers?: string[];
148
+ }): Promise<SwapRouteResult | null>;
149
+ /**
150
+ * Build a swap PTB from a route result. The caller must provide an input coin
151
+ * obtained by splitting/merging wallet coins.
152
+ *
153
+ * **Important:** Cetus's `routerSwap` reads the overlay-fee config from the
154
+ * AggregatorClient instance. The `overlayFee` param here MUST match the one
155
+ * passed to `findSwapRoute` for the same swap (otherwise you'll hit the cache
156
+ * boundary and get a different client with different overlay config).
157
+ */
158
+ declare function buildSwapTx(params: {
159
+ walletAddress: string;
160
+ route: SwapRouteResult;
161
+ tx: Transaction;
162
+ inputCoin: TransactionObjectArgument;
163
+ slippage: number;
164
+ overlayFee?: OverlayFeeConfig;
165
+ }): Promise<TransactionObjectArgument>;
166
+ /**
167
+ * Append a swap fragment to an existing PTB. SPEC 7 § "Layer 1" Cetus
168
+ * appender. Two modes, dispatched by the presence of `input.inputCoin`:
169
+ *
170
+ * - **Wallet mode** (`inputCoin` omitted) — fetches `from`-asset coins
171
+ * from the sender's wallet (paginated), merges/splits to the
172
+ * requested amount, runs the swap. Mirrors the audric host's
173
+ * `transactions/prepare/route.ts` swap branch (P2.2c will retire that
174
+ * branch in favor of this appender via `composeTx`).
175
+ *
176
+ * - **Chain mode** (`inputCoin` provided) — consumes the passed-in coin
177
+ * reference (typically produced by an upstream appender like
178
+ * `addWithdrawToTx`) directly, no wallet fetch / no merge / no
179
+ * split. This is the SPEC 7 multi-write enabler ("withdraw → swap →
180
+ * save" without intermediate wallet materialization).
181
+ *
182
+ * **SUI in wallet mode:** uses `client.getCoins` like every other
183
+ * token. This works for sponsored flows (Enoki — `tx.gas` belongs to
184
+ * the sponsor, swap input comes from the user's separate SUI coin
185
+ * objects). For non-sponsored flows where `tx.gas` IS the user's SUI,
186
+ * the caller should pre-build the inputCoin via
187
+ * `tx.splitCoins(tx.gas, [rawAmount])[0]` and pass it via chain mode
188
+ * instead. (`T2000.swap()` already handles this internally — direct SDK
189
+ * users go through the high-level class, not through this appender.)
190
+ *
191
+ * **`swapAll` semantics (wallet mode):** if the requested raw amount
192
+ * is >= the wallet's total `from` balance, the appender consumes the
193
+ * entire merged primary coin (not a split), matching audric's host
194
+ * route's `swapAll` clipping. The returned `effectiveAmountIn` reflects
195
+ * the actual consumed amount in display units.
196
+ *
197
+ * **Slippage:** clamped to [0.001, 0.05] (0.1% – 5%). Defaults to 0.01.
198
+ *
199
+ * @returns
200
+ * - `coin` — output coin reference, ready for downstream consumption
201
+ * (e.g. `addSaveToTx`) or wallet transfer (`tx.transferObjects`).
202
+ * - `effectiveAmountIn` — display-units input amount the swap actually
203
+ * consumes (handles `swapAll` clipping in wallet mode; in chain mode
204
+ * echoes the requested `input.amount`).
205
+ * - `expectedAmountOut` — display-units output amount per the route
206
+ * quote. Actual on-chain output may differ within slippage.
207
+ * - `route` — raw `SwapRouteResult` for downstream telemetry / logging.
208
+ */
209
+ declare function addSwapToTx(tx: Transaction, client: SuiJsonRpcClient, address: string, input: {
210
+ from: string;
211
+ to: string;
212
+ amount: number;
213
+ slippage?: number;
214
+ byAmountIn?: boolean;
215
+ overlayFee?: OverlayFeeConfig;
216
+ inputCoin?: TransactionObjectArgument;
217
+ /**
218
+ * Optional Cetus provider allow-list. Forwarded to `findSwapRoute`.
219
+ * Sponsored flows (Enoki) MUST pass `getProvidersExcluding([...])`
220
+ * to remove Pyth-dependent providers — see `findSwapRoute`'s JSDoc
221
+ * for the exclusion list. Non-sponsored callers omit this.
222
+ */
223
+ providers?: string[];
224
+ /**
225
+ * [SPEC 20.2 D-3 (b)] Precomputed route from a prior `findSwapRoute()`
226
+ * call (typically captured by `swap_quote` and threaded through
227
+ * `pending_action.cetusRoute`). When present AND not stale (per
228
+ * `isCetusRouteFresh`) AND the input/output coins match, this skips
229
+ * the ~400-500ms `findSwapRoute()` discovery call. Stale routes are
230
+ * silently ignored (caller falls back to fresh discovery).
231
+ *
232
+ * Caller responsibility: pass the SAME `overlayFee` / `providers` /
233
+ * `byAmountIn` that produced the precomputed route. Mismatch will
234
+ * still produce a working swap but may use the wrong overlay-fee
235
+ * config (the route data already encodes the chosen DEX path).
236
+ */
237
+ precomputedRoute?: SwapRouteResult;
238
+ }): Promise<{
239
+ coin: TransactionObjectArgument;
240
+ effectiveAmountIn: number;
241
+ expectedAmountOut: number;
242
+ route: SwapRouteResult;
243
+ /** True when `precomputedRoute` was used (no `findSwapRoute()` call). */
244
+ usedPrecomputedRoute: boolean;
245
+ }>;
246
+
247
+ interface T2000Options {
248
+ keyPath?: string;
249
+ /** PIN to decrypt the key file. Accepts any string (4+ chars). */
250
+ pin?: string;
251
+ /** @deprecated Use `pin` instead. */
252
+ passphrase?: string;
253
+ network?: 'mainnet' | 'testnet';
254
+ rpcUrl?: string;
255
+ }
256
+ interface GasReserve {
257
+ sui: number;
258
+ usdEquiv: number;
259
+ }
260
+ interface BalanceResponse {
261
+ available: number;
262
+ savings: number;
263
+ debt: number;
264
+ pendingRewards: number;
265
+ gasReserve: GasReserve;
266
+ total: number;
267
+ stables: Record<string, number>;
268
+ }
269
+ interface SendResult {
270
+ success: boolean;
271
+ tx: string;
272
+ amount: number;
273
+ to: string;
274
+ contactName?: string;
275
+ gasCost: number;
276
+ gasCostUnit: string;
277
+ balance: BalanceResponse;
278
+ }
279
+ interface SaveResult {
280
+ success: boolean;
281
+ tx: string;
282
+ amount: number;
283
+ apy: number;
284
+ fee: number;
285
+ gasCost: number;
286
+ savingsBalance: number;
287
+ }
288
+ interface WithdrawResult {
289
+ success: boolean;
290
+ tx: string;
291
+ amount: number;
292
+ asset?: string;
293
+ gasCost: number;
294
+ }
295
+ interface BorrowResult {
296
+ success: boolean;
297
+ tx: string;
298
+ amount: number;
299
+ /** [v0.51.0] Asset borrowed — 'USDC' or 'USDsui'. Optional for backward compat. */
300
+ asset?: string;
301
+ fee: number;
302
+ healthFactor: number;
303
+ gasCost: number;
304
+ }
305
+ interface RepayResult {
306
+ success: boolean;
307
+ tx: string;
308
+ amount: number;
309
+ /** [v0.51.1] Asset repaid — 'USDC' or 'USDsui'. Optional for backward compat. */
310
+ asset?: string;
311
+ remainingDebt: number;
312
+ gasCost: number;
313
+ }
314
+ interface HealthFactorResult {
315
+ healthFactor: number;
316
+ supplied: number;
317
+ borrowed: number;
318
+ maxBorrow: number;
319
+ liquidationThreshold: number;
320
+ }
321
+ interface MaxWithdrawResult {
322
+ maxAmount: number;
323
+ healthFactorAfter: number;
324
+ currentHF: number;
325
+ }
326
+ interface MaxBorrowResult {
327
+ maxAmount: number;
328
+ healthFactorAfter: number;
329
+ currentHF: number;
330
+ }
331
+ interface AssetRates {
332
+ saveApy: number;
333
+ borrowApy: number;
334
+ }
335
+ interface RatesResult {
336
+ [asset: string]: AssetRates;
337
+ }
338
+ interface PositionEntry {
339
+ protocol: string;
340
+ asset: string;
341
+ type: 'save' | 'borrow';
342
+ amount: number;
343
+ amountUsd?: number;
344
+ apy: number;
345
+ }
346
+ interface PositionsResult {
347
+ positions: PositionEntry[];
348
+ }
349
+ interface EarningsResult {
350
+ totalYieldEarned: number;
351
+ currentApy: number;
352
+ dailyEarning: number;
353
+ supplied: number;
354
+ }
355
+ interface FundStatusResult {
356
+ supplied: number;
357
+ apy: number;
358
+ earnedToday: number;
359
+ earnedAllTime: number;
360
+ projectedMonthly: number;
361
+ }
362
+ interface DepositInfo {
363
+ address: string;
364
+ network: string;
365
+ supportedAssets: string[];
366
+ instructions: string;
367
+ }
368
+ interface PaymentRequest {
369
+ address: string;
370
+ network: string;
371
+ amount: number | null;
372
+ currency: string;
373
+ memo: string | null;
374
+ label: string | null;
375
+ /** Unique payment identifier (UUID) for Payment Kit registry */
376
+ nonce: string;
377
+ /** Payment Kit URI (sui:pay?...) for QR codes and wallet deep links */
378
+ qrUri: string;
379
+ /** Human-readable summary */
380
+ displayText: string;
381
+ }
382
+ interface TransactionRecord {
383
+ digest: string;
384
+ /** Coarse bucket — `'send' | 'lending' | 'swap' | 'transaction'`. STABLE. */
385
+ action: string;
386
+ /**
387
+ * Finer-grained display label derived from the Move-call function
388
+ * name (e.g. `'deposit'`, `'withdraw'`, `'payment_link'`,
389
+ * `'on-chain'`). Optional — frontends should fall back to `action`
390
+ * when missing. Never used by ACI filters.
391
+ */
392
+ label?: string;
393
+ amount?: number;
394
+ asset?: string;
395
+ recipient?: string;
396
+ /**
397
+ * Direction of the user's principal (non-gas) balance movement on
398
+ * this tx — `'out'` if they spent, `'in'` if they received.
399
+ * Computed from on-chain balance changes (NOT from `label`), so the
400
+ * card can render the correct sign even for opaque actions like
401
+ * `swap`/`router`. Undefined when no user balance change is
402
+ * detectable (e.g. pure read-only or admin txs).
403
+ */
404
+ direction?: 'in' | 'out';
405
+ timestamp: number;
406
+ gasCost?: number;
407
+ }
408
+ interface PendingReward {
409
+ protocol: string;
410
+ asset: string;
411
+ coinType: string;
412
+ symbol: string;
413
+ amount: number;
414
+ estimatedValueUsd: number;
415
+ }
416
+ interface ClaimRewardsResult {
417
+ success: boolean;
418
+ tx: string;
419
+ rewards: PendingReward[];
420
+ totalValueUsd: number;
421
+ gasCost: number;
422
+ }
423
+ interface CompoundRewardsResult {
424
+ success: boolean;
425
+ claimTx: string;
426
+ swapTxs: string[];
427
+ depositTx: string;
428
+ rewards: PendingReward[];
429
+ totalCompoundedUsdc: number;
430
+ totalGasCost: number;
431
+ }
432
+ interface StakeVSuiResult {
433
+ success: boolean;
434
+ tx: string;
435
+ amountSui: number;
436
+ vSuiReceived: number;
437
+ apy: number;
438
+ gasCost: number;
439
+ }
440
+ interface UnstakeVSuiResult {
441
+ success: boolean;
442
+ tx: string;
443
+ vSuiAmount: number;
444
+ suiReceived: number;
445
+ gasCost: number;
446
+ }
447
+ interface SwapResult {
448
+ success: boolean;
449
+ tx: string;
450
+ fromToken: string;
451
+ toToken: string;
452
+ fromAmount: number;
453
+ toAmount: number;
454
+ priceImpact: number;
455
+ route: string;
456
+ gasCost: number;
457
+ }
458
+ interface SwapQuoteResult {
459
+ fromToken: string;
460
+ toToken: string;
461
+ fromAmount: number;
462
+ toAmount: number;
463
+ priceImpact: number;
464
+ route: string;
465
+ /**
466
+ * [SPEC 20.2 / D-1 (a)] Structured Cetus route captured at quote time.
467
+ * Threaded through `pending_action.cetusRoute` so the prepare-route can
468
+ * skip the ~400-500ms `findSwapRoute()` re-discovery, and so the
469
+ * post-write resume system prompt can ground LLM narration against the
470
+ * canonical route (closing S19-F2). Optional for backward compat with
471
+ * pre-SPEC-20.2 callers (CLI, server-only direct calls).
472
+ */
473
+ serializedRoute?: SerializedCetusRoute;
474
+ }
475
+ interface PayOptions {
476
+ url: string;
477
+ method?: string;
478
+ body?: string;
479
+ headers?: Record<string, string>;
480
+ maxPrice?: number;
481
+ }
482
+ interface PayResult {
483
+ status: number;
484
+ body: unknown;
485
+ paid: boolean;
486
+ cost?: number;
487
+ receipt?: {
488
+ reference: string;
489
+ timestamp: string;
490
+ };
491
+ }
492
+ type HFAlertLevel = 'none' | 'warn' | 'critical';
493
+ interface FinancialSummary {
494
+ walletAddress: string;
495
+ usdcAvailable: number;
496
+ savingsBalance: number;
497
+ debtBalance: number;
498
+ idleUsdc: number;
499
+ healthFactor: number;
500
+ hfAlertLevel: HFAlertLevel;
501
+ saveApy: number;
502
+ borrowApy: number;
503
+ dailyYield: number;
504
+ gasReserveSui: number;
505
+ gasReserveUsd: number;
506
+ fetchedAt: number;
507
+ }
508
+
509
+ export { type AssetRates as A, type BalanceResponse as B, type ClaimRewardsResult as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasReserve as G, type HealthFactorResult as H, serializeCetusRoute as I, verifyCetusRouteCoinMatch as J, type MaxBorrowResult as M, OVERLAY_FEE_RATE as O, type PayOptions as P, type RatesResult as R, type SaveResult as S, type TransactionRecord as T, type UnstakeVSuiResult as U, type WithdrawResult as W, type BorrowResult as a, type MaxWithdrawResult as b, type OverlayFeeConfig as c, type PayResult as d, type PendingReward as e, type PositionEntry as f, type PositionsResult as g, type RepayResult as h, type SendResult as i, type SwapRouteResult as j, buildSwapTx as k, findSwapRoute as l, type T2000Options as m, type StakeVSuiResult as n, type SwapResult as o, type SwapQuoteResult as p, type PaymentRequest as q, type CompoundRewardsResult as r, type FinancialSummary as s, type HFAlertLevel as t, type SerializedCetusRoute as u, type SerializedCetusRoutePath as v, type SerializedRouterDataV3 as w, addSwapToTx as x, deserializeCetusRoute as y, isCetusRouteFresh as z };