@t2000/sdk 3.3.0 → 4.0.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.
package/README.md CHANGED
@@ -1,285 +1,197 @@
1
1
  # @t2000/sdk
2
2
 
3
- The complete TypeScript SDK for Agentic Wallets on Sui. Send USDC, earn yield via NAVI, and borrow against collateral — all from a single class. USDC in, USDC out.
3
+ The TypeScript SDK for Agent Wallets on Sui. Send USDC + USDsui gasless, swap via Cetus Aggregator, and pay MPP-protected APIs — all from a single class.
4
4
 
5
- In Audric, this SDK powers **Audric Passport** (wallet, signing), **Audric Finance** (NAVI lending/borrowing builders, Cetus swap), and **Audric Pay** (USDC transfers, payment links), and is wrapped by `@t2000/engine` to implement **Audric Intelligence**'s Agent Harness.
5
+ In [Audric](https://audric.ai), this SDK powers **Audric Passport** (wallet, signing), **Audric Finance** (NAVI lending/borrowing builders, Cetus swap), and **Audric Pay** (USDC transfers, payment links), and is wrapped by [`@t2000/engine`](https://www.npmjs.com/package/@t2000/engine) to implement **Audric Intelligence**'s Agent Harness.
6
6
 
7
- [![npm](https://img.shields.io/npm/v/@t2000/sdk)](https://www.npmjs.com/package/@t2000/sdk)
8
- [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
9
-
10
- **[Website](https://t2000.ai)** · **[GitHub](https://github.com/mission69b/t2000)** · **[CLI](https://www.npmjs.com/package/@t2000/cli)** · **[MPP](https://www.npmjs.com/package/@suimpp/mpp)** · **[MCP](https://www.npmjs.com/package/@t2000/mcp)**
7
+ [![npm @t2000/sdk](https://img.shields.io/npm/v/@t2000/sdk?label=%40t2000%2Fsdk)](https://www.npmjs.com/package/@t2000/sdk)
8
+ [![npm @t2000/cli](https://img.shields.io/npm/v/@t2000/cli?label=%40t2000%2Fcli)](https://www.npmjs.com/package/@t2000/cli)
9
+ [![docs](https://img.shields.io/badge/docs-t2000.ai-00D395)](https://t2000.ai)
10
+ [![license](https://img.shields.io/badge/license-MIT-blue)](https://github.com/mission69b/t2000/blob/main/LICENSE)
11
11
 
12
12
  ## Installation
13
13
 
14
14
  ```bash
15
- npm install @t2000/sdk
16
- # or
17
- pnpm add @t2000/sdk
18
- # or
19
- yarn add @t2000/sdk
15
+ npm install @t2000/sdk # or pnpm add / yarn add
20
16
  ```
21
17
 
22
- **Requirements:** Node.js 18+ · TypeScript 5+ (optional but recommended)
18
+ **Requires** Node.js 18+ · TypeScript 5+ (recommended).
23
19
 
24
20
  ## Quick Start
25
21
 
26
22
  ```typescript
27
23
  import { T2000 } from '@t2000/sdk';
28
24
 
29
- // Create a new Agentic Wallet
30
- const { agent, address } = await T2000.init({ pin: 'my-secret' });
25
+ // Create a new wallet (plain Bech32, 0o600 perms, no PIN)
26
+ const { agent, address } = await T2000.init();
27
+
28
+ // Or load an existing wallet from ~/.t2000/wallet.key
29
+ const agent = await T2000.create();
31
30
 
32
- // Or load an existing one
33
- const agent = await T2000.create({ pin: 'my-secret' });
31
+ // Or from a Bech32 secret in memory (no file)
32
+ const agent = T2000.fromPrivateKey('suiprivkey1…');
34
33
 
35
- // Check balance
34
+ // Inspect
36
35
  const balance = await agent.balance();
37
36
  console.log(`$${balance.available} USDC available`);
38
37
 
39
- // Send USDC recipient can be a 0x address, a SuiNS name, or a saved contact alias
40
- await agent.send({ to: '0x...', amount: 10 });
41
- await agent.send({ to: 'alex.sui', amount: 10 }); // SuiNS — resolved on-chain
42
- // Legacy contact aliases (~/.t2000/contacts.json) still work but emit a deprecation
43
- // warning on first use per process. Sunset target: next major SDK release.
38
+ // Send — asset is REQUIRED; USDC + USDsui are gasless via 0x2::balance::send_funds
39
+ await agent.send({ to: 'alice.sui', amount: 5, asset: 'USDC' });
40
+ await agent.send({ to: '0x8b3e…', amount: 5, asset: 'USDsui' });
44
41
 
45
- // Save (earn yield auto-selects best rate via NAVI)
46
- await agent.save({ amount: 50 });
42
+ // Swap Cetus Aggregator V3 across 20+ Sui DEXs. Requires SUI for gas.
43
+ await agent.swap({ from: 'USDC', to: 'SUI', amount: 100 });
47
44
 
48
- // Borrow USDC against your collateral
49
- await agent.borrow({ amount: 25 });
50
-
51
- // Withdraw from savings (USDC)
52
- await agent.withdraw({ amount: 25 });
45
+ // Pay — MPP-protected API. Gasless USDC; handles HTTP 402 transparently.
46
+ const result = await agent.pay({
47
+ url: 'https://mpp.t2000.ai/openai/v1/chat/completions',
48
+ method: 'POST',
49
+ body: JSON.stringify({ model: 'gpt-4o-mini', messages: […] }),
50
+ maxPrice: 0.10,
51
+ });
53
52
  ```
54
53
 
55
- ## API Reference
54
+ ## Factory Methods
56
55
 
57
- ### `T2000.init(options)` Create a new wallet
56
+ | Static | Returns | Use when |
57
+ |---|---|---|
58
+ | `T2000.init({ keyPath?, name? })` | `{ agent, address }` | Generating a brand-new wallet. Writes a plain Bech32 JSON file to `~/.t2000/wallet.key` (override with `keyPath`). |
59
+ | `T2000.create({ keyPath?, rpcUrl? })` | `T2000` | Loading the existing wallet from disk. Throws `WALLET_NOT_FOUND` if the file is missing, `WALLET_CORRUPT` if it's a v3 PIN-encrypted file or otherwise malformed. |
60
+ | `T2000.fromPrivateKey(secret, { network?, rpcUrl? })` | `T2000` | Synchronous in-memory load from a `suiprivkey1…` Bech32 or hex secret. No filesystem read or write. |
58
61
 
59
- Creates a new Agentic Wallet (generates keypair, encrypts, and saves to disk). Fund the returned address with a small amount of SUI for gas (Mercuryo: https://exchange.mercuryo.io/?widget_id=89960d1a-8db7-49e5-8823-4c5e01c1cea2) plus USDC to transact.
62
+ > **v3 v4.** `T2000.create({ pin })` is gone. The `pin` and `passphrase` fields are accepted (back-compat) but **ignored** — v4 wallets are plain Bech32 JSON with `0o600` perms. If you're upgrading a v3 PIN-encrypted wallet: export the secret from the v3 binary, then `T2000.init` followed by replacing the generated file with one carrying that secret (or just use [`@t2000/cli`](https://www.npmjs.com/package/@t2000/cli)'s `t2 init --import` flow).
60
63
 
61
- ```typescript
62
- const { agent, address } = await T2000.init({
63
- pin: 'my-secret', // Required — encrypts the key
64
- keyPath: '~/.t2000/wallet.key', // Optional — custom key file path
65
- });
66
- ```
64
+ ## Agent Wallet API
67
65
 
68
- ### `T2000.create(options)`Load an existing wallet
66
+ These methods cover the v4 Agent Wallet brand sending USDC, receiving, swapping, paying for MPP APIs. They mirror the [`@t2000/cli`](https://www.npmjs.com/package/@t2000/cli) surface 1:1.
69
67
 
70
- Loads an existing Agentic Wallet from an encrypted key file. Throws `WALLET_NOT_FOUND` if no wallet exists.
68
+ | Method | Returns | Notes |
69
+ |---|---|---|
70
+ | `agent.address()` | `string` | Sui address. |
71
+ | `agent.balance()` | `BalanceResponse` | USDC / USDsui / SUI + gas reserve + total USD. |
72
+ | `agent.history({ limit? })` | `TransactionRecord[]` | Sends / swaps / MPP payments with Suiscan digests. |
73
+ | `agent.send({ to, amount, asset })` | `SendResult` | **`asset` is required** (`'USDC'` / `'USDsui'` / `'SUI'`). USDC + USDsui are gasless via Sui foundation's `0x2::balance::send_funds` sponsor; SUI uses standard gas. `to` resolves in priority order: hex address > SuiNS name (`alice.sui`) > `@audric` handle > saved contact. |
74
+ | `agent.resolveRecipient(input)` | `{ address, suinsName?, contactName? }` | Public resolver — same lookup `send` uses. Handy for dry-run previews. |
75
+ | `agent.swap({ from, to, amount, slippage? })` | `SwapResult` | Cetus Aggregator V3 (20+ DEXs). User-friendly names (`'USDC'`, `'SUI'`, `'CETUS'`, …) or full coin types. Default slippage 1%, max 5%. **Requires SUI for gas** — Cetus is not in the gasless allowlist. |
76
+ | `agent.swapQuote({ from, to, amount, slippage? })` | `SwapQuoteResult` | Preview route + output + price impact (no execution). |
77
+ | `agent.pay(options)` | `PayResult` | MPP-protected paid API. Handles 402 → quote → USDC payment → retry. USDC transfer is gasless. `options.maxPrice` caps spend (default 1 USDC). |
78
+ | `agent.receive({ amount?, currency?, memo?, label? })` | `PaymentRequest` | Builds a Payment Kit `sui:pay?…` URI with a unique nonce. Scannable by any Sui wallet. |
79
+ | `agent.exportKey()` | `string` | Print the Bech32 (`suiprivkey1…`) secret for the underlying keypair. |
80
+
81
+ ### Events
71
82
 
72
83
  ```typescript
73
- const agent = await T2000.create({
74
- pin: 'my-secret', // Required decrypts the key
75
- keyPath: '~/.t2000/wallet.key', // Optional custom key file path
76
- rpcUrl: 'https://...', // Optional custom Sui RPC endpoint
77
- });
84
+ agent.on('balanceChange', (e) => { /* asset, previous, current, cause, tx? */ });
85
+ agent.on('healthWarning', (e) => { /* healthFactor, threshold */ });
86
+ agent.on('healthCritical', (e) => { /* healthFactor < 1.2 */ });
87
+ agent.on('yield', (e) => { /* earned, total, apy, timestamp */ });
88
+ agent.on('error', (e) => { /* T2000Error */ });
78
89
  ```
79
90
 
80
- ### `T2000.fromPrivateKey(key, options?)` — Load from raw key
91
+ ### Exposed Internals
81
92
 
82
- Synchronous factory that creates an agent from a raw private key (bech32 `suiprivkey1...` or hex).
93
+ For integrations (`@suimpp/mpp`, `@t2000/engine`, audric web-v2):
83
94
 
84
95
  ```typescript
85
- const agent = T2000.fromPrivateKey('suiprivkey1q...');
96
+ agent.suiClient; // SuiJsonRpcClient
97
+ agent.signer; // TransactionSigner (works for keypair + zkLogin)
98
+ agent.keypair; // Ed25519Keypair (throws for zkLogin instances)
86
99
  ```
87
100
 
88
- ### Core Methods
89
-
90
- | Method | Description | Returns |
91
- |--------|-------------|---------|
92
- | `agent.address()` | Wallet Sui address | `string` |
93
- | `agent.balance()` | Available USDC + savings + gas reserve | `BalanceResponse` |
94
- | `agent.send({ to, amount, asset? })` | Transfer USDC (or other supported asset) to a 0x address, SuiNS name (`alex.sui`), or saved contact alias. Priority: hex > SuiNS > contact. `SendResult.suinsName` / `.contactName` flag which path resolved. | `SendResult` |
95
- | `agent.resolveRecipient(input)` | Public resolver — same hex / SuiNS / contact priority used by `send()`. Useful for dryRun previews where you need the resolved address before committing. | `{ address, suinsName?, contactName? }` |
96
- | `agent.receive({ amount?, currency?, memo?, label? })` | Generate payment request with Payment Kit URI (`sui:pay?...`), nonce for duplicate prevention | `PaymentRequest` |
97
- | `agent.save({ amount, asset?, protocol? })` | Deposit **USDC or USDsui** to NAVI savings (v0.51.0+). `asset` defaults to `'USDC'`. Auto-selects best rate or specify `protocol`. `amount` can be `'all'`. | `SaveResult` |
98
- | `agent.withdraw({ amount, asset? })` | Withdraw from savings. `amount` can be `'all'`. Optional `asset` (default: USDC; also supports USDsui plus legacy USDe / SUI). | `WithdrawResult` |
99
- | `agent.borrow({ amount, asset? })` | Borrow **USDC or USDsui** against collateral (v0.51.0+). `asset` defaults to `'USDC'`. | `BorrowResult` |
100
- | `agent.repay({ amount, asset? })` | Repay outstanding **USDC or USDsui** debt (v0.51.1+). Pass `asset` to target a specific debt; omit for highest-APY repay. **Symmetry enforced:** USDsui debt is repaid with USDsui coins (and USDC with USDC). `amount` can be `'all'`. | `RepayResult` |
101
- | `agent.swap({ from, to, amount, slippage? })` | Swap tokens via Cetus Aggregator (20+ DEXs). User-friendly names or full coin types. | `SwapResult` |
102
- | `agent.exportKey()` | Export private key (bech32 format) | `string` |
103
-
104
- ### Query Methods
105
-
106
- | Method | Description | Returns |
107
- |--------|-------------|---------|
108
- | `agent.healthFactor()` | Lending health factor | `HealthFactorResult` |
109
- | `agent.earnings()` | Yield earned to date | `EarningsResult` |
110
- | `agent.rates()` | Best save/borrow APYs across protocols | `RatesResult` |
111
- | `agent.allRatesAcrossAssets()` | Per-protocol rate data across assets | `Array<{ protocol, asset, rates }>` |
112
- | `agent.positions()` | All open DeFi positions | `PositionsResult` |
113
- | `agent.fundStatus()` | Complete savings summary | `FundStatusResult` |
114
- | `agent.maxWithdraw()` | Max safe withdrawal amount | `MaxWithdrawResult` |
115
- | `agent.maxBorrow()` | Max safe borrow amount | `MaxBorrowResult` |
116
- | `agent.deposit()` | Wallet address + funding instructions | `DepositInfo` |
117
- | `agent.history({ limit? })` | Transaction history (default: all) | `TransactionRecord[]` |
118
- | `agent.swapQuote({ from, to, amount })` | Preview swap route, output amount, and price impact (no execution) | `SwapQuoteResult` |
119
-
120
- ### Contacts Methods
121
-
122
- | Method | Description | Returns |
123
- |--------|-------------|---------|
124
- | `agent.contacts.add(name, address)` | Save a named contact | `void` |
125
- | `agent.contacts.remove(name)` | Remove a contact | `void` |
126
- | `agent.contacts.list()` | List all saved contacts | `Contact[]` |
127
- | `agent.contacts.get(name)` | Get a contact by name | `Contact` |
128
- | `agent.contacts.resolve(nameOrAddress)` | Resolve name to address (passthrough if already an address) | `string` |
129
-
130
- ### Safeguards (Enforcer)
131
-
132
- | Method | Description | Returns |
133
- |--------|-------------|---------|
134
- | `agent.enforcer.getConfig()` | Get safeguard settings | `SafeguardConfig` |
135
- | `agent.enforcer.set({ maxPerTx?, maxDailySend? })` | Set per-transaction and/or daily send limits | `void` |
136
- | `agent.enforcer.lock()` | Lock agent (freeze all operations) | `void` |
137
- | `agent.enforcer.unlock(pin)` | Unlock agent | `void` |
138
- | `agent.enforcer.check(amount)` | Check if amount is allowed under limits | `void` (throws `SafeguardError` if not) |
139
- | `agent.enforcer.recordUsage(amount)` | Record send for daily limit tracking | `void` |
140
- | `agent.enforcer.isConfigured()` | Whether safeguards are set up | `boolean` |
141
-
142
- **Types:** `SafeguardConfig` — `{ maxPerTx?, maxDailySend?, locked? }` · `SafeguardError` — thrown when limits exceeded or agent locked
143
-
144
- ### Key Management
145
-
146
- ```typescript
147
- import {
148
- generateKeypair,
149
- keypairFromPrivateKey,
150
- exportPrivateKey,
151
- getAddress,
152
- saveKey,
153
- loadKey,
154
- walletExists,
155
- } from '@t2000/sdk';
101
+ ## Programmatic DeFi API (no CLI alias)
156
102
 
157
- // Generate a new keypair
158
- const keypair = generateKeypair();
103
+ These methods power [Audric Finance](https://audric.ai) — save (NAVI lend), borrow (NAVI), repay, withdraw, plus the supporting read tools. **They have no `t2` CLI alias in v4** by design: the CLI is a focused Agent Wallet (send / swap / pay); DeFi flows live in consumer apps and the `@t2000/engine` Agent Harness. They are still load-bearing for `@t2000/engine` 4.x and any consumer app building on the SDK.
159
104
 
160
- // Import from private key (bech32 or hex)
161
- const imported = keypairFromPrivateKey('suiprivkey1...');
105
+ | Method | Notes |
106
+ |---|---|
107
+ | `agent.save({ amount, asset?, protocol? })` | Deposit **USDC or USDsui** to NAVI savings (default `'USDC'`). `amount` can be `'all'`. |
108
+ | `agent.withdraw({ amount, asset?, protocol? })` | Withdraw from savings (default `'USDC'`; also supports USDsui + legacy USDe / SUI positions). `amount` can be `'all'`. |
109
+ | `agent.borrow({ amount, asset?, protocol? })` | Borrow USDC or USDsui against collateral (default `'USDC'`). |
110
+ | `agent.repay({ amount, asset?, protocol? })` | Repay outstanding debt. **Symmetry enforced** — USDsui debt is repaid with USDsui (USDC with USDC). `amount` can be `'all'`. |
111
+ | `agent.claimRewards()` | Claim pending NAVI rewards. |
112
+ | `agent.healthFactor()` | NAVI lending health factor. |
113
+ | `agent.maxWithdraw()` · `agent.maxBorrow()` | Safe limits without breaching health factor. |
114
+ | `agent.positions()` | Open save + borrow positions across protocols. |
115
+ | `agent.rates()` | Best save/borrow APYs across protocols. |
116
+ | `agent.earnings()` | Yield earned to date. |
117
+ | `agent.fundStatus()` | Complete savings summary. |
118
+ | `agent.deposit()` · `agent.fund()` | Wallet address + funding instructions (used by Audric's deposit UI). |
162
119
 
163
- // Export private key (bech32 format)
164
- const privkey = exportPrivateKey(keypair);
165
-
166
- // Get the Sui address
167
- const address = getAddress(keypair);
168
-
169
- // Check if wallet exists on disk
170
- const exists = await walletExists();
171
-
172
- // Save/load encrypted key
173
- await saveKey(keypair, 'my-pin');
174
- const loaded = await loadKey('my-pin');
175
- ```
176
-
177
- ### Events
120
+ ## Utility Exports
178
121
 
179
122
  ```typescript
180
- agent.on('balanceChange', (e) => {
181
- console.log(`${e.cause}: ${e.asset} ${e.previous} → ${e.current}`);
182
- });
123
+ import {
124
+ // Key management
125
+ generateKeypair, keypairFromPrivateKey, exportPrivateKey, getAddress,
126
+ saveKey, loadKey, walletExists,
183
127
 
184
- agent.on('healthWarning', (e) => {
185
- console.log(`Health factor: ${e.healthFactor} (warning)`);
186
- });
128
+ // Token data
129
+ COIN_REGISTRY, TOKEN_MAP, SUI_TYPE, USDC_TYPE,
130
+ isTier1, isTier2, isSupported, getTier,
131
+ getDecimalsForCoinType, resolveSymbol, resolveTokenType,
187
132
 
188
- agent.on('healthCritical', (e) => {
189
- console.log(`Health factor: ${e.healthFactor} (critical — below 1.2)`);
190
- });
133
+ // Asset allowlist
134
+ SUPPORTED_ASSETS, SENDABLE_ASSETS, assertAllowedAsset,
135
+ GASLESS_MIN_STABLE_AMOUNT, GASLESS_STABLE_TYPES,
191
136
 
192
- agent.on('yield', (e) => {
193
- console.log(`Earned: $${e.earned}, total: $${e.total}`);
194
- });
137
+ // Numbers + formatting
138
+ mistToSui, suiToMist, usdcToRaw, rawToUsdc,
139
+ formatUsd, formatSui, truncateAddress, validateAddress,
195
140
 
196
- agent.on('error', (e) => {
197
- console.error(`Error: ${e.code} — ${e.message}`);
198
- });
141
+ // Sui clients
142
+ getSuiClient, getSuiGrpcClient, DEFAULT_GRPC_URL,
143
+
144
+ // Fees (consumer apps only — SDK + CLI are fee-free)
145
+ addFeeTransfer, T2000_OVERLAY_FEE_WALLET,
146
+ } from '@t2000/sdk';
199
147
  ```
200
148
 
201
- ### Utility Functions
149
+ ## Supported Assets
202
150
 
203
- ```typescript
204
- import {
205
- mistToSui,
206
- suiToMist,
207
- usdcToRaw,
208
- rawToUsdc,
209
- formatUsd,
210
- formatSui,
211
- validateAddress,
212
- truncateAddress,
213
- } from '@t2000/sdk';
151
+ Token metadata + tiers live in `COIN_REGISTRY` (`packages/sdk/src/token-registry.ts`). **19 tokens** total.
214
152
 
215
- mistToSui(1_000_000_000n); // 1.0
216
- usdcToRaw(10.50); // 10_500_000n
217
- formatUsd(1234.5); // "$1234.50"
218
- truncateAddress('0xabcdef...1234'); // "0xabcd...1234"
219
- validateAddress('0x...'); // throws if invalid
220
- ```
153
+ - **Tier 1 — financial layer (1):** USDC. Save / borrow / receive / yield, marketplace, MPP.
154
+ - **Tier 2 — swap assets (15):** SUI, wBTC, ETH, GOLD, DEEP, WAL, NS, IKA, CETUS, NAVX, vSUI, haSUI, afSUI, LOFI, MANIFEST. Hold + swap + send only.
155
+ - **Legacy — no tier, display only (3):** USDT, USDe, USDsui. Kept so existing NAVI positions still render accurately.
221
156
 
222
- ### Advanced: Exposed Internals
157
+ > **Strategic exception.** `OPERATION_ASSETS.save` and `OPERATION_ASSETS.borrow` accept **both** USDC and USDsui — USDsui is no-tier in the registry but saveable/borrowable via the allowlist (NAVI runs a separate USDsui pool, often at a different APY than the USDC pool, since v0.51.0). Repay symmetry is enforced: USDsui debt must be repaid with USDsui (USDC debt with USDC).
223
158
 
224
- For integrations (like `@suimpp/mpp`), the agent exposes:
159
+ **`OPERATION_ASSETS`** constrains each write:
225
160
 
226
161
  ```typescript
227
- agent.suiClient; // SuiJsonRpcClient instance
228
- agent.signer; // Ed25519Keypair
229
- ```
162
+ import { OPERATION_ASSETS, assertAllowedAsset } from '@t2000/sdk';
230
163
 
231
- ## Gas
164
+ OPERATION_ASSETS.send; // ['USDC', 'USDsui', 'SUI']
165
+ OPERATION_ASSETS.save; // ['USDC', 'USDsui']
166
+ OPERATION_ASSETS.borrow; // ['USDC', 'USDsui']
232
167
 
233
- Every transaction is self-funded by the agent's wallet. Keep at least ~0.05 SUI on hand. If gas runs out the SDK throws `INSUFFICIENT_GAS` top up via Mercuryo (https://exchange.mercuryo.io/?widget_id=89960d1a-8db7-49e5-8823-4c5e01c1cea2) or any Sui exchange.
234
-
235
- > **Audric web app exception:** Audric web users transact under Enoki gas sponsorship (zkLogin), so `INSUFFICIENT_GAS` is not a user-facing concern there. The SDK itself is sponsorship-agnostic — sponsorship is wired in at the host layer (Audric web), not inside `@t2000/sdk`.
168
+ assertAllowedAsset('send', 'USDY'); // throws — not in the allowlist
169
+ ```
236
170
 
237
- **Architecture:** Each protocol operation (NAVI, send) exposes both `buildXxxTx()` (standalone transaction) and `addXxxToTx()` (composable fragment) functions. Multi-step flows compose multiple protocol calls into a single atomic Payment Intent (a Sui Programmable Transaction Block under the hood). If any step within a Payment Intent fails, the entire transaction reverts — no funds left in intermediate states.
171
+ ## Gasless
238
172
 
239
- ## Configuration
173
+ USDC + USDsui sends and MPP USDC payments are gasless. Build path goes through `SuiGrpcClient` so the SDK's gasless-eligibility resolver detects the `0x2::balance::send_funds` Move call at build time and zeroes out `gasPrice` / `gasBudget` / `gasPayment` automatically. Submission still goes through the JSON-RPC client (hybrid pattern documented at [`docs.sui.io`](https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers)).
240
174
 
241
- | Environment Variable | Description | Default |
242
- |---------------------|-------------|---------|
243
- | `T2000_API_URL` | t2000 API base URL | `https://api.t2000.ai` |
175
+ Other writes (SUI sends, Cetus swaps, NAVI save / borrow / withdraw / repay / claim) require gas. Keep ~0.05 SUI on hand. The SDK throws `INSUFFICIENT_GAS` if you run dry.
244
176
 
245
- Options like `pin`, `keyPath`, and `rpcUrl` are passed directly to `T2000.create()` or `T2000.init()`. The CLI handles env vars like `T2000_PIN` see the [CLI README](https://www.npmjs.com/package/@t2000/cli).
177
+ > **Consumer apps:** sponsored gas via Enoki / zkLogin is the host's responsibility. The SDK is sponsorship-agnostic Audric wires Enoki at the host layer (`audric/apps/web-v2`); the SDK doesn't know or care. See `audric/.cursor/rules/audric-transaction-flow.mdc` in the audric repo.
246
178
 
247
- ## Supported Assets
179
+ ## Fees
248
180
 
249
- Token metadata and **tiers** live in `token-registry.ts` (`COIN_REGISTRY`). **17 tokens** total:
181
+ The SDK + CLI are **fee-free by design** (`@t2000/sdk@1.1.0+`). No t2000 protocol fees on any operation.
250
182
 
251
- - **Tier 1 (saveable / borrowable):** USDC, USDsui save, borrow, send, swap. USDsui is a strategic exception (v0.51.0+) because NAVI runs a separate USDsui pool that often quotes a different APY than USDC. Repay symmetry is enforced (USDsui debt → USDsui repay).
252
- - **Tier 2 (15):** SUI, wBTC, ETH, GOLD, DEEP, WAL, NS, IKA, CETUS, NAVX, vSUI, haSUI, afSUI, LOFI, MANIFEST — send and swap only (not for new save/borrow deposits).
253
- - **Legacy (no tier):** USDT, USDe, USDSUI — display and withdraw of existing positions; still send/swap where applicable.
183
+ Network gas (SUI) and third-party fees (Cetus routing, NAVI lending spread) still apply at on-chain rates.
254
184
 
255
- Six tokens were removed from the registry (FDUSD, AUSD, BUCK, BLUB, SCA, TURBOS). `STABLE_ASSETS = ['USDC']` (the canonical USD unit for balance aggregation), but **`OPERATION_ASSETS.save` and `OPERATION_ASSETS.borrow` accept both `'USDC'` and `'USDsui'`** (v0.51.0+). Use `isAllowedAsset(op, asset)` / `assertAllowedAsset(op, asset)` to validate.
185
+ Consumer apps that want to charge an overlay fee Audric does this on save / borrow / swap call `addFeeTransfer(tx, paymentCoin, FEE_BPS, receiverAddress, amount)` inside the same PTB. The SDK never assumes a t2000 treasury; pass any receiver.
256
186
 
257
- ```typescript
258
- import {
259
- COIN_REGISTRY,
260
- TOKEN_MAP,
261
- isTier1,
262
- isTier2,
263
- isSupported,
264
- getTier,
265
- getDecimalsForCoinType,
266
- resolveSymbol,
267
- resolveTokenType,
268
- SUI_TYPE,
269
- USDC_TYPE,
270
- USDT_TYPE,
271
- IKA_TYPE,
272
- LOFI_TYPE,
273
- MANIFEST_TYPE,
274
- } from '@t2000/sdk';
187
+ ## Configuration
275
188
 
276
- isTier1(USDC_TYPE); // true
277
- isTier2(SUI_TYPE); // true
278
- isSupported(USDT_TYPE); // false (legacy no tier)
279
- getTier(SUI_TYPE); // 2
280
- ```
189
+ | Env var | Effect |
190
+ |---|---|
191
+ | `T2000_RPC_URL` | Custom Sui JSON-RPC endpoint. |
192
+ | `T2000_GRPC_URL` | Custom Sui gRPC endpoint (defaults to `fullnode.mainnet.sui.io`). Used during gasless USDC/USDsui send + pay build paths. |
281
193
 
282
- Swap uses Cetus Aggregator V3. Per-call `overlayFee` is opt-in — the SDK and CLI never charge fees by default. Consumer apps that want to charge an overlay (e.g. Audric) pass `overlayFee: { rate: 10n, receiver: T2000_OVERLAY_FEE_WALLET }` to `findSwapRoute` / `buildSwapTx`. Use `COIN_REGISTRY`, `getDecimalsForCoinType()`, `resolveSymbol()`, and `resolveTokenType()` for token data.
194
+ Per-call options like `keyPath` and `rpcUrl` are passed to `T2000.create()` / `T2000.init()`.
283
195
 
284
196
  ## Error Handling
285
197
 
@@ -287,58 +199,38 @@ Swap uses Cetus Aggregator V3. Per-call `overlayFee` is opt-in — the SDK and C
287
199
  import { T2000Error } from '@t2000/sdk';
288
200
 
289
201
  try {
290
- await agent.send({ to: 'alex.sui', amount: 1000 });
202
+ await agent.send({ to: 'alice.sui', amount: 1000, asset: 'USDC' });
291
203
  } catch (e) {
292
204
  if (e instanceof T2000Error) {
293
- console.log(e.code);
294
- // 'INSUFFICIENT_BALANCE' | 'SUINS_NOT_REGISTERED' | 'CONTACT_NOT_FOUND' | …
295
- console.log(e.message); // Human-readable message
205
+ // e.code + e.message
296
206
  }
297
207
  }
298
208
  ```
299
209
 
300
- Common error codes: `INSUFFICIENT_BALANCE` · `INVALID_ADDRESS` · `INVALID_AMOUNT` · `INVALID_ASSET` · `HEALTH_FACTOR_TOO_LOW` · `NO_COLLATERAL` · `WALLET_NOT_FOUND` · `WALLET_LOCKED` · `WALLET_EXISTS` · `SIMULATION_FAILED` · `TRANSACTION_FAILED` · `PROTOCOL_PAUSED` · `INSUFFICIENT_GAS` · `WITHDRAW_WOULD_LIQUIDATE` · `SWAP_NO_ROUTE` · `SWAP_FAILED`
210
+ Common codes:
301
211
 
302
- ## Protocol Integration
212
+ `WALLET_NOT_FOUND` · `WALLET_CORRUPT` · `INVALID_KEY` · `INSUFFICIENT_BALANCE` · `INSUFFICIENT_GAS` · `INVALID_ADDRESS` · `INVALID_AMOUNT` · `INVALID_ASSET` · `ASSET_NOT_SUPPORTED` · `SUINS_NOT_REGISTERED` · `CONTACT_NOT_FOUND` · `SWAP_NO_ROUTE` · `SWAP_FAILED` · `HEALTH_FACTOR_TOO_LOW` · `NO_COLLATERAL` · `WITHDRAW_WOULD_LIQUIDATE` · `PROTOCOL_PAUSED` · `SIMULATION_FAILED` · `TRANSACTION_FAILED`
303
213
 
304
- t2000 uses an MCP-first integration model: NAVI MCP for reads, thin transaction builders for writes. No protocol SDK dependencies needed.
214
+ ## Architecture
215
+
216
+ t2000 uses an MCP-first model for DeFi reads + thin transaction builders for writes. No protocol SDK dependencies needed in user code.
305
217
 
306
218
  | Protocol | Integration | Used for |
307
- |----------|------------|----------|
308
- | NAVI | MCP (reads) + thin tx builders (writes) | Lending positions, deposits, withdrawals, borrows, rewards |
309
- | Cetus Aggregator V3 | `@cetusprotocol/aggregator-sdk` (isolated) | Multi-DEX swap routing — overlay fee on swaps (`cetus-swap.ts`) |
219
+ |---|---|---|
220
+ | Sui foundation gasless | `0x2::balance::send_funds` Move call (built via `SuiGrpcClient`) | USDC + USDsui transfers, MPP USDC payments |
221
+ | Cetus Aggregator V3 | `@cetusprotocol/aggregator-sdk` (isolated to `protocols/cetus-swap.ts`) | Multi-DEX swap routing |
222
+ | NAVI | NAVI MCP (reads) + thin tx builders (writes) | Save / borrow / withdraw / repay / rewards / positions / rates |
223
+ | MPP | `mppx` + `@suimpp/mpp/client` | Paid API access — 40+ services on `mpp.t2000.ai` |
224
+
225
+ Each NAVI op exposes both `buildXxxTx()` (standalone) and `addXxxToTx()` (composable fragment) so multi-step flows compose atomically as a single Programmable Transaction Block — any step failing reverts the whole bundle.
310
226
 
311
227
  ## Testing
312
228
 
313
229
  ```bash
314
- # Run all SDK unit tests
315
- pnpm --filter @t2000/sdk test
316
-
317
- # Run smoke tests against mainnet RPC (read-only, no transactions)
318
- SMOKE=1 pnpm --filter @t2000/sdk test -- src/__smoke__
230
+ pnpm --filter @t2000/sdk test # unit
231
+ SMOKE=1 pnpm --filter @t2000/sdk test -- src/__smoke__ # read-only mainnet smokes
319
232
  ```
320
233
 
321
- ## Protocol Fees
322
-
323
- > **The SDK and CLI are fee-free by design (as of `@t2000/sdk@1.1.0`, B5 v2 / 2026-04-30).** Direct SDK / CLI calls — `t2000 save`, `t2000 borrow`, `t2000 swap`, plus `T2000.save()` / `T2000.borrow()` / `swapExecute()` from any third-party integrator — never charge a t2000 protocol fee. The CLI is dev-focused tooling and intentionally has no monetization.
324
-
325
- Fees only apply when the **Audric** consumer app calls these primitives. Audric layers a fee transfer step (`addFeeTransfer`) inside the same PTB and routes the USDC to `T2000_OVERLAY_FEE_WALLET`.
326
-
327
- | Operation | Audric fee | SDK / CLI fee | Notes |
328
- |-----------|-----------|--------------|-------|
329
- | Save (deposit) | 0.10% | Free | USDC only; USDsui save is free in Audric too |
330
- | Borrow | 0.05% | Free | USDC only; USDsui borrow is free in Audric too |
331
- | Swap | 0.10% | Free | Audric passes Cetus `overlayFee`. CLI omits it. Cetus Aggregator network fees still apply both ways. |
332
- | Withdraw / Repay / Send / Receive / Pay (MPP) | Free | Free | No surcharge anywhere. |
333
-
334
- How Audric collects fees: `prepare/route.ts` calls `addFeeTransfer(tx, paymentCoin, FEE_BPS, T2000_OVERLAY_FEE_WALLET, amount)` for save/borrow and passes `overlayFee.receiver = T2000_OVERLAY_FEE_WALLET` for swaps. Both flows produce a USDC transfer to the treasury wallet inside the same atomic Payment Intent. The t2000 server-side indexer detects the on-chain USDC inflow and records a `ProtocolFeeLedger` row — no off-chain submission is involved.
335
-
336
- Need to charge an overlay fee in your own consumer app? Import `addFeeTransfer` and `T2000_OVERLAY_FEE_WALLET` from `@t2000/sdk` (or use your own receiver address — the SDK never assumes the t2000 treasury).
337
-
338
- ## MCP Server
339
-
340
- The SDK powers the [`@t2000/mcp`](https://www.npmjs.com/package/@t2000/mcp) server for Claude Desktop, Cursor, and any MCP-compatible AI platform. Run `t2000 mcp` to start.
341
-
342
234
  ## License
343
235
 
344
- MIT — see [LICENSE](https://github.com/mission69b/t2000/blob/main/LICENSE)
236
+ MIT — see [LICENSE](https://github.com/mission69b/t2000/blob/main/LICENSE).