@t2000/sdk 9.7.0 → 9.7.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/token-registry.ts","../src/wallet/coinSelection.ts","../src/wallet/keypairSigner.ts","../src/wallet/zkLoginSigner.ts","../src/wallet/pay.ts","../src/mpp-cost.ts","../src/wallet/executeTx.ts","../src/preflight.ts","../src/browser.ts","../src/constants.ts","../src/utils/sui.ts","../src/wallet/classify.ts","../src/wallet/history.ts","../src/utils/format.ts","../src/utils/base64.ts","../src/protocols/cetus-swap.ts","../src/wallet/send.ts","../src/wallet/job.ts"],"names":["T2000Error","COIN_REGISTRY","ETH_TYPE","IKA_TYPE","LOFI_TYPE","MANIFEST_TYPE","NAVX_TYPE","SUI_TYPE","TOKEN_MAP","USDC_TYPE","USDE_TYPE","USDSUI_TYPE","USDT_TYPE","WAL_TYPE","WBTC_TYPE","coinWithBalance","requested","swapAll","effectiveAmount","coin","Transaction","isValidSuiAddress","normalizeSuiAddress","fromBase64","result","buildCoinToAddressBalanceMigration","SuiGrpcClient","getDecimalsForCoinType","AggregatorClient","Env","CLOCK_ID"],"mappings":"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","file":"browser.cjs","sourcesContent":["export type T2000ErrorCode =\n | 'INSUFFICIENT_BALANCE'\n | 'ADDRESS_BALANCE_UNSPONSORABLE'\n | 'INSUFFICIENT_GAS'\n | 'INVALID_ADDRESS'\n | 'INVALID_AMOUNT'\n | 'WALLET_NOT_FOUND'\n | 'WALLET_LOCKED'\n | 'WALLET_EXISTS'\n | 'WALLET_CORRUPT'\n | 'INVALID_KEY'\n | 'SIMULATION_FAILED'\n | 'TRANSACTION_FAILED'\n | 'ASSET_NOT_SUPPORTED'\n | 'INVALID_ASSET'\n | 'PROTOCOL_UNAVAILABLE'\n | 'RPC_ERROR'\n | 'RPC_UNREACHABLE'\n | 'PRICE_EXCEEDS_LIMIT'\n | 'UNSUPPORTED_NETWORK'\n | 'PAYMENT_EXPIRED'\n | 'DUPLICATE_PAYMENT'\n | 'FACILITATOR_REJECTION'\n | 'CONTACT_NOT_FOUND'\n | 'INVALID_CONTACT_NAME'\n | 'SUINS_NOT_REGISTERED'\n | 'FACILITATOR_TIMEOUT'\n | 'SAFEGUARD_BLOCKED'\n | 'SWAP_NO_ROUTE'\n | 'SWAP_FAILED'\n | 'DIALECT_UNSUPPORTED'\n | 'CHAIN_MODE_INVALID'\n | 'INFERENCE_FAILED'\n | 'UNKNOWN';\n\nexport interface T2000ErrorData {\n reason?: string;\n [key: string]: unknown;\n}\n\nexport class T2000Error extends Error {\n readonly code: T2000ErrorCode;\n readonly data?: T2000ErrorData;\n readonly retryable: boolean;\n\n constructor(code: T2000ErrorCode, message: string, data?: T2000ErrorData, retryable = false) {\n super(message);\n this.name = 'T2000Error';\n this.code = code;\n this.data = data;\n this.retryable = retryable;\n }\n\n toJSON() {\n return {\n error: this.code,\n message: this.message,\n ...(this.data && { data: this.data }),\n retryable: this.retryable,\n };\n }\n}\n\nexport function mapWalletError(error: unknown): T2000Error {\n const msg = error instanceof Error ? error.message : String(error);\n\n if (msg.includes('rejected') || msg.includes('cancelled')) {\n return new T2000Error('TRANSACTION_FAILED', 'Transaction cancelled');\n }\n if (msg.includes('Insufficient') || msg.includes('insufficient')) {\n return new T2000Error('INSUFFICIENT_BALANCE', 'Insufficient balance');\n }\n\n return new T2000Error('UNKNOWN', msg, undefined, true);\n}\n\nexport function mapMoveAbortCode(code: number): string {\n const abortMessages: Record<number, string> = {\n 1: 'Protocol is temporarily paused',\n 2: 'Amount must be greater than zero',\n 3: 'Invalid operation type',\n 4: 'Fee rate exceeds maximum',\n 5: 'Insufficient treasury balance',\n 6: 'Not authorized',\n 7: 'Package version mismatch — upgrade required',\n 8: 'Timelock is active — wait for expiry',\n 9: 'No pending change to execute',\n 10: 'Already at current version',\n // NAVI Protocol abort codes\n 1502: 'Oracle price is stale — try again in a moment',\n 1503: 'Withdrawal amount is invalid (zero or dust) — try a specific amount instead of \"all\"',\n 1600: 'Health factor too low — withdrawal would risk liquidation',\n 1605: 'Asset borrowing is disabled or at capacity on this protocol',\n // NAVI utils abort codes\n 46000: 'Insufficient balance to repay — withdraw some savings first to get cash',\n };\n return abortMessages[code] ?? `Move abort code: ${code}`;\n}\n\n/**\n * Check if an error message contains a MoveAbort — these are on-chain\n * failures that will fail no matter how many times you retry.\n */\nexport function isMoveAbort(msg: string): boolean {\n return msg.includes('MoveAbort') || msg.includes('MovePrimitiveRuntimeError');\n}\n\nexport function parseMoveAbortMessage(msg: string): string {\n const abortMatch = msg.match(/abort code:\\s*(\\d+)/i) ?? msg.match(/MoveAbort[^,]*,\\s*(\\d+)/);\n if (abortMatch) {\n const code = parseInt(abortMatch[1], 10);\n\n const moduleMatch = msg.match(/Identifier\\(\"([^\"]+)\"\\)/) ?? msg.match(/in '([^']+)'/);\n const fnMatch = msg.match(/function_name:\\s*Some\\(\"([^\"]+)\"\\)/);\n const context = `${moduleMatch?.[1] ?? ''}${fnMatch ? `::${fnMatch[1]}` : ''}`.toLowerCase();\n const suffix = moduleMatch\n ? ` [${moduleMatch[1]}${fnMatch ? `::${fnMatch[1]}` : ''}]`\n : '';\n\n if (context.includes('slippage')) {\n return `Slippage too high — price moved during execution${suffix}`;\n }\n if (context.includes('balance::split') || context.includes('balance::ENotEnough')) {\n return `Insufficient on-chain balance${suffix}`;\n }\n\n const mapped = mapMoveAbortCode(code);\n return `${mapped}${suffix}`;\n }\n return msg;\n}\n","/**\n * Unified token registry — single source of truth for coin types, decimals,\n * and symbols. ZERO heavy dependencies; safe to import anywhere (server,\n * browser, Edge).\n *\n * Used for swap-by-symbol resolution, amount formatting (decimals), and\n * history/balance display. USDC is the settlement stable (send / receive /\n * x402 pay); everything else is holdable / swappable. There is no curated\n * \"tier\" gate — swaps accept any coin type (Cetus routes); the registry just\n * makes the common tokens ergonomic to reference by symbol.\n *\n * To add a token: add ONE entry to COIN_REGISTRY below — everything derives\n * from it.\n */\n\nexport interface CoinMeta {\n type: string;\n decimals: number;\n symbol: string;\n}\n\n/**\n * Canonical coin registry.\n * Key = user-friendly name (used in swap, CLI, prompts).\n */\nexport const COIN_REGISTRY: Record<string, CoinMeta> = {\n // ── Settlement stable ─────────────────────────────────────────────────\n USDC: { type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', decimals: 6, symbol: 'USDC' },\n\n // ── Common swap assets (symbol ergonomics — any coin type still swaps) ─\n SUI: { type: '0x2::sui::SUI', decimals: 9, symbol: 'SUI' },\n wBTC: { type: '0x0041f9f9344cac094454cd574e333c4fdb132d7bcc9379bcd4aab485b2a63942::wbtc::WBTC', decimals: 8, symbol: 'wBTC' },\n ETH: { type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH', decimals: 8, symbol: 'ETH' },\n GOLD: { type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM', decimals: 9, symbol: 'GOLD' },\n DEEP: { type: '0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP', decimals: 6, symbol: 'DEEP' },\n WAL: { type: '0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL', decimals: 9, symbol: 'WAL' },\n NS: { type: '0x5145494a5f5100e645e4b0aa950fa6b68f614e8c59e17bc5ded3495123a79178::ns::NS', decimals: 6, symbol: 'NS' },\n IKA: { type: '0x7262fb2f7a3a14c888c438a3cd9b912469a58cf60f367352c46584262e8299aa::ika::IKA', decimals: 9, symbol: 'IKA' },\n CETUS: { type: '0x06864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b::cetus::CETUS', decimals: 9, symbol: 'CETUS' },\n NAVX: { type: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX', decimals: 9, symbol: 'NAVX' },\n vSUI: { type: '0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT', decimals: 9, symbol: 'vSUI' },\n haSUI: { type: '0xbde4ba4c2e274a60ce15c1cfff9e5c42e41654ac8b6d906a57efa4bd3c29f47d::hasui::HASUI', decimals: 9, symbol: 'haSUI' },\n afSUI: { type: '0xf325ce1300e8dac124071d3152c5c5ee6174914f8bc2161e88329cf579246efc::afsui::AFSUI', decimals: 9, symbol: 'afSUI' },\n LOFI: { type: '0xf22da9a24ad027cccb5f2d496cbe91de953d363513db08a3a734d361c7c17503::LOFI::LOFI', decimals: 9, symbol: 'LOFI' },\n MANIFEST: { type: '0xc466c28d87b3d5cd34f3d5c088751532d71a38d93a8aae4551dd56272cfb4355::manifest::MANIFEST', decimals: 9, symbol: 'MANIFEST' },\n\n // ── Other stables (display / classification) ──────────────────────────\n USDT: { type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT', decimals: 6, symbol: 'USDT' },\n USDe: { type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE', decimals: 6, symbol: 'USDe' },\n USDSUI: { type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI', decimals: 6, symbol: 'USDsui' },\n};\n\n/** Reverse lookup: coin type → CoinMeta. Built once at import time. */\nconst BY_TYPE = new Map<string, CoinMeta>();\nfor (const meta of Object.values(COIN_REGISTRY)) {\n BY_TYPE.set(meta.type, meta);\n}\n\n// ── Lookup helpers ───────────────────────────────────────────────────────\n\n/**\n * Returns the registry metadata for a coin type, or `undefined` if the coin\n * is not in the registry. Used for canonical-symbol + decimal resolution.\n */\nexport function getCoinMeta(coinType: string): CoinMeta | undefined {\n return BY_TYPE.get(coinType);\n}\n\n/**\n * Returns true if the coin type appears in COIN_REGISTRY. Useful as a\n * canonical-symbol gate — e.g. so the registry's mixed-case `USDsui` wins\n * over a vendor feed's uppercase `USDSUI`.\n */\nexport function isInRegistry(coinType: string): boolean {\n return BY_TYPE.has(coinType);\n}\n\n// ── Lookup helpers ───────────────────────────────────────────────────────\n\n/**\n * Get decimals for any coin type. Checks full type match, then suffix match,\n * then defaults to 9. Works for any token, registered or not.\n */\nexport function getDecimalsForCoinType(coinType: string): number {\n const direct = BY_TYPE.get(coinType);\n if (direct) return direct.decimals;\n\n const suffix = coinType.split('::').slice(1).join('::').toUpperCase();\n if (suffix) {\n for (const meta of BY_TYPE.values()) {\n const metaSuffix = meta.type.split('::').slice(1).join('::').toUpperCase();\n if (metaSuffix === suffix) return meta.decimals;\n }\n }\n\n return 9;\n}\n\n/** Minimal structural client — just the coin-metadata read this needs. */\ninterface CoinMetadataClient {\n core: { getCoinMetadata: (opts: { coinType: string }) => Promise<unknown> };\n}\n\n/**\n * [2.11] Decimals for any coin type, resolved correctly for arbitrary tokens.\n * Registry tokens return their known decimals (no network). A coin type NOT in\n * the registry is read ON-CHAIN via coin metadata — never the 9-default guess,\n * because a wrong `from` decimal would corrupt a swap's input amount\n * (financial-amounts rule). Falls back to the registry heuristic only if the\n * on-chain read fails or returns no usable decimals.\n */\nexport async function resolveCoinDecimals(\n client: CoinMetadataClient,\n coinType: string,\n): Promise<number> {\n if (isInRegistry(coinType)) return getDecimalsForCoinType(coinType);\n try {\n const res = (await client.core.getCoinMetadata({ coinType })) as {\n metadata?: { decimals?: number };\n decimals?: number;\n };\n const d = res?.metadata?.decimals ?? res?.decimals;\n if (typeof d === 'number' && Number.isFinite(d)) return d;\n } catch {\n /* on-chain read failed — fall through to the registry heuristic */\n }\n return getDecimalsForCoinType(coinType);\n}\n\n/**\n * Resolve a full coin type to a user-friendly symbol.\n * Returns the last `::` segment if not in the registry.\n */\nexport function resolveSymbol(coinType: string): string {\n const direct = BY_TYPE.get(coinType);\n if (direct) return direct.symbol;\n\n const suffix = coinType.split('::').slice(1).join('::').toUpperCase();\n if (suffix) {\n for (const meta of BY_TYPE.values()) {\n const metaSuffix = meta.type.split('::').slice(1).join('::').toUpperCase();\n if (metaSuffix === suffix) return meta.symbol;\n }\n }\n\n return coinType.split('::').pop() ?? coinType;\n}\n\n/**\n * Name → type map for swap resolution. Derived from COIN_REGISTRY.\n * Contains BOTH original-case and UPPERCASE keys for case-insensitive lookup.\n */\nexport const TOKEN_MAP: Record<string, string> = (() => {\n const map: Record<string, string> = {};\n for (const [name, meta] of Object.entries(COIN_REGISTRY)) {\n map[name] = meta.type;\n map[name.toUpperCase()] = meta.type;\n }\n return map;\n})();\n\n/**\n * Resolve a user-friendly token name to its full coin type.\n * Returns the input unchanged if already a full coin type (contains \"::\").\n * Case-insensitive: 'usde', 'USDe', 'USDE' all resolve correctly.\n */\nexport function resolveTokenType(nameOrType: string): string | null {\n if (nameOrType.includes('::')) return nameOrType;\n return TOKEN_MAP[nameOrType] ?? TOKEN_MAP[nameOrType.toUpperCase()] ?? null;\n}\n\n/** Common type constants for direct import. */\nexport const SUI_TYPE = COIN_REGISTRY.SUI.type;\nexport const USDC_TYPE = COIN_REGISTRY.USDC.type;\nexport const USDT_TYPE = COIN_REGISTRY.USDT.type;\nexport const USDSUI_TYPE = COIN_REGISTRY.USDSUI.type;\nexport const USDE_TYPE = COIN_REGISTRY.USDe.type;\nexport const ETH_TYPE = COIN_REGISTRY.ETH.type;\nexport const WBTC_TYPE = COIN_REGISTRY.wBTC.type;\nexport const WAL_TYPE = COIN_REGISTRY.WAL.type;\nexport const NAVX_TYPE = COIN_REGISTRY.NAVX.type;\nexport const IKA_TYPE = COIN_REGISTRY.IKA.type;\nexport const LOFI_TYPE = COIN_REGISTRY.LOFI.type;\nexport const MANIFEST_TYPE = COIN_REGISTRY.MANIFEST.type;\n","/**\n * Wallet-side coin selection helpers — single source of truth for the\n * \"produce a `Coin<T>` argument holding `amount` raw units of `coinType`,\n * owned by `address`\" pattern. Used by every wallet-mode appender that\n * needs a coin input (save, send, swap, repay, stake, etc.).\n *\n * **2026-05-22 — address-balance migration.** Sui mainnet's address-balance\n * feature ships funds account-style instead of as discrete `Coin<T>` objects.\n * After a payment via `0x2::balance::send_funds`, the leftover lands in the\n * sender's address balance with a synthetic \"coin reservation\" representing\n * the deposit. `client.getCoins()` correctly filters those reservations out\n * (they aren't real owned objects), so the old fetch+merge+split pattern\n * threw `INSUFFICIENT_BALANCE` for users whose stables had drifted into\n * address balance — even when `getBalance().totalBalance` showed plenty.\n *\n * The fix is structural: hand the work to `coinWithBalance({ type, balance })`\n * from `@mysten/sui/transactions`. Its build-time resolver inspects coins +\n * address balance together (`getBalance` + `listCoins`), then emits the\n * right shape — direct `redeem_funds` from address balance when AB ≥\n * required, or merge-and-split across coins + AB withdrawal when not. Multi\n * intents per coin type get batched into a single merge in one PTB, so the\n * old per-PTB merge cache is no longer needed.\n *\n * Pre-flight uses `client.getBalance().totalBalance` (sums coins + AB)\n * instead of summing the paginated `getCoins` page. That's the OTHER half\n * of the migration — the legacy path could see `0` from `getCoins` and\n * mistakenly throw before `coinWithBalance` ever ran.\n */\nimport {\n Transaction,\n coinWithBalance,\n type TransactionObjectArgument,\n} from '@mysten/sui/transactions';\nimport type { SuiCoreClient } from '../utils/sui.js';\nimport { T2000Error } from '../errors.js';\n\nexport interface CoinPage {\n ids: string[];\n totalBalance: bigint;\n}\n\n/**\n * Sum every coin of `coinType` owned by `owner`, INCLUDING address balance.\n * Returns the IDs of any discrete coin objects that exist (callers\n * occasionally need this for non-`coinWithBalance` paths, e.g. SUIns name\n * registration which expects raw object IDs).\n *\n * Pre-2026-05-22 this function paginated `client.getCoins` and summed\n * the page balances. That misses address-balance funds (the SDK filters\n * them out of `getCoins` for back-compat). The new implementation calls\n * `getBalance` for the canonical total and `getCoins` for the optional\n * ID list — both round-trips, but they happen in parallel.\n */\nexport async function fetchAllCoins(\n client: SuiCoreClient,\n owner: string,\n coinType: string,\n): Promise<CoinPage> {\n const [balance, ids] = await Promise.all([\n client.core.getBalance({ owner, coinType }),\n (async () => {\n const out: string[] = [];\n let cursor: string | null | undefined;\n let hasNext = true;\n while (hasNext) {\n const page = await client.core.listCoins({ owner, coinType, cursor: cursor ?? undefined });\n for (const c of page.objects) out.push(c.objectId);\n cursor = page.cursor;\n hasNext = page.hasNextPage;\n }\n return out;\n })(),\n ]);\n return { ids, totalBalance: BigInt(balance.balance.balance) };\n}\n\nexport interface SelectAndSplitResult {\n /** TransactionObjectArgument for a coin holding `effectiveAmount` raw units. */\n coin: TransactionObjectArgument;\n /** Actual raw amount the returned coin holds. May be < requested if `swapAll` is true. */\n effectiveAmount: bigint;\n /** True iff the request consumed the entire wallet balance (no split needed). */\n swapAll: boolean;\n}\n\n/**\n * Wallet-mode coin selection prelude. Pre-flights against\n * `getBalance().totalBalance` (coins + address balance combined), then\n * returns a `coinWithBalance({ type, balance })` argument that the\n * `@mysten/sui` resolver fulfills at build time.\n *\n * Throws `T2000Error` (`INSUFFICIENT_BALANCE`) when:\n * - `amount` is bigger than the total balance AND the caller did NOT\n * opt into `swapAll: true` clipping.\n * - `amount === 'all'` AND total balance is zero.\n *\n * @param tx — PTB to register the `coinWithBalance` intent against.\n * @param client — Sui RPC client for the pre-flight `getBalance` lookup.\n * @param owner — wallet address whose coins to source from.\n * @param coinType — fully-qualified Sui coin type (e.g. `\"0x...::usdc::USDC\"`).\n * @param amount — raw amount to source (in MIST / smallest unit). Pass\n * `'all'` to consume the entire balance.\n * @param options.allowSwapAll — if true (default), `amount` >= totalBalance\n * auto-clips to total. If false, throws when the request would over-consume.\n * @param options.sponsoredContext — when true, source ONLY from discrete coin\n * objects (never the address balance). See the long note below — this exists\n * because Enoki's gas station can't yet deserialize a `TransactionData` that\n * contains the address-balance `FundsWithdrawal` reservation that\n * `coinWithBalance` emits. Self-funded callers leave this false: the fullnode\n * handles `FundsWithdrawal` fine, so the address-balance path is preferred\n * (it can reach funds that aren't held as coin objects).\n *\n * @returns\n * - `coin` — `TransactionObjectArgument` ready for downstream consumption.\n * - `effectiveAmount` — the raw amount the returned coin holds (handles\n * swapAll clipping).\n * - `swapAll` — true iff the entire balance was consumed.\n */\nexport async function selectAndSplitCoin(\n tx: Transaction,\n client: SuiCoreClient,\n owner: string,\n coinType: string,\n amount: bigint | 'all',\n options: {\n allowSwapAll?: boolean;\n sponsoredContext?: boolean;\n mergeCache?: SponsoredCoinMergeCache;\n } = {},\n): Promise<SelectAndSplitResult> {\n // [2026-05-30] Sponsored Enoki path — coin objects only. `coinWithBalance`\n // reaches into the address balance (mysten Address Balances feature) when\n // `addressBalance >= required`, emitting `0x2::coin::redeem_funds` + a\n // `FundsWithdrawal` reservation input. That input is a newer `TransactionData`\n // field; Enoki's sponsor endpoint accepts the kind bytes (200) but its gas\n // station rejects the assembled `TransactionData` at execute with\n // \"Invalid bcs bytes for TransactionData\". The fullnode parses it fine — only\n // Enoki can't (yet). So under sponsorship we source from discrete coin objects\n // and surface a clear error when the user's funds are address-balance-only.\n // See github.com/mission69b/t2000 issue #93.\n if (options.sponsoredContext) {\n return selectCoinObjectsOnly(\n tx,\n client,\n owner,\n coinType,\n amount,\n options.allowSwapAll ?? true,\n options.mergeCache,\n );\n }\n\n const balanceResp = await client.core.getBalance({ owner, coinType });\n const totalBalance = BigInt(balanceResp.balance.balance);\n\n if (totalBalance === 0n) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `No balance found for ${coinType}`);\n }\n\n const allowSwapAll = options.allowSwapAll ?? true;\n\n if (amount !== 'all' && amount > totalBalance && !allowSwapAll) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `Insufficient balance for ${coinType}`, {\n available: totalBalance.toString(),\n required: amount.toString(),\n });\n }\n\n const requested = amount === 'all' ? totalBalance : amount;\n const swapAll = amount === 'all' || requested >= totalBalance;\n const effectiveAmount = swapAll ? totalBalance : requested;\n\n const coin = coinWithBalance({ type: coinType, balance: effectiveAmount })(tx);\n\n return { coin, effectiveAmount, swapAll };\n}\n\n/**\n * Coin-object-only selection for sponsored (Enoki) transactions. Fetches the\n * owner's discrete `Coin<T>` objects (NOT the address balance — `getCoins`\n * excludes it), merges them, and splits the requested amount. Never emits a\n * `FundsWithdrawal` reservation, so the resulting `TransactionData` stays on\n * the shape Enoki's gas station can serialize.\n *\n * Throws `ADDRESS_BALANCE_UNSPONSORABLE` when the coin objects don't cover the\n * request — which, for a user whose `getBalance().totalBalance` shows funds,\n * means those funds live in the address balance (e.g. received via a gasless\n * stablecoin transfer) and can't be moved through a sponsored transaction yet.\n */\n/**\n * Per-PTB cache of merged sponsored coin-object primaries, keyed by coin\n * type. The FIRST `selectCoinObjectsOnly` call for a given coin type in a\n * PTB fetches the owner's discrete `Coin<T>` objects, merges them into one\n * `primary`, and records it here alongside the remaining (unspent) balance.\n * EVERY subsequent leg sourcing the same coin type splits from that cached\n * `primary` instead of re-fetching + re-merging.\n *\n * Why this exists (S.xxx, 2026-06-02): a sponsored bundle with 2+ legs\n * sourcing the same coin (e.g. `SUI→WAL` + `SUI→DEEP`, or `swap USDC` +\n * `save USDC`) called `selectCoinObjectsOnly` once per leg. Each call\n * emitted its own `mergeCoins` over the SAME coin objects, so the second\n * leg's merge referenced coins the first leg already consumed → Enoki\n * dry-run failed with `CommandArgumentError { ArgumentWithoutValue }`.\n *\n * This is NOT SUI-specific. Under sponsorship, `selectAndSplitCoin` routes\n * EVERY asset through `selectCoinObjectsOnly` (the `coinWithBalance`\n * batching that would otherwise dedup these merges only runs for\n * non-sponsored CLI/direct flows — its address-balance `FundsWithdrawal`\n * reservation is what Enoki can't deserialize, issue #93). So the cache is\n * the dedup layer for ALL coin types in a sponsored multi-leg PTB, keyed\n * by coin type. SUI was simply the first asset observed failing in the\n * wild because it's the most common swap source.\n */\nexport type SponsoredCoinMergeCache = Map<\n string,\n { primary: TransactionObjectArgument; remaining: bigint }\n>;\n\nasync function selectCoinObjectsOnly(\n tx: Transaction,\n client: SuiCoreClient,\n owner: string,\n coinType: string,\n amount: bigint | 'all',\n allowSwapAll: boolean,\n mergeCache?: SponsoredCoinMergeCache,\n): Promise<SelectAndSplitResult> {\n // Cache hit — a prior leg in THIS PTB already merged this coin type's\n // objects into `cached.primary`. Re-running the fetch+merge below would\n // emit a second `mergeCoins` over already-consumed coins → dry-run\n // `ArgumentWithoutValue`. Split from the cached primary instead.\n const cached = mergeCache?.get(coinType);\n if (cached) {\n const requested = amount === 'all' ? cached.remaining : amount;\n if (cached.remaining === 0n || requested > cached.remaining) {\n throw new T2000Error(\n 'ADDRESS_BALANCE_UNSPONSORABLE',\n `Not enough ${coinType} in coin objects to cover all legs of this ` +\n `sponsored bundle. The remaining funds are in your address balance, ` +\n `which sponsored transactions can't access yet.`,\n { remaining: cached.remaining.toString(), requested: requested.toString(), coinType },\n );\n }\n const swapAll = amount === 'all' || requested >= cached.remaining;\n const effectiveAmount = swapAll ? cached.remaining : requested;\n const coin = swapAll\n ? cached.primary\n : tx.splitCoins(cached.primary, [effectiveAmount])[0];\n cached.remaining -= effectiveAmount;\n return { coin, effectiveAmount, swapAll };\n }\n\n const objects: { objectId: string; balance: bigint }[] = [];\n let coinObjectTotal = 0n;\n let cursor: string | null | undefined;\n let hasNext = true;\n while (hasNext) {\n const page = await client.core.listCoins({ owner, coinType, cursor: cursor ?? undefined });\n for (const c of page.objects) {\n objects.push({ objectId: c.objectId, balance: BigInt(c.balance) });\n coinObjectTotal += BigInt(c.balance);\n }\n cursor = page.cursor;\n hasNext = page.hasNextPage;\n }\n\n const unsponsorable = (): T2000Error =>\n new T2000Error(\n 'ADDRESS_BALANCE_UNSPONSORABLE',\n `These funds are in your address balance, which sponsored transactions ` +\n `can't access yet. (Funds received via gasless transfers land there.) ` +\n `This will work once the gas sponsor adds address-balance support.`,\n { coinObjectTotal: coinObjectTotal.toString(), coinType },\n );\n\n if (coinObjectTotal === 0n) {\n throw unsponsorable();\n }\n\n const requested = amount === 'all' ? coinObjectTotal : amount;\n if (requested > coinObjectTotal) {\n // Not enough in coin objects. If the caller allows clipping to the\n // available coin-object total (\"swap all\"), do so; otherwise the shortfall\n // is sitting in the address balance → unsponsorable.\n if (allowSwapAll && amount === 'all') {\n // unreachable (requested === coinObjectTotal here) — kept for clarity.\n } else {\n throw unsponsorable();\n }\n }\n\n const swapAll = amount === 'all' || requested >= coinObjectTotal;\n const effectiveAmount = swapAll ? coinObjectTotal : requested;\n\n const [first, ...rest] = objects;\n const primary = tx.object(first.objectId);\n if (rest.length > 0) {\n tx.mergeCoins(\n primary,\n rest.map((o) => tx.object(o.objectId)),\n );\n }\n\n // Consume the whole merged coin when taking everything; otherwise split the\n // exact amount and leave the remainder on the (sender-owned) primary coin.\n const coin = swapAll ? primary : tx.splitCoins(primary, [effectiveAmount])[0];\n\n // Record the merged primary so later legs in the same PTB reuse it\n // rather than re-fetching + re-merging the same (now-consumed) coins.\n // When `swapAll`, the primary was consumed (remaining 0) — a later leg\n // hitting the cache then throws the unsponsorable shortfall above.\n mergeCache?.set(coinType, {\n primary,\n remaining: coinObjectTotal - effectiveAmount,\n });\n\n return { coin, effectiveAmount, swapAll };\n}\n\n/**\n * Build a GASLESS coin→address-balance migration.\n *\n * Sends WHOLE `Coin<T>` objects to `owner`'s OWN SIP-58 address balance via\n * `0x2::coin::send_funds(coin, owner)` — one allowlisted framework MoveCall\n * per coin, with NO native `SplitCoins` / `MergeCoins` commands. That shape is\n * what makes it gasless: the gRPC build resolver only zeros gas for PTBs whose\n * every command is a MoveCall into the `0x2` gasless allowlist (`send_funds` /\n * `redeem_funds` / `withdrawal_split` / `into_balance`). The same eligibility\n * the gasless `balance::send_funds` send + the x402 `redeem_funds`+`send_funds`\n * withdrawal rely on. (The old migration merged+split first → native commands →\n * fell outside the allowlist → needed SUI. See `pay.ts ensureAddressBalanceCovers`.)\n *\n * Selects the FEWEST coins (largest first) whose combined balance covers\n * `minAmount`, minimizing the MoveCall count. Over-migration is harmless — the\n * surplus just lands in the address balance. Pure / network-free: callers pass\n * coins they've already fetched, so this is unit-testable offline.\n *\n * Throws `INSUFFICIENT_BALANCE` when the supplied coin objects can't cover\n * `minAmount`.\n */\nexport function buildCoinToAddressBalanceMigration(args: {\n coins: { objectId: string; balance: bigint }[];\n coinType: string;\n owner: string;\n minAmount: bigint;\n}): { tx: Transaction; migratedRaw: bigint } {\n const { coins, coinType, owner, minAmount } = args;\n\n // Largest first → fewest whole-coin sends to cover the shortfall.\n const sorted = [...coins]\n .filter((c) => c.balance > 0n)\n .sort((a, b) => (b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0));\n\n const selected: { objectId: string; balance: bigint }[] = [];\n let migratedRaw = 0n;\n for (const c of sorted) {\n if (migratedRaw >= minAmount) break;\n selected.push(c);\n migratedRaw += c.balance;\n }\n\n if (migratedRaw < minAmount) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `Insufficient ${coinType} coin objects to migrate`, {\n available: migratedRaw.toString(),\n required: minAmount.toString(),\n });\n }\n\n const tx = new Transaction();\n for (const c of selected) {\n tx.moveCall({\n target: '0x2::coin::send_funds',\n typeArguments: [coinType],\n arguments: [tx.object(c.objectId), tx.pure.address(owner)],\n });\n }\n return { tx, migratedRaw };\n}\n\n/**\n * SUI-specific coin selection. Branches on sponsorship context:\n *\n * - **Self-funded (`sponsoredContext: false`)** — splits from `tx.gas`\n * directly (the user's gas coin IS their SUI). More efficient — no\n * `getBalance` RTT.\n *\n * - **Sponsored (`sponsoredContext: true`)** — sources from the user's\n * discrete SUI coin objects (`selectCoinObjectsOnly`). This both (a) avoids\n * `tx.gas`, which belongs to the Enoki sponsor — NOT the user — under\n * sponsored flows (the original S.260 reason for `useGasCoin: false`), AND\n * (b) avoids `coinWithBalance`'s address-balance `FundsWithdrawal`, which\n * Enoki's gas station can't deserialize (issue #93). If the user's SUI is\n * address-balance-only, it raises `ADDRESS_BALANCE_UNSPONSORABLE`.\n */\nexport async function selectSuiCoin(\n tx: Transaction,\n client: SuiCoreClient,\n owner: string,\n amountMist: bigint,\n sponsoredContext: boolean,\n mergeCache?: SponsoredCoinMergeCache,\n): Promise<SelectAndSplitResult> {\n if (sponsoredContext) {\n const { SUI_TYPE } = await import('../token-registry.js');\n return selectCoinObjectsOnly(tx, client, owner, SUI_TYPE, amountMist, false, mergeCache);\n }\n\n const [coin] = tx.splitCoins(tx.gas, [amountMist]);\n return { coin, effectiveAmount: amountMist, swapAll: false };\n}\n","import type { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\nimport type { TransactionSigner } from '../signer.js';\n\nexport class KeypairSigner implements TransactionSigner {\n readonly kind = 'keypair' as const;\n\n constructor(private readonly keypair: Ed25519Keypair) {}\n\n getAddress(): string {\n return this.keypair.getPublicKey().toSuiAddress();\n }\n\n async signTransaction(txBytes: Uint8Array): Promise<{ signature: string }> {\n return this.keypair.signTransaction(txBytes);\n }\n\n async signPersonalMessage(messageBytes: Uint8Array): Promise<{ signature: string; bytes: string }> {\n return this.keypair.signPersonalMessage(messageBytes);\n }\n\n /** Access the underlying keypair for APIs that still require it directly. */\n getKeypair(): Ed25519Keypair {\n return this.keypair;\n }\n}\n","import type { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\nimport type { TransactionSigner } from '../signer.js';\n\nexport interface ZkLoginProof {\n proofPoints: {\n a: string[];\n b: string[][];\n c: string[];\n };\n issBase64Details: {\n indexMod4: number;\n value: string;\n };\n headerBase64: string;\n addressSeed: string;\n}\n\nexport class ZkLoginSigner implements TransactionSigner {\n readonly kind = 'zklogin' as const;\n\n constructor(\n private readonly ephemeralKeypair: Ed25519Keypair,\n private readonly zkProof: ZkLoginProof,\n private readonly userAddress: string,\n private readonly maxEpoch: number,\n ) {}\n\n getAddress(): string {\n return this.userAddress;\n }\n\n async signTransaction(txBytes: Uint8Array): Promise<{ signature: string }> {\n const { getZkLoginSignature } = await import('@mysten/zklogin');\n const ephSig = await this.ephemeralKeypair.signTransaction(txBytes);\n return {\n signature: getZkLoginSignature({\n inputs: this.zkProof,\n maxEpoch: this.maxEpoch,\n userSignature: ephSig.signature,\n }),\n };\n }\n\n async signPersonalMessage(messageBytes: Uint8Array): Promise<{ signature: string; bytes: string }> {\n const { getZkLoginSignature } = await import('@mysten/zklogin');\n const { signature: ephSig, bytes } = await this.ephemeralKeypair.signPersonalMessage(messageBytes);\n return {\n signature: getZkLoginSignature({\n inputs: this.zkProof,\n maxEpoch: this.maxEpoch,\n userSignature: ephSig,\n }),\n bytes,\n };\n }\n\n isExpired(currentEpoch: number): boolean {\n return currentEpoch >= this.maxEpoch;\n }\n}\n","import type { SuiGrpcClient } from '@mysten/sui/grpc';\nimport { fromBase64 } from '@mysten/sui/utils';\nimport type { X402Requirements } from '@suimpp/mpp/x402';\nimport type { TransactionSigner } from '../signer.js';\nimport type { PayOptions, PayResult } from '../types.js';\nimport { T2000Error } from '../errors.js';\nimport { parseChallengeAmount } from '../mpp-cost.js';\nimport { executeTx } from './executeTx.js';\nimport {\n type PreflightResult,\n PREFLIGHT_OK,\n preflightFail,\n checkPositiveAmount,\n} from '../preflight.js';\n\n/**\n * Synchronous, network-free preflight for `pay` (x402 Service call). Validates\n * the target URL shape and the `maxPrice` ceiling when present — the cheap\n * checks the v3 host runs before dispatching the paid tool / showing the\n * tap-to-confirm card. Returns a `PreflightResult`; never throws. The probe +\n * 402 handshake + balance migration stay in `payWithMpp` (network).\n */\nexport function preflightPay(input: { url: string; maxPrice?: number }): PreflightResult {\n if (typeof input.url !== 'string' || input.url.trim() === '') {\n return preflightFail('FACILITATOR_REJECTION', 'A target URL is required to pay');\n }\n let parsed: URL;\n try {\n parsed = new URL(input.url);\n } catch {\n return preflightFail('FACILITATOR_REJECTION', `Invalid URL: ${input.url}`);\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return preflightFail(\n 'FACILITATOR_REJECTION',\n `URL must be http(s): got ${parsed.protocol}//`,\n );\n }\n // `maxPrice` is optional (no ceiling = pay whatever the 402 asks). Validate\n // only when the caller set one — a malformed ceiling is a fat-finger.\n if (input.maxPrice !== undefined) {\n const priceCheck = checkPositiveAmount(input.maxPrice, 'maxPrice');\n if (!priceCheck.valid) return priceCheck;\n }\n return PREFLIGHT_OK;\n}\n\n// ---------------------------------------------------------------------------\n// payWithMpp — the SDK's single source of truth for the pay loop. Browser-safe\n// (no fs / keyManager / SafeguardEnforcer), so the Audric client can run it\n// in-browser on the zkLogin session key. `T2000.pay()` delegates here.\n//\n// TWO dialects, ONE preference order (both ride the SAME gasless\n// `send_funds<USDC>` rail; the only difference is who submits):\n//\n// 1. x402 `sui-exact` (preferred — SPEC_AGENT_PAYMENTS_X402 1.2; scheme =\n// SUIMPP_X402_SCHEME.md v0.3): the 402 body carries `accepts[]`; the\n// client signs an authorization, the SERVER settles (settle-then-serve,\n// so a failed upstream is never charged). The withdrawal form draws from\n// the SIP-58 address balance, so coin-object funds are migrated in first\n// when needed (S.414 finding).\n//\n// 2. MPP header dialect (fallback — suimpp.dev/spec): the 402 carries only a\n// `WWW-Authenticate: Payment … method=\"sui\"` challenge, no x402 body. The\n// CLIENT broadcasts the gasless USDC transfer and retries with the digest\n// credential. S.452 retired this path assuming all sellers were our\n// gateway (which dual-serves); the first EXTERNAL seller (JMPR, S.453)\n// shipped header-only — the client must speak everything the gateway and\n// suimpp spec serve, so the fallback is back. Trade-off vs x402: the\n// client pays BEFORE the server proves it can deliver, so a broken seller\n// can charge without serving — x402 stays preferred whenever offered.\n// ---------------------------------------------------------------------------\n\nexport async function payWithMpp(args: {\n signer: TransactionSigner;\n client: SuiGrpcClient;\n options: PayOptions;\n}): Promise<PayResult> {\n const { signer, client } = args;\n let options = args.options;\n\n // Layer 2 — cheap synchronous preflight (URL shape + maxPrice sanity) before\n // any network round-trip. Rethrow the precise code+message verbatim.\n const pf = preflightPay({ url: options.url, maxPrice: options.maxPrice });\n if (!pf.valid) throw new T2000Error(pf.code, pf.error);\n\n const method = (options.method ?? 'GET').toUpperCase();\n const canHaveBody = method !== 'GET' && method !== 'HEAD';\n\n // Default `content-type: application/json` when the body IS JSON and the\n // caller didn't say otherwise. Without it, fetch stamps `text/plain` and\n // strict servers (FastAPI et al.) receive the body as a string — a 422\n // before the 402 ever fires (live finding vs JMPR, the first external\n // seller). Every retry below reads from the normalized `options`.\n if (\n canHaveBody &&\n typeof options.body === 'string' &&\n isJsonText(options.body) &&\n !hasContentType(options.headers)\n ) {\n options = {\n ...options,\n headers: { ...(options.headers ?? {}), 'content-type': 'application/json' },\n };\n }\n\n const reqInit: RequestInit = {\n method,\n headers: options.headers,\n body: canHaveBody ? options.body : undefined,\n };\n\n // Probe (no payment). A paid endpoint answers 402; a free/cached one serves.\n const probe = await fetch(options.url, reqInit);\n if (probe.status !== 402) {\n return finalize(probe, { paid: false });\n }\n\n const requirements = await pickSuiExactRequirements(probe, client.network);\n if (requirements) {\n const result = await payViaX402({ signer, client, options, reqInit, requirements });\n await reportDirectPayment(result, options.url);\n return result;\n }\n\n // No x402 envelope — fall back to the MPP header dialect when the 402\n // advertises a `sui` method challenge.\n const headerChallenge = await parseMppSuiChallenge(probe);\n if (headerChallenge) {\n // Fail CLOSED before any money moves: the header dialect pays first and\n // proves identity with a personal-message signature the SELLER verifies.\n // zkLogin signatures are ZK constructs external sellers can't check —\n // the payment settles on-chain, then the retry 402s and the buyer ate\n // the charge (live: JMPR × Audric Passport, 2026-07-17). x402 is immune\n // (the tx itself carries the zkLogin sig; the CHAIN verifies it), so\n // zkLogin payers require sellers that offer x402.\n if (signer.kind === 'zklogin') {\n throw new T2000Error(\n 'DIALECT_UNSUPPORTED',\n 'This seller only offers the MPP header dialect, which zkLogin (Passport) wallets ' +\n 'cannot safely pay: the seller cannot verify zkLogin signatures, so the payment ' +\n 'would settle on-chain without the service delivering. No payment was made. ' +\n 'Use an x402-capable service, or pay from a keypair wallet (t2 CLI / MCP).',\n { dialect: 'mpp-header', signerKind: 'zklogin' },\n );\n }\n const result = await payViaMppHeader({ signer, client, options });\n await reportDirectPayment(result, options.url);\n return result;\n }\n\n throw new T2000Error(\n 'FACILITATOR_REJECTION',\n `Endpoint returned 402 without an x402 'exact' / sui:${client.network} requirement in the body ` +\n `or an MPP 'sui' challenge in WWW-Authenticate. Nothing this SDK can pay.`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Direct-seller activity reporting (S.743). Gateway-proxied payments are\n// logged server-side by the gateway itself; DIRECT payments (catalog\n// federation — seller's own origin) never touch it, leaving the activity\n// feed blind. After a paid call to a non-gateway origin, tell the gateway\n// \"look at this digest for this url\" — it verifies on-chain (USDC inflow to\n// the cataloged seller's pinned payTo) before recording, so the report\n// carries no trusted data. Best-effort by construction: timeout-capped and\n// error-swallowed, a lost report never fails or delays the payment. Awaited\n// (not fire-and-forget) so short-lived CLI processes don't drop it on exit.\n// ---------------------------------------------------------------------------\n\nconst MPP_REPORT_URL = 'https://mpp.t2000.ai/api/mpp/report';\nconst REPORT_TIMEOUT_MS = 2_000;\n\nasync function reportDirectPayment(result: PayResult, url: string): Promise<void> {\n if (!result.paid || !result.receipt?.reference) return;\n try {\n if (new URL(url).origin === new URL(MPP_REPORT_URL).origin) return;\n await fetch(MPP_REPORT_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ digest: result.receipt.reference, url }),\n signal: AbortSignal.timeout(REPORT_TIMEOUT_MS),\n });\n } catch {\n // Best-effort: the payment already succeeded; the feed row is analytics.\n }\n}\n\n/**\n * Parse the MPP header dialect from a 402 response: the\n * `WWW-Authenticate: Payment …` challenge(s), looking for `method=\"sui\"`.\n * Returns the decoded `{ amount, currency, recipient }` request (amount is a\n * decimal string, e.g. \"0.02\") or `undefined` when the response carries no\n * sui challenge. Exported for the CLI's `t2 pay --estimate`.\n */\nexport async function parseMppSuiChallenge(\n response: Response,\n): Promise<{ amount: string; currency: string; recipient: string; description?: string } | undefined> {\n try {\n const { Challenge } = await import('mppx');\n const challenges = Challenge.fromResponseList(response);\n const suiChallenge = challenges.find((c) => c.method === 'sui' && c.intent === 'charge');\n if (!suiChallenge) return undefined;\n const req = suiChallenge.request as Record<string, unknown>;\n if (typeof req?.amount !== 'string' || typeof req?.recipient !== 'string') return undefined;\n return {\n amount: req.amount,\n currency: typeof req.currency === 'string' ? req.currency : '',\n recipient: req.recipient,\n description: suiChallenge.description,\n };\n } catch {\n return undefined;\n }\n}\n\n// ---------------------------------------------------------------------------\n// x402 `sui-exact` — sign-then-settle\n// ---------------------------------------------------------------------------\n\nasync function pickSuiExactRequirements(\n response: Response,\n network: string,\n): Promise<X402Requirements | undefined> {\n try {\n const body = (await response.clone().json()) as { accepts?: X402Requirements[] };\n const want = `sui:${network === 'testnet' ? 'testnet' : 'mainnet'}`;\n return body.accepts?.find((a) => a.scheme === 'exact' && a.network === want);\n } catch {\n return undefined;\n }\n}\n\nasync function payViaX402(args: {\n signer: TransactionSigner;\n client: SuiGrpcClient;\n options: PayOptions;\n reqInit: RequestInit;\n requirements: X402Requirements;\n}): Promise<PayResult> {\n const { signer, client, options, reqInit, requirements } = args;\n const { buildX402SignedPayment, X402_PAYMENT_HEADER, X402_PAYMENT_RESPONSE_HEADER } = await import(\n '@suimpp/mpp/x402'\n );\n\n const amountRaw = BigInt(requirements.maxAmountRequired);\n assertWithinMaxPrice(atomicToHuman(amountRaw, await assetDecimals(requirements.asset)), options.maxPrice);\n\n // The x402 withdrawal form spends ONLY the SIP-58 address balance. A wallet\n // funded by ordinary coin transfers (or swap output) holds Coin<USDC>\n // objects → migrate enough in first (S.414 finding; SUIMPP_X402_SCHEME §4).\n const migrationGasSui = await ensureAddressBalanceCovers({\n signer,\n client,\n asset: requirements.asset,\n amountRaw,\n });\n\n // Build + sign — NEVER submitted client-side; the gateway settles. The\n // builder only reads toSuiAddress() + signTransaction(), both of which every\n // TransactionSigner (keypair AND zkLogin) provides.\n const signerAdapter = {\n toSuiAddress: () => signer.getAddress(),\n signTransaction: (bytes: Uint8Array) => signer.signTransaction(bytes),\n } as unknown as Parameters<typeof buildX402SignedPayment>[0]['signer'];\n\n const { header } = await buildX402SignedPayment({ requirements, signer: signerAdapter });\n\n const res = await fetch(options.url, {\n ...reqInit,\n headers: { ...(options.headers ?? {}), [X402_PAYMENT_HEADER]: header },\n });\n\n // Settled iff the gateway returned the x402 receipt header.\n const settleHeader = res.headers.get(X402_PAYMENT_RESPONSE_HEADER);\n const paid = !!settleHeader;\n let digest: string | undefined;\n if (settleHeader) {\n try {\n digest = (JSON.parse(new TextDecoder().decode(fromBase64(settleHeader))) as { transaction?: string })\n .transaction;\n } catch {\n digest = undefined;\n }\n }\n\n const result = await finalize(res, { paid });\n if (!paid) return { ...result, dialect: 'x402' };\n return {\n ...result,\n dialect: 'x402',\n cost: atomicToHuman(amountRaw, await assetDecimals(requirements.asset)),\n gasCostSui: migrationGasSui,\n receipt: digest\n ? { reference: digest, timestamp: new Date().toISOString() }\n : result.receipt,\n };\n}\n\n// ---------------------------------------------------------------------------\n// MPP header dialect — client broadcasts, retries with the digest credential.\n// The pre-S.452 `payViaLegacy`, restored (S.453) for header-only external\n// sellers. mppx's client handles the 402 → pay → retry loop; we plug in the\n// Sui charge method with an `execute` override that routes the on-chain leg\n// through `executeTx` (gRPC build → gasless resolver → the same\n// `send_funds<USDC>` rail as x402).\n// ---------------------------------------------------------------------------\n\nasync function payViaMppHeader(args: {\n signer: TransactionSigner;\n client: SuiGrpcClient;\n options: PayOptions;\n}): Promise<PayResult> {\n const { signer, client, options } = args;\n\n const { Mppx } = await import('mppx/client');\n const { sui, USDC, USDC_TESTNET } = await import('@suimpp/mpp/client');\n\n const signerAddress = signer.getAddress();\n const network: 'mainnet' | 'testnet' = client.network === 'testnet' ? 'testnet' : 'mainnet';\n const grpcClient = await makeGrpcBuildClient(client);\n\n let paymentDigest: string | undefined;\n let gasCostSui = 0;\n // The real amount charged on-chain is the 402 challenge price (a decimal\n // USDC string like \"0.01\"), NOT the caller's `maxPrice` ceiling (Bug 1,\n // dogfood 2026-05-31). Capture it in `onChallenge` — and enforce the\n // ceiling THERE, before any credential is created: the header dialect pays\n // client-side, so this hook is the last stop before money moves.\n let chargedAmount: number | undefined;\n\n const mppx = Mppx.create({\n polyfill: false,\n onChallenge: async (challenge: { request?: { amount?: unknown } }) => {\n const parsed = parseChallengeAmount(challenge);\n if (parsed !== undefined) {\n chargedAmount = parsed;\n assertWithinMaxPrice(parsed, options.maxPrice);\n }\n return undefined;\n },\n methods: [\n sui({\n client,\n currency: network === 'testnet' ? USDC_TESTNET : USDC,\n signer: {\n toSuiAddress: () => signerAddress,\n signPersonalMessage: (bytes: Uint8Array) => signer.signPersonalMessage(bytes),\n } as unknown as Parameters<typeof sui>[0]['signer'],\n execute: async (tx) => {\n const result = await executeTx(client, signer, () => tx, { buildClient: grpcClient });\n paymentDigest = result.digest;\n gasCostSui = result.gasCostSui;\n return { digest: result.digest };\n },\n }),\n ],\n });\n\n const method = (options.method ?? 'GET').toUpperCase();\n const canHaveBody = method !== 'GET' && method !== 'HEAD';\n\n const response = await mppx.fetch(options.url, {\n method,\n headers: options.headers,\n body: canHaveBody ? options.body : undefined,\n });\n\n const paid = !!paymentDigest;\n const result = await finalize(response, { paid });\n if (!paid) return { ...result, dialect: 'legacy' };\n return {\n ...result,\n dialect: 'legacy',\n cost: chargedAmount ?? options.maxPrice ?? undefined,\n gasCostSui,\n receipt: paymentDigest\n ? { reference: paymentDigest, timestamp: new Date().toISOString() }\n : undefined,\n };\n}\n\n/** Throw `PRICE_EXCEEDS_LIMIT` when the challenge price exceeds the caller's\n * `maxPrice` ceiling (no ceiling = pay whatever the 402 asks). */\nfunction assertWithinMaxPrice(price: number, maxPrice: number | undefined): void {\n if (maxPrice !== undefined && price > maxPrice) {\n throw new T2000Error(\n 'PRICE_EXCEEDS_LIMIT',\n `Service price $${price} exceeds maxPrice ceiling $${maxPrice}`,\n { price, maxPrice },\n );\n }\n}\n\n/**\n * Ensure the sender's SIP-58 address balance covers `amountRaw` of `asset`.\n * Returns the SUI gas spent migrating (0 when no migration was needed or the\n * migration was gasless). Throws `INSUFFICIENT_BALANCE` when the wallet\n * doesn't hold enough of the asset at all (coins + address balance combined).\n */\nasync function ensureAddressBalanceCovers(args: {\n signer: TransactionSigner;\n client: SuiGrpcClient;\n asset: string;\n amountRaw: bigint;\n}): Promise<number> {\n const { signer, client, asset, amountRaw } = args;\n const owner = signer.getAddress();\n\n // total = coins + address balance (the canonical combined read)\n const balanceResp = await client.core.getBalance({ owner, coinType: asset });\n const total = BigInt(balanceResp.balance.balance);\n if (total < amountRaw) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `Insufficient ${asset} to pay`, {\n available: total.toString(),\n required: amountRaw.toString(),\n });\n }\n\n // address balance = total − discrete coin-object sum (listCoins excludes AB).\n // Collect the coin objects too — we reuse them to build the migration.\n const coins: { objectId: string; balance: bigint }[] = [];\n let coinSum = 0n;\n let cursor: string | null | undefined;\n let hasNext = true;\n while (hasNext) {\n const page = await client.core.listCoins({ owner, coinType: asset, cursor: cursor ?? undefined });\n for (const c of page.objects) {\n coins.push({ objectId: c.objectId, balance: BigInt(c.balance) });\n coinSum += BigInt(c.balance);\n }\n cursor = page.cursor;\n hasNext = page.hasNextPage;\n }\n const addressBalance = total - coinSum;\n if (addressBalance >= amountRaw) return 0; // address balance already covers it\n\n // Move the shortfall from coin objects into the address balance by sending\n // WHOLE coin objects to self via `0x2::coin::send_funds` — one allowlisted\n // framework MoveCall per coin, NO native merge/split. Built on the gRPC\n // client so its resolver detects the all-allowlisted-MoveCall shape and zeros\n // gas: the migration itself is gasless (the same eligibility the x402\n // withdrawal + the gasless send rely on). The old merge+split+send shape had\n // native `SplitCoins`/`MergeCoins` commands → fell outside the allowlist →\n // forced SUI gas, breaking coin-object holders with 0 SUI.\n const shortfall = amountRaw - addressBalance;\n const { buildCoinToAddressBalanceMigration } = await import('./coinSelection.js');\n const grpcClient = await makeGrpcBuildClient(client);\n const { tx } = buildCoinToAddressBalanceMigration({ coins, coinType: asset, owner, minAmount: shortfall });\n const migration = await executeTx(client, signer, () => tx, { buildClient: grpcClient });\n return migration.gasCostSui;\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\n/** Cheap \"is this JSON?\" check — parse, don't guess from the first char. */\nfunction isJsonText(text: string): boolean {\n try {\n JSON.parse(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Case-insensitive content-type presence check on a plain header record. */\nfunction hasContentType(headers: Record<string, string> | undefined): boolean {\n if (!headers) return false;\n return Object.keys(headers).some((k) => k.toLowerCase() === 'content-type');\n}\n\n/** Read the response body (json or text) and assemble the base PayResult. */\nasync function finalize(response: Response, opts: { paid: boolean }): Promise<PayResult> {\n const contentType = response.headers.get('content-type') ?? '';\n let body: unknown;\n try {\n body = contentType.includes('application/json') ? await response.json() : await response.text();\n } catch {\n body = null;\n }\n return { status: response.status, body, paid: opts.paid };\n}\n\n/** A gRPC client for tx BUILD — its resolver auto-detects the gasless\n * stablecoin shape (gasPrice/gasBudget/gasPayment zeroed). */\nasync function makeGrpcBuildClient(client: SuiGrpcClient): Promise<SuiGrpcClient> {\n const { SuiGrpcClient } = await import('@mysten/sui/grpc');\n const network: 'mainnet' | 'testnet' = client.network === 'testnet' ? 'testnet' : 'mainnet';\n const baseUrl =\n network === 'testnet' ? 'https://fullnode.testnet.sui.io' : 'https://fullnode.mainnet.sui.io';\n return new SuiGrpcClient({ baseUrl, network });\n}\n\nfunction atomicToHuman(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nasync function assetDecimals(coinType: string): Promise<number> {\n try {\n const { getDecimalsForCoinType } = await import('../token-registry.js');\n const d = getDecimalsForCoinType(coinType);\n return typeof d === 'number' ? d : 6;\n } catch {\n return 6;\n }\n}\n","/**\n * MPP cost extraction — the truthful-`cost` fix (Bug 1, dogfood 2026-05-31).\n *\n * `T2000.pay()` used to report `options.maxPrice` (the caller's ceiling, default\n * 1.0 in MCP) as the `cost`, wildly overstating the real charge. The real\n * amount is the 402 challenge price, a decimal USDC string like \"0.01\" carried\n * on `challenge.request.amount`. mppx surfaces the parsed challenge via its\n * `onChallenge` hook; this pure helper pulls the amount out so the extraction\n * is unit-testable in isolation (the ordering/format invariant can't silently\n * regress).\n */\n\n/** Minimal structural view of an mppx payment challenge. */\nexport type MppChallenge = { request?: { amount?: unknown } } | null | undefined;\n\n/**\n * Parse the charged amount (USD) from a payment challenge. Returns `undefined`\n * when the challenge has no usable numeric amount, so callers can fall back to\n * the `maxPrice` ceiling rather than reporting a wrong number.\n */\nexport function parseChallengeAmount(challenge: MppChallenge): number | undefined {\n const raw = challenge?.request?.amount;\n const n =\n typeof raw === 'string' ? Number(raw) : typeof raw === 'number' ? raw : Number.NaN;\n return Number.isFinite(n) ? n : undefined;\n}\n","import type { SuiClientTypes } from '@mysten/sui/client';\nimport type { Transaction } from '@mysten/sui/transactions';\nimport type { TransactionSigner } from '../signer.js';\nimport type { SuiCoreClient } from '../utils/sui.js';\n\n// ---------------------------------------------------------------------------\n// executeTx — build + sign + submit + wait, the SDK's one tx-execution helper.\n//\n// Browser-safe (no fs / keyManager imports) so it can back\n// both the Node-side `T2000` methods AND the browser-side `payWithMpp`\n// (gasless MPP runs client-side on the zkLogin session key). Moved out of\n// `t2000.ts` so `wallet/pay.ts` can share it without pulling the Node-only\n// `T2000` module graph into the browser bundle.\n//\n// [gRPC migration] Submit + wait go through the unified `client.core.*`\n// API (`executeTransaction` + `waitForTransaction`), which is transport-\n// agnostic across the JSON-RPC and gRPC clients.\n// ---------------------------------------------------------------------------\n\nexport type SuiTransactionEffects = SuiClientTypes.TransactionEffects;\nexport type BuildClient = NonNullable<Parameters<Transaction['build']>[0]>['client'];\n\nexport async function executeTx(\n client: SuiCoreClient,\n signer: TransactionSigner,\n buildTx: () => Promise<Transaction> | Transaction,\n options: { buildClient?: BuildClient } = {},\n): Promise<{ digest: string; gasCostSui: number; effects: SuiTransactionEffects | undefined }> {\n const tx = await buildTx();\n tx.setSender(signer.getAddress());\n // [2026-05-22] Optional buildClient. When set, `tx.build()` uses it to\n // resolve the PTB — relevant for gasless stablecoin transfers where the\n // SuiGrpcClient build path auto-detects allowlisted ops and zeros out\n // gasPrice/gasBudget/gasPayment. See `payWithMpp`.\n const txBytes = await tx.build({ client: options.buildClient ?? client });\n const { signature } = await signer.signTransaction(txBytes);\n const result = await client.core.executeTransaction({\n transaction: txBytes,\n signatures: [signature],\n include: { effects: true },\n });\n const txn = result.$kind === 'Transaction' ? result.Transaction : result.FailedTransaction;\n try {\n await client.core.waitForTransaction({ digest: txn.digest });\n } catch (err) {\n // A successful executeTransaction already returned the certified effects —\n // the wait only provides read-your-write index visibility. On a lagging\n // fullnode it can time out AFTER the tx landed; propagating that turns a\n // SUCCESSFUL on-chain payment into a reported failure, which bait-invites\n // a double-pay retry (S.453 JMPR e2e: two 0.02 USDC charges for one call).\n // Effects in hand = executed + certified → proceed. No effects = nothing\n // proves execution → rethrow.\n if (!txn.effects) throw err;\n }\n const effects = txn.effects ?? undefined;\n const gasUsed = effects?.gasUsed;\n let gasCostSui = 0;\n if (gasUsed) {\n const total = BigInt(gasUsed.computationCost) + BigInt(gasUsed.storageCost) - BigInt(gasUsed.storageRebate);\n gasCostSui = Number(total) / 1e9;\n }\n return { digest: txn.digest, gasCostSui, effects };\n}\n","// Builder-appropriate safety, layer 2 (SPEC_AUDRIC_V3 §7 / safeguards-defense-\n// in-depth.mdc). `preflight()` is CHEAP, PURE, SYNCHRONOUS input validation —\n// no network, no I/O, no context lookup. It runs BEFORE the LLM round-trip /\n// before the tap-to-confirm card, so a malformed intent is rejected without\n// the user ever seeing a confirm for it.\n//\n// Each write builder co-locates its own `preflight*` validator (send.ts →\n// `preflightSend`, pay.ts → `preflightPay`, cetus-swap.ts → `preflightSwap`).\n// This module owns ONLY the shared result type + the two pure primitives those\n// validators compose (amount sanity + sync address validity). The agent-loop\n// guards that read conversation/session state stay in the v3 HOST (they are\n// NOT builder-appropriate, S.442/S.443).\n\nimport { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport type { T2000ErrorCode } from './errors.js';\n\n/**\n * The result of a synchronous preflight check. `valid: false` carries a\n * `T2000ErrorCode` + human message so the host can surface a precise reason\n * (and the builder can rethrow it as a `T2000Error` verbatim).\n */\nexport type PreflightResult =\n | { valid: true }\n | { valid: false; code: T2000ErrorCode; error: string };\n\n/**\n * Fat-finger / overflow ceiling for an asset amount. NOT a spending policy\n * (that's the `@t2000/sdk/limits` module — USD-denominated, opt-in, stateful);\n * this is the \"obviously wrong number\" guard the safeguards rule prescribes\n * (`amount > 1_000_000` → unreasonable).\n */\nexport const PREFLIGHT_MAX_AMOUNT = 1_000_000;\n\nexport const PREFLIGHT_OK: PreflightResult = { valid: true };\n\nexport function preflightFail(code: T2000ErrorCode, error: string): PreflightResult {\n return { valid: false, code, error };\n}\n\n/**\n * Pure positive-finite-amount sanity check (no network). Rejects NaN/Infinity\n * and non-positive values. The absurd-value ceiling defaults to\n * {@link PREFLIGHT_MAX_AMOUNT} but callers can raise it — pass\n * `max: Number.POSITIVE_INFINITY` for swaps of low-unit-value tokens\n * (memecoins legitimately trade in millions/billions of units), where a fixed\n * display-amount ceiling would be a false positive.\n */\nexport function checkPositiveAmount(\n amount: number,\n label = 'Amount',\n max: number = PREFLIGHT_MAX_AMOUNT,\n): PreflightResult {\n if (typeof amount !== 'number' || !Number.isFinite(amount)) {\n return preflightFail('INVALID_AMOUNT', `${label} must be a finite number`);\n }\n if (amount <= 0) {\n return preflightFail('INVALID_AMOUNT', `${label} must be greater than zero`);\n }\n if (amount > max) {\n return preflightFail('INVALID_AMOUNT', `${label} ${amount} exceeds the sane maximum (${max})`);\n }\n return PREFLIGHT_OK;\n}\n\n/**\n * Pure, synchronous Sui-address validity (no throw, no network) — the\n * non-throwing sibling of `validateAddress`. Use in preflight; use\n * `validateAddress` when you need the normalized form.\n */\nexport function checkSuiAddress(address: string, label = 'recipient'): PreflightResult {\n try {\n // `normalizeSuiAddress('')` pads to the zero address (which is \"valid\"), so\n // guard empty / whitespace-only input before normalizing.\n if (typeof address === 'string' && address.trim() !== '' &&\n isValidSuiAddress(normalizeSuiAddress(address))) {\n return PREFLIGHT_OK;\n }\n } catch {\n // normalizeSuiAddress throws on malformed input → fall through to the fail.\n }\n return preflightFail('INVALID_ADDRESS', `Invalid ${label} address: ${address}`);\n}\n","/**\n * Browser-safe entry point for @t2000/sdk.\n *\n * Exports everything the web app needs WITHOUT Node-only modules\n * (e.g. the fs-based keyManager is excluded).\n */\n\n// Signer abstraction\nexport type { TransactionSigner } from './signer.js';\nexport { KeypairSigner } from './wallet/keypairSigner.js';\nexport { ZkLoginSigner, type ZkLoginProof } from './wallet/zkLoginSigner.js';\n\n// Gasless MPP pay — browser-safe; the Audric client runs this in-browser on\n// the zkLogin session key (unified gasless write path). Same canonical loop\n// `T2000.pay()` delegates to. Pair with `executeTx` for advanced callers.\n// (`PayOptions` / `PayResult` are exported from the types block below.)\nexport { payWithMpp, preflightPay, parseMppSuiChallenge } from './wallet/pay.js';\nexport { executeTx } from './wallet/executeTx.js';\n\n// Error handling\nexport { T2000Error, mapWalletError, mapMoveAbortCode } from './errors.js';\nexport type { T2000ErrorCode, T2000ErrorData } from './errors.js';\n\n// Constants\nexport {\n MIST_PER_SUI,\n SUI_DECIMALS,\n USDC_DECIMALS,\n T2000_OVERLAY_FEE_WALLET,\n SUPPORTED_ASSETS,\n CLOCK_ID,\n DEFAULT_NETWORK,\n} from './constants.js';\nexport type { SupportedAsset, StableAsset } from './constants.js';\nexport {\n STABLE_ASSETS,\n GAS_RESERVE_MIN,\n} from './constants.js';\n\n// Utilities\nexport { validateAddress, truncateAddress } from './utils/sui.js';\nexport {\n KNOWN_TARGETS,\n LABEL_PATTERNS,\n classifyAction,\n classifyLabel,\n fallbackLabel,\n refineLendingLabel,\n classifyTransaction,\n extractTransferDetails,\n extractAllUserLegs,\n} from './wallet/classify.js';\nexport type {\n ClassifyBalanceChange,\n ClassifyResult,\n ExtractedTransfer,\n TxDirection,\n} from './wallet/classify.js';\n/**\n * Tx parsing helpers. Safe in the browser — they only do shape\n * inspection / classification and do not import any Node-only modules.\n * `queryHistory` and `queryTransaction` are not re-exported here\n * because they reach the network (GraphQL) directly; browser consumers\n * can build the same flow with `parseSuiRpcTx` + their own fetch.\n */\nexport {\n parseSuiRpcTx,\n extractTxSender,\n extractTxCommands,\n} from './wallet/history.js';\nexport type { SuiRpcTxBlock } from './wallet/history.js';\nexport {\n mistToSui,\n suiToMist,\n usdcToRaw,\n rawToUsdc,\n stableToRaw,\n rawToStable,\n getDecimals,\n formatUsd,\n formatSui,\n formatAssetAmount,\n} from './utils/format.js';\nexport { toBase64, fromBase64 } from './utils/base64.js';\n\n// Simulation — use dynamic import() to avoid Buffer dependency in browser bundles\n// import { simulateTransaction } from '@t2000/sdk' (main entry) for Node usage\nexport type { SimulationResult } from './utils/simulate.js';\n\n// Protocol fee\n// Cetus aggregator helpers — Audric prepare/route.ts uses these directly to\n// build swap PTBs with overlay fees (per-call, not module-global).\nexport { findSwapRoute, buildSwapTx, OVERLAY_FEE_RATE, preflightSwap } from './protocols/cetus-swap.js';\nexport type { SwapRouteResult, OverlayFeeConfig } from './protocols/cetus-swap.js';\n\n// Synchronous, network-free preflight (layer 2) — pure, browser-safe. The v3\n// host runs these in the agent loop before the tap-to-confirm card.\n// buildSendTx is browser-safe (builds a gasless PTB; the client is injected) —\n// the Audric client signs it in-browser with the zkLogin session (send_transfer).\nexport { buildSendTx, preflightSend } from './wallet/send.js';\n\n// A2A escrow job builders + readers — browser-safe (client injected, no fs).\n// Store surfaces build the buyer-side legs on a zkLogin session key.\nexport {\n A2A_ESCROW_PACKAGE_ID,\n MAX_JOB_USDC,\n JOB_STATES,\n preflightCreateJob,\n buildCreateJobTx,\n buildDeliverJobTx,\n buildReleaseJobTx,\n buildRejectJobTx,\n buildRefundJobTx,\n getJob,\n jobActionsFor,\n verifyJobForSeller,\n} from './wallet/job.js';\nexport type { Job, JobState, JobTerms, JobVerification } from './wallet/job.js';\nexport {\n type PreflightResult,\n PREFLIGHT_MAX_AMOUNT,\n PREFLIGHT_OK,\n preflightFail,\n checkPositiveAmount,\n checkSuiAddress,\n} from './preflight.js';\n\n// Spending limits are Node-only (`@t2000/sdk/limits` uses node:fs) — NOT\n// exported here. The browser (Audric) write path skips client-side limits;\n// the server budget ledger is the cap there.\n\n// Types\nexport type {\n BalanceResponse,\n SuiHolding,\n SendResult,\n DepositInfo,\n TransactionRecord,\n TransactionLeg,\n PayOptions,\n PayResult,\n} from './types.js';\n\n// Token registry — zero Node.js deps, safe for client-side use\nexport {\n COIN_REGISTRY,\n TOKEN_MAP,\n resolveTokenType,\n resolveSymbol,\n getDecimalsForCoinType,\n SUI_TYPE,\n USDC_TYPE,\n USDT_TYPE,\n USDSUI_TYPE,\n USDE_TYPE,\n ETH_TYPE,\n WBTC_TYPE,\n WAL_TYPE,\n NAVX_TYPE,\n IKA_TYPE,\n LOFI_TYPE,\n MANIFEST_TYPE,\n} from './token-registry.js';\nexport type { CoinMeta } from './token-registry.js';\n","import { T2000Error } from './errors.js';\n\nexport const MIST_PER_SUI = 1_000_000_000n;\nexport const SUI_DECIMALS = 9;\nexport const USDC_DECIMALS = 6;\n\nexport const PRECISION = 1_000_000_000_000_000_000n;\n\nexport const MIN_DEPOSIT = 1_000_000n; // 1 USDC (6 decimals)\n\nexport const CLOCK_ID = '0x6';\n\nexport const SUPPORTED_ASSETS = {\n USDC: {\n type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',\n decimals: 6,\n symbol: 'USDC',\n displayName: 'USDC',\n },\n USDT: {\n type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT',\n decimals: 6,\n symbol: 'USDT',\n displayName: 'suiUSDT',\n },\n USDe: {\n type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE',\n decimals: 6,\n symbol: 'USDe',\n displayName: 'suiUSDe',\n },\n USDsui: {\n type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI',\n decimals: 6,\n symbol: 'USDsui',\n displayName: 'USDsui',\n },\n SUI: {\n type: '0x2::sui::SUI',\n decimals: 9,\n symbol: 'SUI',\n displayName: 'SUI',\n },\n WAL: {\n type: '0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL',\n decimals: 9,\n symbol: 'WAL',\n displayName: 'WAL',\n },\n ETH: {\n type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH',\n decimals: 8,\n symbol: 'ETH',\n displayName: 'suiETH',\n },\n NAVX: {\n type: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX',\n decimals: 9,\n symbol: 'NAVX',\n displayName: 'NAVX',\n },\n GOLD: {\n type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM',\n decimals: 6,\n symbol: 'GOLD',\n displayName: 'XAUM',\n },\n} as const;\n\nexport type SupportedAsset = keyof typeof SUPPORTED_ASSETS;\n\n// [SPEC_AGENTIC_STACK P1 / SDK F3 — 2026-05-25]\n// `StableAsset` = \"what we treat as worth $1 for wallet pricing and balance roll-up\".\n// Pre-Phase 1: USDC only — left USDsui wallet holdings invisible to balance.ts.\n// Phase 1: widened to USDC + USDsui (both are NAVI-native stables with $1 peg).\n// USDT / USDe stay OUT of this set deliberately — they are stables, but the\n// codebase has never priced them at $1, and adding them here would require\n// auditing balance.ts callers downstream. Keep the carve minimal.\nexport type StableAsset = 'USDC' | 'USDsui';\nexport const STABLE_ASSETS: readonly StableAsset[] = ['USDC', 'USDsui'] as const;\n\n// ---------------------------------------------------------------------------\n// Operation → allowed asset rules (single source of truth)\n// ---------------------------------------------------------------------------\n\n// [v4.0 Phase A Day 2 — 2026-05-26] `send` is constrained to\n// `['USDC', 'USDsui', 'SUI']`. Rationale (SPEC_AGENT_WALLET_GREENFIELD §A):\n// - USDC + USDsui are gasless via `0x2::balance::send_funds` (Sui mainnet\n// protocol allowlist) — the two foundation stables.\n// - SUI is the only non-stable kept on the allowlist so users with no\n// stablecoin balance can still pay gas-native SUI transfers.\n// - USDT, USDe, WAL, ETH, NAVX, GOLD are NOT sendable — users must swap to\n// USDC/USDsui first (one-step) or hold SUI and use a manual Move call.\n// `swap` is unrestricted (Cetus routes any pair). The DeFi operations\n// (save/borrow/withdraw/repay) were removed with NAVI.\nexport const OPERATION_ASSETS = {\n send: ['USDC', 'USDsui', 'SUI'],\n swap: '*',\n} as const;\n\nexport type Operation = keyof typeof OPERATION_ASSETS;\n\nexport function isAllowedAsset(op: Operation, asset: string): boolean {\n const allowed = OPERATION_ASSETS[op];\n if (allowed === '*') return true;\n // [v0.51.0] Mixed-case canonical keys (USDsui, suiUSDT) need case-insensitive\n // membership. Pre-v0.51 we only had USDC ↔ USDC (uppercase identity), so\n // a one-sided uppercase compare looked correct. Now that USDsui is in the\n // set, normalize both sides.\n const target = asset.toLowerCase();\n return (allowed as readonly string[]).some((a) => a.toLowerCase() === target);\n}\n\n/**\n * Throws if the asset is not permitted for the given operation.\n *\n * [v4.0 Phase A Day 2] Pre-v4 this allowed `undefined` as a silent default\n * to USDC. Removed because every write path now requires explicit asset\n * (see `T2000.send` + `buildSendTx` + `composeTx.send_transfer`). The\n * `undefined → no-op` branch is kept defensively; the `send_transfer` flow\n * validates non-undefined.\n */\nexport function assertAllowedAsset(op: Operation, asset: string | undefined): void {\n if (!asset) return;\n if (!isAllowedAsset(op, asset)) {\n const allowed = OPERATION_ASSETS[op];\n const list = Array.isArray(allowed) ? allowed.join(', ') : 'any';\n const swapHint =\n op === 'send' ? ' Swap to USDC or USDsui first, or send SUI.' : '';\n throw new T2000Error(\n 'INVALID_ASSET',\n `${op} only supports ${list}. Cannot use ${asset}.${swapHint}`,\n );\n }\n}\n\n/**\n * [v4.0 Phase A Day 2] Narrow type alias for assets sendable through the\n * Agent Wallet. Matches `OPERATION_ASSETS.send` exactly. Exported so the\n * CLI / SDK / composeTx can share one type without re-declaring it.\n */\nexport type SendableAsset = 'USDC' | 'USDsui' | 'SUI';\nexport const SENDABLE_ASSETS: readonly SendableAsset[] = ['USDC', 'USDsui', 'SUI'] as const;\n\n/**\n * [v4.0 Phase A Day 2] Coin types for the two gasless-allowlisted stables.\n * Used by `wallet/send.ts` + `composeTx.send_transfer` to construct the\n * `0x2::balance::send_funds` Move call's `typeArguments`. SUI is excluded\n * because SUI transfers are NOT gasless (gas-native, uses `tx.gas` split +\n * `transferObjects` per the existing path).\n */\nexport const GASLESS_STABLE_TYPES: Record<'USDC' | 'USDsui', string> = {\n USDC: SUPPORTED_ASSETS.USDC.type,\n USDsui: SUPPORTED_ASSETS.USDsui.type,\n};\n\n// Swap overlay fees route here. Audric's prepare/route.ts passes\n// `overlayFee.receiver = T2000_OVERLAY_FEE_WALLET` to the Cetus aggregator. The\n// CLI/SDK never charge fees — this constant is exported for consumer apps only.\n//\n// Address corresponds to the treasury admin wallet. Override via env for local dev /\n// testnet only — production must use the canonical mainnet address below.\nexport const T2000_OVERLAY_FEE_WALLET = process.env.T2000_OVERLAY_FEE_WALLET\n ?? '0x5366efbf2b4fe5767fe2e78eb197aa5f5d138d88ac3333fbf3f80a1927da473a';\n\nexport const DEFAULT_NETWORK = 'mainnet' as const;\n// gRPC fullnode endpoint. Post-flip this is the canonical transport for the\n// whole SDK: `getSuiClient()` (reads + execution) AND `getSuiGrpcClient()`\n// (gasless stablecoin build detection) both target it. Override the read/exec\n// client with T2000_RPC_URL and the build client with T2000_GRPC_URL.\nexport const DEFAULT_RPC_URL = 'https://fullnode.mainnet.sui.io:443';\nexport const DEFAULT_GRPC_URL = 'https://fullnode.mainnet.sui.io:443';\n// [gRPC migration] GraphQL endpoint for the query surface that has NO gRPC\n// `core` equivalent — `transactionBlocks` (history). Used by\n// `getSuiGraphQLClient()`. The canonical mainnet host is `graphql.mainnet.sui.io`\n// (parallel to the gRPC fullnode); the older `sui-mainnet.mystenlabs.com/graphql`\n// host was dropped 2026-06-15 after it began resetting TLS connections (live\n// smoke). Public endpoint is rate-limited — production hosts override with\n// T2000_GRAPHQL_URL to a dedicated provider.\nexport const DEFAULT_GRAPHQL_URL = 'https://graphql.mainnet.sui.io/graphql';\nexport const DEFAULT_KEY_PATH = '~/.t2000/wallet.key';\nexport const DEFAULT_CONFIG_PATH = '~/.t2000/config.json';\n\n// [v4.0 Phase A Day 2] Minimum stablecoin amount for protocol-level gasless\n// transfers via `0x2::balance::send_funds`. The Sui mainnet allowlist enforces\n// this floor at the protocol level to prevent dust spam; we surface a clear\n// error before signing rather than letting the tx revert on-chain.\nexport const GASLESS_MIN_STABLE_AMOUNT = 0.01;\n\n// Cetus USDC/SUI pool — read-only for SUI price oracle (no SDK dependency)\nexport const CETUS_USDC_SUI_POOL = '0x51e883ba7c0b566a26cbc8a94cd33eb0abd418a77cc1e60ad22fd9b1f29cd2ab';\n\nexport const GAS_RESERVE_MIN = 0.05; // minimum SUI to keep for gas\n","import { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';\nimport { SuiGrpcClient } from '@mysten/sui/grpc';\nimport { SuiGraphQLClient } from '@mysten/sui/graphql';\nimport { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport { DEFAULT_GRAPHQL_URL, DEFAULT_GRPC_URL, DEFAULT_RPC_URL } from '../constants.js';\nimport { T2000Error } from '../errors.js';\n\n/**\n * [gRPC migration / S.438] Transport-agnostic client type for the migration.\n *\n * Both `SuiJsonRpcClient` and `SuiGrpcClient` extend `BaseClient` and expose\n * an identical `.core.*` API. During the migration, call sites are rewritten\n * from legacy methods (`getBalance`, `getObject`, `executeTransactionBlock`)\n * to the unified `client.core.*` API and typed against this union — so the\n * rewrite is behavior-preserving while still on JSON-RPC, and the final\n * transport flip (gRPC) is a one-line change in `getSuiClient()`.\n *\n * The query surface that has no gRPC `core` equivalent (`queryTransactionBlocks`\n * / `queryEvents`, Stage 0 finding A) uses `getSuiGraphQLClient()` instead.\n */\nexport type SuiCoreClient = SuiJsonRpcClient | SuiGrpcClient;\n\n/**\n * Resolve the effective JSON-RPC URL: explicit arg > env var > default.\n * `T2000_RPC_URL` is an OPTIONAL override per the Greenfield SPEC's env\n * contract — no required vars, so we read inline (allowed by\n * `env-validation-gate.mdc` carve-out for packages with zero required\n * env vars).\n */\nfunction resolveRpcUrl(rpcUrl?: string): string {\n if (rpcUrl) return rpcUrl;\n const envUrl = process.env.T2000_RPC_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_RPC_URL;\n}\n\n/**\n * Same shape as `resolveRpcUrl` for the gRPC endpoint.\n */\nfunction resolveGrpcUrl(grpcUrl?: string): string {\n if (grpcUrl) return grpcUrl;\n const envUrl = process.env.T2000_GRPC_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_GRPC_URL;\n}\n\n/**\n * Same shape as `resolveRpcUrl` for the GraphQL endpoint.\n */\nfunction resolveGraphqlUrl(graphqlUrl?: string): string {\n if (graphqlUrl) return graphqlUrl;\n const envUrl = process.env.T2000_GRAPHQL_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_GRAPHQL_URL;\n}\n\n/**\n * Canonical agent client cache, keyed by URL. The earlier impl cached\n * unconditionally and ignored URL changes after the first call —\n * brittle for testnet smokes and custom-RPC test setups.\n */\nconst rpcClientCache = new Map<string, SuiGrpcClient>();\n\n/**\n * [gRPC cutover] The canonical agent client is now gRPC. Mysten deactivates\n * the JSON-RPC fullnode interface on 2026-07-31, so reads (`.core.*`) and\n * execution route over gRPC — transaction *builds* already do\n * (`getSuiGrpcClient`). The whole SDK was first refactored onto the unified\n * `.core` API (behavior-preserving on JSON-RPC), then flipped here. The\n * `rpcUrl` arg / `T2000_RPC_URL` override now resolve a gRPC `baseUrl`\n * (`DEFAULT_RPC_URL` is the same host as `DEFAULT_GRPC_URL`). The historical\n * query surface stays on `getSuiGraphQLClient()`.\n */\nexport function getSuiClient(rpcUrl?: string): SuiGrpcClient {\n const url = resolveRpcUrl(rpcUrl);\n const cached = rpcClientCache.get(url);\n if (cached) return cached;\n const client = new SuiGrpcClient({ baseUrl: url, network: 'mainnet' });\n rpcClientCache.set(url, client);\n return client;\n}\n\n/**\n * gRPC client cache, keyed by URL. Same rationale as the JSON-RPC cache:\n * different URLs must produce different clients.\n */\nconst grpcClientCache = new Map<string, SuiGrpcClient>();\n\n/**\n * Cached `SuiGrpcClient` for gasless stablecoin transfer builds.\n *\n * [v4.0 Phase A Day 2 — SPEC_AGENT_WALLET_GREENFIELD §A]\n *\n * Why this exists: Sui mainnet's protocol-level gasless stablecoin transfers\n * (`0x2::balance::send_funds` on the USDC + USDsui allowlist) are detected\n * ONLY when the transaction is built through a `SuiGrpcClient`. The gRPC\n * client's build resolver inspects the PTB at `tx.build()` time and, if it\n * matches the gasless pattern, sets `gasPrice=0` + `gasBudget=0` automatically.\n * Building the SAME PTB through `SuiJsonRpcClient` produces the same bytes\n * but with non-zero gas — the tx still works, but the user pays SUI gas.\n *\n * Execution stays on JSON-RPC (`SuiJsonRpcClient.executeTransactionBlock`)\n * because (a) the rest of the SDK expects JSON-RPC and (b) Sui's docs\n * explicitly support a \"build via gRPC, execute via JSON-RPC\" hybrid:\n * https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers\n *\n * Override the endpoint with the `T2000_GRPC_URL` env var or the\n * `grpcUrl` arg. Cache is keyed by URL so multiple endpoints can\n * co-exist (e.g., the rare testnet smoke + production usage from the\n * same process).\n */\nexport function getSuiGrpcClient(grpcUrl?: string): SuiGrpcClient {\n const baseUrl = resolveGrpcUrl(grpcUrl);\n const cached = grpcClientCache.get(baseUrl);\n if (cached) return cached;\n const client = new SuiGrpcClient({ baseUrl, network: 'mainnet' });\n grpcClientCache.set(baseUrl, client);\n return client;\n}\n\n/**\n * GraphQL client cache, keyed by URL. Same rationale as the other caches.\n */\nconst graphqlClientCache = new Map<string, SuiGraphQLClient>();\n\n/**\n * Cached `SuiGraphQLClient` for the query surface that has NO gRPC `core`\n * equivalent: `queryTransactionBlocks` + `queryEvents` (Stage 0 finding A —\n * `SPEC_FULL_GRPC_MIGRATION.md`). Mysten's gRPC successor doesn't cover the\n * historical query/event API; GraphQL is its documented home. Consumers:\n * `wallet/history.ts` + the swap-event read in `protocols/cetus-swap.ts`.\n *\n * Override the endpoint with `T2000_GRAPHQL_URL` or the `graphqlUrl` arg.\n */\nexport function getSuiGraphQLClient(graphqlUrl?: string): SuiGraphQLClient {\n const url = resolveGraphqlUrl(graphqlUrl);\n const cached = graphqlClientCache.get(url);\n if (cached) return cached;\n const client = new SuiGraphQLClient({ url, network: 'mainnet' });\n graphqlClientCache.set(url, client);\n return client;\n}\n\nexport function validateAddress(address: string): string {\n const normalized = normalizeSuiAddress(address);\n if (!isValidSuiAddress(normalized)) {\n throw new T2000Error('INVALID_ADDRESS', `Invalid Sui address: ${address}`);\n }\n return normalized;\n}\n\nexport function truncateAddress(address: string): string {\n if (address.length <= 10) return address;\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n\n/**\n * Normalize a Sui coin type to its canonical long-form 64-hex address.\n * `0x2::sui::SUI` → `0x0000…0002::sui::SUI`. Idempotent on already-long\n * forms. Returns the input unchanged if it doesn't look like a coin type\n * (`<address>::<module>::<name>`) so callers can pass arbitrary strings\n * without crashing.\n *\n * Why this exists: BlockVision's `/v2/sui/coin/price/list` endpoint\n * silently returns an empty `prices` map for short-form coin types\n * (notably `0x2::sui::SUI` — the native gas coin). Internal callers must\n * pass the long form, but external callers (LLM tool args, cached\n * coin-type strings, audit logs) commonly use the short form. Normalize\n * before the network call, denormalize back to the caller's input shape\n * after, and short/long become interchangeable.\n */\nexport function normalizeCoinType(coinType: string): string {\n const parts = coinType.split('::');\n if (parts.length !== 3) return coinType;\n const [addr, mod, name] = parts;\n if (!addr.startsWith('0x')) return coinType;\n return `${normalizeSuiAddress(addr)}::${mod}::${name}`;\n}\n","/**\n * Shared transaction classifier.\n *\n * Consumed by both the SDK's `parseTxRecord` (production agent path) and\n * the engine's `transaction_history` tool (cold-start RPC path). Keeping\n * a single source of truth here prevents the two paths from drifting —\n * see v1.5.3 regression where the SDK path was emitting `action:\n * 'transaction'` (rendered as \"On-chain\") while the engine path was\n * already producing fine-grained labels.\n */\n\nimport { getDecimalsForCoinType, resolveSymbol, SUI_TYPE } from '../token-registry.js';\n\n/**\n * Coarse action bucket — one of `'send' | 'lending' | 'swap' |\n * 'transaction'`. Used by the ACI `action` filter on the\n * `transaction_history` tool. STABLE: downstream queries depend on\n * exactly these values.\n *\n * Order matters: more specific buckets first. Lending patterns precede\n * swap patterns so a NAVI `::swap` helper (if one ever existed) would\n * still bucket as lending.\n */\nexport const KNOWN_TARGETS: readonly [RegExp, string][] = [\n [/::suilend|::obligation/, 'lending'],\n [/::navi|::lending_core|::incentive_v\\d+|::oracle_pro/, 'lending'],\n /**\n * DEX modules — both direct calls and aggregator legs. The Cetus\n * aggregator dispatches through a per-DEX module (e.g.\n * `cetus::swap`, `flowx_amm::swap`, `aftermath::swap`, …) plus\n * router glue functions. We list every DEX module the aggregator\n * supports today so a single-DEX call still classifies cleanly.\n */\n [/::cetus(?:_dlmm)?::|::pool::|::deepbook|::flowx_(?:amm|clmm)::|::kriya_(?:amm|clmm)::|::turbos::|::aftermath::|::afsui::|::bluefin::|::bluemove::|::ferra_(?:clmm|dlmm)::|::haedal_hmm::|::hasui::|::hawal::|::magma::|::momentum::|::obric::|::springsui::|::steamm_cpmm::|::fullsail::|::alphafi::|::volo_swap::/, 'swap'],\n /**\n * Cetus aggregator router glue. These are the swap-context and\n * balance-handling helpers the aggregator emits around per-DEX\n * legs. Without this entry a tx that ONLY had router calls\n * (theoretically possible for setup/cleanup) would slip through;\n * in practice these always coexist with a DEX leg, but the entry\n * is cheap insurance.\n */\n [/::router::(?:new_swap_context(?:_v)?|confirm_swap|transfer_balance|take_balance|transfer_or_destroy_coin)/, 'swap'],\n [/::transfer::public_transfer/, 'send'],\n];\n\n/**\n * Finer-grained display labels — derived from MoveCall function names.\n * The card renders `label ?? action`, so when this map matches we get\n * \"Deposit\" / \"Withdraw\" / \"Borrow\" / \"Repay\" / \"Payment link\" instead\n * of the generic \"Lending\" or \"Transaction\".\n *\n * Order matters: more specific patterns first. Each entry is\n * (regex, label) where the regex is matched against the\n * fully-qualified MoveCall target `pkg::module::function`.\n */\nexport const LABEL_PATTERNS: readonly [RegExp, string][] = [\n [/::pay(?:ment_kit|_kit)?::|::create_payment_link|::pay_link/, 'payment_link'],\n [/::create_invoice|::invoice::/, 'invoice'],\n [/::deposit|::supply|::mint_ctokens/, 'deposit'],\n [/::withdraw|::redeem|::redeem_ctokens/, 'withdraw'],\n [/::borrow/, 'borrow'],\n [/::repay/, 'repay'],\n [/::claim_reward|::claim::|::claim_incentive/, 'claim'],\n [/::stake/, 'stake'],\n [/::unstake|::burn::/, 'unstake'],\n [/::liquidate/, 'liquidate'],\n];\n\nexport interface ClassifyBalanceChange {\n owner: { AddressOwner?: string } | string;\n coinType: string;\n amount: string;\n}\n\nfunction resolveOwner(owner: ClassifyBalanceChange['owner']): string | null {\n if (typeof owner === 'object' && owner.AddressOwner) return owner.AddressOwner;\n if (typeof owner === 'string') return owner;\n return null;\n}\n\nexport function classifyAction(targets: string[], commandTypes: string[]): string {\n for (const target of targets) {\n for (const [pattern, label] of KNOWN_TARGETS) {\n if (pattern.test(target)) return label;\n }\n }\n if (commandTypes.includes('TransferObjects') && !commandTypes.includes('MoveCall')) return 'send';\n return 'transaction';\n}\n\n/**\n * Last-resort fallback when neither `LABEL_PATTERNS` nor the action\n * bucket produces something useful.\n *\n * Returns the first MoveCall's *module* name (e.g. \"navi\", \"spam\") so\n * the card shows something better than the literal word \"transaction\".\n * When no MoveCall exists, returns 'on-chain'.\n *\n * Note: callers should prefer `classifyLabel` which now layers\n * pattern-match → coarse action → module name (see commentary there).\n */\nexport function fallbackLabel(targets: string[]): string {\n if (!targets.length) return 'on-chain';\n const first = targets[0];\n const parts = first.split('::');\n if (parts.length >= 2 && parts[1]) return parts[1].toLowerCase();\n return 'on-chain';\n}\n\n/**\n * Three-tier label resolution for the transaction history card:\n * 1. Specific keyword match in `LABEL_PATTERNS` (\"deposit\",\n * \"payment_link\", …).\n * 2. Coarse action bucket from `classifyAction` (\"swap\", \"send\",\n * \"lending\") — prevents leaking opaque internal module names like\n * \"router\" (Cetus aggregator) or \"cross_swap\" (third-party DEX\n * aggregators) for txs that we already classified as a swap.\n * 3. Module name from the first MoveCall (`fallbackLabel`) — only\n * used when the action bucket itself is the generic \"transaction\".\n *\n * Pre-v0.46.2 we skipped tier 2, so swaps showed labels like \"router\",\n * \"cross_swap\", \"scallop_router\", etc. instead of the clean \"swap\".\n */\nexport function classifyLabel(targets: string[], commandTypes: string[]): string {\n for (const target of targets) {\n for (const [pattern, label] of LABEL_PATTERNS) {\n if (pattern.test(target)) return label;\n }\n }\n if (commandTypes.includes('TransferObjects') && !commandTypes.includes('MoveCall')) return 'send';\n const action = classifyAction(targets, commandTypes);\n if (action !== 'transaction') return action;\n return fallbackLabel(targets);\n}\n\n/**\n * Balance-direction tiebreaker for ambiguous lending calls.\n *\n * Many lending modules expose generic entry points (NAVI's bundled\n * flash actions, `lending_core::*::entry_*`, etc.) that don't carry\n * a `deposit`/`withdraw`/`borrow`/`repay` keyword in the function\n * name. When `classifyLabel` falls back to a bare module name like\n * `\"lending\"` for a known lending tx, infer direction from the user's\n * non-SUI balance change:\n * - net outflow of the supplied asset → deposit (also covers repay,\n * but repay-without-keyword is essentially never emitted).\n * - net inflow of the supplied asset → withdraw (also covers borrow).\n * SUI is excluded so gas-only transactions don't get mislabeled.\n *\n * If `LABEL_PATTERNS` matched a specific keyword, the existing label is\n * returned unchanged.\n */\nexport function refineLendingLabel(\n currentAction: string,\n currentLabel: string,\n moveCallTargets: string[],\n changes: ClassifyBalanceChange[],\n address: string,\n): string {\n if (currentAction !== 'lending') return currentLabel;\n const labelMatchedSpecific = LABEL_PATTERNS.some(([p]) =>\n moveCallTargets.some((t) => p.test(t)),\n );\n if (labelMatchedSpecific) return currentLabel;\n\n const userNonSuiOutflow = changes.find(\n (c) => resolveOwner(c.owner) === address && c.coinType !== SUI_TYPE && BigInt(c.amount) < 0n,\n );\n if (userNonSuiOutflow) return 'deposit';\n\n const userNonSuiInflow = changes.find(\n (c) => resolveOwner(c.owner) === address && c.coinType !== SUI_TYPE && BigInt(c.amount) > 0n,\n );\n if (userNonSuiInflow) return 'withdraw';\n\n return currentLabel;\n}\n\nexport interface ClassifyResult {\n action: string;\n label: string;\n}\n\nexport function classifyTransaction(\n moveCallTargets: string[],\n commandTypes: string[],\n balanceChanges: ClassifyBalanceChange[],\n address: string,\n): ClassifyResult {\n const action = classifyAction(moveCallTargets, commandTypes);\n const baseLabel = classifyLabel(moveCallTargets, commandTypes);\n const label = refineLendingLabel(action, baseLabel, moveCallTargets, balanceChanges, address);\n return { action, label };\n}\n\n/**\n * Direction of the user's net non-gas movement for this transaction.\n *\n * - `'out'` — the user spent the asset (sends, deposits, repays,\n * swap-in, payment-link payouts).\n * - `'in'` — the user received the asset (withdraws, borrows,\n * swap-out, claims, deposits credited from another wallet).\n *\n * Used by the `TransactionHistoryCard` to choose the `+`/`−` sign and\n * color. Direction is computed from the actual on-chain balance change\n * — never from the textual label — so opaque action types (`'router'`,\n * `'cross_swap'`, …) still render the correct sign.\n */\nexport type TxDirection = 'in' | 'out';\n\nexport interface ExtractedTransfer {\n amount?: number;\n asset?: string;\n recipient?: string;\n direction?: TxDirection;\n}\n\n/**\n * Extracts the principal amount/asset/direction for a transaction\n * from its `balanceChanges`.\n *\n * Algorithm:\n * 1. Restrict to the user's *own* balance changes.\n * 2. Prefer non-SUI changes (gas-only SUI deltas are noise).\n * 3. Pick the change with the largest absolute value — the \"principal\".\n * 4. If no non-SUI change exists, fall back to the largest SUI change\n * so pure-SUI transfers (stake/unstake/native send) still render.\n * 5. Direction follows the sign of the principal.\n * 6. Recipient is set only on outflows, by finding a matching inflow\n * on a *non-user* address with the same coinType.\n *\n * Pre-v0.46.2 this function only inspected outflows, so withdraws,\n * borrows, claims, swap-receives and payment-link receives all\n * rendered with no amount on the rich card (and with a wrong sign,\n * because the card guessed direction from the label string).\n */\nexport function extractTransferDetails(\n changes: ClassifyBalanceChange[] | undefined,\n sender: string,\n): ExtractedTransfer {\n if (!changes || changes.length === 0) return {};\n\n const userChanges = changes.filter((c) => resolveOwner(c.owner) === sender);\n if (userChanges.length === 0) return {};\n\n const userNonSui = userChanges.filter((c) => c.coinType !== SUI_TYPE);\n const pool = userNonSui.length > 0 ? userNonSui : userChanges;\n\n let primary = pool[0];\n let primaryAbs = bigintAbs(BigInt(primary.amount));\n for (let i = 1; i < pool.length; i++) {\n const abs = bigintAbs(BigInt(pool[i].amount));\n if (abs > primaryAbs) {\n primary = pool[i];\n primaryAbs = abs;\n }\n }\n\n const raw = BigInt(primary.amount);\n if (raw === 0n) return {};\n\n const decimals = getDecimalsForCoinType(primary.coinType);\n const amount = Number(primaryAbs) / 10 ** decimals;\n const asset = resolveSymbol(primary.coinType);\n const direction: TxDirection = raw < 0n ? 'out' : 'in';\n\n let recipient: string | undefined;\n if (direction === 'out') {\n const recipientChange = changes.find(\n (c) =>\n resolveOwner(c.owner) !== sender &&\n c.coinType === primary.coinType &&\n BigInt(c.amount) > 0n,\n );\n recipient = recipientChange ? resolveOwner(recipientChange.owner) ?? undefined : undefined;\n }\n\n return { amount, asset, recipient, direction };\n}\n\nfunction bigintAbs(n: bigint): bigint {\n return n < 0n ? -n : n;\n}\n\n/**\n * Extract every non-zero user balance leg for a transaction — not\n * just the largest one. Order is RPC order; callers responsible for\n * any sorting (e.g. audric sorts by USD value once it's priced).\n *\n * Sui collapses balance changes by coin type, so a 3-step bundle\n * touching USDC three times surfaces as ONE leg of net USDC delta.\n * Distinguishing per-step legs would require parsing the PTB's\n * commands; this helper deliberately stops at the balance-change\n * granularity because that's what's reliably available across all\n * Sui RPC versions.\n *\n * Pre-v1.27.2 the only public API was `extractTransferDetails`,\n * which returned a single \"primary\" leg and made swap rows\n * unrenderable (showed `Swapped 987.60 MANIFEST` because MANIFEST\n * was the largest raw delta even though USDC was the value side).\n */\nexport function extractAllUserLegs(\n changes: ClassifyBalanceChange[] | undefined,\n sender: string,\n): import('../types.js').TransactionLeg[] {\n if (!changes || changes.length === 0) return [];\n\n const legs: import('../types.js').TransactionLeg[] = [];\n for (const c of changes) {\n if (resolveOwner(c.owner) !== sender) continue;\n const raw = BigInt(c.amount);\n if (raw === 0n) continue;\n const decimals = getDecimalsForCoinType(c.coinType);\n const absAmount = bigintAbs(raw);\n legs.push({\n coinType: c.coinType,\n asset: resolveSymbol(c.coinType),\n decimals,\n amount: Number(absAmount) / 10 ** decimals,\n rawAmount: raw.toString(),\n direction: raw < 0n ? 'out' : 'in',\n });\n }\n\n return legs;\n}\n","import type { TransactionRecord } from '../types.js';\nimport { getSuiGraphQLClient } from '../utils/sui.js';\nimport {\n classifyTransaction,\n extractAllUserLegs,\n extractTransferDetails,\n type ClassifyBalanceChange,\n} from './classify.js';\n\n// ---------------------------------------------------------------------------\n// [gRPC migration / S.447 + S.450] Transaction history is the one surface with\n// NO gRPC `core.*` equivalent (Stage 0 finding A): list-by-affected-address +\n// per-tx-by-digest live in the GraphQL RPC, not gRPC. Both go through the\n// Sui GraphQL endpoint (`getSuiGraphQLClient()`), share one node fragment +\n// one mapper, and feed the existing (tested) classifier in `classify.ts`.\n//\n// LIVE-VERIFIED 2026-06-15 (S.450) against `graphql.mainnet.sui.io` with a\n// real sender (send + Cetus swap digests). The live schema differs from the\n// older `transactionBlocks` one: the query is `transactions` / `transaction`\n// (filter `affectedAddress` — sender, sponsor, or recipient), the programmable kind is `ProgrammableTransaction`\n// (was `ProgrammableTransactionBlock`) with `commands { nodes }` (was\n// `transactions`), and a move call is `MoveCallCommand` with a nested\n// `function { name module { name package { address } } }` (was a flat\n// `MoveCallTransaction { package module functionName }`). GraphQL errors are\n// now SURFACED, not swallowed (the old `?? []` hid this schema drift as an\n// empty history for a whole session). Schema ref: https://docs.sui.io/references/sui-graphql\n// ---------------------------------------------------------------------------\n\nconst TX_NODE_FRAGMENT = `\n digest\n effects {\n timestamp\n gasEffects { gasSummary { computationCost storageCost storageRebate } }\n balanceChanges { nodes { amount coinType { repr } owner { address } } }\n }\n kind {\n __typename\n ... on ProgrammableTransaction {\n commands {\n nodes {\n __typename\n ... on MoveCallCommand { function { name module { name package { address } } } }\n }\n }\n }\n }\n`;\n\n// `affectedAddress` (not `sentAddress`) so history includes INCOMING transactions\n// — received payments, x402/MPP refunds, airdrops — not just ones the agent\n// signed. Per the Sui GraphQL schema: \"transactions that interacted with the\n// given address … as a sender, sponsor, or recipient.\" The shared classifier\n// already labels each leg's direction ('in' / 'out'), so inbound txns render\n// correctly downstream.\nconst HISTORY_QUERY = `query History($address: SuiAddress!, $last: Int!) {\n transactions(last: $last, filter: { affectedAddress: $address }) {\n nodes {${TX_NODE_FRAGMENT}}\n }\n}`;\n\nconst TX_BY_DIGEST_QUERY = `query TxByDigest($digest: String!) {\n transaction(digest: $digest) {${TX_NODE_FRAGMENT}}\n}`;\n\n/** Minimal shape of a Sui GraphQL transaction node we consume. */\ninterface GqlTxNode {\n digest?: string;\n effects?: {\n timestamp?: string;\n // Live schema returns gas as numbers; `Number()` in the mapper tolerates both.\n gasEffects?: { gasSummary?: { computationCost?: string | number; storageCost?: string | number; storageRebate?: string | number } };\n balanceChanges?: { nodes?: Array<{ amount?: string; coinType?: { repr?: string }; owner?: { address?: string } }> };\n };\n kind?: {\n __typename?: string;\n commands?: {\n nodes?: Array<{\n __typename?: string;\n function?: { name?: string; module?: { name?: string; package?: { address?: string } } };\n }>;\n };\n };\n}\n\n/** GraphQL transport result with the optional `errors` array surfaced. */\ninterface GqlResult<T> {\n data?: T;\n errors?: Array<{ message?: string }>;\n}\n\nfunction assertNoGqlErrors(res: GqlResult<unknown>, what: string): void {\n if (res.errors?.length) {\n throw new Error(\n `Sui GraphQL ${what} failed: ${res.errors.map((e) => e.message ?? 'unknown error').join('; ')}`,\n );\n }\n}\n\nexport async function queryHistory(\n address: string,\n limit = 20,\n): Promise<TransactionRecord[]> {\n const gql = getSuiGraphQLClient();\n const res = (await gql.query({ query: HISTORY_QUERY, variables: { address, last: limit } })) as GqlResult<{\n transactions?: { nodes?: GqlTxNode[] };\n }>;\n assertNoGqlErrors(res, 'history query');\n const nodes = res.data?.transactions?.nodes ?? [];\n // GraphQL `last` returns ascending; the legacy JSON-RPC path returned\n // descending (newest first) — reverse to preserve caller expectations.\n return nodes.map((n) => recordFromGqlNode(n, address)).reverse();\n}\n\nexport async function queryTransaction(\n digest: string,\n senderAddress: string,\n): Promise<TransactionRecord | null> {\n const gql = getSuiGraphQLClient();\n const res = (await gql.query({ query: TX_BY_DIGEST_QUERY, variables: { digest } })) as GqlResult<{\n transaction?: GqlTxNode | null;\n }>;\n assertNoGqlErrors(res, 'transaction query');\n const node = res.data?.transaction;\n if (!node) return null; // genuine not-found (distinct from a query error, which throws above)\n return recordFromGqlNode(node, senderAddress);\n}\n\n/**\n * Map a Sui GraphQL transactionBlock node → the primitives the shared\n * classifier consumes, then build the record. Isolated so the legacy\n * JSON-RPC `parseTxRecord` (back-compat, below) and this GraphQL path\n * converge on one classification routine.\n */\nfunction recordFromGqlNode(node: GqlTxNode, address: string): TransactionRecord {\n const gs = node.effects?.gasEffects?.gasSummary;\n const gasCost = gs\n ? (Number(gs.computationCost ?? 0) + Number(gs.storageCost ?? 0) - Number(gs.storageRebate ?? 0)) / 1e9\n : undefined;\n\n const balanceChanges: ClassifyBalanceChange[] = (node.effects?.balanceChanges?.nodes ?? [])\n .filter((b) => b.coinType?.repr && b.amount != null)\n .map((b) => ({ coinType: b.coinType!.repr!, amount: String(b.amount), owner: b.owner?.address ?? '' }));\n\n const moveCallTargets: string[] = [];\n const commandTypes: string[] = [];\n if (node.kind?.__typename === 'ProgrammableTransaction') {\n for (const cmd of node.kind.commands?.nodes ?? []) {\n if (cmd.__typename === 'MoveCallCommand') {\n commandTypes.push('MoveCall');\n const fn = cmd.function;\n const pkg = fn?.module?.package?.address;\n const mod = fn?.module?.name;\n const name = fn?.name;\n if (pkg && mod && name) {\n moveCallTargets.push(`${pkg}::${mod}::${name}`);\n }\n } else if (cmd.__typename === 'TransferObjectsCommand') {\n commandTypes.push('TransferObjects');\n }\n }\n }\n\n // GraphQL effects.timestamp is an ISO datetime; the record wants ms.\n const ts = node.effects?.timestamp ? Date.parse(node.effects.timestamp) : 0;\n\n return buildRecord({\n digest: node.digest ?? '',\n moveCallTargets,\n commandTypes,\n balanceChanges,\n timestampMs: Number.isFinite(ts) ? ts : 0,\n gasCost,\n address,\n });\n}\n\n/** Shared record builder — classification + leg/transfer extraction. */\nfunction buildRecord(args: {\n digest: string;\n moveCallTargets: string[];\n commandTypes: string[];\n balanceChanges: ClassifyBalanceChange[];\n timestampMs: number;\n gasCost: number | undefined;\n address: string;\n}): TransactionRecord {\n const { digest, moveCallTargets, commandTypes, balanceChanges, timestampMs, gasCost, address } = args;\n const legs = extractAllUserLegs(balanceChanges, address);\n const { amount, asset, recipient, direction } = extractTransferDetails(balanceChanges, address);\n const { action, label } = classifyTransaction(moveCallTargets, commandTypes, balanceChanges, address);\n return { digest, action, label, legs, amount, asset, recipient, direction, timestamp: timestampMs, gasCost };\n}\n\n/**\n * Shape of a transaction block as returned by `suix_queryTransactionBlocks`\n * with `showEffects | showInput | showBalanceChanges` enabled. Exported so\n * downstream consumers (audric dashboard `/api/history`, `/api/activity`,\n * etc.) can type their RPC calls without redeclaring the structure.\n */\nexport interface SuiRpcTxBlock {\n digest: string;\n timestampMs?: string;\n transaction?: unknown;\n effects?: { gasUsed?: { computationCost: string; storageCost: string; storageRebate: string } };\n balanceChanges?: ClassifyBalanceChange[];\n}\n\n/**\n * Convert a single Sui RPC transaction block to a {@link TransactionRecord}\n * using the canonical (shared) classifier and balance-change extractor.\n *\n * This is the single source of truth for transaction parsing across the\n * agent-tool path AND the dashboard-API path. Use it instead of writing\n * a bespoke parser per surface.\n *\n * @param tx Raw RPC tx block (must include `effects`, `input`, `balanceChanges`).\n * @param address Wallet address whose perspective we're parsing from.\n */\nexport function parseSuiRpcTx(tx: SuiRpcTxBlock, address: string): TransactionRecord {\n return parseTxRecord(tx, address);\n}\n\n/**\n * Extract the sender (signer) address from a raw RPC tx block.\n * Returns `null` if the block shape is unexpected.\n */\nexport function extractTxSender(txBlock: unknown): string | null {\n try {\n if (!txBlock || typeof txBlock !== 'object') return null;\n const data = 'data' in txBlock ? (txBlock as Record<string, unknown>).data : undefined;\n if (!data || typeof data !== 'object') return null;\n return ((data as Record<string, unknown>).sender as string) ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract MoveCall targets (`<pkg>::<module>::<function>`) and the\n * sequence of programmable-transaction command types (e.g. `MoveCall`,\n * `TransferObjects`) from a raw RPC tx block. Tolerates both the\n * legacy `inner.transactions` field and the newer `inner.commands`\n * field.\n */\nexport function extractTxCommands(txBlock: unknown): {\n moveCallTargets: string[];\n commandTypes: string[];\n} {\n return extractCommands(txBlock);\n}\n\n// [back-compat] Legacy JSON-RPC-shape parser. The live history path is now\n// GraphQL (above); this stays for external consumers that already hold a\n// JSON-RPC tx block (e.g. via `parseSuiRpcTx`). Routes through `buildRecord`\n// so classification is identical to the GraphQL path.\nfunction parseTxRecord(tx: SuiRpcTxBlock, address: string): TransactionRecord {\n const gasUsed = tx.effects?.gasUsed;\n const gasCost = gasUsed\n ? (Number(gasUsed.computationCost) +\n Number(gasUsed.storageCost) -\n Number(gasUsed.storageRebate)) /\n 1e9\n : undefined;\n\n const { moveCallTargets, commandTypes } = extractCommands(tx.transaction);\n return buildRecord({\n digest: tx.digest,\n moveCallTargets,\n commandTypes,\n balanceChanges: tx.balanceChanges ?? [],\n timestampMs: Number(tx.timestampMs ?? 0),\n gasCost,\n address,\n });\n}\n\ninterface CommandInfo {\n moveCallTargets: string[];\n commandTypes: string[];\n}\n\nfunction extractCommands(txBlock: unknown): CommandInfo {\n const result: CommandInfo = { moveCallTargets: [], commandTypes: [] };\n try {\n if (!txBlock || typeof txBlock !== 'object') return result;\n const data = 'data' in txBlock ? (txBlock as Record<string, unknown>).data : undefined;\n if (!data || typeof data !== 'object') return result;\n const inner = 'transaction' in (data as Record<string, unknown>)\n ? (data as Record<string, unknown>).transaction\n : undefined;\n if (!inner || typeof inner !== 'object') return result;\n const commands = 'commands' in (inner as Record<string, unknown>)\n ? (inner as Record<string, unknown>).commands\n : 'transactions' in (inner as Record<string, unknown>)\n ? (inner as Record<string, unknown>).transactions\n : undefined;\n if (!Array.isArray(commands)) return result;\n\n for (const cmd of commands as Record<string, unknown>[]) {\n if (cmd.MoveCall) {\n const mc = cmd.MoveCall as { package: string; module: string; function: string };\n result.moveCallTargets.push(`${mc.package}::${mc.module}::${mc.function}`);\n result.commandTypes.push('MoveCall');\n } else if (cmd.TransferObjects) {\n result.commandTypes.push('TransferObjects');\n }\n }\n } catch { /* best effort */ }\n return result;\n}\n","import { MIST_PER_SUI, USDC_DECIMALS, SUPPORTED_ASSETS } from '../constants.js';\nimport type { SupportedAsset } from '../constants.js';\n\nexport function mistToSui(mist: bigint): number {\n return Number(mist) / Number(MIST_PER_SUI);\n}\n\nexport function suiToMist(sui: number): bigint {\n return BigInt(Math.round(sui * Number(MIST_PER_SUI)));\n}\n\nexport function usdcToRaw(amount: number): bigint {\n return BigInt(Math.round(amount * 10 ** USDC_DECIMALS));\n}\n\nexport function rawToUsdc(raw: bigint): number {\n return Number(raw) / 10 ** USDC_DECIMALS;\n}\n\nexport function stableToRaw(amount: number, decimals: number): bigint {\n return BigInt(Math.round(amount * 10 ** decimals));\n}\n\nexport function rawToStable(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nexport function getDecimals(asset: SupportedAsset): number {\n return SUPPORTED_ASSETS[asset].decimals;\n}\n\nexport function rawToDisplay(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nexport function displayToRaw(amount: number, decimals: number): bigint {\n return BigInt(Math.round(amount * 10 ** decimals));\n}\n\nexport function formatUsd(amount: number): string {\n return `$${amount.toFixed(2)}`;\n}\n\nexport function formatSui(amount: number): string {\n if (amount < 0.001) return `${amount.toFixed(6)} SUI`;\n return `${amount.toFixed(3)} SUI`;\n}\n\nexport function formatLargeNumber(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toFixed(2);\n}\n\nexport function formatAssetAmount(amount: number, asset: string): string {\n if (asset === 'BTC') return amount.toFixed(8);\n if (asset === 'GOLD') return amount.toFixed(6);\n if (asset === 'ETH') return amount.toFixed(6);\n return amount.toFixed(4);\n}\n\nconst ASSET_LOOKUP: Map<string, string> = new Map();\nfor (const [key, info] of Object.entries(SUPPORTED_ASSETS)) {\n ASSET_LOOKUP.set(key.toUpperCase(), key);\n if (info.displayName && info.displayName.toUpperCase() !== key.toUpperCase()) {\n ASSET_LOOKUP.set(info.displayName.toUpperCase(), key);\n }\n}\n\n/**\n * Case-insensitive lookup against SUPPORTED_ASSETS keys AND display names.\n * 'usde' → 'USDe', 'suiusde' → 'USDe', 'suiusdt' → 'USDT', 'usdsui' → 'USDsui'.\n * Returns the original input if not found so downstream validation can reject it.\n */\nexport function normalizeAsset(input: string): string {\n return ASSET_LOOKUP.get(input.toUpperCase()) ?? input;\n}\n","/** Cross-platform (Node + browser) base64 helpers. */\n\nexport function toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\nexport function fromBase64(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n","/**\n * Cetus Aggregator V3 SDK wrapper — the ONLY file that imports @cetusprotocol/aggregator-sdk.\n * Documented CLAUDE.md exception: multi-DEX routing cannot be feasibly replaced by thin tx builders.\n *\n * [B5 v2 / @t2000/sdk@1.1.0 / 2026-04-30]\n * Overlay fee config is now per-call instead of a module-level singleton. CLI / direct\n * SDK callers (`T2000.swap()`) DON'T pass `overlayFee` → fee-free swap. Audric's\n * prepare/route.ts ALWAYS passes `overlayFee = { rate: OVERLAY_FEE_RATE, receiver:\n * T2000_OVERLAY_FEE_WALLET }` → fee charged. Structural inclusion (Audric's code can't\n * forget to pass it because it IS the code), not a toggle that defaults to safe.\n *\n * Pre-1.1.0: a module-level `OVERLAY_FEE_RECEIVER` constant defaulted to a Move object\n * ID. USDC sent there became OwnedObjects keyed to the object and was inaccessible.\n * Fixed by making the receiver a regular wallet address (T2000_OVERLAY_FEE_WALLET) AND\n * by removing the singleton pattern that hid the misconfig.\n */\nimport { AggregatorClient, Env, type FindRouterParams, type RouterDataV3 } from '@cetusprotocol/aggregator-sdk';\nimport { Transaction, type TransactionObjectArgument } from '@mysten/sui/transactions';\nimport BN from 'bn.js';\nimport { resolveTokenType, getDecimalsForCoinType } from '../token-registry.js';\nimport type { SuiCoreClient } from '../utils/sui.js';\nimport type { SponsoredCoinMergeCache } from '../wallet/coinSelection.js';\nimport {\n type PreflightResult,\n PREFLIGHT_OK,\n preflightFail,\n checkPositiveAmount,\n} from '../preflight.js';\n\n/**\n * Synchronous, network-free preflight for `swap`. Validates the from/to token\n * args + amount sanity, and rejects an identity swap — the cheap checks the\n * host runs before routing. Returns a `PreflightResult`; never throws.\n * Route-finding, liquidity, slippage + decimals resolution stay in the async\n * path (`findSwapRoute`/`buildSwapTx`/`getSwapQuote`).\n *\n * v3 drops the swap *tool*, but `swap` survives as an SDK/CLI builder (§8) so\n * it gets the same builder-appropriate preflight as send/pay.\n */\nexport function preflightSwap(input: {\n from: string;\n to: string;\n amount: number;\n}): PreflightResult {\n if (typeof input.from !== 'string' || input.from.trim() === '') {\n return preflightFail('INVALID_ASSET', 'A `from` token is required to swap');\n }\n if (typeof input.to !== 'string' || input.to.trim() === '') {\n return preflightFail('INVALID_ASSET', 'A `to` token is required to swap');\n }\n\n // No upper ceiling — swaps route arbitrary tokens, and low-unit-value tokens\n // legitimately trade in millions/billions of units.\n const amountCheck = checkPositiveAmount(input.amount, 'Amount', Number.POSITIVE_INFINITY);\n if (!amountCheck.valid) return amountCheck;\n\n // Identity swap is a no-op the router can't route — catch it cheaply.\n // Resolve symbol → coin type so \"USDC\" and the USDC coin type compare equal.\n // Guard the null===null case (two unknown symbols both resolve to null) by\n // also requiring the resolved value to be non-null, falling back to a raw\n // string compare.\n const resolvedFrom = resolveTokenType(input.from);\n const resolvedTo = resolveTokenType(input.to);\n const sameToken =\n input.from.trim() === input.to.trim() ||\n (resolvedFrom !== null && resolvedFrom === resolvedTo);\n if (sameToken) {\n return preflightFail('INVALID_ASSET', `Cannot swap ${input.from} to itself`);\n }\n\n return PREFLIGHT_OK;\n}\n\nexport interface OverlayFeeConfig {\n /** Fee rate as a fraction (e.g. 0.001 = 0.1%). Pass 0 to disable. */\n rate: number;\n /** Wallet address that receives the overlay fee. */\n receiver: string;\n}\n\nexport interface SwapRouteResult {\n routerData: RouterDataV3;\n amountIn: string;\n amountOut: string;\n byAmountIn: boolean;\n priceImpact: number;\n insufficientLiquidity: boolean;\n}\n\n// [SPEC 20.2 / D-1 (a)] Typed JSON-friendly representation of a Cetus\n// `RouterDataV3` for cross-process / cross-network transport. The native\n// shape contains `BN` instances (`bn.js`) and a `Map<string, string>`\n// (`packages`) that don't survive JSON.stringify / JSON.parse cleanly:\n// - `BN.toJSON()` returns the internal `{negative,words,length,red}` blob\n// - `Map.toJSON()` returns `{}`\n// Round-tripping via `serializeCetusRoute` + `deserializeCetusRoute`\n// converts BN ↔ decimal string and Map ↔ Record. Engine + audric both\n// reference fields by path (`route.routerData.paths[i].provider`) without\n// needing to know about the underlying BN/Map types.\nexport interface SerializedCetusRoutePath {\n id: string;\n direction: boolean;\n provider: string;\n from: string;\n target: string;\n feeRate: number;\n amountIn: string;\n amountOut: string;\n version?: string;\n publishedAt?: string;\n extendedDetails?: Record<string, unknown>;\n}\n\nexport interface SerializedRouterDataV3 {\n quoteID?: string;\n /** RouterDataV3.amountIn (BN) → decimal string */\n amountIn: string;\n /** RouterDataV3.amountOut (BN) → decimal string */\n amountOut: string;\n byAmountIn: boolean;\n paths: SerializedCetusRoutePath[];\n insufficientLiquidity: boolean;\n deviationRatio: number;\n /** RouterDataV3.packages (Map) → Record */\n packages?: Record<string, string>;\n totalDeepFee?: number;\n error?: { code: number; msg: string };\n overlayFee?: number;\n}\n\nexport interface SerializedCetusRoute {\n routerData: SerializedRouterDataV3;\n amountIn: string;\n amountOut: string;\n byAmountIn: boolean;\n priceImpact: number;\n insufficientLiquidity: boolean;\n /**\n * Wall-clock timestamp (ms since epoch) at which the route was discovered.\n * Used by audric's prepare-route for SPEC 20.2 D-3 TTL re-validation: if\n * the route is older than the threshold AND price impact has shifted\n * beyond tolerance, fall back to a fresh `findSwapRoute()` call.\n */\n discoveredAt: number;\n /**\n * Snapshot of the input/output coin types the route was discovered for.\n * SPEC 20.2 D-2 (b) structural verification: prepare-route asserts\n * input/output coins match before using the fast-path; mismatch falls\n * back to fresh discovery (defense against client-side tampering and\n * against legitimate token-type drift in the request).\n */\n fromCoinType: string;\n toCoinType: string;\n}\n\nexport function serializeCetusRoute(\n route: SwapRouteResult,\n context: { fromCoinType: string; toCoinType: string },\n): SerializedCetusRoute {\n return {\n routerData: serializeRouterDataV3(route.routerData),\n amountIn: route.amountIn,\n amountOut: route.amountOut,\n byAmountIn: route.byAmountIn,\n priceImpact: route.priceImpact,\n insufficientLiquidity: route.insufficientLiquidity,\n discoveredAt: Date.now(),\n fromCoinType: context.fromCoinType,\n toCoinType: context.toCoinType,\n };\n}\n\nexport function deserializeCetusRoute(serialized: SerializedCetusRoute): SwapRouteResult {\n return {\n routerData: deserializeRouterDataV3(serialized.routerData),\n amountIn: serialized.amountIn,\n amountOut: serialized.amountOut,\n byAmountIn: serialized.byAmountIn,\n priceImpact: serialized.priceImpact,\n insufficientLiquidity: serialized.insufficientLiquidity,\n };\n}\n\nfunction serializeRouterDataV3(rd: RouterDataV3): SerializedRouterDataV3 {\n const out: SerializedRouterDataV3 = {\n amountIn: rd.amountIn.toString(),\n amountOut: rd.amountOut.toString(),\n byAmountIn: rd.byAmountIn,\n paths: rd.paths.map(serializeCetusRoutePath),\n insufficientLiquidity: rd.insufficientLiquidity,\n deviationRatio: rd.deviationRatio,\n };\n if (rd.quoteID !== undefined) out.quoteID = rd.quoteID;\n if (rd.packages) {\n const obj: Record<string, string> = {};\n for (const [k, v] of rd.packages) obj[k] = v;\n out.packages = obj;\n }\n if (rd.totalDeepFee !== undefined) out.totalDeepFee = rd.totalDeepFee;\n if (rd.error) out.error = { code: rd.error.code, msg: rd.error.msg };\n if (rd.overlayFee !== undefined) out.overlayFee = rd.overlayFee;\n return out;\n}\n\nfunction deserializeRouterDataV3(s: SerializedRouterDataV3): RouterDataV3 {\n const out: RouterDataV3 = {\n amountIn: new BN(s.amountIn),\n amountOut: new BN(s.amountOut),\n byAmountIn: s.byAmountIn,\n paths: s.paths.map(deserializeCetusRoutePath),\n insufficientLiquidity: s.insufficientLiquidity,\n deviationRatio: s.deviationRatio,\n };\n if (s.quoteID !== undefined) out.quoteID = s.quoteID;\n if (s.packages) out.packages = new Map(Object.entries(s.packages));\n if (s.totalDeepFee !== undefined) out.totalDeepFee = s.totalDeepFee;\n if (s.error) out.error = { code: s.error.code, msg: s.error.msg };\n if (s.overlayFee !== undefined) out.overlayFee = s.overlayFee;\n return out;\n}\n\nfunction serializeCetusRoutePath(p: RouterDataV3['paths'][number]): SerializedCetusRoutePath {\n const out: SerializedCetusRoutePath = {\n id: p.id,\n direction: p.direction,\n provider: p.provider,\n from: p.from,\n target: p.target,\n feeRate: p.feeRate,\n amountIn: p.amountIn,\n amountOut: p.amountOut,\n };\n if (p.version !== undefined) out.version = p.version;\n if (p.publishedAt !== undefined) out.publishedAt = p.publishedAt;\n if (p.extendedDetails) out.extendedDetails = { ...p.extendedDetails };\n return out;\n}\n\nfunction deserializeCetusRoutePath(p: SerializedCetusRoutePath): RouterDataV3['paths'][number] {\n const out: RouterDataV3['paths'][number] = {\n id: p.id,\n direction: p.direction,\n provider: p.provider,\n from: p.from,\n target: p.target,\n feeRate: p.feeRate,\n amountIn: p.amountIn,\n amountOut: p.amountOut,\n };\n if (p.version !== undefined) out.version = p.version;\n if (p.publishedAt !== undefined) out.publishedAt = p.publishedAt;\n if (p.extendedDetails) out.extendedDetails = { ...p.extendedDetails };\n return out;\n}\n\n/**\n * SPEC 20.2 D-2 (b) structural verification helper. Returns true when the\n * serialized route matches the requested coin types (i.e. it's safe to use\n * as the prepare-route fast-path), false otherwise (tampered, or input\n * mismatch from a legitimate but stale pending action). Caller falls back\n * to a fresh `findSwapRoute()` call when verification fails.\n */\nexport function verifyCetusRouteCoinMatch(\n serialized: SerializedCetusRoute,\n expected: { fromCoinType: string; toCoinType: string },\n): boolean {\n return serialized.fromCoinType === expected.fromCoinType && serialized.toCoinType === expected.toCoinType;\n}\n\n/**\n * SPEC 20.2 D-3 (b) TTL helper. Returns true when the serialized route is\n * fresh enough to use as the fast-path (< `maxAgeMs` old). Returns false\n * for stale routes — caller falls back to fresh `findSwapRoute()` to pick\n * up any pool-price drift since route discovery.\n *\n * Default 30s aligns with the existing quote-freshness contract surfaced\n * to users via `pending_action.quoteAge` (the PermissionCard \"QUOTE Ns OLD\"\n * badge starts warning the user past 30s).\n */\nexport function isCetusRouteFresh(serialized: SerializedCetusRoute, maxAgeMs: number = 30_000): boolean {\n return Date.now() - serialized.discoveredAt < maxAgeMs;\n}\n\n/**\n * Default Audric swap overlay fee — 0.1%. Exported for consumers that want to use\n * the canonical Audric rate (the Audric prepare-route does this). Changing this\n * rate requires a coordinated SDK + audric release.\n */\nexport const OVERLAY_FEE_RATE = 0.001;\n\n/**\n * Cache `AggregatorClient` instances by `(signer + overlay rate + overlay receiver)`.\n * Per-call instantiation is cheap (the client is mostly config), but caching avoids\n * pointless re-allocation when the same caller swaps multiple times in a loop.\n */\nconst clientCache = new Map<string, AggregatorClient>();\n\nfunction getClient(walletAddress: string, overlayFee?: OverlayFeeConfig): AggregatorClient {\n const rate = overlayFee?.rate ?? 0;\n const receiver = overlayFee?.receiver ?? '';\n const key = `${walletAddress}|${rate}|${receiver}`;\n\n const cached = clientCache.get(key);\n if (cached) return cached;\n\n const client = new AggregatorClient({\n signer: walletAddress,\n env: Env.Mainnet,\n ...(rate > 0 && receiver\n ? { overlayFeeRate: rate, overlayFeeReceiver: receiver }\n : {}),\n });\n clientCache.set(key, client);\n return client;\n}\n\n/**\n * [Bug A defense-in-depth / 2026-05-10] Returns true when every path\n * provider in `route.routerData.paths` is present in the active\n * `providers` allow-list. Cetus's `getProvidersExcluding(...)` returns\n * an inclusion list (the complement of the exclusion), so when a caller\n * passes `providers`, every walked provider must be IN that list to be\n * compatible.\n *\n * When `providers` is undefined (non-sponsored caller, e.g. CLI) every\n * route is compatible — same semantics as `findSwapRoute` itself.\n *\n * Why per-path: a Cetus aggregator route can split across multiple DEXes\n * (e.g. 60% Cetus + 40% Bluefin). A single excluded provider in any path\n * triggers `tx.gas` usage in `routerSwap`. Reject the whole route if any\n * leg is excluded.\n */\nexport function isPrecomputedRouteCompatibleWithProviders(\n route: SwapRouteResult,\n providers: string[] | undefined,\n): boolean {\n if (!providers || providers.length === 0) return true;\n const allowed = new Set(providers);\n for (const path of route.routerData.paths) {\n if (!allowed.has(path.provider)) return false;\n }\n return true;\n}\n\n/**\n * Find the optimal swap route via Cetus Aggregator REST API.\n *\n * Pass `overlayFee` to charge an overlay fee on the output (Audric's pattern).\n * Omit it for a fee-free swap (CLI / direct SDK pattern).\n */\nexport async function findSwapRoute(params: {\n walletAddress: string;\n from: string;\n to: string;\n amount: bigint;\n byAmountIn: boolean;\n overlayFee?: OverlayFeeConfig;\n /**\n * Optional Cetus provider allow-list. When omitted, all 30+ DEXes\n * are eligible. Sponsored flows (Enoki) MUST pass an exclusion list\n * computed via `getProvidersExcluding([...])` from the Cetus SDK to\n * remove Pyth-dependent providers (HAEDALPMM, METASTABLE, OBRIC,\n * STEAMM_OMM, STEAMM_OMM_V2, SEVENK, HAEDALHMMV2) — those reference\n * `tx.gas` for oracle fees, which Enoki rejects in sponsored txs.\n * Non-sponsored callers (CLI, direct SDK) leave this undefined.\n */\n providers?: string[];\n}): Promise<SwapRouteResult | null> {\n const client = getClient(params.walletAddress, params.overlayFee);\n\n const findParams: FindRouterParams = {\n from: params.from,\n target: params.to,\n amount: params.amount.toString(),\n byAmountIn: params.byAmountIn,\n ...(params.providers ? { providers: params.providers } : {}),\n };\n\n const routerData = await client.findRouters(findParams);\n if (!routerData) return null;\n\n if (routerData.insufficientLiquidity) {\n return {\n routerData,\n amountIn: routerData.amountIn.toString(),\n amountOut: routerData.amountOut.toString(),\n byAmountIn: params.byAmountIn,\n priceImpact: normalizePriceImpact(routerData.deviationRatio),\n insufficientLiquidity: true,\n };\n }\n\n if (routerData.error) {\n const { T2000Error } = await import('../errors.js');\n throw new T2000Error('SWAP_FAILED', `Cetus routing error: ${routerData.error.msg} (code ${routerData.error.code})`);\n }\n\n return {\n routerData,\n amountIn: routerData.amountIn.toString(),\n amountOut: routerData.amountOut.toString(),\n byAmountIn: params.byAmountIn,\n priceImpact: normalizePriceImpact(routerData.deviationRatio),\n insufficientLiquidity: false,\n };\n}\n\n/**\n * Cetus' aggregator types `deviationRatio` as `number`, but in some routes\n * the router actually returns a string (\"0.001234\"). The SDK type lies, so we\n * always coerce to a finite number here (NaN/null/undefined → 0). Without\n * this every downstream consumer that calls `priceImpact.toFixed(...)` will\n * crash at runtime — including the Audric SwapQuoteCard, which takes the\n * whole chat UI down through its error boundary.\n */\nfunction normalizePriceImpact(value: unknown): number {\n const n = typeof value === 'number' ? value : Number(value);\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Build a swap PTB from a route result. The caller must provide an input coin\n * obtained by splitting/merging wallet coins.\n *\n * **Important:** Cetus's `routerSwap` reads the overlay-fee config from the\n * AggregatorClient instance. The `overlayFee` param here MUST match the one\n * passed to `findSwapRoute` for the same swap (otherwise you'll hit the cache\n * boundary and get a different client with different overlay config).\n */\nexport async function buildSwapTx(params: {\n walletAddress: string;\n route: SwapRouteResult;\n tx: Transaction;\n inputCoin: TransactionObjectArgument;\n slippage: number;\n overlayFee?: OverlayFeeConfig;\n}): Promise<TransactionObjectArgument> {\n const client = getClient(params.walletAddress, params.overlayFee);\n const clampedSlippage = Math.max(0.001, Math.min(params.slippage, 0.05));\n\n const outputCoin = await client.routerSwap({\n router: params.route.routerData,\n inputCoin: params.inputCoin,\n slippage: clampedSlippage,\n txb: params.tx,\n });\n\n return outputCoin;\n}\n\n/**\n * Append a swap fragment to an existing PTB. SPEC 7 § \"Layer 1\" Cetus\n * appender. Two modes, dispatched by the presence of `input.inputCoin`:\n *\n * - **Wallet mode** (`inputCoin` omitted) — sources `from`-asset funds\n * via `coinWithBalance({ type, balance })` (resolves coin objects +\n * address balance at build time), runs the swap. Mirrors the audric\n * host's `transactions/prepare/route.ts` swap branch (P2.2c will\n * retire that branch in favor of this appender via `composeTx`).\n *\n * - **Chain mode** (`inputCoin` provided) — consumes the passed-in coin\n * reference (typically produced by an upstream appender like\n * `addWithdrawToTx`) directly, no wallet fetch / no merge / no\n * split. This is the SPEC 7 multi-write enabler (\"withdraw → swap →\n * save\" without intermediate wallet materialization).\n *\n * **SUI in wallet mode:** ALWAYS sources through `selectSuiCoin` (which\n * routes via `coinWithBalance({ type: SUI, useGasCoin: false })` under\n * sponsored flows, OR `tx.splitCoins(tx.gas, ...)` under self-funded\n * flows). The caller MUST set `sponsoredContext` correctly — otherwise\n * sponsored swaps with SUI source fail with `Cannot use GasCoin as a\n * transaction argument` (Enoki owns `tx.gas`, the PTB body referencing\n * it as an argument is invalid for sponsorship). 2.14.0 shipped without\n * this branch and broke audric/web-v2 SUI→USDC swaps; restored in 2.14.1\n * (S.260). For non-sponsored flows (CLI), `T2000.swap()` pre-builds the\n * inputCoin via `tx.splitCoins(tx.gas, [rawAmount])[0]` and uses chain\n * mode, sidestepping wallet-mode entirely — this branch is a defensive\n * safety net for future direct SDK users who pass SUI in wallet mode.\n *\n * **`swapAll` semantics (wallet mode):** if the requested raw amount\n * is >= the wallet's total `from` balance, the appender consumes the\n * entire merged primary coin (not a split), matching audric's host\n * route's `swapAll` clipping. The returned `effectiveAmountIn` reflects\n * the actual consumed amount in display units.\n *\n * **Slippage:** clamped to [0.001, 0.05] (0.1% – 5%). Defaults to 0.01.\n *\n * @returns\n * - `coin` — output coin reference, ready for downstream consumption\n * (e.g. `addSaveToTx`) or wallet transfer (`tx.transferObjects`).\n * - `effectiveAmountIn` — display-units input amount the swap actually\n * consumes (handles `swapAll` clipping in wallet mode; in chain mode\n * echoes the requested `input.amount`).\n * - `expectedAmountOut` — display-units output amount per the route\n * quote. Actual on-chain output may differ within slippage.\n * - `route` — raw `SwapRouteResult` for downstream telemetry / logging.\n */\nexport async function addSwapToTx(\n tx: Transaction,\n client: SuiCoreClient,\n address: string,\n input: {\n from: string;\n to: string;\n amount: number;\n slippage?: number;\n byAmountIn?: boolean;\n overlayFee?: OverlayFeeConfig;\n inputCoin?: TransactionObjectArgument;\n /**\n * Optional Cetus provider allow-list. Forwarded to `findSwapRoute`.\n * Sponsored flows (Enoki) MUST pass `getProvidersExcluding([...])`\n * to remove Pyth-dependent providers — see `findSwapRoute`'s JSDoc\n * for the exclusion list. Non-sponsored callers omit this.\n */\n providers?: string[];\n /**\n * [SPEC 20.2 D-3 (b)] Precomputed route from a prior `findSwapRoute()`\n * call (typically captured by `swap_quote` and threaded through\n * `pending_action.cetusRoute`). When present AND not stale (per\n * `isCetusRouteFresh`) AND the input/output coins match, this skips\n * the ~400-500ms `findSwapRoute()` discovery call. Stale routes are\n * silently ignored (caller falls back to fresh discovery).\n *\n * Caller responsibility: pass the SAME `overlayFee` / `providers` /\n * `byAmountIn` that produced the precomputed route. Mismatch will\n * still produce a working swap but may use the wrong overlay-fee\n * config (the route data already encodes the chosen DEX path).\n */\n precomputedRoute?: SwapRouteResult;\n /**\n * Whether this swap is being built inside a sponsored-tx flow (Enoki)\n * vs self-funded (CLI / direct sign). Load-bearing for SUI-source\n * swaps in wallet mode: under sponsored flows, `tx.gas` belongs to\n * the sponsor and CANNOT be referenced as a transaction argument\n * (Sui protocol rejects with `Cannot use GasCoin as a transaction\n * argument`). When `true`, SUI source routes through `selectSuiCoin`\n * with `useGasCoin: false` so the resolver sources from the user's\n * SUI coin objects + address balance instead. Defaults to `false`\n * (back-compat — pre-2.14.1 behavior). Audric/web-v2's compose path\n * threads this through via `composeTx({ sponsoredContext: true })`.\n */\n sponsoredContext?: boolean;\n /**\n * Per-PTB merge cache for sponsored coin-object sourcing (any coin\n * type — SUI in the dedicated branch, USDC/USDsui/etc. in the wallet\n * branch). Provided by `composeTx`'s orchestration loop so multiple\n * legs sourcing the same coin in one bundle share a single merged\n * primary coin instead of each emitting its own `mergeCoins` (the\n * second of which references already-consumed coins → Enoki dry-run\n * `ArgumentWithoutValue`). Single swaps don't need it; omit. See\n * `SponsoredCoinMergeCache` JSDoc.\n */\n coinMergeCache?: SponsoredCoinMergeCache;\n },\n): Promise<{\n coin: TransactionObjectArgument;\n effectiveAmountIn: number;\n expectedAmountOut: number;\n route: SwapRouteResult;\n /** True when `precomputedRoute` was used (no `findSwapRoute()` call). */\n usedPrecomputedRoute: boolean;\n}> {\n const { T2000Error } = await import('../errors.js');\n\n const fromType = resolveTokenType(input.from);\n const toType = resolveTokenType(input.to);\n if (!fromType) throw new T2000Error('ASSET_NOT_SUPPORTED', `Unknown token: ${input.from}. Provide the symbol (USDC, SUI, ...) or full coin type.`);\n if (!toType) throw new T2000Error('ASSET_NOT_SUPPORTED', `Unknown token: ${input.to}. Provide the symbol (USDC, SUI, ...) or full coin type.`);\n if (fromType === toType) throw new T2000Error('SWAP_FAILED', 'Cannot swap a token to itself');\n if (!Number.isFinite(input.amount) || input.amount <= 0) {\n throw new T2000Error('INVALID_AMOUNT', 'Amount must be greater than zero');\n }\n\n const fromDecimals = getDecimalsForCoinType(fromType);\n const toDecimals = getDecimalsForCoinType(toType);\n const requestedRaw = BigInt(Math.floor(input.amount * 10 ** fromDecimals));\n\n const slippage = Math.max(0.001, Math.min(input.slippage ?? 0.01, 0.05));\n const byAmountIn = input.byAmountIn ?? true;\n\n let inputCoin: TransactionObjectArgument;\n let effectiveRaw: bigint;\n\n if (input.inputCoin) {\n inputCoin = input.inputCoin;\n effectiveRaw = requestedRaw;\n } else if (fromType === '0x2::sui::SUI') {\n // SUI source needs special handling: under sponsored flows (Enoki),\n // referencing `tx.gas` as a transaction argument is forbidden (sponsor\n // owns the gas coin). `selectSuiCoin` does the right thing for both\n // sponsored (uses `coinWithBalance({ useGasCoin: false })`) and\n // self-funded (splits from `tx.gas` directly). The 2.14.0 release\n // shipped without this branch and broke audric/web-v2 SUI→USDC swaps\n // (\"Cannot use GasCoin as a transaction argument\" from Enoki); fixed\n // in 2.14.1 (S.260).\n const { selectSuiCoin } = await import('../wallet/coinSelection.js');\n const result = await selectSuiCoin(\n tx,\n client,\n address,\n requestedRaw,\n input.sponsoredContext ?? false,\n input.coinMergeCache,\n );\n inputCoin = result.coin;\n effectiveRaw = result.effectiveAmount;\n } else {\n // Non-SUI wallet-mode source — delegate to the canonical prelude.\n // NON-sponsored: pre-flights against `getBalance().totalBalance` and\n // returns a `coinWithBalance({ type, balance })` arg, whose `@mysten/sui`\n // resolver batches all intents for a coin type into a single build-time\n // merge — so same-asset multi-leg bundles dedup automatically.\n //\n // SPONSORED: routes through `selectCoinObjectsOnly` instead (coinWithBalance's\n // address-balance `FundsWithdrawal` reservation is what Enoki can't\n // deserialize, issue #93). That manual path has NO build-time batching, so\n // two legs sourcing the same coin would each emit their own `mergeCoins`\n // over the SAME objects → second merge references consumed coins → Enoki\n // dry-run `ArgumentWithoutValue`. The `coinMergeCache` supplies the dedup:\n // first leg merges once + caches the primary, later legs split from it.\n const { selectAndSplitCoin } = await import('../wallet/coinSelection.js');\n const result = await selectAndSplitCoin(tx, client, address, fromType, requestedRaw, {\n sponsoredContext: input.sponsoredContext ?? false,\n mergeCache: input.coinMergeCache,\n });\n inputCoin = result.coin;\n effectiveRaw = result.effectiveAmount;\n }\n\n // [SPEC 20.2 D-3 (b)] Use the precomputed route when available + valid.\n // Validity = same input/output coin types AND the requested raw amount\n // matches what the route was discovered for (mismatch indicates the user\n // edited the amount post-quote, in which case we must re-discover at the\n // new amount because price impact is amount-dependent). The caller\n // (`audric prepare-route`) owns the staleness check (`isCetusRouteFresh`)\n // and only forwards `precomputedRoute` when fresh.\n //\n // [Bug A defense-in-depth / 2026-05-10] Even with the engine fix that\n // makes `swap_quote` discover sponsor-safe routes, this layer also\n // validates the precomputed route against the active providers\n // allow-list. If the route walks any excluded provider (e.g. a stale\n // `pending_action.cetusRoute` from before the engine fix shipped, or a\n // provider list that drifted between quote and execute), fall back to\n // fresh discovery. Better to eat 400ms than to let a Pyth-dependent\n // route reach Enoki and revert with HTTP 400.\n let route: SwapRouteResult | null;\n let usedPrecomputedRoute = false;\n if (\n input.precomputedRoute &&\n input.precomputedRoute.amountIn === effectiveRaw.toString() &&\n input.precomputedRoute.byAmountIn === byAmountIn &&\n isPrecomputedRouteCompatibleWithProviders(input.precomputedRoute, input.providers)\n ) {\n route = input.precomputedRoute;\n usedPrecomputedRoute = true;\n } else {\n route = await findSwapRoute({\n walletAddress: address,\n from: fromType,\n to: toType,\n amount: effectiveRaw,\n byAmountIn,\n overlayFee: input.overlayFee,\n providers: input.providers,\n });\n }\n\n if (!route) {\n throw new T2000Error('SWAP_NO_ROUTE', `No swap route found for ${input.from} → ${input.to}`);\n }\n if (route.insufficientLiquidity) {\n throw new T2000Error('SWAP_NO_ROUTE', `Insufficient liquidity for ${input.from} → ${input.to}`);\n }\n\n const outputCoin = await buildSwapTx({\n walletAddress: address,\n route,\n tx,\n inputCoin,\n slippage,\n overlayFee: input.overlayFee,\n });\n\n return {\n coin: outputCoin,\n effectiveAmountIn: Number(effectiveRaw) / 10 ** fromDecimals,\n expectedAmountOut: Number(route.amountOut) / 10 ** toDecimals,\n route,\n usedPrecomputedRoute,\n };\n}\n\n// Re-export from the canonical token registry for backward-compat.\nexport { TOKEN_MAP, resolveTokenType } from '../token-registry.js';\n","import {\n Transaction,\n type TransactionObjectArgument,\n} from '@mysten/sui/transactions';\nimport {\n GASLESS_MIN_STABLE_AMOUNT,\n GASLESS_STABLE_TYPES,\n SUPPORTED_ASSETS,\n assertAllowedAsset,\n type SendableAsset,\n} from '../constants.js';\nimport { T2000Error } from '../errors.js';\nimport { validateAddress, type SuiCoreClient } from '../utils/sui.js';\nimport { displayToRaw } from '../utils/format.js';\nimport {\n type PreflightResult,\n PREFLIGHT_OK,\n preflightFail,\n checkPositiveAmount,\n checkSuiAddress,\n} from '../preflight.js';\n\n/**\n * Synchronous, network-free preflight for `send`. Validates asset membership,\n * amount sanity, the gasless stable floor, and recipient address shape — the\n * cheap checks the v3 host runs before the LLM round-trip / tap-to-confirm.\n * Returns a `PreflightResult`; never throws. `buildSendTx` calls this first,\n * then layers the network balance read on top.\n */\nexport function preflightSend(input: {\n to: string;\n amount: number;\n asset: string;\n}): PreflightResult {\n // Asset membership — reuse the canonical message (single source of truth).\n try {\n assertAllowedAsset('send', input.asset);\n } catch (e) {\n return preflightFail('INVALID_ASSET', (e as T2000Error).message);\n }\n\n const amountCheck = checkPositiveAmount(input.amount);\n if (!amountCheck.valid) return amountCheck;\n\n // Gasless protocol allowlist enforces a 0.01 minimum on the stables.\n if (\n (input.asset === 'USDC' || input.asset === 'USDsui') &&\n input.amount < GASLESS_MIN_STABLE_AMOUNT\n ) {\n return preflightFail(\n 'INVALID_AMOUNT',\n `Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${input.asset}. Got ${input.amount}.`,\n );\n }\n\n const addressCheck = checkSuiAddress(input.to);\n if (!addressCheck.valid) return addressCheck;\n\n return PREFLIGHT_OK;\n}\n\n/**\n * Build a PTB that sends `amount` of `asset` from `address` to `to`.\n *\n * [v4.0 Phase A Day 2 — SPEC_AGENT_WALLET_GREENFIELD §A]\n *\n * Asset constraint: `'USDC' | 'USDsui' | 'SUI'` only. Other assets throw\n * `INVALID_ASSET` via `assertAllowedAsset('send', asset)`. The constrained\n * set matches Sui mainnet's gasless allowlist (USDC + USDsui) plus SUI\n * for users who want a gas-native transfer.\n *\n * Build paths:\n * - **USDC / USDsui** — `0x2::balance::send_funds` Move call with a\n * `tx.balance({ type, balance })` input. When built via `SuiGrpcClient`,\n * the gRPC resolver auto-detects gasless eligibility and zeros gas.\n * When built via `SuiJsonRpcClient`, the same PTB still executes but\n * the caller pays normal gas. Minimum 0.01 (protocol allowlist floor).\n * - **SUI** — `tx.splitCoins(tx.gas, [amount]) → tx.transferObjects()`.\n * Standard gas-native transfer. No minimum.\n *\n * Pre-flight balance check stays on JSON-RPC (`client.getBalance`) — it\n * sums coin objects + address balance so the legacy `getCoins` page miss\n * doesn't break for users whose stables landed via gasless deposits.\n *\n * `asset` is REQUIRED (no implicit USDC default — pre-v4 hid LLM intent\n * errors). Callers passing the wrong asset get an explicit error rather\n * than a silent currency substitution.\n */\nexport async function buildSendTx({\n client,\n address,\n to,\n amount,\n asset,\n}: {\n client: SuiCoreClient;\n address: string;\n to: string;\n amount: number;\n asset: SendableAsset;\n}): Promise<Transaction> {\n // Layer 2 — cheap synchronous preflight (asset / amount / gasless floor /\n // recipient shape). Rethrow the precise code+message verbatim.\n const pf = preflightSend({ to, amount, asset });\n if (!pf.valid) throw new T2000Error(pf.code, pf.error);\n\n const recipient = validateAddress(to);\n const assetInfo = SUPPORTED_ASSETS[asset];\n if (!assetInfo) throw new T2000Error('ASSET_NOT_SUPPORTED', `Asset ${asset} is not supported`);\n\n const rawAmount = displayToRaw(amount, assetInfo.decimals);\n const tx = new Transaction();\n tx.setSender(address);\n\n // Balance pre-flight against `core.getBalance().balance.balance` (sums\n // coins + address balance). The legacy `getCoins` page miss broke for\n // users whose stables had drifted into address balance via @suimpp/mpp 0.7+.\n const balanceResp = await client.core.getBalance({ owner: address, coinType: assetInfo.type });\n const totalBalance = BigInt(balanceResp.balance.balance);\n if (totalBalance < rawAmount) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `Insufficient ${asset} balance`, {\n available: Number(totalBalance) / 10 ** assetInfo.decimals,\n required: amount,\n });\n }\n\n if (asset === 'SUI') {\n // Standard gas-native transfer — split from the gas coin, transfer\n // the resulting object. NOT gasless (SUI is not on the protocol\n // allowlist for `balance::send_funds`).\n const [sendCoin] = tx.splitCoins(tx.gas, [rawAmount]);\n tx.transferObjects([sendCoin], recipient);\n return tx;\n }\n\n // USDC / USDsui — gasless via `0x2::balance::send_funds`. The gRPC\n // build resolver inspects this PTB shape at `tx.build()` time and,\n // when it matches the protocol allowlist, sets gasPrice=0/gasBudget=0\n // automatically. The Move signature is:\n // public fun send_funds<T>(balance: Balance<T>, recipient: address)\n // `tx.balance({ type, balance })` produces a Balance<T> input sourced\n // from the sender's address balance + coin objects (auto-merged).\n const coinType = GASLESS_STABLE_TYPES[asset];\n tx.moveCall({\n target: '0x2::balance::send_funds',\n typeArguments: [coinType],\n arguments: [\n tx.balance({ type: coinType, balance: rawAmount }),\n tx.pure.address(recipient),\n ],\n });\n return tx;\n}\n\n/**\n * Fragment-appender for the chain-mode send leg of SPEC 7 multi-write\n * Payment Intents. Consumes a coin reference produced by a previous\n * appender (e.g. `addWithdrawToTx`, `addSwapToTx`) and transfers it to\n * `recipient` within the same Payment Intent — no intermediate wallet\n * materialization.\n *\n * Codifies the hand-built send leg from\n * `scripts/smoke-spec7-withdraw-then-send.ts` (P2.1) into a typed\n * appender. SPEC 7 § \"Layer 1\" — P2.2b will register this in the\n * `WRITE_APPENDER_REGISTRY` under `send_transfer` for chain-mode\n * dispatch; the registry adapter will handle the wallet-fetch fallback\n * by delegating to `buildSendTx` when no upstream coin is available.\n *\n * For single-step send_transfer flows (no chained predecessor), use\n * `buildSendTx` directly — it builds a complete tx including the\n * wallet-coin selection / merge / split prelude.\n *\n * [v4.0 Phase A Day 2] Stays on the legacy `transferObjects` path\n * because chain-mode bundles are NEVER gasless — by definition they\n * combine multiple Move calls (`withdraw → send`, `swap → send`) which\n * fail the protocol allowlist check (only `balance::send_funds` and\n * a few related helpers are eligible). The bundled flow still works,\n * the user just pays gas (or has it sponsored by audric via Enoki).\n *\n * @returns void — the coin is consumed by `tx.transferObjects`. Callers\n * that need the post-transfer \"effective amount\" should rely on the\n * upstream appender's `effectiveAmount` (e.g. `addWithdrawToTx`'s\n * return), not on this appender.\n */\nexport function addSendToTx(\n tx: Transaction,\n coin: TransactionObjectArgument,\n recipient: string,\n): void {\n const validRecipient = validateAddress(recipient);\n tx.transferObjects([coin], validRecipient);\n}\n","import { Transaction } from '@mysten/sui/transactions';\nimport { T2000Error } from '../errors.js';\nimport { USDC_TYPE } from '../token-registry.js';\nimport { USDC_DECIMALS } from '../constants.js';\nimport {\n type PreflightResult,\n PREFLIGHT_OK,\n preflightFail,\n checkSuiAddress,\n} from '../preflight.js';\nimport { validateAddress, type SuiCoreClient } from '../utils/sui.js';\nimport { selectAndSplitCoin } from './coinSelection.js';\n\n/**\n * A2A Escrow — client for the `a2a_escrow::escrow` Move package\n * (SPEC_A2A_ESCROW, t2 Agents Phase 3).\n *\n * One shared `Job<USDC>` object per engagement; the escrow balance lives IN\n * the object (no treasury, no admin key). These builders construct UNSIGNED\n * transactions; the caller signs (buyer for create/release/reject, seller\n * for deliver, ANYONE for the two timeout cranks) and may sponsor gas — the\n * Move calls authorize on `ctx.sender()`, so sponsorship never weakens auth.\n *\n * Browser-safe (no fs / keyManager imports) so store surfaces can build the\n * buyer-side legs on a zkLogin session key.\n *\n * Deployed on Sui mainnet 2026-07-17. Override via env for testnet/dev.\n */\n\n/** The published `a2a_escrow` package id (mainnet). */\nexport const A2A_ESCROW_PACKAGE_ID =\n process.env.A2A_ESCROW_PACKAGE_ID ??\n '0x9e67c380fb7079d793d6d15ff916b24d82779d7119bfa4631863102ed485c0a0';\n\nconst CLOCK_ID = '0x6';\nconst MODULE = 'escrow';\n\n/** v1 job-value cap in USDC — same instinct as the catalog price cap: the\n * no-arbitration reject-split is only fair at sizes where neither side is\n * incentivized to game it (SPEC_A2A_ESCROW §2). */\nexport const MAX_JOB_USDC = 50;\n\n/** Job lifecycle states, mirroring the Move constants. */\nexport const JOB_STATES = [\n 'funded',\n 'delivered',\n 'released',\n 'refunded',\n 'rejected',\n] as const;\nexport type JobState = (typeof JOB_STATES)[number];\n\nexport interface JobTerms {\n /** The seller's wallet (the listing's payTo / claimed Agent ID wallet). */\n seller: string;\n /** Job value in display USDC (e.g. `5` = 5 USDC). ≤ `MAX_JOB_USDC`. */\n amountUsdc: number;\n /** Hash/commitment of the job spec (hex string, `0x…` or bare). */\n specHash: string;\n /** Epoch-ms deadline the seller must deliver by. */\n deliverByMs: number;\n /** Buyer's accept/reject window (ms) after delivery; lapse = release. */\n reviewWindowMs: number;\n /** Buyer's share in basis points on reject (0–10000). Fixed at create. */\n rejectSplitBps: number;\n}\n\n/** Parsed on-chain `Job` object. */\nexport interface Job {\n id: string;\n buyer: string;\n seller: string;\n /** Locked amount in display USDC (immutable record). */\n amountUsdc: number;\n /** What's still in the object — 0 after settlement. */\n escrowUsdc: number;\n specHash: string;\n deliverByMs: number;\n reviewWindowMs: number;\n rejectSplitBps: number;\n state: JobState;\n deliveryHash: string | null;\n deliveredAtMs: number | null;\n createdAtMs: number;\n}\n\n// ---------------------------------------------------------------------------\n// Hash plumbing — spec/delivery commitments travel as vector<u8>.\n// ---------------------------------------------------------------------------\n\nfunction hexToBytes(hex: string): number[] {\n const clean = hex.startsWith('0x') ? hex.slice(2) : hex;\n if (clean.length === 0 || clean.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean)) {\n throw new T2000Error(\n 'INVALID_AMOUNT',\n `Expected a hex hash (0x…), got \"${hex.slice(0, 32)}\"`,\n );\n }\n const out: number[] = [];\n for (let i = 0; i < clean.length; i += 2) {\n out.push(Number.parseInt(clean.slice(i, i + 2), 16));\n }\n return out;\n}\n\nfunction bytesToHex(bytes: number[] | Uint8Array): string {\n let s = '0x';\n for (const b of bytes) s += b.toString(16).padStart(2, '0');\n return s;\n}\n\n// ---------------------------------------------------------------------------\n// Preflight\n// ---------------------------------------------------------------------------\n\n/**\n * Synchronous, network-free preflight for `create`. Terms sanity only —\n * the balance read happens in `buildCreateJobTx`.\n */\nexport function preflightCreateJob(terms: JobTerms): PreflightResult {\n const addressCheck = checkSuiAddress(terms.seller);\n if (!addressCheck.valid) return addressCheck;\n if (!Number.isFinite(terms.amountUsdc) || terms.amountUsdc <= 0) {\n return preflightFail('INVALID_AMOUNT', `Amount must be positive. Got ${terms.amountUsdc}.`);\n }\n if (terms.amountUsdc > MAX_JOB_USDC) {\n return preflightFail(\n 'INVALID_AMOUNT',\n `v1 caps escrow jobs at ${MAX_JOB_USDC} USDC (no-arbitration split only stays fair at small sizes). Got ${terms.amountUsdc}.`,\n );\n }\n if (terms.deliverByMs <= Date.now()) {\n return preflightFail('INVALID_AMOUNT', 'deliverByMs must be in the future.');\n }\n if (terms.reviewWindowMs < 0) {\n return preflightFail('INVALID_AMOUNT', 'reviewWindowMs must be ≥ 0.');\n }\n if (\n !Number.isInteger(terms.rejectSplitBps) ||\n terms.rejectSplitBps < 0 ||\n terms.rejectSplitBps > 10_000\n ) {\n return preflightFail('INVALID_AMOUNT', 'rejectSplitBps must be an integer 0–10000.');\n }\n try {\n hexToBytes(terms.specHash);\n } catch (e) {\n return preflightFail('INVALID_AMOUNT', (e as T2000Error).message);\n }\n return PREFLIGHT_OK;\n}\n\n// ---------------------------------------------------------------------------\n// Transaction builders (unsigned; caller signs + executes / sponsors)\n// ---------------------------------------------------------------------------\n\n/**\n * Buyer creates AND funds a job in one PTB — `escrow::create` consumes a\n * `Coin<USDC>` sourced from the buyer's coins + address balance.\n */\nexport async function buildCreateJobTx({\n client,\n buyer,\n terms,\n}: {\n client: SuiCoreClient;\n buyer: string;\n terms: JobTerms;\n}): Promise<Transaction> {\n const pf = preflightCreateJob(terms);\n if (!pf.valid) throw new T2000Error(pf.code, pf.error);\n\n const seller = validateAddress(terms.seller);\n if (seller === validateAddress(buyer)) {\n throw new T2000Error('INVALID_ADDRESS', 'Buyer and seller must be different wallets.');\n }\n // Floor, never round up — a rounded-up raw amount can exceed the on-chain\n // balance (financial-amounts discipline).\n const rawAmount = BigInt(Math.floor(terms.amountUsdc * 10 ** USDC_DECIMALS));\n\n const tx = new Transaction();\n const { coin } = await selectAndSplitCoin(tx, client, buyer, USDC_TYPE, rawAmount, {\n allowSwapAll: false,\n });\n tx.moveCall({\n target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::create`,\n typeArguments: [USDC_TYPE],\n arguments: [\n tx.pure.address(seller),\n coin,\n tx.pure.vector('u8', hexToBytes(terms.specHash)),\n tx.pure.u64(terms.deliverByMs),\n tx.pure.u64(terms.reviewWindowMs),\n tx.pure.u64(terms.rejectSplitBps),\n tx.object(CLOCK_ID),\n ],\n });\n return tx;\n}\n\nfunction jobCall(jobId: string, fn: 'release' | 'refund' | 'reject'): Transaction {\n const tx = new Transaction();\n tx.moveCall({\n target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::${fn}`,\n typeArguments: [USDC_TYPE],\n arguments: [tx.object(jobId), tx.object(CLOCK_ID)],\n });\n return tx;\n}\n\n/** Seller posts the delivery commitment (hex hash) before the deadline. */\nexport function buildDeliverJobTx(jobId: string, deliveryHash: string): Transaction {\n const tx = new Transaction();\n tx.moveCall({\n target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::deliver`,\n typeArguments: [USDC_TYPE],\n arguments: [\n tx.object(jobId),\n tx.pure.vector('u8', hexToBytes(deliveryHash)),\n tx.object(CLOCK_ID),\n ],\n });\n return tx;\n}\n\n/** Buyer accepts (or anyone, once the review window lapsed) → funds to seller. */\nexport function buildReleaseJobTx(jobId: string): Transaction {\n return jobCall(jobId, 'release');\n}\n\n/** Buyer rejects within the review window → split per the create terms. */\nexport function buildRejectJobTx(jobId: string): Transaction {\n return jobCall(jobId, 'reject');\n}\n\n/** Anyone, after the deadline with no delivery → funds back to the buyer. */\nexport function buildRefundJobTx(jobId: string): Transaction {\n return jobCall(jobId, 'refund');\n}\n\n// ---------------------------------------------------------------------------\n// Reads\n// ---------------------------------------------------------------------------\n\n/** Fetch + parse a `Job` shared object. Throws `RPC_ERROR` when the id\n * doesn't resolve to an a2a_escrow Job. */\nexport async function getJob(client: SuiCoreClient, jobId: string): Promise<Job> {\n const resp = await client.core\n .getObject({ objectId: jobId, include: { json: true } })\n .catch((e: unknown) => {\n throw new T2000Error(\n 'RPC_ERROR',\n `Job ${jobId} not found: ${e instanceof Error ? e.message : String(e)}`,\n );\n });\n const objType = resp.object?.type ?? '';\n const json = resp.object?.json as Record<string, unknown> | null | undefined;\n if (!json || !objType.includes(`::${MODULE}::Job<`)) {\n throw new T2000Error('RPC_ERROR', `Object ${jobId} is not an a2a_escrow Job.`);\n }\n const stateNum = Number(json.state ?? -1);\n const state = JOB_STATES[stateNum];\n if (!state) {\n throw new T2000Error('RPC_ERROR', `Job ${jobId} has unknown state ${stateNum}.`);\n }\n const deliveredAtMs = Number(json.delivered_at_ms ?? 0);\n const deliveryBytes = (json.delivery_hash ?? []) as number[] | Uint8Array;\n const hasDelivery = deliveredAtMs > 0;\n return {\n id: jobId,\n buyer: String(json.buyer),\n seller: String(json.seller),\n amountUsdc: Number(json.amount) / 10 ** USDC_DECIMALS,\n escrowUsdc: Number(json.escrow) / 10 ** USDC_DECIMALS,\n specHash: bytesToHex((json.spec_hash ?? []) as number[] | Uint8Array),\n deliverByMs: Number(json.deliver_by_ms),\n reviewWindowMs: Number(json.review_window_ms),\n rejectSplitBps: Number(json.reject_split_bps),\n state,\n deliveryHash: hasDelivery ? bytesToHex(deliveryBytes) : null,\n deliveredAtMs: hasDelivery ? deliveredAtMs : null,\n createdAtMs: Number(json.created_at_ms),\n };\n}\n\n/** What `caller` can do to `job` right now — drives `t2 job watch` (the\n * ACP-style \"available action\" readout) and any host UI. */\nexport function jobActionsFor(\n job: Job,\n caller: string,\n nowMs = Date.now(),\n): string[] {\n const me = validateAddress(caller);\n const isBuyer = me === job.buyer;\n const isSeller = me === job.seller;\n const actions: string[] = [];\n if (job.state === 'funded') {\n if (isSeller && nowMs <= job.deliverByMs) actions.push('deliver');\n if (isBuyer) actions.push('release');\n if (nowMs > job.deliverByMs) actions.push('refund');\n } else if (job.state === 'delivered') {\n const windowClosesMs = (job.deliveredAtMs ?? 0) + job.reviewWindowMs;\n if (isBuyer && nowMs <= windowClosesMs) actions.push('release', 'reject');\n if (nowMs > windowClosesMs) actions.push('release');\n }\n return actions;\n}\n\nexport interface JobVerification {\n ok: boolean;\n job: Job;\n /** Human-readable reasons when `ok` is false. */\n problems: string[];\n}\n\n/**\n * Seller-side escrow verification — the x402 `intent: \"escrow\"` credential\n * check. Before starting work on a job id received in an `X-PAYMENT` header,\n * the seller confirms ON-CHAIN (works for every buyer signer, incl. zkLogin):\n * funded, pays ME, covers the price, and leaves enough runway to deliver.\n */\nexport async function verifyJobForSeller({\n client,\n jobId,\n seller,\n minAmountUsdc,\n minRunwayMs = 60_000,\n}: {\n client: SuiCoreClient;\n jobId: string;\n seller: string;\n /** The listing's price for this job class. */\n minAmountUsdc: number;\n /** Minimum time-to-deadline to accept the job (default 60s). */\n minRunwayMs?: number;\n}): Promise<JobVerification> {\n const job = await getJob(client, jobId);\n const problems: string[] = [];\n if (job.state !== 'funded') {\n problems.push(`state is \"${job.state}\", expected \"funded\"`);\n }\n if (job.seller !== validateAddress(seller)) {\n problems.push(`job pays ${job.seller}, not this seller`);\n }\n if (job.escrowUsdc < minAmountUsdc) {\n problems.push(`escrow holds ${job.escrowUsdc} USDC, price is ${minAmountUsdc}`);\n }\n if (job.deliverByMs - Date.now() < minRunwayMs) {\n problems.push('deadline too close to accept');\n }\n return { ok: problems.length === 0, job, problems };\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/token-registry.ts","../src/wallet/coinSelection.ts","../src/wallet/keypairSigner.ts","../src/wallet/zkLoginSigner.ts","../src/wallet/pay.ts","../src/mpp-cost.ts","../src/wallet/executeTx.ts","../src/preflight.ts","../src/browser.ts","../src/constants.ts","../src/utils/sui.ts","../src/wallet/classify.ts","../src/wallet/history.ts","../src/utils/format.ts","../src/utils/base64.ts","../src/protocols/cetus-swap.ts","../src/wallet/send.ts","../src/wallet/job.ts"],"names":["T2000Error","COIN_REGISTRY","ETH_TYPE","IKA_TYPE","LOFI_TYPE","MANIFEST_TYPE","NAVX_TYPE","SUI_TYPE","TOKEN_MAP","USDC_TYPE","USDE_TYPE","USDSUI_TYPE","USDT_TYPE","WAL_TYPE","WBTC_TYPE","coinWithBalance","requested","swapAll","effectiveAmount","coin","Transaction","isValidSuiAddress","normalizeSuiAddress","fromBase64","result","buildCoinToAddressBalanceMigration","SuiGrpcClient","getDecimalsForCoinType","AggregatorClient","Env","CLOCK_ID"],"mappings":"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","file":"browser.cjs","sourcesContent":["export type T2000ErrorCode =\n | 'INSUFFICIENT_BALANCE'\n | 'ADDRESS_BALANCE_UNSPONSORABLE'\n | 'INSUFFICIENT_GAS'\n | 'INVALID_ADDRESS'\n | 'INVALID_AMOUNT'\n | 'WALLET_NOT_FOUND'\n | 'WALLET_LOCKED'\n | 'WALLET_EXISTS'\n | 'WALLET_CORRUPT'\n | 'INVALID_KEY'\n | 'SIMULATION_FAILED'\n | 'TRANSACTION_FAILED'\n | 'ASSET_NOT_SUPPORTED'\n | 'INVALID_ASSET'\n | 'PROTOCOL_UNAVAILABLE'\n | 'RPC_ERROR'\n | 'RPC_UNREACHABLE'\n | 'PRICE_EXCEEDS_LIMIT'\n | 'UNSUPPORTED_NETWORK'\n | 'PAYMENT_EXPIRED'\n | 'DUPLICATE_PAYMENT'\n | 'FACILITATOR_REJECTION'\n | 'CONTACT_NOT_FOUND'\n | 'INVALID_CONTACT_NAME'\n | 'SUINS_NOT_REGISTERED'\n | 'FACILITATOR_TIMEOUT'\n | 'SAFEGUARD_BLOCKED'\n | 'SWAP_NO_ROUTE'\n | 'SWAP_FAILED'\n | 'DIALECT_UNSUPPORTED'\n | 'CHAIN_MODE_INVALID'\n | 'INFERENCE_FAILED'\n | 'UNKNOWN';\n\nexport interface T2000ErrorData {\n reason?: string;\n [key: string]: unknown;\n}\n\nexport class T2000Error extends Error {\n readonly code: T2000ErrorCode;\n readonly data?: T2000ErrorData;\n readonly retryable: boolean;\n\n constructor(code: T2000ErrorCode, message: string, data?: T2000ErrorData, retryable = false) {\n super(message);\n this.name = 'T2000Error';\n this.code = code;\n this.data = data;\n this.retryable = retryable;\n }\n\n toJSON() {\n return {\n error: this.code,\n message: this.message,\n ...(this.data && { data: this.data }),\n retryable: this.retryable,\n };\n }\n}\n\nexport function mapWalletError(error: unknown): T2000Error {\n const msg = error instanceof Error ? error.message : String(error);\n\n if (msg.includes('rejected') || msg.includes('cancelled')) {\n return new T2000Error('TRANSACTION_FAILED', 'Transaction cancelled');\n }\n if (msg.includes('Insufficient') || msg.includes('insufficient')) {\n return new T2000Error('INSUFFICIENT_BALANCE', 'Insufficient balance');\n }\n\n return new T2000Error('UNKNOWN', msg, undefined, true);\n}\n\nexport function mapMoveAbortCode(code: number): string {\n const abortMessages: Record<number, string> = {\n 1: 'Protocol is temporarily paused',\n 2: 'Amount must be greater than zero',\n 3: 'Invalid operation type',\n 4: 'Fee rate exceeds maximum',\n 5: 'Insufficient treasury balance',\n 6: 'Not authorized',\n 7: 'Package version mismatch — upgrade required',\n 8: 'Timelock is active — wait for expiry',\n 9: 'No pending change to execute',\n 10: 'Already at current version',\n // NAVI Protocol abort codes\n 1502: 'Oracle price is stale — try again in a moment',\n 1503: 'Withdrawal amount is invalid (zero or dust) — try a specific amount instead of \"all\"',\n 1600: 'Health factor too low — withdrawal would risk liquidation',\n 1605: 'Asset borrowing is disabled or at capacity on this protocol',\n // NAVI utils abort codes\n 46000: 'Insufficient balance to repay — withdraw some savings first to get cash',\n };\n return abortMessages[code] ?? `Move abort code: ${code}`;\n}\n\n/**\n * Check if an error message contains a MoveAbort — these are on-chain\n * failures that will fail no matter how many times you retry.\n */\nexport function isMoveAbort(msg: string): boolean {\n return msg.includes('MoveAbort') || msg.includes('MovePrimitiveRuntimeError');\n}\n\nexport function parseMoveAbortMessage(msg: string): string {\n const abortMatch = msg.match(/abort code:\\s*(\\d+)/i) ?? msg.match(/MoveAbort[^,]*,\\s*(\\d+)/);\n if (abortMatch) {\n const code = parseInt(abortMatch[1], 10);\n\n const moduleMatch = msg.match(/Identifier\\(\"([^\"]+)\"\\)/) ?? msg.match(/in '([^']+)'/);\n const fnMatch = msg.match(/function_name:\\s*Some\\(\"([^\"]+)\"\\)/);\n const context = `${moduleMatch?.[1] ?? ''}${fnMatch ? `::${fnMatch[1]}` : ''}`.toLowerCase();\n const suffix = moduleMatch\n ? ` [${moduleMatch[1]}${fnMatch ? `::${fnMatch[1]}` : ''}]`\n : '';\n\n if (context.includes('slippage')) {\n return `Slippage too high — price moved during execution${suffix}`;\n }\n if (context.includes('balance::split') || context.includes('balance::ENotEnough')) {\n return `Insufficient on-chain balance${suffix}`;\n }\n\n const mapped = mapMoveAbortCode(code);\n return `${mapped}${suffix}`;\n }\n return msg;\n}\n","/**\n * Unified token registry — single source of truth for coin types, decimals,\n * and symbols. ZERO heavy dependencies; safe to import anywhere (server,\n * browser, Edge).\n *\n * Used for swap-by-symbol resolution, amount formatting (decimals), and\n * history/balance display. USDC is the settlement stable (send / receive /\n * x402 pay); everything else is holdable / swappable. There is no curated\n * \"tier\" gate — swaps accept any coin type (Cetus routes); the registry just\n * makes the common tokens ergonomic to reference by symbol.\n *\n * To add a token: add ONE entry to COIN_REGISTRY below — everything derives\n * from it.\n */\n\nexport interface CoinMeta {\n type: string;\n decimals: number;\n symbol: string;\n}\n\n/**\n * Canonical coin registry.\n * Key = user-friendly name (used in swap, CLI, prompts).\n */\nexport const COIN_REGISTRY: Record<string, CoinMeta> = {\n // ── Settlement stable ─────────────────────────────────────────────────\n USDC: { type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', decimals: 6, symbol: 'USDC' },\n\n // ── Common swap assets (symbol ergonomics — any coin type still swaps) ─\n SUI: { type: '0x2::sui::SUI', decimals: 9, symbol: 'SUI' },\n wBTC: { type: '0x0041f9f9344cac094454cd574e333c4fdb132d7bcc9379bcd4aab485b2a63942::wbtc::WBTC', decimals: 8, symbol: 'wBTC' },\n ETH: { type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH', decimals: 8, symbol: 'ETH' },\n GOLD: { type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM', decimals: 9, symbol: 'GOLD' },\n DEEP: { type: '0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP', decimals: 6, symbol: 'DEEP' },\n WAL: { type: '0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL', decimals: 9, symbol: 'WAL' },\n NS: { type: '0x5145494a5f5100e645e4b0aa950fa6b68f614e8c59e17bc5ded3495123a79178::ns::NS', decimals: 6, symbol: 'NS' },\n IKA: { type: '0x7262fb2f7a3a14c888c438a3cd9b912469a58cf60f367352c46584262e8299aa::ika::IKA', decimals: 9, symbol: 'IKA' },\n CETUS: { type: '0x06864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b::cetus::CETUS', decimals: 9, symbol: 'CETUS' },\n NAVX: { type: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX', decimals: 9, symbol: 'NAVX' },\n vSUI: { type: '0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT', decimals: 9, symbol: 'vSUI' },\n haSUI: { type: '0xbde4ba4c2e274a60ce15c1cfff9e5c42e41654ac8b6d906a57efa4bd3c29f47d::hasui::HASUI', decimals: 9, symbol: 'haSUI' },\n afSUI: { type: '0xf325ce1300e8dac124071d3152c5c5ee6174914f8bc2161e88329cf579246efc::afsui::AFSUI', decimals: 9, symbol: 'afSUI' },\n LOFI: { type: '0xf22da9a24ad027cccb5f2d496cbe91de953d363513db08a3a734d361c7c17503::LOFI::LOFI', decimals: 9, symbol: 'LOFI' },\n MANIFEST: { type: '0xc466c28d87b3d5cd34f3d5c088751532d71a38d93a8aae4551dd56272cfb4355::manifest::MANIFEST', decimals: 9, symbol: 'MANIFEST' },\n\n // ── Other stables (display / classification) ──────────────────────────\n USDT: { type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT', decimals: 6, symbol: 'USDT' },\n USDe: { type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE', decimals: 6, symbol: 'USDe' },\n USDSUI: { type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI', decimals: 6, symbol: 'USDsui' },\n};\n\n/** Reverse lookup: coin type → CoinMeta. Built once at import time. */\nconst BY_TYPE = new Map<string, CoinMeta>();\nfor (const meta of Object.values(COIN_REGISTRY)) {\n BY_TYPE.set(meta.type, meta);\n}\n\n// ── Lookup helpers ───────────────────────────────────────────────────────\n\n/**\n * Returns the registry metadata for a coin type, or `undefined` if the coin\n * is not in the registry. Used for canonical-symbol + decimal resolution.\n */\nexport function getCoinMeta(coinType: string): CoinMeta | undefined {\n return BY_TYPE.get(coinType);\n}\n\n/**\n * Returns true if the coin type appears in COIN_REGISTRY. Useful as a\n * canonical-symbol gate — e.g. so the registry's mixed-case `USDsui` wins\n * over a vendor feed's uppercase `USDSUI`.\n */\nexport function isInRegistry(coinType: string): boolean {\n return BY_TYPE.has(coinType);\n}\n\n// ── Lookup helpers ───────────────────────────────────────────────────────\n\n/**\n * Get decimals for any coin type. Checks full type match, then suffix match,\n * then defaults to 9. Works for any token, registered or not.\n */\nexport function getDecimalsForCoinType(coinType: string): number {\n const direct = BY_TYPE.get(coinType);\n if (direct) return direct.decimals;\n\n const suffix = coinType.split('::').slice(1).join('::').toUpperCase();\n if (suffix) {\n for (const meta of BY_TYPE.values()) {\n const metaSuffix = meta.type.split('::').slice(1).join('::').toUpperCase();\n if (metaSuffix === suffix) return meta.decimals;\n }\n }\n\n return 9;\n}\n\n/** Minimal structural client — just the coin-metadata read this needs. */\ninterface CoinMetadataClient {\n core: { getCoinMetadata: (opts: { coinType: string }) => Promise<unknown> };\n}\n\n/**\n * [2.11] Decimals for any coin type, resolved correctly for arbitrary tokens.\n * Registry tokens return their known decimals (no network). A coin type NOT in\n * the registry is read ON-CHAIN via coin metadata — never the 9-default guess,\n * because a wrong `from` decimal would corrupt a swap's input amount\n * (financial-amounts rule). Falls back to the registry heuristic only if the\n * on-chain read fails or returns no usable decimals.\n */\nexport async function resolveCoinDecimals(\n client: CoinMetadataClient,\n coinType: string,\n): Promise<number> {\n if (isInRegistry(coinType)) return getDecimalsForCoinType(coinType);\n try {\n const res = (await client.core.getCoinMetadata({ coinType })) as {\n metadata?: { decimals?: number };\n decimals?: number;\n };\n const d = res?.metadata?.decimals ?? res?.decimals;\n if (typeof d === 'number' && Number.isFinite(d)) return d;\n } catch {\n /* on-chain read failed — fall through to the registry heuristic */\n }\n return getDecimalsForCoinType(coinType);\n}\n\n/**\n * Resolve a full coin type to a user-friendly symbol.\n * Returns the last `::` segment if not in the registry.\n */\nexport function resolveSymbol(coinType: string): string {\n const direct = BY_TYPE.get(coinType);\n if (direct) return direct.symbol;\n\n const suffix = coinType.split('::').slice(1).join('::').toUpperCase();\n if (suffix) {\n for (const meta of BY_TYPE.values()) {\n const metaSuffix = meta.type.split('::').slice(1).join('::').toUpperCase();\n if (metaSuffix === suffix) return meta.symbol;\n }\n }\n\n return coinType.split('::').pop() ?? coinType;\n}\n\n/**\n * Name → type map for swap resolution. Derived from COIN_REGISTRY.\n * Contains BOTH original-case and UPPERCASE keys for case-insensitive lookup.\n */\nexport const TOKEN_MAP: Record<string, string> = (() => {\n const map: Record<string, string> = {};\n for (const [name, meta] of Object.entries(COIN_REGISTRY)) {\n map[name] = meta.type;\n map[name.toUpperCase()] = meta.type;\n }\n return map;\n})();\n\n/**\n * Resolve a user-friendly token name to its full coin type.\n * Returns the input unchanged if already a full coin type (contains \"::\").\n * Case-insensitive: 'usde', 'USDe', 'USDE' all resolve correctly.\n */\nexport function resolveTokenType(nameOrType: string): string | null {\n if (nameOrType.includes('::')) return nameOrType;\n return TOKEN_MAP[nameOrType] ?? TOKEN_MAP[nameOrType.toUpperCase()] ?? null;\n}\n\n/** Common type constants for direct import. */\nexport const SUI_TYPE = COIN_REGISTRY.SUI.type;\nexport const USDC_TYPE = COIN_REGISTRY.USDC.type;\nexport const USDT_TYPE = COIN_REGISTRY.USDT.type;\nexport const USDSUI_TYPE = COIN_REGISTRY.USDSUI.type;\nexport const USDE_TYPE = COIN_REGISTRY.USDe.type;\nexport const ETH_TYPE = COIN_REGISTRY.ETH.type;\nexport const WBTC_TYPE = COIN_REGISTRY.wBTC.type;\nexport const WAL_TYPE = COIN_REGISTRY.WAL.type;\nexport const NAVX_TYPE = COIN_REGISTRY.NAVX.type;\nexport const IKA_TYPE = COIN_REGISTRY.IKA.type;\nexport const LOFI_TYPE = COIN_REGISTRY.LOFI.type;\nexport const MANIFEST_TYPE = COIN_REGISTRY.MANIFEST.type;\n","/**\n * Wallet-side coin selection helpers — single source of truth for the\n * \"produce a `Coin<T>` argument holding `amount` raw units of `coinType`,\n * owned by `address`\" pattern. Used by every wallet-mode appender that\n * needs a coin input (save, send, swap, repay, stake, etc.).\n *\n * **2026-05-22 — address-balance migration.** Sui mainnet's address-balance\n * feature ships funds account-style instead of as discrete `Coin<T>` objects.\n * After a payment via `0x2::balance::send_funds`, the leftover lands in the\n * sender's address balance with a synthetic \"coin reservation\" representing\n * the deposit. `client.getCoins()` correctly filters those reservations out\n * (they aren't real owned objects), so the old fetch+merge+split pattern\n * threw `INSUFFICIENT_BALANCE` for users whose stables had drifted into\n * address balance — even when `getBalance().totalBalance` showed plenty.\n *\n * The fix is structural: hand the work to `coinWithBalance({ type, balance })`\n * from `@mysten/sui/transactions`. Its build-time resolver inspects coins +\n * address balance together (`getBalance` + `listCoins`), then emits the\n * right shape — direct `redeem_funds` from address balance when AB ≥\n * required, or merge-and-split across coins + AB withdrawal when not. Multi\n * intents per coin type get batched into a single merge in one PTB, so the\n * old per-PTB merge cache is no longer needed.\n *\n * Pre-flight uses `client.getBalance().totalBalance` (sums coins + AB)\n * instead of summing the paginated `getCoins` page. That's the OTHER half\n * of the migration — the legacy path could see `0` from `getCoins` and\n * mistakenly throw before `coinWithBalance` ever ran.\n */\nimport {\n Transaction,\n coinWithBalance,\n type TransactionObjectArgument,\n} from '@mysten/sui/transactions';\nimport type { SuiCoreClient } from '../utils/sui.js';\nimport { T2000Error } from '../errors.js';\n\nexport interface CoinPage {\n ids: string[];\n totalBalance: bigint;\n}\n\n/**\n * Sum every coin of `coinType` owned by `owner`, INCLUDING address balance.\n * Returns the IDs of any discrete coin objects that exist (callers\n * occasionally need this for non-`coinWithBalance` paths, e.g. SUIns name\n * registration which expects raw object IDs).\n *\n * Pre-2026-05-22 this function paginated `client.getCoins` and summed\n * the page balances. That misses address-balance funds (the SDK filters\n * them out of `getCoins` for back-compat). The new implementation calls\n * `getBalance` for the canonical total and `getCoins` for the optional\n * ID list — both round-trips, but they happen in parallel.\n */\nexport async function fetchAllCoins(\n client: SuiCoreClient,\n owner: string,\n coinType: string,\n): Promise<CoinPage> {\n const [balance, ids] = await Promise.all([\n client.core.getBalance({ owner, coinType }),\n (async () => {\n const out: string[] = [];\n let cursor: string | null | undefined;\n let hasNext = true;\n while (hasNext) {\n const page = await client.core.listCoins({ owner, coinType, cursor: cursor ?? undefined });\n for (const c of page.objects) out.push(c.objectId);\n cursor = page.cursor;\n hasNext = page.hasNextPage;\n }\n return out;\n })(),\n ]);\n return { ids, totalBalance: BigInt(balance.balance.balance) };\n}\n\nexport interface SelectAndSplitResult {\n /** TransactionObjectArgument for a coin holding `effectiveAmount` raw units. */\n coin: TransactionObjectArgument;\n /** Actual raw amount the returned coin holds. May be < requested if `swapAll` is true. */\n effectiveAmount: bigint;\n /** True iff the request consumed the entire wallet balance (no split needed). */\n swapAll: boolean;\n}\n\n/**\n * Wallet-mode coin selection prelude. Pre-flights against\n * `getBalance().totalBalance` (coins + address balance combined), then\n * returns a `coinWithBalance({ type, balance })` argument that the\n * `@mysten/sui` resolver fulfills at build time.\n *\n * Throws `T2000Error` (`INSUFFICIENT_BALANCE`) when:\n * - `amount` is bigger than the total balance AND the caller did NOT\n * opt into `swapAll: true` clipping.\n * - `amount === 'all'` AND total balance is zero.\n *\n * @param tx — PTB to register the `coinWithBalance` intent against.\n * @param client — Sui RPC client for the pre-flight `getBalance` lookup.\n * @param owner — wallet address whose coins to source from.\n * @param coinType — fully-qualified Sui coin type (e.g. `\"0x...::usdc::USDC\"`).\n * @param amount — raw amount to source (in MIST / smallest unit). Pass\n * `'all'` to consume the entire balance.\n * @param options.allowSwapAll — if true (default), `amount` >= totalBalance\n * auto-clips to total. If false, throws when the request would over-consume.\n * @param options.sponsoredContext — when true, source ONLY from discrete coin\n * objects (never the address balance). See the long note below — this exists\n * because Enoki's gas station can't yet deserialize a `TransactionData` that\n * contains the address-balance `FundsWithdrawal` reservation that\n * `coinWithBalance` emits. Self-funded callers leave this false: the fullnode\n * handles `FundsWithdrawal` fine, so the address-balance path is preferred\n * (it can reach funds that aren't held as coin objects).\n *\n * @returns\n * - `coin` — `TransactionObjectArgument` ready for downstream consumption.\n * - `effectiveAmount` — the raw amount the returned coin holds (handles\n * swapAll clipping).\n * - `swapAll` — true iff the entire balance was consumed.\n */\nexport async function selectAndSplitCoin(\n tx: Transaction,\n client: SuiCoreClient,\n owner: string,\n coinType: string,\n amount: bigint | 'all',\n options: {\n allowSwapAll?: boolean;\n sponsoredContext?: boolean;\n mergeCache?: SponsoredCoinMergeCache;\n } = {},\n): Promise<SelectAndSplitResult> {\n // [2026-05-30] Sponsored Enoki path — coin objects only. `coinWithBalance`\n // reaches into the address balance (mysten Address Balances feature) when\n // `addressBalance >= required`, emitting `0x2::coin::redeem_funds` + a\n // `FundsWithdrawal` reservation input. That input is a newer `TransactionData`\n // field; Enoki's sponsor endpoint accepts the kind bytes (200) but its gas\n // station rejects the assembled `TransactionData` at execute with\n // \"Invalid bcs bytes for TransactionData\". The fullnode parses it fine — only\n // Enoki can't (yet). So under sponsorship we source from discrete coin objects\n // and surface a clear error when the user's funds are address-balance-only.\n // See github.com/mission69b/t2000 issue #93.\n if (options.sponsoredContext) {\n return selectCoinObjectsOnly(\n tx,\n client,\n owner,\n coinType,\n amount,\n options.allowSwapAll ?? true,\n options.mergeCache,\n );\n }\n\n const balanceResp = await client.core.getBalance({ owner, coinType });\n const totalBalance = BigInt(balanceResp.balance.balance);\n\n if (totalBalance === 0n) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `No balance found for ${coinType}`);\n }\n\n const allowSwapAll = options.allowSwapAll ?? true;\n\n if (amount !== 'all' && amount > totalBalance && !allowSwapAll) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `Insufficient balance for ${coinType}`, {\n available: totalBalance.toString(),\n required: amount.toString(),\n });\n }\n\n const requested = amount === 'all' ? totalBalance : amount;\n const swapAll = amount === 'all' || requested >= totalBalance;\n const effectiveAmount = swapAll ? totalBalance : requested;\n\n const coin = coinWithBalance({ type: coinType, balance: effectiveAmount })(tx);\n\n return { coin, effectiveAmount, swapAll };\n}\n\n/**\n * Coin-object-only selection for sponsored (Enoki) transactions. Fetches the\n * owner's discrete `Coin<T>` objects (NOT the address balance — `getCoins`\n * excludes it), merges them, and splits the requested amount. Never emits a\n * `FundsWithdrawal` reservation, so the resulting `TransactionData` stays on\n * the shape Enoki's gas station can serialize.\n *\n * Throws `ADDRESS_BALANCE_UNSPONSORABLE` when the coin objects don't cover the\n * request — which, for a user whose `getBalance().totalBalance` shows funds,\n * means those funds live in the address balance (e.g. received via a gasless\n * stablecoin transfer) and can't be moved through a sponsored transaction yet.\n */\n/**\n * Per-PTB cache of merged sponsored coin-object primaries, keyed by coin\n * type. The FIRST `selectCoinObjectsOnly` call for a given coin type in a\n * PTB fetches the owner's discrete `Coin<T>` objects, merges them into one\n * `primary`, and records it here alongside the remaining (unspent) balance.\n * EVERY subsequent leg sourcing the same coin type splits from that cached\n * `primary` instead of re-fetching + re-merging.\n *\n * Why this exists (S.xxx, 2026-06-02): a sponsored bundle with 2+ legs\n * sourcing the same coin (e.g. `SUI→WAL` + `SUI→DEEP`, or `swap USDC` +\n * `save USDC`) called `selectCoinObjectsOnly` once per leg. Each call\n * emitted its own `mergeCoins` over the SAME coin objects, so the second\n * leg's merge referenced coins the first leg already consumed → Enoki\n * dry-run failed with `CommandArgumentError { ArgumentWithoutValue }`.\n *\n * This is NOT SUI-specific. Under sponsorship, `selectAndSplitCoin` routes\n * EVERY asset through `selectCoinObjectsOnly` (the `coinWithBalance`\n * batching that would otherwise dedup these merges only runs for\n * non-sponsored CLI/direct flows — its address-balance `FundsWithdrawal`\n * reservation is what Enoki can't deserialize, issue #93). So the cache is\n * the dedup layer for ALL coin types in a sponsored multi-leg PTB, keyed\n * by coin type. SUI was simply the first asset observed failing in the\n * wild because it's the most common swap source.\n */\nexport type SponsoredCoinMergeCache = Map<\n string,\n { primary: TransactionObjectArgument; remaining: bigint }\n>;\n\nasync function selectCoinObjectsOnly(\n tx: Transaction,\n client: SuiCoreClient,\n owner: string,\n coinType: string,\n amount: bigint | 'all',\n allowSwapAll: boolean,\n mergeCache?: SponsoredCoinMergeCache,\n): Promise<SelectAndSplitResult> {\n // Cache hit — a prior leg in THIS PTB already merged this coin type's\n // objects into `cached.primary`. Re-running the fetch+merge below would\n // emit a second `mergeCoins` over already-consumed coins → dry-run\n // `ArgumentWithoutValue`. Split from the cached primary instead.\n const cached = mergeCache?.get(coinType);\n if (cached) {\n const requested = amount === 'all' ? cached.remaining : amount;\n if (cached.remaining === 0n || requested > cached.remaining) {\n throw new T2000Error(\n 'ADDRESS_BALANCE_UNSPONSORABLE',\n `Not enough ${coinType} in coin objects to cover all legs of this ` +\n `sponsored bundle. The remaining funds are in your address balance, ` +\n `which sponsored transactions can't access yet.`,\n { remaining: cached.remaining.toString(), requested: requested.toString(), coinType },\n );\n }\n const swapAll = amount === 'all' || requested >= cached.remaining;\n const effectiveAmount = swapAll ? cached.remaining : requested;\n const coin = swapAll\n ? cached.primary\n : tx.splitCoins(cached.primary, [effectiveAmount])[0];\n cached.remaining -= effectiveAmount;\n return { coin, effectiveAmount, swapAll };\n }\n\n const objects: { objectId: string; balance: bigint }[] = [];\n let coinObjectTotal = 0n;\n let cursor: string | null | undefined;\n let hasNext = true;\n while (hasNext) {\n const page = await client.core.listCoins({ owner, coinType, cursor: cursor ?? undefined });\n for (const c of page.objects) {\n objects.push({ objectId: c.objectId, balance: BigInt(c.balance) });\n coinObjectTotal += BigInt(c.balance);\n }\n cursor = page.cursor;\n hasNext = page.hasNextPage;\n }\n\n const unsponsorable = (): T2000Error =>\n new T2000Error(\n 'ADDRESS_BALANCE_UNSPONSORABLE',\n `These funds are in your address balance, which sponsored transactions ` +\n `can't access yet. (Funds received via gasless transfers land there.) ` +\n `This will work once the gas sponsor adds address-balance support.`,\n { coinObjectTotal: coinObjectTotal.toString(), coinType },\n );\n\n if (coinObjectTotal === 0n) {\n throw unsponsorable();\n }\n\n const requested = amount === 'all' ? coinObjectTotal : amount;\n if (requested > coinObjectTotal) {\n // Not enough in coin objects. If the caller allows clipping to the\n // available coin-object total (\"swap all\"), do so; otherwise the shortfall\n // is sitting in the address balance → unsponsorable.\n if (allowSwapAll && amount === 'all') {\n // unreachable (requested === coinObjectTotal here) — kept for clarity.\n } else {\n throw unsponsorable();\n }\n }\n\n const swapAll = amount === 'all' || requested >= coinObjectTotal;\n const effectiveAmount = swapAll ? coinObjectTotal : requested;\n\n const [first, ...rest] = objects;\n const primary = tx.object(first.objectId);\n if (rest.length > 0) {\n tx.mergeCoins(\n primary,\n rest.map((o) => tx.object(o.objectId)),\n );\n }\n\n // Consume the whole merged coin when taking everything; otherwise split the\n // exact amount and leave the remainder on the (sender-owned) primary coin.\n const coin = swapAll ? primary : tx.splitCoins(primary, [effectiveAmount])[0];\n\n // Record the merged primary so later legs in the same PTB reuse it\n // rather than re-fetching + re-merging the same (now-consumed) coins.\n // When `swapAll`, the primary was consumed (remaining 0) — a later leg\n // hitting the cache then throws the unsponsorable shortfall above.\n mergeCache?.set(coinType, {\n primary,\n remaining: coinObjectTotal - effectiveAmount,\n });\n\n return { coin, effectiveAmount, swapAll };\n}\n\n/**\n * Build a GASLESS coin→address-balance migration.\n *\n * Sends WHOLE `Coin<T>` objects to `owner`'s OWN SIP-58 address balance via\n * `0x2::coin::send_funds(coin, owner)` — one allowlisted framework MoveCall\n * per coin, with NO native `SplitCoins` / `MergeCoins` commands. That shape is\n * what makes it gasless: the gRPC build resolver only zeros gas for PTBs whose\n * every command is a MoveCall into the `0x2` gasless allowlist (`send_funds` /\n * `redeem_funds` / `withdrawal_split` / `into_balance`). The same eligibility\n * the gasless `balance::send_funds` send + the x402 `redeem_funds`+`send_funds`\n * withdrawal rely on. (The old migration merged+split first → native commands →\n * fell outside the allowlist → needed SUI. See `pay.ts ensureAddressBalanceCovers`.)\n *\n * Selects the FEWEST coins (largest first) whose combined balance covers\n * `minAmount`, minimizing the MoveCall count. Over-migration is harmless — the\n * surplus just lands in the address balance. Pure / network-free: callers pass\n * coins they've already fetched, so this is unit-testable offline.\n *\n * Throws `INSUFFICIENT_BALANCE` when the supplied coin objects can't cover\n * `minAmount`.\n */\nexport function buildCoinToAddressBalanceMigration(args: {\n coins: { objectId: string; balance: bigint }[];\n coinType: string;\n owner: string;\n minAmount: bigint;\n}): { tx: Transaction; migratedRaw: bigint } {\n const { coins, coinType, owner, minAmount } = args;\n\n // Largest first → fewest whole-coin sends to cover the shortfall.\n const sorted = [...coins]\n .filter((c) => c.balance > 0n)\n .sort((a, b) => (b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0));\n\n const selected: { objectId: string; balance: bigint }[] = [];\n let migratedRaw = 0n;\n for (const c of sorted) {\n if (migratedRaw >= minAmount) break;\n selected.push(c);\n migratedRaw += c.balance;\n }\n\n if (migratedRaw < minAmount) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `Insufficient ${coinType} coin objects to migrate`, {\n available: migratedRaw.toString(),\n required: minAmount.toString(),\n });\n }\n\n const tx = new Transaction();\n for (const c of selected) {\n tx.moveCall({\n target: '0x2::coin::send_funds',\n typeArguments: [coinType],\n arguments: [tx.object(c.objectId), tx.pure.address(owner)],\n });\n }\n return { tx, migratedRaw };\n}\n\n/**\n * SUI-specific coin selection. Branches on sponsorship context:\n *\n * - **Self-funded (`sponsoredContext: false`)** — splits from `tx.gas`\n * directly (the user's gas coin IS their SUI). More efficient — no\n * `getBalance` RTT.\n *\n * - **Sponsored (`sponsoredContext: true`)** — sources from the user's\n * discrete SUI coin objects (`selectCoinObjectsOnly`). This both (a) avoids\n * `tx.gas`, which belongs to the Enoki sponsor — NOT the user — under\n * sponsored flows (the original S.260 reason for `useGasCoin: false`), AND\n * (b) avoids `coinWithBalance`'s address-balance `FundsWithdrawal`, which\n * Enoki's gas station can't deserialize (issue #93). If the user's SUI is\n * address-balance-only, it raises `ADDRESS_BALANCE_UNSPONSORABLE`.\n */\nexport async function selectSuiCoin(\n tx: Transaction,\n client: SuiCoreClient,\n owner: string,\n amountMist: bigint,\n sponsoredContext: boolean,\n mergeCache?: SponsoredCoinMergeCache,\n): Promise<SelectAndSplitResult> {\n if (sponsoredContext) {\n const { SUI_TYPE } = await import('../token-registry.js');\n return selectCoinObjectsOnly(tx, client, owner, SUI_TYPE, amountMist, false, mergeCache);\n }\n\n const [coin] = tx.splitCoins(tx.gas, [amountMist]);\n return { coin, effectiveAmount: amountMist, swapAll: false };\n}\n","import type { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\nimport type { TransactionSigner } from '../signer.js';\n\nexport class KeypairSigner implements TransactionSigner {\n readonly kind = 'keypair' as const;\n\n constructor(private readonly keypair: Ed25519Keypair) {}\n\n getAddress(): string {\n return this.keypair.getPublicKey().toSuiAddress();\n }\n\n async signTransaction(txBytes: Uint8Array): Promise<{ signature: string }> {\n return this.keypair.signTransaction(txBytes);\n }\n\n async signPersonalMessage(messageBytes: Uint8Array): Promise<{ signature: string; bytes: string }> {\n return this.keypair.signPersonalMessage(messageBytes);\n }\n\n /** Access the underlying keypair for APIs that still require it directly. */\n getKeypair(): Ed25519Keypair {\n return this.keypair;\n }\n}\n","import type { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';\nimport type { TransactionSigner } from '../signer.js';\n\nexport interface ZkLoginProof {\n proofPoints: {\n a: string[];\n b: string[][];\n c: string[];\n };\n issBase64Details: {\n indexMod4: number;\n value: string;\n };\n headerBase64: string;\n addressSeed: string;\n}\n\nexport class ZkLoginSigner implements TransactionSigner {\n readonly kind = 'zklogin' as const;\n\n constructor(\n private readonly ephemeralKeypair: Ed25519Keypair,\n private readonly zkProof: ZkLoginProof,\n private readonly userAddress: string,\n private readonly maxEpoch: number,\n ) {}\n\n getAddress(): string {\n return this.userAddress;\n }\n\n async signTransaction(txBytes: Uint8Array): Promise<{ signature: string }> {\n const { getZkLoginSignature } = await import('@mysten/zklogin');\n const ephSig = await this.ephemeralKeypair.signTransaction(txBytes);\n return {\n signature: getZkLoginSignature({\n inputs: this.zkProof,\n maxEpoch: this.maxEpoch,\n userSignature: ephSig.signature,\n }),\n };\n }\n\n async signPersonalMessage(messageBytes: Uint8Array): Promise<{ signature: string; bytes: string }> {\n const { getZkLoginSignature } = await import('@mysten/zklogin');\n const { signature: ephSig, bytes } = await this.ephemeralKeypair.signPersonalMessage(messageBytes);\n return {\n signature: getZkLoginSignature({\n inputs: this.zkProof,\n maxEpoch: this.maxEpoch,\n userSignature: ephSig,\n }),\n bytes,\n };\n }\n\n isExpired(currentEpoch: number): boolean {\n return currentEpoch >= this.maxEpoch;\n }\n}\n","import type { SuiGrpcClient } from '@mysten/sui/grpc';\nimport { fromBase64 } from '@mysten/sui/utils';\nimport type { X402Requirements } from '@suimpp/mpp/x402';\nimport type { TransactionSigner } from '../signer.js';\nimport type { PayOptions, PayResult } from '../types.js';\nimport { T2000Error } from '../errors.js';\nimport { parseChallengeAmount } from '../mpp-cost.js';\nimport { executeTx } from './executeTx.js';\nimport {\n type PreflightResult,\n PREFLIGHT_OK,\n preflightFail,\n checkPositiveAmount,\n} from '../preflight.js';\n\n/**\n * Synchronous, network-free preflight for `pay` (x402 Service call). Validates\n * the target URL shape and the `maxPrice` ceiling when present — the cheap\n * checks the v3 host runs before dispatching the paid tool / showing the\n * tap-to-confirm card. Returns a `PreflightResult`; never throws. The probe +\n * 402 handshake + balance migration stay in `payWithMpp` (network).\n */\nexport function preflightPay(input: { url: string; maxPrice?: number }): PreflightResult {\n if (typeof input.url !== 'string' || input.url.trim() === '') {\n return preflightFail('FACILITATOR_REJECTION', 'A target URL is required to pay');\n }\n let parsed: URL;\n try {\n parsed = new URL(input.url);\n } catch {\n return preflightFail('FACILITATOR_REJECTION', `Invalid URL: ${input.url}`);\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return preflightFail(\n 'FACILITATOR_REJECTION',\n `URL must be http(s): got ${parsed.protocol}//`,\n );\n }\n // `maxPrice` is optional (no ceiling = pay whatever the 402 asks). Validate\n // only when the caller set one — a malformed ceiling is a fat-finger.\n if (input.maxPrice !== undefined) {\n const priceCheck = checkPositiveAmount(input.maxPrice, 'maxPrice');\n if (!priceCheck.valid) return priceCheck;\n }\n return PREFLIGHT_OK;\n}\n\n// ---------------------------------------------------------------------------\n// payWithMpp — the SDK's single source of truth for the pay loop. Browser-safe\n// (no fs / keyManager / SafeguardEnforcer), so the Audric client can run it\n// in-browser on the zkLogin session key. `T2000.pay()` delegates here.\n//\n// TWO dialects, ONE preference order (both ride the SAME gasless\n// `send_funds<USDC>` rail; the only difference is who submits):\n//\n// 1. x402 `sui-exact` (preferred — SPEC_AGENT_PAYMENTS_X402 1.2; scheme =\n// SUIMPP_X402_SCHEME.md v0.3): the 402 body carries `accepts[]`; the\n// client signs an authorization, the SERVER settles (settle-then-serve,\n// so a failed upstream is never charged). The withdrawal form draws from\n// the SIP-58 address balance, so coin-object funds are migrated in first\n// when needed (S.414 finding).\n//\n// 2. MPP header dialect (fallback — suimpp.dev/spec): the 402 carries only a\n// `WWW-Authenticate: Payment … method=\"sui\"` challenge, no x402 body. The\n// CLIENT broadcasts the gasless USDC transfer and retries with the digest\n// credential. S.452 retired this path assuming all sellers were our\n// gateway (which dual-serves); the first EXTERNAL seller (JMPR, S.453)\n// shipped header-only — the client must speak everything the gateway and\n// suimpp spec serve, so the fallback is back. Trade-off vs x402: the\n// client pays BEFORE the server proves it can deliver, so a broken seller\n// can charge without serving — x402 stays preferred whenever offered.\n// ---------------------------------------------------------------------------\n\nexport async function payWithMpp(args: {\n signer: TransactionSigner;\n client: SuiGrpcClient;\n options: PayOptions;\n}): Promise<PayResult> {\n const { signer, client } = args;\n let options = args.options;\n\n // Layer 2 — cheap synchronous preflight (URL shape + maxPrice sanity) before\n // any network round-trip. Rethrow the precise code+message verbatim.\n const pf = preflightPay({ url: options.url, maxPrice: options.maxPrice });\n if (!pf.valid) throw new T2000Error(pf.code, pf.error);\n\n const method = (options.method ?? 'GET').toUpperCase();\n const canHaveBody = method !== 'GET' && method !== 'HEAD';\n\n // Default `content-type: application/json` when the body IS JSON and the\n // caller didn't say otherwise. Without it, fetch stamps `text/plain` and\n // strict servers (FastAPI et al.) receive the body as a string — a 422\n // before the 402 ever fires (live finding vs JMPR, the first external\n // seller). Every retry below reads from the normalized `options`.\n if (\n canHaveBody &&\n typeof options.body === 'string' &&\n isJsonText(options.body) &&\n !hasContentType(options.headers)\n ) {\n options = {\n ...options,\n headers: { ...(options.headers ?? {}), 'content-type': 'application/json' },\n };\n }\n\n const reqInit: RequestInit = {\n method,\n headers: options.headers,\n body: canHaveBody ? options.body : undefined,\n };\n\n // Probe (no payment). A paid endpoint answers 402; a free/cached one serves.\n const probe = await fetch(options.url, reqInit);\n if (probe.status !== 402) {\n return finalize(probe, { paid: false });\n }\n\n const requirements = await pickSuiExactRequirements(probe, client.network);\n if (requirements) {\n const result = await payViaX402({ signer, client, options, reqInit, requirements });\n await reportDirectPayment(result, options.url);\n return result;\n }\n\n // No x402 envelope — fall back to the MPP header dialect when the 402\n // advertises a `sui` method challenge.\n const headerChallenge = await parseMppSuiChallenge(probe);\n if (headerChallenge) {\n // Fail CLOSED before any money moves: the header dialect pays first and\n // proves identity with a personal-message signature the SELLER verifies.\n // zkLogin signatures are ZK constructs external sellers can't check —\n // the payment settles on-chain, then the retry 402s and the buyer ate\n // the charge (live: JMPR × Audric Passport, 2026-07-17). x402 is immune\n // (the tx itself carries the zkLogin sig; the CHAIN verifies it), so\n // zkLogin payers require sellers that offer x402.\n if (signer.kind === 'zklogin') {\n throw new T2000Error(\n 'DIALECT_UNSUPPORTED',\n 'This seller only offers the MPP header dialect, which zkLogin (Passport) wallets ' +\n 'cannot safely pay: the seller cannot verify zkLogin signatures, so the payment ' +\n 'would settle on-chain without the service delivering. No payment was made. ' +\n 'Use an x402-capable service, or pay from a keypair wallet (t2 CLI / MCP).',\n { dialect: 'mpp-header', signerKind: 'zklogin' },\n );\n }\n const result = await payViaMppHeader({ signer, client, options });\n await reportDirectPayment(result, options.url);\n return result;\n }\n\n throw new T2000Error(\n 'FACILITATOR_REJECTION',\n `Endpoint returned 402 without an x402 'exact' / sui:${client.network} requirement in the body ` +\n `or an MPP 'sui' challenge in WWW-Authenticate. Nothing this SDK can pay.`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Direct-seller activity reporting (S.743). Gateway-proxied payments are\n// logged server-side by the gateway itself; DIRECT payments (catalog\n// federation — seller's own origin) never touch it, leaving the activity\n// feed blind. After a paid call to a non-gateway origin, tell the gateway\n// \"look at this digest for this url\" — it verifies on-chain (USDC inflow to\n// the cataloged seller's pinned payTo) before recording, so the report\n// carries no trusted data. Best-effort by construction: timeout-capped and\n// error-swallowed, a lost report never fails or delays the payment. Awaited\n// (not fire-and-forget) so short-lived CLI processes don't drop it on exit.\n// ---------------------------------------------------------------------------\n\nconst MPP_REPORT_URL = 'https://mpp.t2000.ai/api/mpp/report';\nconst REPORT_TIMEOUT_MS = 2_000;\n\nasync function reportDirectPayment(result: PayResult, url: string): Promise<void> {\n if (!result.paid || !result.receipt?.reference) return;\n try {\n if (new URL(url).origin === new URL(MPP_REPORT_URL).origin) return;\n await fetch(MPP_REPORT_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ digest: result.receipt.reference, url }),\n signal: AbortSignal.timeout(REPORT_TIMEOUT_MS),\n });\n } catch {\n // Best-effort: the payment already succeeded; the feed row is analytics.\n }\n}\n\n/**\n * Parse the MPP header dialect from a 402 response: the\n * `WWW-Authenticate: Payment …` challenge(s), looking for `method=\"sui\"`.\n * Returns the decoded `{ amount, currency, recipient }` request (amount is a\n * decimal string, e.g. \"0.02\") or `undefined` when the response carries no\n * sui challenge. Exported for the CLI's `t2 pay --estimate`.\n */\nexport async function parseMppSuiChallenge(\n response: Response,\n): Promise<{ amount: string; currency: string; recipient: string; description?: string } | undefined> {\n try {\n const { Challenge } = await import('mppx');\n const challenges = Challenge.fromResponseList(response);\n const suiChallenge = challenges.find((c) => c.method === 'sui' && c.intent === 'charge');\n if (!suiChallenge) return undefined;\n const req = suiChallenge.request as Record<string, unknown>;\n if (typeof req?.amount !== 'string' || typeof req?.recipient !== 'string') return undefined;\n return {\n amount: req.amount,\n currency: typeof req.currency === 'string' ? req.currency : '',\n recipient: req.recipient,\n description: suiChallenge.description,\n };\n } catch {\n return undefined;\n }\n}\n\n// ---------------------------------------------------------------------------\n// x402 `sui-exact` — sign-then-settle\n// ---------------------------------------------------------------------------\n\nasync function pickSuiExactRequirements(\n response: Response,\n network: string,\n): Promise<X402Requirements | undefined> {\n try {\n const body = (await response.clone().json()) as { accepts?: X402Requirements[] };\n const want = `sui:${network === 'testnet' ? 'testnet' : 'mainnet'}`;\n return body.accepts?.find((a) => a.scheme === 'exact' && a.network === want);\n } catch {\n return undefined;\n }\n}\n\nasync function payViaX402(args: {\n signer: TransactionSigner;\n client: SuiGrpcClient;\n options: PayOptions;\n reqInit: RequestInit;\n requirements: X402Requirements;\n}): Promise<PayResult> {\n const { signer, client, options, reqInit, requirements } = args;\n const { buildX402SignedPayment, X402_PAYMENT_HEADER, X402_PAYMENT_RESPONSE_HEADER } = await import(\n '@suimpp/mpp/x402'\n );\n\n const amountRaw = BigInt(requirements.maxAmountRequired);\n assertWithinMaxPrice(atomicToHuman(amountRaw, await assetDecimals(requirements.asset)), options.maxPrice);\n\n // The x402 withdrawal form spends ONLY the SIP-58 address balance. A wallet\n // funded by ordinary coin transfers (or swap output) holds Coin<USDC>\n // objects → migrate enough in first (S.414 finding; SUIMPP_X402_SCHEME §4).\n const migrationGasSui = await ensureAddressBalanceCovers({\n signer,\n client,\n asset: requirements.asset,\n amountRaw,\n });\n\n // Build + sign — NEVER submitted client-side; the gateway settles. The\n // builder only reads toSuiAddress() + signTransaction(), both of which every\n // TransactionSigner (keypair AND zkLogin) provides.\n const signerAdapter = {\n toSuiAddress: () => signer.getAddress(),\n signTransaction: (bytes: Uint8Array) => signer.signTransaction(bytes),\n } as unknown as Parameters<typeof buildX402SignedPayment>[0]['signer'];\n\n const { header } = await buildX402SignedPayment({ requirements, signer: signerAdapter });\n\n const res = await fetch(options.url, {\n ...reqInit,\n headers: { ...(options.headers ?? {}), [X402_PAYMENT_HEADER]: header },\n });\n\n // Settled iff the gateway returned the x402 receipt header.\n const settleHeader = res.headers.get(X402_PAYMENT_RESPONSE_HEADER);\n const paid = !!settleHeader;\n let digest: string | undefined;\n if (settleHeader) {\n try {\n digest = (JSON.parse(new TextDecoder().decode(fromBase64(settleHeader))) as { transaction?: string })\n .transaction;\n } catch {\n digest = undefined;\n }\n }\n\n const result = await finalize(res, { paid });\n if (!paid) return { ...result, dialect: 'x402' };\n return {\n ...result,\n dialect: 'x402',\n cost: atomicToHuman(amountRaw, await assetDecimals(requirements.asset)),\n gasCostSui: migrationGasSui,\n receipt: digest\n ? { reference: digest, timestamp: new Date().toISOString() }\n : result.receipt,\n };\n}\n\n// ---------------------------------------------------------------------------\n// MPP header dialect — client broadcasts, retries with the digest credential.\n// The pre-S.452 `payViaLegacy`, restored (S.453) for header-only external\n// sellers. mppx's client handles the 402 → pay → retry loop; we plug in the\n// Sui charge method with an `execute` override that routes the on-chain leg\n// through `executeTx` (gRPC build → gasless resolver → the same\n// `send_funds<USDC>` rail as x402).\n// ---------------------------------------------------------------------------\n\nasync function payViaMppHeader(args: {\n signer: TransactionSigner;\n client: SuiGrpcClient;\n options: PayOptions;\n}): Promise<PayResult> {\n const { signer, client, options } = args;\n\n const { Mppx } = await import('mppx/client');\n const { sui, USDC, USDC_TESTNET } = await import('@suimpp/mpp/client');\n\n const signerAddress = signer.getAddress();\n const network: 'mainnet' | 'testnet' = client.network === 'testnet' ? 'testnet' : 'mainnet';\n const grpcClient = await makeGrpcBuildClient(client);\n\n let paymentDigest: string | undefined;\n let gasCostSui = 0;\n // The real amount charged on-chain is the 402 challenge price (a decimal\n // USDC string like \"0.01\"), NOT the caller's `maxPrice` ceiling (Bug 1,\n // dogfood 2026-05-31). Capture it in `onChallenge` — and enforce the\n // ceiling THERE, before any credential is created: the header dialect pays\n // client-side, so this hook is the last stop before money moves.\n let chargedAmount: number | undefined;\n\n const mppx = Mppx.create({\n polyfill: false,\n onChallenge: async (challenge: { request?: { amount?: unknown } }) => {\n const parsed = parseChallengeAmount(challenge);\n if (parsed !== undefined) {\n chargedAmount = parsed;\n assertWithinMaxPrice(parsed, options.maxPrice);\n }\n return undefined;\n },\n methods: [\n sui({\n client,\n currency: network === 'testnet' ? USDC_TESTNET : USDC,\n signer: {\n toSuiAddress: () => signerAddress,\n signPersonalMessage: (bytes: Uint8Array) => signer.signPersonalMessage(bytes),\n } as unknown as Parameters<typeof sui>[0]['signer'],\n execute: async (tx) => {\n const result = await executeTx(client, signer, () => tx, { buildClient: grpcClient });\n paymentDigest = result.digest;\n gasCostSui = result.gasCostSui;\n return { digest: result.digest };\n },\n }),\n ],\n });\n\n const method = (options.method ?? 'GET').toUpperCase();\n const canHaveBody = method !== 'GET' && method !== 'HEAD';\n\n const response = await mppx.fetch(options.url, {\n method,\n headers: options.headers,\n body: canHaveBody ? options.body : undefined,\n });\n\n const paid = !!paymentDigest;\n const result = await finalize(response, { paid });\n if (!paid) return { ...result, dialect: 'legacy' };\n return {\n ...result,\n dialect: 'legacy',\n cost: chargedAmount ?? options.maxPrice ?? undefined,\n gasCostSui,\n receipt: paymentDigest\n ? { reference: paymentDigest, timestamp: new Date().toISOString() }\n : undefined,\n };\n}\n\n/** Throw `PRICE_EXCEEDS_LIMIT` when the challenge price exceeds the caller's\n * `maxPrice` ceiling (no ceiling = pay whatever the 402 asks). */\nfunction assertWithinMaxPrice(price: number, maxPrice: number | undefined): void {\n if (maxPrice !== undefined && price > maxPrice) {\n throw new T2000Error(\n 'PRICE_EXCEEDS_LIMIT',\n `Service price $${price} exceeds maxPrice ceiling $${maxPrice}`,\n { price, maxPrice },\n );\n }\n}\n\n/**\n * Ensure the sender's SIP-58 address balance covers `amountRaw` of `asset`.\n * Returns the SUI gas spent migrating (0 when no migration was needed or the\n * migration was gasless). Throws `INSUFFICIENT_BALANCE` when the wallet\n * doesn't hold enough of the asset at all (coins + address balance combined).\n */\nasync function ensureAddressBalanceCovers(args: {\n signer: TransactionSigner;\n client: SuiGrpcClient;\n asset: string;\n amountRaw: bigint;\n}): Promise<number> {\n const { signer, client, asset, amountRaw } = args;\n const owner = signer.getAddress();\n\n // total = coins + address balance (the canonical combined read)\n const balanceResp = await client.core.getBalance({ owner, coinType: asset });\n const total = BigInt(balanceResp.balance.balance);\n if (total < amountRaw) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `Insufficient ${asset} to pay`, {\n available: total.toString(),\n required: amountRaw.toString(),\n });\n }\n\n // address balance = total − discrete coin-object sum (listCoins excludes AB).\n // Collect the coin objects too — we reuse them to build the migration.\n const coins: { objectId: string; balance: bigint }[] = [];\n let coinSum = 0n;\n let cursor: string | null | undefined;\n let hasNext = true;\n while (hasNext) {\n const page = await client.core.listCoins({ owner, coinType: asset, cursor: cursor ?? undefined });\n for (const c of page.objects) {\n coins.push({ objectId: c.objectId, balance: BigInt(c.balance) });\n coinSum += BigInt(c.balance);\n }\n cursor = page.cursor;\n hasNext = page.hasNextPage;\n }\n const addressBalance = total - coinSum;\n if (addressBalance >= amountRaw) return 0; // address balance already covers it\n\n // Move the shortfall from coin objects into the address balance by sending\n // WHOLE coin objects to self via `0x2::coin::send_funds` — one allowlisted\n // framework MoveCall per coin, NO native merge/split. Built on the gRPC\n // client so its resolver detects the all-allowlisted-MoveCall shape and zeros\n // gas: the migration itself is gasless (the same eligibility the x402\n // withdrawal + the gasless send rely on). The old merge+split+send shape had\n // native `SplitCoins`/`MergeCoins` commands → fell outside the allowlist →\n // forced SUI gas, breaking coin-object holders with 0 SUI.\n const shortfall = amountRaw - addressBalance;\n const { buildCoinToAddressBalanceMigration } = await import('./coinSelection.js');\n const grpcClient = await makeGrpcBuildClient(client);\n const { tx } = buildCoinToAddressBalanceMigration({ coins, coinType: asset, owner, minAmount: shortfall });\n const migration = await executeTx(client, signer, () => tx, { buildClient: grpcClient });\n return migration.gasCostSui;\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\n/** Cheap \"is this JSON?\" check — parse, don't guess from the first char. */\nfunction isJsonText(text: string): boolean {\n try {\n JSON.parse(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Case-insensitive content-type presence check on a plain header record. */\nfunction hasContentType(headers: Record<string, string> | undefined): boolean {\n if (!headers) return false;\n return Object.keys(headers).some((k) => k.toLowerCase() === 'content-type');\n}\n\n/** Read the response body (json or text) and assemble the base PayResult. */\nasync function finalize(response: Response, opts: { paid: boolean }): Promise<PayResult> {\n const contentType = response.headers.get('content-type') ?? '';\n let body: unknown;\n try {\n body = contentType.includes('application/json') ? await response.json() : await response.text();\n } catch {\n body = null;\n }\n return { status: response.status, body, paid: opts.paid };\n}\n\n/** A gRPC client for tx BUILD — its resolver auto-detects the gasless\n * stablecoin shape (gasPrice/gasBudget/gasPayment zeroed). */\nasync function makeGrpcBuildClient(client: SuiGrpcClient): Promise<SuiGrpcClient> {\n const { SuiGrpcClient } = await import('@mysten/sui/grpc');\n const network: 'mainnet' | 'testnet' = client.network === 'testnet' ? 'testnet' : 'mainnet';\n const baseUrl =\n network === 'testnet' ? 'https://fullnode.testnet.sui.io' : 'https://fullnode.mainnet.sui.io';\n return new SuiGrpcClient({ baseUrl, network });\n}\n\nfunction atomicToHuman(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nasync function assetDecimals(coinType: string): Promise<number> {\n try {\n const { getDecimalsForCoinType } = await import('../token-registry.js');\n const d = getDecimalsForCoinType(coinType);\n return typeof d === 'number' ? d : 6;\n } catch {\n return 6;\n }\n}\n","/**\n * MPP cost extraction — the truthful-`cost` fix (Bug 1, dogfood 2026-05-31).\n *\n * `T2000.pay()` used to report `options.maxPrice` (the caller's ceiling, default\n * 1.0 in MCP) as the `cost`, wildly overstating the real charge. The real\n * amount is the 402 challenge price, a decimal USDC string like \"0.01\" carried\n * on `challenge.request.amount`. mppx surfaces the parsed challenge via its\n * `onChallenge` hook; this pure helper pulls the amount out so the extraction\n * is unit-testable in isolation (the ordering/format invariant can't silently\n * regress).\n */\n\n/** Minimal structural view of an mppx payment challenge. */\nexport type MppChallenge = { request?: { amount?: unknown } } | null | undefined;\n\n/**\n * Parse the charged amount (USD) from a payment challenge. Returns `undefined`\n * when the challenge has no usable numeric amount, so callers can fall back to\n * the `maxPrice` ceiling rather than reporting a wrong number.\n */\nexport function parseChallengeAmount(challenge: MppChallenge): number | undefined {\n const raw = challenge?.request?.amount;\n const n =\n typeof raw === 'string' ? Number(raw) : typeof raw === 'number' ? raw : Number.NaN;\n return Number.isFinite(n) ? n : undefined;\n}\n","import type { SuiClientTypes } from '@mysten/sui/client';\nimport type { Transaction } from '@mysten/sui/transactions';\nimport type { TransactionSigner } from '../signer.js';\nimport type { SuiCoreClient } from '../utils/sui.js';\n\n// ---------------------------------------------------------------------------\n// executeTx — build + sign + submit + wait, the SDK's one tx-execution helper.\n//\n// Browser-safe (no fs / keyManager imports) so it can back\n// both the Node-side `T2000` methods AND the browser-side `payWithMpp`\n// (gasless MPP runs client-side on the zkLogin session key). Moved out of\n// `t2000.ts` so `wallet/pay.ts` can share it without pulling the Node-only\n// `T2000` module graph into the browser bundle.\n//\n// [gRPC migration] Submit + wait go through the unified `client.core.*`\n// API (`executeTransaction` + `waitForTransaction`), which is transport-\n// agnostic across the JSON-RPC and gRPC clients.\n// ---------------------------------------------------------------------------\n\nexport type SuiTransactionEffects = SuiClientTypes.TransactionEffects;\nexport type BuildClient = NonNullable<Parameters<Transaction['build']>[0]>['client'];\n\nexport async function executeTx(\n client: SuiCoreClient,\n signer: TransactionSigner,\n buildTx: () => Promise<Transaction> | Transaction,\n options: { buildClient?: BuildClient } = {},\n): Promise<{ digest: string; gasCostSui: number; effects: SuiTransactionEffects | undefined }> {\n const tx = await buildTx();\n tx.setSender(signer.getAddress());\n // [2026-05-22] Optional buildClient. When set, `tx.build()` uses it to\n // resolve the PTB — relevant for gasless stablecoin transfers where the\n // SuiGrpcClient build path auto-detects allowlisted ops and zeros out\n // gasPrice/gasBudget/gasPayment. See `payWithMpp`.\n const txBytes = await tx.build({ client: options.buildClient ?? client });\n const { signature } = await signer.signTransaction(txBytes);\n const result = await client.core.executeTransaction({\n transaction: txBytes,\n signatures: [signature],\n include: { effects: true },\n });\n const txn = result.$kind === 'Transaction' ? result.Transaction : result.FailedTransaction;\n try {\n await client.core.waitForTransaction({ digest: txn.digest });\n } catch (err) {\n // A successful executeTransaction already returned the certified effects —\n // the wait only provides read-your-write index visibility. On a lagging\n // fullnode it can time out AFTER the tx landed; propagating that turns a\n // SUCCESSFUL on-chain payment into a reported failure, which bait-invites\n // a double-pay retry (S.453 JMPR e2e: two 0.02 USDC charges for one call).\n // Effects in hand = executed + certified → proceed. No effects = nothing\n // proves execution → rethrow.\n if (!txn.effects) throw err;\n }\n const effects = txn.effects ?? undefined;\n const gasUsed = effects?.gasUsed;\n let gasCostSui = 0;\n if (gasUsed) {\n const total = BigInt(gasUsed.computationCost) + BigInt(gasUsed.storageCost) - BigInt(gasUsed.storageRebate);\n gasCostSui = Number(total) / 1e9;\n }\n return { digest: txn.digest, gasCostSui, effects };\n}\n","// Builder-appropriate safety, layer 2 (SPEC_AUDRIC_V3 §7 / safeguards-defense-\n// in-depth.mdc). `preflight()` is CHEAP, PURE, SYNCHRONOUS input validation —\n// no network, no I/O, no context lookup. It runs BEFORE the LLM round-trip /\n// before the tap-to-confirm card, so a malformed intent is rejected without\n// the user ever seeing a confirm for it.\n//\n// Each write builder co-locates its own `preflight*` validator (send.ts →\n// `preflightSend`, pay.ts → `preflightPay`, cetus-swap.ts → `preflightSwap`).\n// This module owns ONLY the shared result type + the two pure primitives those\n// validators compose (amount sanity + sync address validity). The agent-loop\n// guards that read conversation/session state stay in the v3 HOST (they are\n// NOT builder-appropriate, S.442/S.443).\n\nimport { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport type { T2000ErrorCode } from './errors.js';\n\n/**\n * The result of a synchronous preflight check. `valid: false` carries a\n * `T2000ErrorCode` + human message so the host can surface a precise reason\n * (and the builder can rethrow it as a `T2000Error` verbatim).\n */\nexport type PreflightResult =\n | { valid: true }\n | { valid: false; code: T2000ErrorCode; error: string };\n\n/**\n * Fat-finger / overflow ceiling for an asset amount. NOT a spending policy\n * (that's the `@t2000/sdk/limits` module — USD-denominated, opt-in, stateful);\n * this is the \"obviously wrong number\" guard the safeguards rule prescribes\n * (`amount > 1_000_000` → unreasonable).\n */\nexport const PREFLIGHT_MAX_AMOUNT = 1_000_000;\n\nexport const PREFLIGHT_OK: PreflightResult = { valid: true };\n\nexport function preflightFail(code: T2000ErrorCode, error: string): PreflightResult {\n return { valid: false, code, error };\n}\n\n/**\n * Pure positive-finite-amount sanity check (no network). Rejects NaN/Infinity\n * and non-positive values. The absurd-value ceiling defaults to\n * {@link PREFLIGHT_MAX_AMOUNT} but callers can raise it — pass\n * `max: Number.POSITIVE_INFINITY` for swaps of low-unit-value tokens\n * (memecoins legitimately trade in millions/billions of units), where a fixed\n * display-amount ceiling would be a false positive.\n */\nexport function checkPositiveAmount(\n amount: number,\n label = 'Amount',\n max: number = PREFLIGHT_MAX_AMOUNT,\n): PreflightResult {\n if (typeof amount !== 'number' || !Number.isFinite(amount)) {\n return preflightFail('INVALID_AMOUNT', `${label} must be a finite number`);\n }\n if (amount <= 0) {\n return preflightFail('INVALID_AMOUNT', `${label} must be greater than zero`);\n }\n if (amount > max) {\n return preflightFail('INVALID_AMOUNT', `${label} ${amount} exceeds the sane maximum (${max})`);\n }\n return PREFLIGHT_OK;\n}\n\n/**\n * Pure, synchronous Sui-address validity (no throw, no network) — the\n * non-throwing sibling of `validateAddress`. Use in preflight; use\n * `validateAddress` when you need the normalized form.\n */\nexport function checkSuiAddress(address: string, label = 'recipient'): PreflightResult {\n try {\n // `normalizeSuiAddress('')` pads to the zero address (which is \"valid\"), so\n // guard empty / whitespace-only input before normalizing.\n if (typeof address === 'string' && address.trim() !== '' &&\n isValidSuiAddress(normalizeSuiAddress(address))) {\n return PREFLIGHT_OK;\n }\n } catch {\n // normalizeSuiAddress throws on malformed input → fall through to the fail.\n }\n return preflightFail('INVALID_ADDRESS', `Invalid ${label} address: ${address}`);\n}\n","/**\n * Browser-safe entry point for @t2000/sdk.\n *\n * Exports everything the web app needs WITHOUT Node-only modules\n * (e.g. the fs-based keyManager is excluded).\n */\n\n// Signer abstraction\nexport type { TransactionSigner } from './signer.js';\nexport { KeypairSigner } from './wallet/keypairSigner.js';\nexport { ZkLoginSigner, type ZkLoginProof } from './wallet/zkLoginSigner.js';\n\n// Gasless MPP pay — browser-safe; the Audric client runs this in-browser on\n// the zkLogin session key (unified gasless write path). Same canonical loop\n// `T2000.pay()` delegates to. Pair with `executeTx` for advanced callers.\n// (`PayOptions` / `PayResult` are exported from the types block below.)\nexport { payWithMpp, preflightPay, parseMppSuiChallenge } from './wallet/pay.js';\nexport { executeTx } from './wallet/executeTx.js';\n\n// Error handling\nexport { T2000Error, mapWalletError, mapMoveAbortCode } from './errors.js';\nexport type { T2000ErrorCode, T2000ErrorData } from './errors.js';\n\n// Constants\nexport {\n MIST_PER_SUI,\n SUI_DECIMALS,\n USDC_DECIMALS,\n T2000_OVERLAY_FEE_WALLET,\n SUPPORTED_ASSETS,\n CLOCK_ID,\n DEFAULT_NETWORK,\n} from './constants.js';\nexport type { SupportedAsset, StableAsset } from './constants.js';\nexport {\n STABLE_ASSETS,\n GAS_RESERVE_MIN,\n} from './constants.js';\n\n// Utilities\nexport { validateAddress, truncateAddress } from './utils/sui.js';\nexport {\n KNOWN_TARGETS,\n LABEL_PATTERNS,\n classifyAction,\n classifyLabel,\n fallbackLabel,\n refineLendingLabel,\n classifyTransaction,\n extractTransferDetails,\n extractAllUserLegs,\n} from './wallet/classify.js';\nexport type {\n ClassifyBalanceChange,\n ClassifyResult,\n ExtractedTransfer,\n TxDirection,\n} from './wallet/classify.js';\n/**\n * Tx parsing helpers. Safe in the browser — they only do shape\n * inspection / classification and do not import any Node-only modules.\n * `queryHistory` and `queryTransaction` are not re-exported here\n * because they reach the network (GraphQL) directly; browser consumers\n * can build the same flow with `parseSuiRpcTx` + their own fetch.\n */\nexport {\n parseSuiRpcTx,\n extractTxSender,\n extractTxCommands,\n} from './wallet/history.js';\nexport type { SuiRpcTxBlock } from './wallet/history.js';\nexport {\n mistToSui,\n suiToMist,\n usdcToRaw,\n rawToUsdc,\n stableToRaw,\n rawToStable,\n getDecimals,\n formatUsd,\n formatSui,\n formatAssetAmount,\n} from './utils/format.js';\nexport { toBase64, fromBase64 } from './utils/base64.js';\n\n// Simulation — use dynamic import() to avoid Buffer dependency in browser bundles\n// import { simulateTransaction } from '@t2000/sdk' (main entry) for Node usage\nexport type { SimulationResult } from './utils/simulate.js';\n\n// Protocol fee\n// Cetus aggregator helpers — Audric prepare/route.ts uses these directly to\n// build swap PTBs with overlay fees (per-call, not module-global).\nexport { findSwapRoute, buildSwapTx, OVERLAY_FEE_RATE, preflightSwap } from './protocols/cetus-swap.js';\nexport type { SwapRouteResult, OverlayFeeConfig } from './protocols/cetus-swap.js';\n\n// Synchronous, network-free preflight (layer 2) — pure, browser-safe. The v3\n// host runs these in the agent loop before the tap-to-confirm card.\n// buildSendTx is browser-safe (builds a gasless PTB; the client is injected) —\n// the Audric client signs it in-browser with the zkLogin session (send_transfer).\nexport { buildSendTx, preflightSend } from './wallet/send.js';\n\n// A2A escrow job builders + readers — browser-safe (client injected, no fs).\n// Store surfaces build the buyer-side legs on a zkLogin session key.\nexport {\n A2A_ESCROW_PACKAGE_ID,\n MAX_JOB_USDC,\n JOB_STATES,\n preflightCreateJob,\n buildCreateJobTx,\n buildDeliverJobTx,\n buildReleaseJobTx,\n buildRejectJobTx,\n buildRefundJobTx,\n getJob,\n jobActionsFor,\n verifyJobForSeller,\n} from './wallet/job.js';\nexport type { Job, JobState, JobTerms, JobVerification } from './wallet/job.js';\nexport {\n type PreflightResult,\n PREFLIGHT_MAX_AMOUNT,\n PREFLIGHT_OK,\n preflightFail,\n checkPositiveAmount,\n checkSuiAddress,\n} from './preflight.js';\n\n// Spending limits are Node-only (`@t2000/sdk/limits` uses node:fs) — NOT\n// exported here. The browser (Audric) write path skips client-side limits;\n// the server budget ledger is the cap there.\n\n// Types\nexport type {\n BalanceResponse,\n SuiHolding,\n SendResult,\n DepositInfo,\n TransactionRecord,\n TransactionLeg,\n PayOptions,\n PayResult,\n} from './types.js';\n\n// Token registry — zero Node.js deps, safe for client-side use\nexport {\n COIN_REGISTRY,\n TOKEN_MAP,\n resolveTokenType,\n resolveSymbol,\n getDecimalsForCoinType,\n SUI_TYPE,\n USDC_TYPE,\n USDT_TYPE,\n USDSUI_TYPE,\n USDE_TYPE,\n ETH_TYPE,\n WBTC_TYPE,\n WAL_TYPE,\n NAVX_TYPE,\n IKA_TYPE,\n LOFI_TYPE,\n MANIFEST_TYPE,\n} from './token-registry.js';\nexport type { CoinMeta } from './token-registry.js';\n","import { T2000Error } from './errors.js';\n\nexport const MIST_PER_SUI = 1_000_000_000n;\nexport const SUI_DECIMALS = 9;\nexport const USDC_DECIMALS = 6;\n\nexport const PRECISION = 1_000_000_000_000_000_000n;\n\nexport const MIN_DEPOSIT = 1_000_000n; // 1 USDC (6 decimals)\n\nexport const CLOCK_ID = '0x6';\n\nexport const SUPPORTED_ASSETS = {\n USDC: {\n type: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',\n decimals: 6,\n symbol: 'USDC',\n displayName: 'USDC',\n },\n USDT: {\n type: '0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT',\n decimals: 6,\n symbol: 'USDT',\n displayName: 'suiUSDT',\n },\n USDe: {\n type: '0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE',\n decimals: 6,\n symbol: 'USDe',\n displayName: 'suiUSDe',\n },\n USDsui: {\n type: '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI',\n decimals: 6,\n symbol: 'USDsui',\n displayName: 'USDsui',\n },\n SUI: {\n type: '0x2::sui::SUI',\n decimals: 9,\n symbol: 'SUI',\n displayName: 'SUI',\n },\n WAL: {\n type: '0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL',\n decimals: 9,\n symbol: 'WAL',\n displayName: 'WAL',\n },\n ETH: {\n type: '0xd0e89b2af5e4910726fbcd8b8dd37bb79b29e5f83f7491bca830e94f7f226d29::eth::ETH',\n decimals: 8,\n symbol: 'ETH',\n displayName: 'suiETH',\n },\n NAVX: {\n type: '0xa99b8952d4f7d947ea77fe0ecdcc9e5fc0bcab2841d6e2a5aa00c3044e5544b5::navx::NAVX',\n decimals: 9,\n symbol: 'NAVX',\n displayName: 'NAVX',\n },\n GOLD: {\n type: '0x9d297676e7a4b771ab023291377b2adfaa4938fb9080b8d12430e4b108b836a9::xaum::XAUM',\n decimals: 6,\n symbol: 'GOLD',\n displayName: 'XAUM',\n },\n} as const;\n\nexport type SupportedAsset = keyof typeof SUPPORTED_ASSETS;\n\n// [SPEC_AGENTIC_STACK P1 / SDK F3 — 2026-05-25]\n// `StableAsset` = \"what we treat as worth $1 for wallet pricing and balance roll-up\".\n// Pre-Phase 1: USDC only — left USDsui wallet holdings invisible to balance.ts.\n// Phase 1: widened to USDC + USDsui (both are NAVI-native stables with $1 peg).\n// USDT / USDe stay OUT of this set deliberately — they are stables, but the\n// codebase has never priced them at $1, and adding them here would require\n// auditing balance.ts callers downstream. Keep the carve minimal.\nexport type StableAsset = 'USDC' | 'USDsui';\nexport const STABLE_ASSETS: readonly StableAsset[] = ['USDC', 'USDsui'] as const;\n\n// ---------------------------------------------------------------------------\n// Operation → allowed asset rules (single source of truth)\n// ---------------------------------------------------------------------------\n\n// [v4.0 Phase A Day 2 — 2026-05-26] `send` is constrained to\n// `['USDC', 'USDsui', 'SUI']`. Rationale (SPEC_AGENT_WALLET_GREENFIELD §A):\n// - USDC + USDsui are gasless via `0x2::balance::send_funds` (Sui mainnet\n// protocol allowlist) — the two foundation stables.\n// - SUI is the only non-stable kept on the allowlist so users with no\n// stablecoin balance can still pay gas-native SUI transfers.\n// - USDT, USDe, WAL, ETH, NAVX, GOLD are NOT sendable — users must swap to\n// USDC/USDsui first (one-step) or hold SUI and use a manual Move call.\n// `swap` is unrestricted (Cetus routes any pair). The DeFi operations\n// (save/borrow/withdraw/repay) were removed with NAVI.\nexport const OPERATION_ASSETS = {\n send: ['USDC', 'USDsui', 'SUI'],\n swap: '*',\n} as const;\n\nexport type Operation = keyof typeof OPERATION_ASSETS;\n\nexport function isAllowedAsset(op: Operation, asset: string): boolean {\n const allowed = OPERATION_ASSETS[op];\n if (allowed === '*') return true;\n // [v0.51.0] Mixed-case canonical keys (USDsui, suiUSDT) need case-insensitive\n // membership. Pre-v0.51 we only had USDC ↔ USDC (uppercase identity), so\n // a one-sided uppercase compare looked correct. Now that USDsui is in the\n // set, normalize both sides.\n const target = asset.toLowerCase();\n return (allowed as readonly string[]).some((a) => a.toLowerCase() === target);\n}\n\n/**\n * Throws if the asset is not permitted for the given operation.\n *\n * [v4.0 Phase A Day 2] Pre-v4 this allowed `undefined` as a silent default\n * to USDC. Removed because every write path now requires explicit asset\n * (see `T2000.send` + `buildSendTx` + `composeTx.send_transfer`). The\n * `undefined → no-op` branch is kept defensively; the `send_transfer` flow\n * validates non-undefined.\n */\nexport function assertAllowedAsset(op: Operation, asset: string | undefined): void {\n if (!asset) return;\n if (!isAllowedAsset(op, asset)) {\n const allowed = OPERATION_ASSETS[op];\n const list = Array.isArray(allowed) ? allowed.join(', ') : 'any';\n const swapHint =\n op === 'send' ? ' Swap to USDC or USDsui first, or send SUI.' : '';\n throw new T2000Error(\n 'INVALID_ASSET',\n `${op} only supports ${list}. Cannot use ${asset}.${swapHint}`,\n );\n }\n}\n\n/**\n * [v4.0 Phase A Day 2] Narrow type alias for assets sendable through the\n * Agent Wallet. Matches `OPERATION_ASSETS.send` exactly. Exported so the\n * CLI / SDK / composeTx can share one type without re-declaring it.\n */\nexport type SendableAsset = 'USDC' | 'USDsui' | 'SUI';\nexport const SENDABLE_ASSETS: readonly SendableAsset[] = ['USDC', 'USDsui', 'SUI'] as const;\n\n/**\n * [v4.0 Phase A Day 2] Coin types for the two gasless-allowlisted stables.\n * Used by `wallet/send.ts` + `composeTx.send_transfer` to construct the\n * `0x2::balance::send_funds` Move call's `typeArguments`. SUI is excluded\n * because SUI transfers are NOT gasless (gas-native, uses `tx.gas` split +\n * `transferObjects` per the existing path).\n */\nexport const GASLESS_STABLE_TYPES: Record<'USDC' | 'USDsui', string> = {\n USDC: SUPPORTED_ASSETS.USDC.type,\n USDsui: SUPPORTED_ASSETS.USDsui.type,\n};\n\n// Swap overlay fees route here. Audric's prepare/route.ts passes\n// `overlayFee.receiver = T2000_OVERLAY_FEE_WALLET` to the Cetus aggregator. The\n// CLI/SDK never charge fees — this constant is exported for consumer apps only.\n//\n// Address corresponds to the treasury admin wallet. Override via env for local dev /\n// testnet only — production must use the canonical mainnet address below.\nexport const T2000_OVERLAY_FEE_WALLET = process.env.T2000_OVERLAY_FEE_WALLET\n ?? '0x5366efbf2b4fe5767fe2e78eb197aa5f5d138d88ac3333fbf3f80a1927da473a';\n\nexport const DEFAULT_NETWORK = 'mainnet' as const;\n// gRPC fullnode endpoint. Post-flip this is the canonical transport for the\n// whole SDK: `getSuiClient()` (reads + execution) AND `getSuiGrpcClient()`\n// (gasless stablecoin build detection) both target it. Override the read/exec\n// client with T2000_RPC_URL and the build client with T2000_GRPC_URL.\nexport const DEFAULT_RPC_URL = 'https://fullnode.mainnet.sui.io:443';\nexport const DEFAULT_GRPC_URL = 'https://fullnode.mainnet.sui.io:443';\n// [gRPC migration] GraphQL endpoint for the query surface that has NO gRPC\n// `core` equivalent — `transactionBlocks` (history). Used by\n// `getSuiGraphQLClient()`. The canonical mainnet host is `graphql.mainnet.sui.io`\n// (parallel to the gRPC fullnode); the older `sui-mainnet.mystenlabs.com/graphql`\n// host was dropped 2026-06-15 after it began resetting TLS connections (live\n// smoke). Public endpoint is rate-limited — production hosts override with\n// T2000_GRAPHQL_URL to a dedicated provider.\nexport const DEFAULT_GRAPHQL_URL = 'https://graphql.mainnet.sui.io/graphql';\nexport const DEFAULT_KEY_PATH = '~/.t2000/wallet.key';\nexport const DEFAULT_CONFIG_PATH = '~/.t2000/config.json';\n\n// [v4.0 Phase A Day 2] Minimum stablecoin amount for protocol-level gasless\n// transfers via `0x2::balance::send_funds`. The Sui mainnet allowlist enforces\n// this floor at the protocol level to prevent dust spam; we surface a clear\n// error before signing rather than letting the tx revert on-chain.\nexport const GASLESS_MIN_STABLE_AMOUNT = 0.01;\n\n// Cetus USDC/SUI pool — read-only for SUI price oracle (no SDK dependency)\nexport const CETUS_USDC_SUI_POOL = '0x51e883ba7c0b566a26cbc8a94cd33eb0abd418a77cc1e60ad22fd9b1f29cd2ab';\n\nexport const GAS_RESERVE_MIN = 0.05; // minimum SUI to keep for gas\n","import { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';\nimport { SuiGrpcClient } from '@mysten/sui/grpc';\nimport { SuiGraphQLClient } from '@mysten/sui/graphql';\nimport { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';\nimport { DEFAULT_GRAPHQL_URL, DEFAULT_GRPC_URL, DEFAULT_RPC_URL } from '../constants.js';\nimport { T2000Error } from '../errors.js';\n\n/**\n * [gRPC migration / S.438] Transport-agnostic client type for the migration.\n *\n * Both `SuiJsonRpcClient` and `SuiGrpcClient` extend `BaseClient` and expose\n * an identical `.core.*` API. During the migration, call sites are rewritten\n * from legacy methods (`getBalance`, `getObject`, `executeTransactionBlock`)\n * to the unified `client.core.*` API and typed against this union — so the\n * rewrite is behavior-preserving while still on JSON-RPC, and the final\n * transport flip (gRPC) is a one-line change in `getSuiClient()`.\n *\n * The query surface that has no gRPC `core` equivalent (`queryTransactionBlocks`\n * / `queryEvents`, Stage 0 finding A) uses `getSuiGraphQLClient()` instead.\n */\nexport type SuiCoreClient = SuiJsonRpcClient | SuiGrpcClient;\n\n/**\n * Resolve the effective JSON-RPC URL: explicit arg > env var > default.\n * `T2000_RPC_URL` is an OPTIONAL override per the Greenfield SPEC's env\n * contract — no required vars, so we read inline (allowed by\n * `env-validation-gate.mdc` carve-out for packages with zero required\n * env vars).\n */\nfunction resolveRpcUrl(rpcUrl?: string): string {\n if (rpcUrl) return rpcUrl;\n const envUrl = process.env.T2000_RPC_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_RPC_URL;\n}\n\n/**\n * Same shape as `resolveRpcUrl` for the gRPC endpoint.\n */\nfunction resolveGrpcUrl(grpcUrl?: string): string {\n if (grpcUrl) return grpcUrl;\n const envUrl = process.env.T2000_GRPC_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_GRPC_URL;\n}\n\n/**\n * Same shape as `resolveRpcUrl` for the GraphQL endpoint.\n */\nfunction resolveGraphqlUrl(graphqlUrl?: string): string {\n if (graphqlUrl) return graphqlUrl;\n const envUrl = process.env.T2000_GRAPHQL_URL?.trim();\n if (envUrl) return envUrl;\n return DEFAULT_GRAPHQL_URL;\n}\n\n/**\n * Canonical agent client cache, keyed by URL. The earlier impl cached\n * unconditionally and ignored URL changes after the first call —\n * brittle for testnet smokes and custom-RPC test setups.\n */\nconst rpcClientCache = new Map<string, SuiGrpcClient>();\n\n/**\n * [gRPC cutover] The canonical agent client is now gRPC. Mysten deactivates\n * the JSON-RPC fullnode interface on 2026-07-31, so reads (`.core.*`) and\n * execution route over gRPC — transaction *builds* already do\n * (`getSuiGrpcClient`). The whole SDK was first refactored onto the unified\n * `.core` API (behavior-preserving on JSON-RPC), then flipped here. The\n * `rpcUrl` arg / `T2000_RPC_URL` override now resolve a gRPC `baseUrl`\n * (`DEFAULT_RPC_URL` is the same host as `DEFAULT_GRPC_URL`). The historical\n * query surface stays on `getSuiGraphQLClient()`.\n */\nexport function getSuiClient(rpcUrl?: string): SuiGrpcClient {\n const url = resolveRpcUrl(rpcUrl);\n const cached = rpcClientCache.get(url);\n if (cached) return cached;\n const client = new SuiGrpcClient({ baseUrl: url, network: 'mainnet' });\n rpcClientCache.set(url, client);\n return client;\n}\n\n/**\n * gRPC client cache, keyed by URL. Same rationale as the JSON-RPC cache:\n * different URLs must produce different clients.\n */\nconst grpcClientCache = new Map<string, SuiGrpcClient>();\n\n/**\n * Cached `SuiGrpcClient` for gasless stablecoin transfer builds.\n *\n * [v4.0 Phase A Day 2 — SPEC_AGENT_WALLET_GREENFIELD §A]\n *\n * Why this exists: Sui mainnet's protocol-level gasless stablecoin transfers\n * (`0x2::balance::send_funds` on the USDC + USDsui allowlist) are detected\n * ONLY when the transaction is built through a `SuiGrpcClient`. The gRPC\n * client's build resolver inspects the PTB at `tx.build()` time and, if it\n * matches the gasless pattern, sets `gasPrice=0` + `gasBudget=0` automatically.\n * Building the SAME PTB through `SuiJsonRpcClient` produces the same bytes\n * but with non-zero gas — the tx still works, but the user pays SUI gas.\n *\n * Execution stays on JSON-RPC (`SuiJsonRpcClient.executeTransactionBlock`)\n * because (a) the rest of the SDK expects JSON-RPC and (b) Sui's docs\n * explicitly support a \"build via gRPC, execute via JSON-RPC\" hybrid:\n * https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers\n *\n * Override the endpoint with the `T2000_GRPC_URL` env var or the\n * `grpcUrl` arg. Cache is keyed by URL so multiple endpoints can\n * co-exist (e.g., the rare testnet smoke + production usage from the\n * same process).\n */\nexport function getSuiGrpcClient(grpcUrl?: string): SuiGrpcClient {\n const baseUrl = resolveGrpcUrl(grpcUrl);\n const cached = grpcClientCache.get(baseUrl);\n if (cached) return cached;\n const client = new SuiGrpcClient({ baseUrl, network: 'mainnet' });\n grpcClientCache.set(baseUrl, client);\n return client;\n}\n\n/**\n * GraphQL client cache, keyed by URL. Same rationale as the other caches.\n */\nconst graphqlClientCache = new Map<string, SuiGraphQLClient>();\n\n/**\n * Cached `SuiGraphQLClient` for the query surface that has NO gRPC `core`\n * equivalent: `queryTransactionBlocks` + `queryEvents` (Stage 0 finding A —\n * `SPEC_FULL_GRPC_MIGRATION.md`). Mysten's gRPC successor doesn't cover the\n * historical query/event API; GraphQL is its documented home. Consumers:\n * `wallet/history.ts` + the swap-event read in `protocols/cetus-swap.ts`.\n *\n * Override the endpoint with `T2000_GRAPHQL_URL` or the `graphqlUrl` arg.\n */\nexport function getSuiGraphQLClient(graphqlUrl?: string): SuiGraphQLClient {\n const url = resolveGraphqlUrl(graphqlUrl);\n const cached = graphqlClientCache.get(url);\n if (cached) return cached;\n const client = new SuiGraphQLClient({ url, network: 'mainnet' });\n graphqlClientCache.set(url, client);\n return client;\n}\n\nexport function validateAddress(address: string): string {\n const normalized = normalizeSuiAddress(address);\n if (!isValidSuiAddress(normalized)) {\n throw new T2000Error('INVALID_ADDRESS', `Invalid Sui address: ${address}`);\n }\n return normalized;\n}\n\nexport function truncateAddress(address: string): string {\n if (address.length <= 10) return address;\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n\n/**\n * Normalize a Sui coin type to its canonical long-form 64-hex address.\n * `0x2::sui::SUI` → `0x0000…0002::sui::SUI`. Idempotent on already-long\n * forms. Returns the input unchanged if it doesn't look like a coin type\n * (`<address>::<module>::<name>`) so callers can pass arbitrary strings\n * without crashing.\n *\n * Why this exists: BlockVision's `/v2/sui/coin/price/list` endpoint\n * silently returns an empty `prices` map for short-form coin types\n * (notably `0x2::sui::SUI` — the native gas coin). Internal callers must\n * pass the long form, but external callers (LLM tool args, cached\n * coin-type strings, audit logs) commonly use the short form. Normalize\n * before the network call, denormalize back to the caller's input shape\n * after, and short/long become interchangeable.\n */\nexport function normalizeCoinType(coinType: string): string {\n const parts = coinType.split('::');\n if (parts.length !== 3) return coinType;\n const [addr, mod, name] = parts;\n if (!addr.startsWith('0x')) return coinType;\n return `${normalizeSuiAddress(addr)}::${mod}::${name}`;\n}\n","/**\n * Shared transaction classifier.\n *\n * Consumed by both the SDK's `parseTxRecord` (production agent path) and\n * the engine's `transaction_history` tool (cold-start RPC path). Keeping\n * a single source of truth here prevents the two paths from drifting —\n * see v1.5.3 regression where the SDK path was emitting `action:\n * 'transaction'` (rendered as \"On-chain\") while the engine path was\n * already producing fine-grained labels.\n */\n\nimport { getDecimalsForCoinType, resolveSymbol, SUI_TYPE } from '../token-registry.js';\n\n/**\n * Coarse action bucket — one of `'send' | 'lending' | 'swap' |\n * 'transaction'`. Used by the ACI `action` filter on the\n * `transaction_history` tool. STABLE: downstream queries depend on\n * exactly these values.\n *\n * Order matters: more specific buckets first. Lending patterns precede\n * swap patterns so a NAVI `::swap` helper (if one ever existed) would\n * still bucket as lending.\n */\nexport const KNOWN_TARGETS: readonly [RegExp, string][] = [\n [/::suilend|::obligation/, 'lending'],\n [/::navi|::lending_core|::incentive_v\\d+|::oracle_pro/, 'lending'],\n /**\n * DEX modules — both direct calls and aggregator legs. The Cetus\n * aggregator dispatches through a per-DEX module (e.g.\n * `cetus::swap`, `flowx_amm::swap`, `aftermath::swap`, …) plus\n * router glue functions. We list every DEX module the aggregator\n * supports today so a single-DEX call still classifies cleanly.\n */\n [/::cetus(?:_dlmm)?::|::pool::|::deepbook|::flowx_(?:amm|clmm)::|::kriya_(?:amm|clmm)::|::turbos::|::aftermath::|::afsui::|::bluefin::|::bluemove::|::ferra_(?:clmm|dlmm)::|::haedal_hmm::|::hasui::|::hawal::|::magma::|::momentum::|::obric::|::springsui::|::steamm_cpmm::|::fullsail::|::alphafi::|::volo_swap::/, 'swap'],\n /**\n * Cetus aggregator router glue. These are the swap-context and\n * balance-handling helpers the aggregator emits around per-DEX\n * legs. Without this entry a tx that ONLY had router calls\n * (theoretically possible for setup/cleanup) would slip through;\n * in practice these always coexist with a DEX leg, but the entry\n * is cheap insurance.\n */\n [/::router::(?:new_swap_context(?:_v)?|confirm_swap|transfer_balance|take_balance|transfer_or_destroy_coin)/, 'swap'],\n [/::transfer::public_transfer/, 'send'],\n];\n\n/**\n * Finer-grained display labels — derived from MoveCall function names.\n * The card renders `label ?? action`, so when this map matches we get\n * \"Deposit\" / \"Withdraw\" / \"Borrow\" / \"Repay\" / \"Payment link\" instead\n * of the generic \"Lending\" or \"Transaction\".\n *\n * Order matters: more specific patterns first. Each entry is\n * (regex, label) where the regex is matched against the\n * fully-qualified MoveCall target `pkg::module::function`.\n */\nexport const LABEL_PATTERNS: readonly [RegExp, string][] = [\n [/::pay(?:ment_kit|_kit)?::|::create_payment_link|::pay_link/, 'payment_link'],\n [/::create_invoice|::invoice::/, 'invoice'],\n [/::deposit|::supply|::mint_ctokens/, 'deposit'],\n [/::withdraw|::redeem|::redeem_ctokens/, 'withdraw'],\n [/::borrow/, 'borrow'],\n [/::repay/, 'repay'],\n [/::claim_reward|::claim::|::claim_incentive/, 'claim'],\n [/::stake/, 'stake'],\n [/::unstake|::burn::/, 'unstake'],\n [/::liquidate/, 'liquidate'],\n];\n\nexport interface ClassifyBalanceChange {\n owner: { AddressOwner?: string } | string;\n coinType: string;\n amount: string;\n}\n\nfunction resolveOwner(owner: ClassifyBalanceChange['owner']): string | null {\n if (typeof owner === 'object' && owner.AddressOwner) return owner.AddressOwner;\n if (typeof owner === 'string') return owner;\n return null;\n}\n\nexport function classifyAction(targets: string[], commandTypes: string[]): string {\n for (const target of targets) {\n for (const [pattern, label] of KNOWN_TARGETS) {\n if (pattern.test(target)) return label;\n }\n }\n if (commandTypes.includes('TransferObjects') && !commandTypes.includes('MoveCall')) return 'send';\n return 'transaction';\n}\n\n/**\n * Last-resort fallback when neither `LABEL_PATTERNS` nor the action\n * bucket produces something useful.\n *\n * Returns the first MoveCall's *module* name (e.g. \"navi\", \"spam\") so\n * the card shows something better than the literal word \"transaction\".\n * When no MoveCall exists, returns 'on-chain'.\n *\n * Note: callers should prefer `classifyLabel` which now layers\n * pattern-match → coarse action → module name (see commentary there).\n */\nexport function fallbackLabel(targets: string[]): string {\n if (!targets.length) return 'on-chain';\n const first = targets[0];\n const parts = first.split('::');\n if (parts.length >= 2 && parts[1]) return parts[1].toLowerCase();\n return 'on-chain';\n}\n\n/**\n * Three-tier label resolution for the transaction history card:\n * 1. Specific keyword match in `LABEL_PATTERNS` (\"deposit\",\n * \"payment_link\", …).\n * 2. Coarse action bucket from `classifyAction` (\"swap\", \"send\",\n * \"lending\") — prevents leaking opaque internal module names like\n * \"router\" (Cetus aggregator) or \"cross_swap\" (third-party DEX\n * aggregators) for txs that we already classified as a swap.\n * 3. Module name from the first MoveCall (`fallbackLabel`) — only\n * used when the action bucket itself is the generic \"transaction\".\n *\n * Pre-v0.46.2 we skipped tier 2, so swaps showed labels like \"router\",\n * \"cross_swap\", \"scallop_router\", etc. instead of the clean \"swap\".\n */\nexport function classifyLabel(targets: string[], commandTypes: string[]): string {\n for (const target of targets) {\n for (const [pattern, label] of LABEL_PATTERNS) {\n if (pattern.test(target)) return label;\n }\n }\n if (commandTypes.includes('TransferObjects') && !commandTypes.includes('MoveCall')) return 'send';\n const action = classifyAction(targets, commandTypes);\n if (action !== 'transaction') return action;\n return fallbackLabel(targets);\n}\n\n/**\n * Balance-direction tiebreaker for ambiguous lending calls.\n *\n * Many lending modules expose generic entry points (NAVI's bundled\n * flash actions, `lending_core::*::entry_*`, etc.) that don't carry\n * a `deposit`/`withdraw`/`borrow`/`repay` keyword in the function\n * name. When `classifyLabel` falls back to a bare module name like\n * `\"lending\"` for a known lending tx, infer direction from the user's\n * non-SUI balance change:\n * - net outflow of the supplied asset → deposit (also covers repay,\n * but repay-without-keyword is essentially never emitted).\n * - net inflow of the supplied asset → withdraw (also covers borrow).\n * SUI is excluded so gas-only transactions don't get mislabeled.\n *\n * If `LABEL_PATTERNS` matched a specific keyword, the existing label is\n * returned unchanged.\n */\nexport function refineLendingLabel(\n currentAction: string,\n currentLabel: string,\n moveCallTargets: string[],\n changes: ClassifyBalanceChange[],\n address: string,\n): string {\n if (currentAction !== 'lending') return currentLabel;\n const labelMatchedSpecific = LABEL_PATTERNS.some(([p]) =>\n moveCallTargets.some((t) => p.test(t)),\n );\n if (labelMatchedSpecific) return currentLabel;\n\n const userNonSuiOutflow = changes.find(\n (c) => resolveOwner(c.owner) === address && c.coinType !== SUI_TYPE && BigInt(c.amount) < 0n,\n );\n if (userNonSuiOutflow) return 'deposit';\n\n const userNonSuiInflow = changes.find(\n (c) => resolveOwner(c.owner) === address && c.coinType !== SUI_TYPE && BigInt(c.amount) > 0n,\n );\n if (userNonSuiInflow) return 'withdraw';\n\n return currentLabel;\n}\n\nexport interface ClassifyResult {\n action: string;\n label: string;\n}\n\nexport function classifyTransaction(\n moveCallTargets: string[],\n commandTypes: string[],\n balanceChanges: ClassifyBalanceChange[],\n address: string,\n): ClassifyResult {\n const action = classifyAction(moveCallTargets, commandTypes);\n const baseLabel = classifyLabel(moveCallTargets, commandTypes);\n const label = refineLendingLabel(action, baseLabel, moveCallTargets, balanceChanges, address);\n return { action, label };\n}\n\n/**\n * Direction of the user's net non-gas movement for this transaction.\n *\n * - `'out'` — the user spent the asset (sends, deposits, repays,\n * swap-in, payment-link payouts).\n * - `'in'` — the user received the asset (withdraws, borrows,\n * swap-out, claims, deposits credited from another wallet).\n *\n * Used by the `TransactionHistoryCard` to choose the `+`/`−` sign and\n * color. Direction is computed from the actual on-chain balance change\n * — never from the textual label — so opaque action types (`'router'`,\n * `'cross_swap'`, …) still render the correct sign.\n */\nexport type TxDirection = 'in' | 'out';\n\nexport interface ExtractedTransfer {\n amount?: number;\n asset?: string;\n recipient?: string;\n direction?: TxDirection;\n}\n\n/**\n * Extracts the principal amount/asset/direction for a transaction\n * from its `balanceChanges`.\n *\n * Algorithm:\n * 1. Restrict to the user's *own* balance changes.\n * 2. Prefer non-SUI changes (gas-only SUI deltas are noise).\n * 3. Pick the change with the largest absolute value — the \"principal\".\n * 4. If no non-SUI change exists, fall back to the largest SUI change\n * so pure-SUI transfers (stake/unstake/native send) still render.\n * 5. Direction follows the sign of the principal.\n * 6. Recipient is set only on outflows, by finding a matching inflow\n * on a *non-user* address with the same coinType.\n *\n * Pre-v0.46.2 this function only inspected outflows, so withdraws,\n * borrows, claims, swap-receives and payment-link receives all\n * rendered with no amount on the rich card (and with a wrong sign,\n * because the card guessed direction from the label string).\n */\nexport function extractTransferDetails(\n changes: ClassifyBalanceChange[] | undefined,\n sender: string,\n): ExtractedTransfer {\n if (!changes || changes.length === 0) return {};\n\n const userChanges = changes.filter((c) => resolveOwner(c.owner) === sender);\n if (userChanges.length === 0) return {};\n\n const userNonSui = userChanges.filter((c) => c.coinType !== SUI_TYPE);\n const pool = userNonSui.length > 0 ? userNonSui : userChanges;\n\n let primary = pool[0];\n let primaryAbs = bigintAbs(BigInt(primary.amount));\n for (let i = 1; i < pool.length; i++) {\n const abs = bigintAbs(BigInt(pool[i].amount));\n if (abs > primaryAbs) {\n primary = pool[i];\n primaryAbs = abs;\n }\n }\n\n const raw = BigInt(primary.amount);\n if (raw === 0n) return {};\n\n const decimals = getDecimalsForCoinType(primary.coinType);\n const amount = Number(primaryAbs) / 10 ** decimals;\n const asset = resolveSymbol(primary.coinType);\n const direction: TxDirection = raw < 0n ? 'out' : 'in';\n\n let recipient: string | undefined;\n if (direction === 'out') {\n const recipientChange = changes.find(\n (c) =>\n resolveOwner(c.owner) !== sender &&\n c.coinType === primary.coinType &&\n BigInt(c.amount) > 0n,\n );\n recipient = recipientChange ? resolveOwner(recipientChange.owner) ?? undefined : undefined;\n }\n\n return { amount, asset, recipient, direction };\n}\n\nfunction bigintAbs(n: bigint): bigint {\n return n < 0n ? -n : n;\n}\n\n/**\n * Extract every non-zero user balance leg for a transaction — not\n * just the largest one. Order is RPC order; callers responsible for\n * any sorting (e.g. audric sorts by USD value once it's priced).\n *\n * Sui collapses balance changes by coin type, so a 3-step bundle\n * touching USDC three times surfaces as ONE leg of net USDC delta.\n * Distinguishing per-step legs would require parsing the PTB's\n * commands; this helper deliberately stops at the balance-change\n * granularity because that's what's reliably available across all\n * Sui RPC versions.\n *\n * Pre-v1.27.2 the only public API was `extractTransferDetails`,\n * which returned a single \"primary\" leg and made swap rows\n * unrenderable (showed `Swapped 987.60 MANIFEST` because MANIFEST\n * was the largest raw delta even though USDC was the value side).\n */\nexport function extractAllUserLegs(\n changes: ClassifyBalanceChange[] | undefined,\n sender: string,\n): import('../types.js').TransactionLeg[] {\n if (!changes || changes.length === 0) return [];\n\n const legs: import('../types.js').TransactionLeg[] = [];\n for (const c of changes) {\n if (resolveOwner(c.owner) !== sender) continue;\n const raw = BigInt(c.amount);\n if (raw === 0n) continue;\n const decimals = getDecimalsForCoinType(c.coinType);\n const absAmount = bigintAbs(raw);\n legs.push({\n coinType: c.coinType,\n asset: resolveSymbol(c.coinType),\n decimals,\n amount: Number(absAmount) / 10 ** decimals,\n rawAmount: raw.toString(),\n direction: raw < 0n ? 'out' : 'in',\n });\n }\n\n return legs;\n}\n","import type { TransactionRecord } from '../types.js';\nimport { getSuiGraphQLClient } from '../utils/sui.js';\nimport {\n classifyTransaction,\n extractAllUserLegs,\n extractTransferDetails,\n type ClassifyBalanceChange,\n} from './classify.js';\n\n// ---------------------------------------------------------------------------\n// [gRPC migration / S.447 + S.450] Transaction history is the one surface with\n// NO gRPC `core.*` equivalent (Stage 0 finding A): list-by-affected-address +\n// per-tx-by-digest live in the GraphQL RPC, not gRPC. Both go through the\n// Sui GraphQL endpoint (`getSuiGraphQLClient()`), share one node fragment +\n// one mapper, and feed the existing (tested) classifier in `classify.ts`.\n//\n// LIVE-VERIFIED 2026-06-15 (S.450) against `graphql.mainnet.sui.io` with a\n// real sender (send + Cetus swap digests). The live schema differs from the\n// older `transactionBlocks` one: the query is `transactions` / `transaction`\n// (filter `affectedAddress` — sender, sponsor, or recipient), the programmable kind is `ProgrammableTransaction`\n// (was `ProgrammableTransactionBlock`) with `commands { nodes }` (was\n// `transactions`), and a move call is `MoveCallCommand` with a nested\n// `function { name module { name package { address } } }` (was a flat\n// `MoveCallTransaction { package module functionName }`). GraphQL errors are\n// now SURFACED, not swallowed (the old `?? []` hid this schema drift as an\n// empty history for a whole session). Schema ref: https://docs.sui.io/references/sui-graphql\n// ---------------------------------------------------------------------------\n\nconst TX_NODE_FRAGMENT = `\n digest\n effects {\n timestamp\n gasEffects { gasSummary { computationCost storageCost storageRebate } }\n balanceChanges { nodes { amount coinType { repr } owner { address } } }\n }\n kind {\n __typename\n ... on ProgrammableTransaction {\n commands {\n nodes {\n __typename\n ... on MoveCallCommand { function { name module { name package { address } } } }\n }\n }\n }\n }\n`;\n\n// `affectedAddress` (not `sentAddress`) so history includes INCOMING transactions\n// — received payments, x402/MPP refunds, airdrops — not just ones the agent\n// signed. Per the Sui GraphQL schema: \"transactions that interacted with the\n// given address … as a sender, sponsor, or recipient.\" The shared classifier\n// already labels each leg's direction ('in' / 'out'), so inbound txns render\n// correctly downstream.\nconst HISTORY_QUERY = `query History($address: SuiAddress!, $last: Int!) {\n transactions(last: $last, filter: { affectedAddress: $address }) {\n nodes {${TX_NODE_FRAGMENT}}\n }\n}`;\n\nconst TX_BY_DIGEST_QUERY = `query TxByDigest($digest: String!) {\n transaction(digest: $digest) {${TX_NODE_FRAGMENT}}\n}`;\n\n/** Minimal shape of a Sui GraphQL transaction node we consume. */\ninterface GqlTxNode {\n digest?: string;\n effects?: {\n timestamp?: string;\n // Live schema returns gas as numbers; `Number()` in the mapper tolerates both.\n gasEffects?: { gasSummary?: { computationCost?: string | number; storageCost?: string | number; storageRebate?: string | number } };\n balanceChanges?: { nodes?: Array<{ amount?: string; coinType?: { repr?: string }; owner?: { address?: string } }> };\n };\n kind?: {\n __typename?: string;\n commands?: {\n nodes?: Array<{\n __typename?: string;\n function?: { name?: string; module?: { name?: string; package?: { address?: string } } };\n }>;\n };\n };\n}\n\n/** GraphQL transport result with the optional `errors` array surfaced. */\ninterface GqlResult<T> {\n data?: T;\n errors?: Array<{ message?: string }>;\n}\n\nfunction assertNoGqlErrors(res: GqlResult<unknown>, what: string): void {\n if (res.errors?.length) {\n throw new Error(\n `Sui GraphQL ${what} failed: ${res.errors.map((e) => e.message ?? 'unknown error').join('; ')}`,\n );\n }\n}\n\nexport async function queryHistory(\n address: string,\n limit = 20,\n): Promise<TransactionRecord[]> {\n const gql = getSuiGraphQLClient();\n const res = (await gql.query({ query: HISTORY_QUERY, variables: { address, last: limit } })) as GqlResult<{\n transactions?: { nodes?: GqlTxNode[] };\n }>;\n assertNoGqlErrors(res, 'history query');\n const nodes = res.data?.transactions?.nodes ?? [];\n // GraphQL `last` returns ascending; the legacy JSON-RPC path returned\n // descending (newest first) — reverse to preserve caller expectations.\n return nodes.map((n) => recordFromGqlNode(n, address)).reverse();\n}\n\nexport async function queryTransaction(\n digest: string,\n senderAddress: string,\n): Promise<TransactionRecord | null> {\n const gql = getSuiGraphQLClient();\n const res = (await gql.query({ query: TX_BY_DIGEST_QUERY, variables: { digest } })) as GqlResult<{\n transaction?: GqlTxNode | null;\n }>;\n assertNoGqlErrors(res, 'transaction query');\n const node = res.data?.transaction;\n if (!node) return null; // genuine not-found (distinct from a query error, which throws above)\n return recordFromGqlNode(node, senderAddress);\n}\n\n/**\n * Map a Sui GraphQL transactionBlock node → the primitives the shared\n * classifier consumes, then build the record. Isolated so the legacy\n * JSON-RPC `parseTxRecord` (back-compat, below) and this GraphQL path\n * converge on one classification routine.\n */\nfunction recordFromGqlNode(node: GqlTxNode, address: string): TransactionRecord {\n const gs = node.effects?.gasEffects?.gasSummary;\n const gasCost = gs\n ? (Number(gs.computationCost ?? 0) + Number(gs.storageCost ?? 0) - Number(gs.storageRebate ?? 0)) / 1e9\n : undefined;\n\n const balanceChanges: ClassifyBalanceChange[] = (node.effects?.balanceChanges?.nodes ?? [])\n .filter((b) => b.coinType?.repr && b.amount != null)\n .map((b) => ({ coinType: b.coinType!.repr!, amount: String(b.amount), owner: b.owner?.address ?? '' }));\n\n const moveCallTargets: string[] = [];\n const commandTypes: string[] = [];\n if (node.kind?.__typename === 'ProgrammableTransaction') {\n for (const cmd of node.kind.commands?.nodes ?? []) {\n if (cmd.__typename === 'MoveCallCommand') {\n commandTypes.push('MoveCall');\n const fn = cmd.function;\n const pkg = fn?.module?.package?.address;\n const mod = fn?.module?.name;\n const name = fn?.name;\n if (pkg && mod && name) {\n moveCallTargets.push(`${pkg}::${mod}::${name}`);\n }\n } else if (cmd.__typename === 'TransferObjectsCommand') {\n commandTypes.push('TransferObjects');\n }\n }\n }\n\n // GraphQL effects.timestamp is an ISO datetime; the record wants ms.\n const ts = node.effects?.timestamp ? Date.parse(node.effects.timestamp) : 0;\n\n return buildRecord({\n digest: node.digest ?? '',\n moveCallTargets,\n commandTypes,\n balanceChanges,\n timestampMs: Number.isFinite(ts) ? ts : 0,\n gasCost,\n address,\n });\n}\n\n/** Shared record builder — classification + leg/transfer extraction. */\nfunction buildRecord(args: {\n digest: string;\n moveCallTargets: string[];\n commandTypes: string[];\n balanceChanges: ClassifyBalanceChange[];\n timestampMs: number;\n gasCost: number | undefined;\n address: string;\n}): TransactionRecord {\n const { digest, moveCallTargets, commandTypes, balanceChanges, timestampMs, gasCost, address } = args;\n const legs = extractAllUserLegs(balanceChanges, address);\n const { amount, asset, recipient, direction } = extractTransferDetails(balanceChanges, address);\n const { action, label } = classifyTransaction(moveCallTargets, commandTypes, balanceChanges, address);\n return { digest, action, label, legs, amount, asset, recipient, direction, timestamp: timestampMs, gasCost };\n}\n\n/**\n * Shape of a transaction block as returned by `suix_queryTransactionBlocks`\n * with `showEffects | showInput | showBalanceChanges` enabled. Exported so\n * downstream consumers (audric dashboard `/api/history`, `/api/activity`,\n * etc.) can type their RPC calls without redeclaring the structure.\n */\nexport interface SuiRpcTxBlock {\n digest: string;\n timestampMs?: string;\n transaction?: unknown;\n effects?: { gasUsed?: { computationCost: string; storageCost: string; storageRebate: string } };\n balanceChanges?: ClassifyBalanceChange[];\n}\n\n/**\n * Convert a single Sui RPC transaction block to a {@link TransactionRecord}\n * using the canonical (shared) classifier and balance-change extractor.\n *\n * This is the single source of truth for transaction parsing across the\n * agent-tool path AND the dashboard-API path. Use it instead of writing\n * a bespoke parser per surface.\n *\n * @param tx Raw RPC tx block (must include `effects`, `input`, `balanceChanges`).\n * @param address Wallet address whose perspective we're parsing from.\n */\nexport function parseSuiRpcTx(tx: SuiRpcTxBlock, address: string): TransactionRecord {\n return parseTxRecord(tx, address);\n}\n\n/**\n * Extract the sender (signer) address from a raw RPC tx block.\n * Returns `null` if the block shape is unexpected.\n */\nexport function extractTxSender(txBlock: unknown): string | null {\n try {\n if (!txBlock || typeof txBlock !== 'object') return null;\n const data = 'data' in txBlock ? (txBlock as Record<string, unknown>).data : undefined;\n if (!data || typeof data !== 'object') return null;\n return ((data as Record<string, unknown>).sender as string) ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract MoveCall targets (`<pkg>::<module>::<function>`) and the\n * sequence of programmable-transaction command types (e.g. `MoveCall`,\n * `TransferObjects`) from a raw RPC tx block. Tolerates both the\n * legacy `inner.transactions` field and the newer `inner.commands`\n * field.\n */\nexport function extractTxCommands(txBlock: unknown): {\n moveCallTargets: string[];\n commandTypes: string[];\n} {\n return extractCommands(txBlock);\n}\n\n// [back-compat] Legacy JSON-RPC-shape parser. The live history path is now\n// GraphQL (above); this stays for external consumers that already hold a\n// JSON-RPC tx block (e.g. via `parseSuiRpcTx`). Routes through `buildRecord`\n// so classification is identical to the GraphQL path.\nfunction parseTxRecord(tx: SuiRpcTxBlock, address: string): TransactionRecord {\n const gasUsed = tx.effects?.gasUsed;\n const gasCost = gasUsed\n ? (Number(gasUsed.computationCost) +\n Number(gasUsed.storageCost) -\n Number(gasUsed.storageRebate)) /\n 1e9\n : undefined;\n\n const { moveCallTargets, commandTypes } = extractCommands(tx.transaction);\n return buildRecord({\n digest: tx.digest,\n moveCallTargets,\n commandTypes,\n balanceChanges: tx.balanceChanges ?? [],\n timestampMs: Number(tx.timestampMs ?? 0),\n gasCost,\n address,\n });\n}\n\ninterface CommandInfo {\n moveCallTargets: string[];\n commandTypes: string[];\n}\n\nfunction extractCommands(txBlock: unknown): CommandInfo {\n const result: CommandInfo = { moveCallTargets: [], commandTypes: [] };\n try {\n if (!txBlock || typeof txBlock !== 'object') return result;\n const data = 'data' in txBlock ? (txBlock as Record<string, unknown>).data : undefined;\n if (!data || typeof data !== 'object') return result;\n const inner = 'transaction' in (data as Record<string, unknown>)\n ? (data as Record<string, unknown>).transaction\n : undefined;\n if (!inner || typeof inner !== 'object') return result;\n const commands = 'commands' in (inner as Record<string, unknown>)\n ? (inner as Record<string, unknown>).commands\n : 'transactions' in (inner as Record<string, unknown>)\n ? (inner as Record<string, unknown>).transactions\n : undefined;\n if (!Array.isArray(commands)) return result;\n\n for (const cmd of commands as Record<string, unknown>[]) {\n if (cmd.MoveCall) {\n const mc = cmd.MoveCall as { package: string; module: string; function: string };\n result.moveCallTargets.push(`${mc.package}::${mc.module}::${mc.function}`);\n result.commandTypes.push('MoveCall');\n } else if (cmd.TransferObjects) {\n result.commandTypes.push('TransferObjects');\n }\n }\n } catch { /* best effort */ }\n return result;\n}\n","import { MIST_PER_SUI, USDC_DECIMALS, SUPPORTED_ASSETS } from '../constants.js';\nimport type { SupportedAsset } from '../constants.js';\n\nexport function mistToSui(mist: bigint): number {\n return Number(mist) / Number(MIST_PER_SUI);\n}\n\nexport function suiToMist(sui: number): bigint {\n return BigInt(Math.round(sui * Number(MIST_PER_SUI)));\n}\n\nexport function usdcToRaw(amount: number): bigint {\n return BigInt(Math.round(amount * 10 ** USDC_DECIMALS));\n}\n\nexport function rawToUsdc(raw: bigint): number {\n return Number(raw) / 10 ** USDC_DECIMALS;\n}\n\nexport function stableToRaw(amount: number, decimals: number): bigint {\n return BigInt(Math.round(amount * 10 ** decimals));\n}\n\nexport function rawToStable(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nexport function getDecimals(asset: SupportedAsset): number {\n return SUPPORTED_ASSETS[asset].decimals;\n}\n\nexport function rawToDisplay(raw: bigint, decimals: number): number {\n return Number(raw) / 10 ** decimals;\n}\n\nexport function displayToRaw(amount: number, decimals: number): bigint {\n return BigInt(Math.round(amount * 10 ** decimals));\n}\n\nexport function formatUsd(amount: number): string {\n return `$${amount.toFixed(2)}`;\n}\n\nexport function formatSui(amount: number): string {\n if (amount < 0.001) return `${amount.toFixed(6)} SUI`;\n return `${amount.toFixed(3)} SUI`;\n}\n\nexport function formatLargeNumber(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toFixed(2);\n}\n\nexport function formatAssetAmount(amount: number, asset: string): string {\n if (asset === 'BTC') return amount.toFixed(8);\n if (asset === 'GOLD') return amount.toFixed(6);\n if (asset === 'ETH') return amount.toFixed(6);\n return amount.toFixed(4);\n}\n\nconst ASSET_LOOKUP: Map<string, string> = new Map();\nfor (const [key, info] of Object.entries(SUPPORTED_ASSETS)) {\n ASSET_LOOKUP.set(key.toUpperCase(), key);\n if (info.displayName && info.displayName.toUpperCase() !== key.toUpperCase()) {\n ASSET_LOOKUP.set(info.displayName.toUpperCase(), key);\n }\n}\n\n/**\n * Case-insensitive lookup against SUPPORTED_ASSETS keys AND display names.\n * 'usde' → 'USDe', 'suiusde' → 'USDe', 'suiusdt' → 'USDT', 'usdsui' → 'USDsui'.\n * Returns the original input if not found so downstream validation can reject it.\n */\nexport function normalizeAsset(input: string): string {\n return ASSET_LOOKUP.get(input.toUpperCase()) ?? input;\n}\n","/** Cross-platform (Node + browser) base64 helpers. */\n\nexport function toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\nexport function fromBase64(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n","/**\n * Cetus Aggregator V3 SDK wrapper — the ONLY file that imports @cetusprotocol/aggregator-sdk.\n * Documented CLAUDE.md exception: multi-DEX routing cannot be feasibly replaced by thin tx builders.\n *\n * [B5 v2 / @t2000/sdk@1.1.0 / 2026-04-30]\n * Overlay fee config is now per-call instead of a module-level singleton. CLI / direct\n * SDK callers (`T2000.swap()`) DON'T pass `overlayFee` → fee-free swap. Audric's\n * prepare/route.ts ALWAYS passes `overlayFee = { rate: OVERLAY_FEE_RATE, receiver:\n * T2000_OVERLAY_FEE_WALLET }` → fee charged. Structural inclusion (Audric's code can't\n * forget to pass it because it IS the code), not a toggle that defaults to safe.\n *\n * Pre-1.1.0: a module-level `OVERLAY_FEE_RECEIVER` constant defaulted to a Move object\n * ID. USDC sent there became OwnedObjects keyed to the object and was inaccessible.\n * Fixed by making the receiver a regular wallet address (T2000_OVERLAY_FEE_WALLET) AND\n * by removing the singleton pattern that hid the misconfig.\n */\nimport { AggregatorClient, Env, type FindRouterParams, type RouterDataV3 } from '@cetusprotocol/aggregator-sdk';\nimport { Transaction, type TransactionObjectArgument } from '@mysten/sui/transactions';\nimport BN from 'bn.js';\nimport { resolveTokenType, getDecimalsForCoinType } from '../token-registry.js';\nimport type { SuiCoreClient } from '../utils/sui.js';\nimport type { SponsoredCoinMergeCache } from '../wallet/coinSelection.js';\nimport {\n type PreflightResult,\n PREFLIGHT_OK,\n preflightFail,\n checkPositiveAmount,\n} from '../preflight.js';\n\n/**\n * Synchronous, network-free preflight for `swap`. Validates the from/to token\n * args + amount sanity, and rejects an identity swap — the cheap checks the\n * host runs before routing. Returns a `PreflightResult`; never throws.\n * Route-finding, liquidity, slippage + decimals resolution stay in the async\n * path (`findSwapRoute`/`buildSwapTx`/`getSwapQuote`).\n *\n * v3 drops the swap *tool*, but `swap` survives as an SDK/CLI builder (§8) so\n * it gets the same builder-appropriate preflight as send/pay.\n */\nexport function preflightSwap(input: {\n from: string;\n to: string;\n amount: number;\n}): PreflightResult {\n if (typeof input.from !== 'string' || input.from.trim() === '') {\n return preflightFail('INVALID_ASSET', 'A `from` token is required to swap');\n }\n if (typeof input.to !== 'string' || input.to.trim() === '') {\n return preflightFail('INVALID_ASSET', 'A `to` token is required to swap');\n }\n\n // No upper ceiling — swaps route arbitrary tokens, and low-unit-value tokens\n // legitimately trade in millions/billions of units.\n const amountCheck = checkPositiveAmount(input.amount, 'Amount', Number.POSITIVE_INFINITY);\n if (!amountCheck.valid) return amountCheck;\n\n // Identity swap is a no-op the router can't route — catch it cheaply.\n // Resolve symbol → coin type so \"USDC\" and the USDC coin type compare equal.\n // Guard the null===null case (two unknown symbols both resolve to null) by\n // also requiring the resolved value to be non-null, falling back to a raw\n // string compare.\n const resolvedFrom = resolveTokenType(input.from);\n const resolvedTo = resolveTokenType(input.to);\n const sameToken =\n input.from.trim() === input.to.trim() ||\n (resolvedFrom !== null && resolvedFrom === resolvedTo);\n if (sameToken) {\n return preflightFail('INVALID_ASSET', `Cannot swap ${input.from} to itself`);\n }\n\n return PREFLIGHT_OK;\n}\n\nexport interface OverlayFeeConfig {\n /** Fee rate as a fraction (e.g. 0.001 = 0.1%). Pass 0 to disable. */\n rate: number;\n /** Wallet address that receives the overlay fee. */\n receiver: string;\n}\n\nexport interface SwapRouteResult {\n routerData: RouterDataV3;\n amountIn: string;\n amountOut: string;\n byAmountIn: boolean;\n priceImpact: number;\n insufficientLiquidity: boolean;\n}\n\n// [SPEC 20.2 / D-1 (a)] Typed JSON-friendly representation of a Cetus\n// `RouterDataV3` for cross-process / cross-network transport. The native\n// shape contains `BN` instances (`bn.js`) and a `Map<string, string>`\n// (`packages`) that don't survive JSON.stringify / JSON.parse cleanly:\n// - `BN.toJSON()` returns the internal `{negative,words,length,red}` blob\n// - `Map.toJSON()` returns `{}`\n// Round-tripping via `serializeCetusRoute` + `deserializeCetusRoute`\n// converts BN ↔ decimal string and Map ↔ Record. Engine + audric both\n// reference fields by path (`route.routerData.paths[i].provider`) without\n// needing to know about the underlying BN/Map types.\nexport interface SerializedCetusRoutePath {\n id: string;\n direction: boolean;\n provider: string;\n from: string;\n target: string;\n feeRate: number;\n amountIn: string;\n amountOut: string;\n version?: string;\n publishedAt?: string;\n extendedDetails?: Record<string, unknown>;\n}\n\nexport interface SerializedRouterDataV3 {\n quoteID?: string;\n /** RouterDataV3.amountIn (BN) → decimal string */\n amountIn: string;\n /** RouterDataV3.amountOut (BN) → decimal string */\n amountOut: string;\n byAmountIn: boolean;\n paths: SerializedCetusRoutePath[];\n insufficientLiquidity: boolean;\n deviationRatio: number;\n /** RouterDataV3.packages (Map) → Record */\n packages?: Record<string, string>;\n totalDeepFee?: number;\n error?: { code: number; msg: string };\n overlayFee?: number;\n}\n\nexport interface SerializedCetusRoute {\n routerData: SerializedRouterDataV3;\n amountIn: string;\n amountOut: string;\n byAmountIn: boolean;\n priceImpact: number;\n insufficientLiquidity: boolean;\n /**\n * Wall-clock timestamp (ms since epoch) at which the route was discovered.\n * Used by audric's prepare-route for SPEC 20.2 D-3 TTL re-validation: if\n * the route is older than the threshold AND price impact has shifted\n * beyond tolerance, fall back to a fresh `findSwapRoute()` call.\n */\n discoveredAt: number;\n /**\n * Snapshot of the input/output coin types the route was discovered for.\n * SPEC 20.2 D-2 (b) structural verification: prepare-route asserts\n * input/output coins match before using the fast-path; mismatch falls\n * back to fresh discovery (defense against client-side tampering and\n * against legitimate token-type drift in the request).\n */\n fromCoinType: string;\n toCoinType: string;\n}\n\nexport function serializeCetusRoute(\n route: SwapRouteResult,\n context: { fromCoinType: string; toCoinType: string },\n): SerializedCetusRoute {\n return {\n routerData: serializeRouterDataV3(route.routerData),\n amountIn: route.amountIn,\n amountOut: route.amountOut,\n byAmountIn: route.byAmountIn,\n priceImpact: route.priceImpact,\n insufficientLiquidity: route.insufficientLiquidity,\n discoveredAt: Date.now(),\n fromCoinType: context.fromCoinType,\n toCoinType: context.toCoinType,\n };\n}\n\nexport function deserializeCetusRoute(serialized: SerializedCetusRoute): SwapRouteResult {\n return {\n routerData: deserializeRouterDataV3(serialized.routerData),\n amountIn: serialized.amountIn,\n amountOut: serialized.amountOut,\n byAmountIn: serialized.byAmountIn,\n priceImpact: serialized.priceImpact,\n insufficientLiquidity: serialized.insufficientLiquidity,\n };\n}\n\nfunction serializeRouterDataV3(rd: RouterDataV3): SerializedRouterDataV3 {\n const out: SerializedRouterDataV3 = {\n amountIn: rd.amountIn.toString(),\n amountOut: rd.amountOut.toString(),\n byAmountIn: rd.byAmountIn,\n paths: rd.paths.map(serializeCetusRoutePath),\n insufficientLiquidity: rd.insufficientLiquidity,\n deviationRatio: rd.deviationRatio,\n };\n if (rd.quoteID !== undefined) out.quoteID = rd.quoteID;\n if (rd.packages) {\n const obj: Record<string, string> = {};\n for (const [k, v] of rd.packages) obj[k] = v;\n out.packages = obj;\n }\n if (rd.totalDeepFee !== undefined) out.totalDeepFee = rd.totalDeepFee;\n if (rd.error) out.error = { code: rd.error.code, msg: rd.error.msg };\n if (rd.overlayFee !== undefined) out.overlayFee = rd.overlayFee;\n return out;\n}\n\nfunction deserializeRouterDataV3(s: SerializedRouterDataV3): RouterDataV3 {\n const out: RouterDataV3 = {\n amountIn: new BN(s.amountIn),\n amountOut: new BN(s.amountOut),\n byAmountIn: s.byAmountIn,\n paths: s.paths.map(deserializeCetusRoutePath),\n insufficientLiquidity: s.insufficientLiquidity,\n deviationRatio: s.deviationRatio,\n };\n if (s.quoteID !== undefined) out.quoteID = s.quoteID;\n if (s.packages) out.packages = new Map(Object.entries(s.packages));\n if (s.totalDeepFee !== undefined) out.totalDeepFee = s.totalDeepFee;\n if (s.error) out.error = { code: s.error.code, msg: s.error.msg };\n if (s.overlayFee !== undefined) out.overlayFee = s.overlayFee;\n return out;\n}\n\nfunction serializeCetusRoutePath(p: RouterDataV3['paths'][number]): SerializedCetusRoutePath {\n const out: SerializedCetusRoutePath = {\n id: p.id,\n direction: p.direction,\n provider: p.provider,\n from: p.from,\n target: p.target,\n feeRate: p.feeRate,\n amountIn: p.amountIn,\n amountOut: p.amountOut,\n };\n if (p.version !== undefined) out.version = p.version;\n if (p.publishedAt !== undefined) out.publishedAt = p.publishedAt;\n if (p.extendedDetails) out.extendedDetails = { ...p.extendedDetails };\n return out;\n}\n\nfunction deserializeCetusRoutePath(p: SerializedCetusRoutePath): RouterDataV3['paths'][number] {\n const out: RouterDataV3['paths'][number] = {\n id: p.id,\n direction: p.direction,\n provider: p.provider,\n from: p.from,\n target: p.target,\n feeRate: p.feeRate,\n amountIn: p.amountIn,\n amountOut: p.amountOut,\n };\n if (p.version !== undefined) out.version = p.version;\n if (p.publishedAt !== undefined) out.publishedAt = p.publishedAt;\n if (p.extendedDetails) out.extendedDetails = { ...p.extendedDetails };\n return out;\n}\n\n/**\n * SPEC 20.2 D-2 (b) structural verification helper. Returns true when the\n * serialized route matches the requested coin types (i.e. it's safe to use\n * as the prepare-route fast-path), false otherwise (tampered, or input\n * mismatch from a legitimate but stale pending action). Caller falls back\n * to a fresh `findSwapRoute()` call when verification fails.\n */\nexport function verifyCetusRouteCoinMatch(\n serialized: SerializedCetusRoute,\n expected: { fromCoinType: string; toCoinType: string },\n): boolean {\n return serialized.fromCoinType === expected.fromCoinType && serialized.toCoinType === expected.toCoinType;\n}\n\n/**\n * SPEC 20.2 D-3 (b) TTL helper. Returns true when the serialized route is\n * fresh enough to use as the fast-path (< `maxAgeMs` old). Returns false\n * for stale routes — caller falls back to fresh `findSwapRoute()` to pick\n * up any pool-price drift since route discovery.\n *\n * Default 30s aligns with the existing quote-freshness contract surfaced\n * to users via `pending_action.quoteAge` (the PermissionCard \"QUOTE Ns OLD\"\n * badge starts warning the user past 30s).\n */\nexport function isCetusRouteFresh(serialized: SerializedCetusRoute, maxAgeMs: number = 30_000): boolean {\n return Date.now() - serialized.discoveredAt < maxAgeMs;\n}\n\n/**\n * Default Audric swap overlay fee — 0.1%. Exported for consumers that want to use\n * the canonical Audric rate (the Audric prepare-route does this). Changing this\n * rate requires a coordinated SDK + audric release.\n */\nexport const OVERLAY_FEE_RATE = 0.001;\n\n/**\n * Cache `AggregatorClient` instances by `(signer + overlay rate + overlay receiver)`.\n * Per-call instantiation is cheap (the client is mostly config), but caching avoids\n * pointless re-allocation when the same caller swaps multiple times in a loop.\n */\nconst clientCache = new Map<string, AggregatorClient>();\n\nfunction getClient(walletAddress: string, overlayFee?: OverlayFeeConfig): AggregatorClient {\n const rate = overlayFee?.rate ?? 0;\n const receiver = overlayFee?.receiver ?? '';\n const key = `${walletAddress}|${rate}|${receiver}`;\n\n const cached = clientCache.get(key);\n if (cached) return cached;\n\n const client = new AggregatorClient({\n signer: walletAddress,\n env: Env.Mainnet,\n ...(rate > 0 && receiver\n ? { overlayFeeRate: rate, overlayFeeReceiver: receiver }\n : {}),\n });\n clientCache.set(key, client);\n return client;\n}\n\n/**\n * [Bug A defense-in-depth / 2026-05-10] Returns true when every path\n * provider in `route.routerData.paths` is present in the active\n * `providers` allow-list. Cetus's `getProvidersExcluding(...)` returns\n * an inclusion list (the complement of the exclusion), so when a caller\n * passes `providers`, every walked provider must be IN that list to be\n * compatible.\n *\n * When `providers` is undefined (non-sponsored caller, e.g. CLI) every\n * route is compatible — same semantics as `findSwapRoute` itself.\n *\n * Why per-path: a Cetus aggregator route can split across multiple DEXes\n * (e.g. 60% Cetus + 40% Bluefin). A single excluded provider in any path\n * triggers `tx.gas` usage in `routerSwap`. Reject the whole route if any\n * leg is excluded.\n */\nexport function isPrecomputedRouteCompatibleWithProviders(\n route: SwapRouteResult,\n providers: string[] | undefined,\n): boolean {\n if (!providers || providers.length === 0) return true;\n const allowed = new Set(providers);\n for (const path of route.routerData.paths) {\n if (!allowed.has(path.provider)) return false;\n }\n return true;\n}\n\n/**\n * Find the optimal swap route via Cetus Aggregator REST API.\n *\n * Pass `overlayFee` to charge an overlay fee on the output (Audric's pattern).\n * Omit it for a fee-free swap (CLI / direct SDK pattern).\n */\nexport async function findSwapRoute(params: {\n walletAddress: string;\n from: string;\n to: string;\n amount: bigint;\n byAmountIn: boolean;\n overlayFee?: OverlayFeeConfig;\n /**\n * Optional Cetus provider allow-list. When omitted, all 30+ DEXes\n * are eligible. Sponsored flows (Enoki) MUST pass an exclusion list\n * computed via `getProvidersExcluding([...])` from the Cetus SDK to\n * remove Pyth-dependent providers (HAEDALPMM, METASTABLE, OBRIC,\n * STEAMM_OMM, STEAMM_OMM_V2, SEVENK, HAEDALHMMV2) — those reference\n * `tx.gas` for oracle fees, which Enoki rejects in sponsored txs.\n * Non-sponsored callers (CLI, direct SDK) leave this undefined.\n */\n providers?: string[];\n}): Promise<SwapRouteResult | null> {\n const client = getClient(params.walletAddress, params.overlayFee);\n\n const findParams: FindRouterParams = {\n from: params.from,\n target: params.to,\n amount: params.amount.toString(),\n byAmountIn: params.byAmountIn,\n ...(params.providers ? { providers: params.providers } : {}),\n };\n\n const routerData = await client.findRouters(findParams);\n if (!routerData) return null;\n\n if (routerData.insufficientLiquidity) {\n return {\n routerData,\n amountIn: routerData.amountIn.toString(),\n amountOut: routerData.amountOut.toString(),\n byAmountIn: params.byAmountIn,\n priceImpact: normalizePriceImpact(routerData.deviationRatio),\n insufficientLiquidity: true,\n };\n }\n\n if (routerData.error) {\n const { T2000Error } = await import('../errors.js');\n throw new T2000Error('SWAP_FAILED', `Cetus routing error: ${routerData.error.msg} (code ${routerData.error.code})`);\n }\n\n return {\n routerData,\n amountIn: routerData.amountIn.toString(),\n amountOut: routerData.amountOut.toString(),\n byAmountIn: params.byAmountIn,\n priceImpact: normalizePriceImpact(routerData.deviationRatio),\n insufficientLiquidity: false,\n };\n}\n\n/**\n * Cetus' aggregator types `deviationRatio` as `number`, but in some routes\n * the router actually returns a string (\"0.001234\"). The SDK type lies, so we\n * always coerce to a finite number here (NaN/null/undefined → 0). Without\n * this every downstream consumer that calls `priceImpact.toFixed(...)` will\n * crash at runtime — including the Audric SwapQuoteCard, which takes the\n * whole chat UI down through its error boundary.\n */\nfunction normalizePriceImpact(value: unknown): number {\n const n = typeof value === 'number' ? value : Number(value);\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Build a swap PTB from a route result. The caller must provide an input coin\n * obtained by splitting/merging wallet coins.\n *\n * **Important:** Cetus's `routerSwap` reads the overlay-fee config from the\n * AggregatorClient instance. The `overlayFee` param here MUST match the one\n * passed to `findSwapRoute` for the same swap (otherwise you'll hit the cache\n * boundary and get a different client with different overlay config).\n */\nexport async function buildSwapTx(params: {\n walletAddress: string;\n route: SwapRouteResult;\n tx: Transaction;\n inputCoin: TransactionObjectArgument;\n slippage: number;\n overlayFee?: OverlayFeeConfig;\n}): Promise<TransactionObjectArgument> {\n const client = getClient(params.walletAddress, params.overlayFee);\n const clampedSlippage = Math.max(0.001, Math.min(params.slippage, 0.05));\n\n const outputCoin = await client.routerSwap({\n router: params.route.routerData,\n inputCoin: params.inputCoin,\n slippage: clampedSlippage,\n txb: params.tx,\n });\n\n return outputCoin;\n}\n\n/**\n * Append a swap fragment to an existing PTB. SPEC 7 § \"Layer 1\" Cetus\n * appender. Two modes, dispatched by the presence of `input.inputCoin`:\n *\n * - **Wallet mode** (`inputCoin` omitted) — sources `from`-asset funds\n * via `coinWithBalance({ type, balance })` (resolves coin objects +\n * address balance at build time), runs the swap. Mirrors the audric\n * host's `transactions/prepare/route.ts` swap branch (P2.2c will\n * retire that branch in favor of this appender via `composeTx`).\n *\n * - **Chain mode** (`inputCoin` provided) — consumes the passed-in coin\n * reference (typically produced by an upstream appender like\n * `addWithdrawToTx`) directly, no wallet fetch / no merge / no\n * split. This is the SPEC 7 multi-write enabler (\"withdraw → swap →\n * save\" without intermediate wallet materialization).\n *\n * **SUI in wallet mode:** ALWAYS sources through `selectSuiCoin` (which\n * routes via `coinWithBalance({ type: SUI, useGasCoin: false })` under\n * sponsored flows, OR `tx.splitCoins(tx.gas, ...)` under self-funded\n * flows). The caller MUST set `sponsoredContext` correctly — otherwise\n * sponsored swaps with SUI source fail with `Cannot use GasCoin as a\n * transaction argument` (Enoki owns `tx.gas`, the PTB body referencing\n * it as an argument is invalid for sponsorship). 2.14.0 shipped without\n * this branch and broke audric/web-v2 SUI→USDC swaps; restored in 2.14.1\n * (S.260). For non-sponsored flows (CLI), `T2000.swap()` pre-builds the\n * inputCoin via `tx.splitCoins(tx.gas, [rawAmount])[0]` and uses chain\n * mode, sidestepping wallet-mode entirely — this branch is a defensive\n * safety net for future direct SDK users who pass SUI in wallet mode.\n *\n * **`swapAll` semantics (wallet mode):** if the requested raw amount\n * is >= the wallet's total `from` balance, the appender consumes the\n * entire merged primary coin (not a split), matching audric's host\n * route's `swapAll` clipping. The returned `effectiveAmountIn` reflects\n * the actual consumed amount in display units.\n *\n * **Slippage:** clamped to [0.001, 0.05] (0.1% – 5%). Defaults to 0.01.\n *\n * @returns\n * - `coin` — output coin reference, ready for downstream consumption\n * (e.g. `addSaveToTx`) or wallet transfer (`tx.transferObjects`).\n * - `effectiveAmountIn` — display-units input amount the swap actually\n * consumes (handles `swapAll` clipping in wallet mode; in chain mode\n * echoes the requested `input.amount`).\n * - `expectedAmountOut` — display-units output amount per the route\n * quote. Actual on-chain output may differ within slippage.\n * - `route` — raw `SwapRouteResult` for downstream telemetry / logging.\n */\nexport async function addSwapToTx(\n tx: Transaction,\n client: SuiCoreClient,\n address: string,\n input: {\n from: string;\n to: string;\n amount: number;\n slippage?: number;\n byAmountIn?: boolean;\n overlayFee?: OverlayFeeConfig;\n inputCoin?: TransactionObjectArgument;\n /**\n * Optional Cetus provider allow-list. Forwarded to `findSwapRoute`.\n * Sponsored flows (Enoki) MUST pass `getProvidersExcluding([...])`\n * to remove Pyth-dependent providers — see `findSwapRoute`'s JSDoc\n * for the exclusion list. Non-sponsored callers omit this.\n */\n providers?: string[];\n /**\n * [SPEC 20.2 D-3 (b)] Precomputed route from a prior `findSwapRoute()`\n * call (typically captured by `swap_quote` and threaded through\n * `pending_action.cetusRoute`). When present AND not stale (per\n * `isCetusRouteFresh`) AND the input/output coins match, this skips\n * the ~400-500ms `findSwapRoute()` discovery call. Stale routes are\n * silently ignored (caller falls back to fresh discovery).\n *\n * Caller responsibility: pass the SAME `overlayFee` / `providers` /\n * `byAmountIn` that produced the precomputed route. Mismatch will\n * still produce a working swap but may use the wrong overlay-fee\n * config (the route data already encodes the chosen DEX path).\n */\n precomputedRoute?: SwapRouteResult;\n /**\n * Whether this swap is being built inside a sponsored-tx flow (Enoki)\n * vs self-funded (CLI / direct sign). Load-bearing for SUI-source\n * swaps in wallet mode: under sponsored flows, `tx.gas` belongs to\n * the sponsor and CANNOT be referenced as a transaction argument\n * (Sui protocol rejects with `Cannot use GasCoin as a transaction\n * argument`). When `true`, SUI source routes through `selectSuiCoin`\n * with `useGasCoin: false` so the resolver sources from the user's\n * SUI coin objects + address balance instead. Defaults to `false`\n * (back-compat — pre-2.14.1 behavior). Audric/web-v2's compose path\n * threads this through via `composeTx({ sponsoredContext: true })`.\n */\n sponsoredContext?: boolean;\n /**\n * Per-PTB merge cache for sponsored coin-object sourcing (any coin\n * type — SUI in the dedicated branch, USDC/USDsui/etc. in the wallet\n * branch). Provided by `composeTx`'s orchestration loop so multiple\n * legs sourcing the same coin in one bundle share a single merged\n * primary coin instead of each emitting its own `mergeCoins` (the\n * second of which references already-consumed coins → Enoki dry-run\n * `ArgumentWithoutValue`). Single swaps don't need it; omit. See\n * `SponsoredCoinMergeCache` JSDoc.\n */\n coinMergeCache?: SponsoredCoinMergeCache;\n },\n): Promise<{\n coin: TransactionObjectArgument;\n effectiveAmountIn: number;\n expectedAmountOut: number;\n route: SwapRouteResult;\n /** True when `precomputedRoute` was used (no `findSwapRoute()` call). */\n usedPrecomputedRoute: boolean;\n}> {\n const { T2000Error } = await import('../errors.js');\n\n const fromType = resolveTokenType(input.from);\n const toType = resolveTokenType(input.to);\n if (!fromType) throw new T2000Error('ASSET_NOT_SUPPORTED', `Unknown token: ${input.from}. Provide the symbol (USDC, SUI, ...) or full coin type.`);\n if (!toType) throw new T2000Error('ASSET_NOT_SUPPORTED', `Unknown token: ${input.to}. Provide the symbol (USDC, SUI, ...) or full coin type.`);\n if (fromType === toType) throw new T2000Error('SWAP_FAILED', 'Cannot swap a token to itself');\n if (!Number.isFinite(input.amount) || input.amount <= 0) {\n throw new T2000Error('INVALID_AMOUNT', 'Amount must be greater than zero');\n }\n\n const fromDecimals = getDecimalsForCoinType(fromType);\n const toDecimals = getDecimalsForCoinType(toType);\n const requestedRaw = BigInt(Math.floor(input.amount * 10 ** fromDecimals));\n\n const slippage = Math.max(0.001, Math.min(input.slippage ?? 0.01, 0.05));\n const byAmountIn = input.byAmountIn ?? true;\n\n let inputCoin: TransactionObjectArgument;\n let effectiveRaw: bigint;\n\n if (input.inputCoin) {\n inputCoin = input.inputCoin;\n effectiveRaw = requestedRaw;\n } else if (fromType === '0x2::sui::SUI') {\n // SUI source needs special handling: under sponsored flows (Enoki),\n // referencing `tx.gas` as a transaction argument is forbidden (sponsor\n // owns the gas coin). `selectSuiCoin` does the right thing for both\n // sponsored (uses `coinWithBalance({ useGasCoin: false })`) and\n // self-funded (splits from `tx.gas` directly). The 2.14.0 release\n // shipped without this branch and broke audric/web-v2 SUI→USDC swaps\n // (\"Cannot use GasCoin as a transaction argument\" from Enoki); fixed\n // in 2.14.1 (S.260).\n const { selectSuiCoin } = await import('../wallet/coinSelection.js');\n const result = await selectSuiCoin(\n tx,\n client,\n address,\n requestedRaw,\n input.sponsoredContext ?? false,\n input.coinMergeCache,\n );\n inputCoin = result.coin;\n effectiveRaw = result.effectiveAmount;\n } else {\n // Non-SUI wallet-mode source — delegate to the canonical prelude.\n // NON-sponsored: pre-flights against `getBalance().totalBalance` and\n // returns a `coinWithBalance({ type, balance })` arg, whose `@mysten/sui`\n // resolver batches all intents for a coin type into a single build-time\n // merge — so same-asset multi-leg bundles dedup automatically.\n //\n // SPONSORED: routes through `selectCoinObjectsOnly` instead (coinWithBalance's\n // address-balance `FundsWithdrawal` reservation is what Enoki can't\n // deserialize, issue #93). That manual path has NO build-time batching, so\n // two legs sourcing the same coin would each emit their own `mergeCoins`\n // over the SAME objects → second merge references consumed coins → Enoki\n // dry-run `ArgumentWithoutValue`. The `coinMergeCache` supplies the dedup:\n // first leg merges once + caches the primary, later legs split from it.\n const { selectAndSplitCoin } = await import('../wallet/coinSelection.js');\n const result = await selectAndSplitCoin(tx, client, address, fromType, requestedRaw, {\n sponsoredContext: input.sponsoredContext ?? false,\n mergeCache: input.coinMergeCache,\n });\n inputCoin = result.coin;\n effectiveRaw = result.effectiveAmount;\n }\n\n // [SPEC 20.2 D-3 (b)] Use the precomputed route when available + valid.\n // Validity = same input/output coin types AND the requested raw amount\n // matches what the route was discovered for (mismatch indicates the user\n // edited the amount post-quote, in which case we must re-discover at the\n // new amount because price impact is amount-dependent). The caller\n // (`audric prepare-route`) owns the staleness check (`isCetusRouteFresh`)\n // and only forwards `precomputedRoute` when fresh.\n //\n // [Bug A defense-in-depth / 2026-05-10] Even with the engine fix that\n // makes `swap_quote` discover sponsor-safe routes, this layer also\n // validates the precomputed route against the active providers\n // allow-list. If the route walks any excluded provider (e.g. a stale\n // `pending_action.cetusRoute` from before the engine fix shipped, or a\n // provider list that drifted between quote and execute), fall back to\n // fresh discovery. Better to eat 400ms than to let a Pyth-dependent\n // route reach Enoki and revert with HTTP 400.\n let route: SwapRouteResult | null;\n let usedPrecomputedRoute = false;\n if (\n input.precomputedRoute &&\n input.precomputedRoute.amountIn === effectiveRaw.toString() &&\n input.precomputedRoute.byAmountIn === byAmountIn &&\n isPrecomputedRouteCompatibleWithProviders(input.precomputedRoute, input.providers)\n ) {\n route = input.precomputedRoute;\n usedPrecomputedRoute = true;\n } else {\n route = await findSwapRoute({\n walletAddress: address,\n from: fromType,\n to: toType,\n amount: effectiveRaw,\n byAmountIn,\n overlayFee: input.overlayFee,\n providers: input.providers,\n });\n }\n\n if (!route) {\n throw new T2000Error('SWAP_NO_ROUTE', `No swap route found for ${input.from} → ${input.to}`);\n }\n if (route.insufficientLiquidity) {\n throw new T2000Error('SWAP_NO_ROUTE', `Insufficient liquidity for ${input.from} → ${input.to}`);\n }\n\n const outputCoin = await buildSwapTx({\n walletAddress: address,\n route,\n tx,\n inputCoin,\n slippage,\n overlayFee: input.overlayFee,\n });\n\n return {\n coin: outputCoin,\n effectiveAmountIn: Number(effectiveRaw) / 10 ** fromDecimals,\n expectedAmountOut: Number(route.amountOut) / 10 ** toDecimals,\n route,\n usedPrecomputedRoute,\n };\n}\n\n// Re-export from the canonical token registry for backward-compat.\nexport { TOKEN_MAP, resolveTokenType } from '../token-registry.js';\n","import {\n Transaction,\n type TransactionObjectArgument,\n} from '@mysten/sui/transactions';\nimport {\n GASLESS_MIN_STABLE_AMOUNT,\n GASLESS_STABLE_TYPES,\n SUPPORTED_ASSETS,\n assertAllowedAsset,\n type SendableAsset,\n} from '../constants.js';\nimport { T2000Error } from '../errors.js';\nimport { validateAddress, type SuiCoreClient } from '../utils/sui.js';\nimport { displayToRaw } from '../utils/format.js';\nimport {\n type PreflightResult,\n PREFLIGHT_OK,\n preflightFail,\n checkPositiveAmount,\n checkSuiAddress,\n} from '../preflight.js';\n\n/**\n * Synchronous, network-free preflight for `send`. Validates asset membership,\n * amount sanity, the gasless stable floor, and recipient address shape — the\n * cheap checks the v3 host runs before the LLM round-trip / tap-to-confirm.\n * Returns a `PreflightResult`; never throws. `buildSendTx` calls this first,\n * then layers the network balance read on top.\n */\nexport function preflightSend(input: {\n to: string;\n amount: number;\n asset: string;\n}): PreflightResult {\n // Asset membership — reuse the canonical message (single source of truth).\n try {\n assertAllowedAsset('send', input.asset);\n } catch (e) {\n return preflightFail('INVALID_ASSET', (e as T2000Error).message);\n }\n\n const amountCheck = checkPositiveAmount(input.amount);\n if (!amountCheck.valid) return amountCheck;\n\n // Gasless protocol allowlist enforces a 0.01 minimum on the stables.\n if (\n (input.asset === 'USDC' || input.asset === 'USDsui') &&\n input.amount < GASLESS_MIN_STABLE_AMOUNT\n ) {\n return preflightFail(\n 'INVALID_AMOUNT',\n `Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${input.asset}. Got ${input.amount}.`,\n );\n }\n\n const addressCheck = checkSuiAddress(input.to);\n if (!addressCheck.valid) return addressCheck;\n\n return PREFLIGHT_OK;\n}\n\n/**\n * Build a PTB that sends `amount` of `asset` from `address` to `to`.\n *\n * [v4.0 Phase A Day 2 — SPEC_AGENT_WALLET_GREENFIELD §A]\n *\n * Asset constraint: `'USDC' | 'USDsui' | 'SUI'` only. Other assets throw\n * `INVALID_ASSET` via `assertAllowedAsset('send', asset)`. The constrained\n * set matches Sui mainnet's gasless allowlist (USDC + USDsui) plus SUI\n * for users who want a gas-native transfer.\n *\n * Build paths:\n * - **USDC / USDsui** — `0x2::balance::send_funds` Move call with a\n * `tx.balance({ type, balance })` input. When built via `SuiGrpcClient`,\n * the gRPC resolver auto-detects gasless eligibility and zeros gas.\n * When built via `SuiJsonRpcClient`, the same PTB still executes but\n * the caller pays normal gas. Minimum 0.01 (protocol allowlist floor).\n * - **SUI** — `tx.splitCoins(tx.gas, [amount]) → tx.transferObjects()`.\n * Standard gas-native transfer. No minimum.\n *\n * Pre-flight balance check stays on JSON-RPC (`client.getBalance`) — it\n * sums coin objects + address balance so the legacy `getCoins` page miss\n * doesn't break for users whose stables landed via gasless deposits.\n *\n * `asset` is REQUIRED (no implicit USDC default — pre-v4 hid LLM intent\n * errors). Callers passing the wrong asset get an explicit error rather\n * than a silent currency substitution.\n */\nexport async function buildSendTx({\n client,\n address,\n to,\n amount,\n asset,\n}: {\n client: SuiCoreClient;\n address: string;\n to: string;\n amount: number;\n asset: SendableAsset;\n}): Promise<Transaction> {\n // Layer 2 — cheap synchronous preflight (asset / amount / gasless floor /\n // recipient shape). Rethrow the precise code+message verbatim.\n const pf = preflightSend({ to, amount, asset });\n if (!pf.valid) throw new T2000Error(pf.code, pf.error);\n\n const recipient = validateAddress(to);\n const assetInfo = SUPPORTED_ASSETS[asset];\n if (!assetInfo) throw new T2000Error('ASSET_NOT_SUPPORTED', `Asset ${asset} is not supported`);\n\n const rawAmount = displayToRaw(amount, assetInfo.decimals);\n const tx = new Transaction();\n tx.setSender(address);\n\n // Balance pre-flight against `core.getBalance().balance.balance` (sums\n // coins + address balance). The legacy `getCoins` page miss broke for\n // users whose stables had drifted into address balance via @suimpp/mpp 0.7+.\n const balanceResp = await client.core.getBalance({ owner: address, coinType: assetInfo.type });\n const totalBalance = BigInt(balanceResp.balance.balance);\n if (totalBalance < rawAmount) {\n throw new T2000Error('INSUFFICIENT_BALANCE', `Insufficient ${asset} balance`, {\n available: Number(totalBalance) / 10 ** assetInfo.decimals,\n required: amount,\n });\n }\n\n if (asset === 'SUI') {\n // Standard gas-native transfer — split from the gas coin, transfer\n // the resulting object. NOT gasless (SUI is not on the protocol\n // allowlist for `balance::send_funds`).\n const [sendCoin] = tx.splitCoins(tx.gas, [rawAmount]);\n tx.transferObjects([sendCoin], recipient);\n return tx;\n }\n\n // USDC / USDsui — gasless via `0x2::balance::send_funds`. The gRPC\n // build resolver inspects this PTB shape at `tx.build()` time and,\n // when it matches the protocol allowlist, sets gasPrice=0/gasBudget=0\n // automatically. The Move signature is:\n // public fun send_funds<T>(balance: Balance<T>, recipient: address)\n // `tx.balance({ type, balance })` produces a Balance<T> input sourced\n // from the sender's address balance + coin objects (auto-merged).\n const coinType = GASLESS_STABLE_TYPES[asset];\n tx.moveCall({\n target: '0x2::balance::send_funds',\n typeArguments: [coinType],\n arguments: [\n tx.balance({ type: coinType, balance: rawAmount }),\n tx.pure.address(recipient),\n ],\n });\n return tx;\n}\n\n/**\n * Fragment-appender for the chain-mode send leg of SPEC 7 multi-write\n * Payment Intents. Consumes a coin reference produced by a previous\n * appender (e.g. `addWithdrawToTx`, `addSwapToTx`) and transfers it to\n * `recipient` within the same Payment Intent — no intermediate wallet\n * materialization.\n *\n * Codifies the hand-built send leg from\n * `scripts/smoke-spec7-withdraw-then-send.ts` (P2.1) into a typed\n * appender. SPEC 7 § \"Layer 1\" — P2.2b will register this in the\n * `WRITE_APPENDER_REGISTRY` under `send_transfer` for chain-mode\n * dispatch; the registry adapter will handle the wallet-fetch fallback\n * by delegating to `buildSendTx` when no upstream coin is available.\n *\n * For single-step send_transfer flows (no chained predecessor), use\n * `buildSendTx` directly — it builds a complete tx including the\n * wallet-coin selection / merge / split prelude.\n *\n * [v4.0 Phase A Day 2] Stays on the legacy `transferObjects` path\n * because chain-mode bundles are NEVER gasless — by definition they\n * combine multiple Move calls (`withdraw → send`, `swap → send`) which\n * fail the protocol allowlist check (only `balance::send_funds` and\n * a few related helpers are eligible). The bundled flow still works,\n * the user just pays gas (or has it sponsored by audric via Enoki).\n *\n * @returns void — the coin is consumed by `tx.transferObjects`. Callers\n * that need the post-transfer \"effective amount\" should rely on the\n * upstream appender's `effectiveAmount` (e.g. `addWithdrawToTx`'s\n * return), not on this appender.\n */\nexport function addSendToTx(\n tx: Transaction,\n coin: TransactionObjectArgument,\n recipient: string,\n): void {\n const validRecipient = validateAddress(recipient);\n tx.transferObjects([coin], validRecipient);\n}\n","import { Transaction } from '@mysten/sui/transactions';\nimport { T2000Error } from '../errors.js';\nimport { USDC_TYPE } from '../token-registry.js';\nimport { USDC_DECIMALS } from '../constants.js';\nimport {\n type PreflightResult,\n PREFLIGHT_OK,\n preflightFail,\n checkSuiAddress,\n} from '../preflight.js';\nimport { validateAddress, type SuiCoreClient } from '../utils/sui.js';\nimport { selectAndSplitCoin } from './coinSelection.js';\n\n/**\n * A2A Escrow — client for the `a2a_escrow::escrow` Move package\n * (SPEC_A2A_ESCROW, t2 Agents Phase 3).\n *\n * One shared `Job<USDC>` object per engagement; the escrow balance lives IN\n * the object (no treasury, no admin key). These builders construct UNSIGNED\n * transactions; the caller signs (buyer for create/release/reject, seller\n * for deliver, ANYONE for the two timeout cranks) and may sponsor gas — the\n * Move calls authorize on `ctx.sender()`, so sponsorship never weakens auth.\n *\n * Browser-safe (no fs / keyManager imports) so store surfaces can build the\n * buyer-side legs on a zkLogin session key.\n *\n * Deployed on Sui mainnet 2026-07-17. Override via env for testnet/dev.\n */\n\n/** The published `a2a_escrow` package id (mainnet). */\nexport const A2A_ESCROW_PACKAGE_ID =\n process.env.A2A_ESCROW_PACKAGE_ID ??\n '0x9e67c380fb7079d793d6d15ff916b24d82779d7119bfa4631863102ed485c0a0';\n\nconst CLOCK_ID = '0x6';\nconst MODULE = 'escrow';\n\n/** v1 job-value cap in USDC — same instinct as the catalog price cap: the\n * no-arbitration reject-split is only fair at sizes where neither side is\n * incentivized to game it (SPEC_A2A_ESCROW §2). */\nexport const MAX_JOB_USDC = 50;\n\n/** Job lifecycle states, mirroring the Move constants. */\nexport const JOB_STATES = [\n 'funded',\n 'delivered',\n 'released',\n 'refunded',\n 'rejected',\n] as const;\nexport type JobState = (typeof JOB_STATES)[number];\n\nexport interface JobTerms {\n /** The seller's wallet (the listing's payTo / claimed Agent ID wallet). */\n seller: string;\n /** Job value in display USDC (e.g. `5` = 5 USDC). ≤ `MAX_JOB_USDC`. */\n amountUsdc: number;\n /** Hash/commitment of the job spec (hex string, `0x…` or bare). */\n specHash: string;\n /** Epoch-ms deadline the seller must deliver by. */\n deliverByMs: number;\n /** Buyer's accept/reject window (ms) after delivery; lapse = release. */\n reviewWindowMs: number;\n /** Buyer's share in basis points on reject (0–10000). Fixed at create. */\n rejectSplitBps: number;\n}\n\n/** Parsed on-chain `Job` object. */\nexport interface Job {\n id: string;\n buyer: string;\n seller: string;\n /** Locked amount in display USDC (immutable record). */\n amountUsdc: number;\n /** What's still in the object — 0 after settlement. */\n escrowUsdc: number;\n specHash: string;\n deliverByMs: number;\n reviewWindowMs: number;\n rejectSplitBps: number;\n state: JobState;\n deliveryHash: string | null;\n deliveredAtMs: number | null;\n createdAtMs: number;\n}\n\n// ---------------------------------------------------------------------------\n// Hash plumbing — spec/delivery commitments travel as vector<u8>.\n// ---------------------------------------------------------------------------\n\nfunction hexToBytes(hex: string): number[] {\n const clean = hex.startsWith('0x') ? hex.slice(2) : hex;\n if (clean.length === 0 || clean.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean)) {\n throw new T2000Error(\n 'INVALID_AMOUNT',\n `Expected a hex hash (0x…), got \"${hex.slice(0, 32)}\"`,\n );\n }\n const out: number[] = [];\n for (let i = 0; i < clean.length; i += 2) {\n out.push(Number.parseInt(clean.slice(i, i + 2), 16));\n }\n return out;\n}\n\n/** gRPC's `json` include renders Move `vector<u8>` as a base64 STRING;\n * JSON-RPC (and tests) hand back number arrays. Accept both. */\nfunction bytesToHex(bytes: number[] | Uint8Array | string): string {\n const arr =\n typeof bytes === 'string'\n ? Array.from(atob(bytes), (c) => c.charCodeAt(0))\n : bytes;\n let s = '0x';\n for (const b of arr) s += b.toString(16).padStart(2, '0');\n return s;\n}\n\n// ---------------------------------------------------------------------------\n// Preflight\n// ---------------------------------------------------------------------------\n\n/**\n * Synchronous, network-free preflight for `create`. Terms sanity only —\n * the balance read happens in `buildCreateJobTx`.\n */\nexport function preflightCreateJob(terms: JobTerms): PreflightResult {\n const addressCheck = checkSuiAddress(terms.seller);\n if (!addressCheck.valid) return addressCheck;\n if (!Number.isFinite(terms.amountUsdc) || terms.amountUsdc <= 0) {\n return preflightFail('INVALID_AMOUNT', `Amount must be positive. Got ${terms.amountUsdc}.`);\n }\n if (terms.amountUsdc > MAX_JOB_USDC) {\n return preflightFail(\n 'INVALID_AMOUNT',\n `v1 caps escrow jobs at ${MAX_JOB_USDC} USDC (no-arbitration split only stays fair at small sizes). Got ${terms.amountUsdc}.`,\n );\n }\n if (terms.deliverByMs <= Date.now()) {\n return preflightFail('INVALID_AMOUNT', 'deliverByMs must be in the future.');\n }\n if (terms.reviewWindowMs < 0) {\n return preflightFail('INVALID_AMOUNT', 'reviewWindowMs must be ≥ 0.');\n }\n if (\n !Number.isInteger(terms.rejectSplitBps) ||\n terms.rejectSplitBps < 0 ||\n terms.rejectSplitBps > 10_000\n ) {\n return preflightFail('INVALID_AMOUNT', 'rejectSplitBps must be an integer 0–10000.');\n }\n try {\n hexToBytes(terms.specHash);\n } catch (e) {\n return preflightFail('INVALID_AMOUNT', (e as T2000Error).message);\n }\n return PREFLIGHT_OK;\n}\n\n// ---------------------------------------------------------------------------\n// Transaction builders (unsigned; caller signs + executes / sponsors)\n// ---------------------------------------------------------------------------\n\n/**\n * Buyer creates AND funds a job in one PTB — `escrow::create` consumes a\n * `Coin<USDC>` sourced from the buyer's coins + address balance.\n */\nexport async function buildCreateJobTx({\n client,\n buyer,\n terms,\n}: {\n client: SuiCoreClient;\n buyer: string;\n terms: JobTerms;\n}): Promise<Transaction> {\n const pf = preflightCreateJob(terms);\n if (!pf.valid) throw new T2000Error(pf.code, pf.error);\n\n const seller = validateAddress(terms.seller);\n if (seller === validateAddress(buyer)) {\n throw new T2000Error('INVALID_ADDRESS', 'Buyer and seller must be different wallets.');\n }\n // Floor, never round up — a rounded-up raw amount can exceed the on-chain\n // balance (financial-amounts discipline).\n const rawAmount = BigInt(Math.floor(terms.amountUsdc * 10 ** USDC_DECIMALS));\n\n const tx = new Transaction();\n const { coin } = await selectAndSplitCoin(tx, client, buyer, USDC_TYPE, rawAmount, {\n allowSwapAll: false,\n });\n tx.moveCall({\n target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::create`,\n typeArguments: [USDC_TYPE],\n arguments: [\n tx.pure.address(seller),\n coin,\n tx.pure.vector('u8', hexToBytes(terms.specHash)),\n tx.pure.u64(terms.deliverByMs),\n tx.pure.u64(terms.reviewWindowMs),\n tx.pure.u64(terms.rejectSplitBps),\n tx.object(CLOCK_ID),\n ],\n });\n return tx;\n}\n\nfunction jobCall(jobId: string, fn: 'release' | 'refund' | 'reject'): Transaction {\n const tx = new Transaction();\n tx.moveCall({\n target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::${fn}`,\n typeArguments: [USDC_TYPE],\n arguments: [tx.object(jobId), tx.object(CLOCK_ID)],\n });\n return tx;\n}\n\n/** Seller posts the delivery commitment (hex hash) before the deadline. */\nexport function buildDeliverJobTx(jobId: string, deliveryHash: string): Transaction {\n const tx = new Transaction();\n tx.moveCall({\n target: `${A2A_ESCROW_PACKAGE_ID}::${MODULE}::deliver`,\n typeArguments: [USDC_TYPE],\n arguments: [\n tx.object(jobId),\n tx.pure.vector('u8', hexToBytes(deliveryHash)),\n tx.object(CLOCK_ID),\n ],\n });\n return tx;\n}\n\n/** Buyer accepts (or anyone, once the review window lapsed) → funds to seller. */\nexport function buildReleaseJobTx(jobId: string): Transaction {\n return jobCall(jobId, 'release');\n}\n\n/** Buyer rejects within the review window → split per the create terms. */\nexport function buildRejectJobTx(jobId: string): Transaction {\n return jobCall(jobId, 'reject');\n}\n\n/** Anyone, after the deadline with no delivery → funds back to the buyer. */\nexport function buildRefundJobTx(jobId: string): Transaction {\n return jobCall(jobId, 'refund');\n}\n\n// ---------------------------------------------------------------------------\n// Reads\n// ---------------------------------------------------------------------------\n\n/** Fetch + parse a `Job` shared object. Throws `RPC_ERROR` when the id\n * doesn't resolve to an a2a_escrow Job. */\nexport async function getJob(client: SuiCoreClient, jobId: string): Promise<Job> {\n const resp = await client.core\n .getObject({ objectId: jobId, include: { json: true } })\n .catch((e: unknown) => {\n throw new T2000Error(\n 'RPC_ERROR',\n `Job ${jobId} not found: ${e instanceof Error ? e.message : String(e)}`,\n );\n });\n const objType = resp.object?.type ?? '';\n const json = resp.object?.json as Record<string, unknown> | null | undefined;\n if (!json || !objType.includes(`::${MODULE}::Job<`)) {\n throw new T2000Error('RPC_ERROR', `Object ${jobId} is not an a2a_escrow Job.`);\n }\n const stateNum = Number(json.state ?? -1);\n const state = JOB_STATES[stateNum];\n if (!state) {\n throw new T2000Error('RPC_ERROR', `Job ${jobId} has unknown state ${stateNum}.`);\n }\n const deliveredAtMs = Number(json.delivered_at_ms ?? 0);\n const deliveryBytes = (json.delivery_hash ?? []) as number[] | Uint8Array;\n const hasDelivery = deliveredAtMs > 0;\n return {\n id: jobId,\n buyer: String(json.buyer),\n seller: String(json.seller),\n amountUsdc: Number(json.amount) / 10 ** USDC_DECIMALS,\n escrowUsdc: Number(json.escrow) / 10 ** USDC_DECIMALS,\n specHash: bytesToHex((json.spec_hash ?? []) as number[] | Uint8Array),\n deliverByMs: Number(json.deliver_by_ms),\n reviewWindowMs: Number(json.review_window_ms),\n rejectSplitBps: Number(json.reject_split_bps),\n state,\n deliveryHash: hasDelivery ? bytesToHex(deliveryBytes) : null,\n deliveredAtMs: hasDelivery ? deliveredAtMs : null,\n createdAtMs: Number(json.created_at_ms),\n };\n}\n\n/** What `caller` can do to `job` right now — drives `t2 job watch` (the\n * ACP-style \"available action\" readout) and any host UI. */\nexport function jobActionsFor(\n job: Job,\n caller: string,\n nowMs = Date.now(),\n): string[] {\n const me = validateAddress(caller);\n const isBuyer = me === job.buyer;\n const isSeller = me === job.seller;\n const actions: string[] = [];\n if (job.state === 'funded') {\n if (isSeller && nowMs <= job.deliverByMs) actions.push('deliver');\n if (isBuyer) actions.push('release');\n if (nowMs > job.deliverByMs) actions.push('refund');\n } else if (job.state === 'delivered') {\n const windowClosesMs = (job.deliveredAtMs ?? 0) + job.reviewWindowMs;\n if (isBuyer && nowMs <= windowClosesMs) actions.push('release', 'reject');\n if (nowMs > windowClosesMs) actions.push('release');\n }\n return actions;\n}\n\nexport interface JobVerification {\n ok: boolean;\n job: Job;\n /** Human-readable reasons when `ok` is false. */\n problems: string[];\n}\n\n/**\n * Seller-side escrow verification — the x402 `intent: \"escrow\"` credential\n * check. Before starting work on a job id received in an `X-PAYMENT` header,\n * the seller confirms ON-CHAIN (works for every buyer signer, incl. zkLogin):\n * funded, pays ME, covers the price, and leaves enough runway to deliver.\n */\nexport async function verifyJobForSeller({\n client,\n jobId,\n seller,\n minAmountUsdc,\n minRunwayMs = 60_000,\n}: {\n client: SuiCoreClient;\n jobId: string;\n seller: string;\n /** The listing's price for this job class. */\n minAmountUsdc: number;\n /** Minimum time-to-deadline to accept the job (default 60s). */\n minRunwayMs?: number;\n}): Promise<JobVerification> {\n const job = await getJob(client, jobId);\n const problems: string[] = [];\n if (job.state !== 'funded') {\n problems.push(`state is \"${job.state}\", expected \"funded\"`);\n }\n if (job.seller !== validateAddress(seller)) {\n problems.push(`job pays ${job.seller}, not this seller`);\n }\n if (job.escrowUsdc < minAmountUsdc) {\n problems.push(`escrow holds ${job.escrowUsdc} USDC, price is ${minAmountUsdc}`);\n }\n if (job.deliverByMs - Date.now() < minRunwayMs) {\n problems.push('deadline too close to accept');\n }\n return { ok: problems.length === 0, job, problems };\n}\n"]}