@t2000/sdk 10.27.1 → 10.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1082,7 +1082,7 @@ type SupportedAsset = keyof typeof SUPPORTED_ASSETS;
1082
1082
  type StableAsset = 'USDC' | 'USDsui';
1083
1083
  declare const STABLE_ASSETS: readonly StableAsset[];
1084
1084
  declare const OPERATION_ASSETS: {
1085
- readonly send: readonly ["USDC", "USDsui", "SUI"];
1085
+ readonly send: "*";
1086
1086
  readonly swap: "*";
1087
1087
  };
1088
1088
  type Operation = keyof typeof OPERATION_ASSETS;
@@ -1098,9 +1098,10 @@ declare function isAllowedAsset(op: Operation, asset: string): boolean;
1098
1098
  */
1099
1099
  declare function assertAllowedAsset(op: Operation, asset: string | undefined): void;
1100
1100
  /**
1101
- * [v4.0 Phase A Day 2] Narrow type alias for assets sendable through the
1102
- * Agent Wallet. Matches `OPERATION_ASSETS.send` exactly. Exported so the
1103
- * CLI / SDK / composeTx can share one type without re-declaring it.
1101
+ * [v4.0 Phase A Day 2] Narrow type alias for the composeTx `send_transfer`
1102
+ * appender (sponsored bundles stay stables+SUI) and the gasless docs.
1103
+ * [S.957] No longer the single-step `send` gate that widened to any
1104
+ * resolvable coin type via `classifySendAsset`.
1104
1105
  */
1105
1106
  type SendableAsset = 'USDC' | 'USDsui' | 'SUI';
1106
1107
  declare const SENDABLE_ASSETS: readonly SendableAsset[];
@@ -1349,11 +1350,43 @@ declare function simulateTransaction(client: SuiCoreClient, tx: Transaction, sen
1349
1350
  declare function throwIfSimulationFailed(sim: SimulationResult): void;
1350
1351
 
1351
1352
  /**
1352
- * Synchronous, network-free preflight for `send`. Validates asset membership,
1353
- * amount sanity, the gasless stable floor, and recipient address shape the
1354
- * cheap checks the v3 host runs before the LLM round-trip / tap-to-confirm.
1355
- * Returns a `PreflightResult`; never throws. `buildSendTx` calls this first,
1356
- * then layers the network balance read on top.
1353
+ * [S.957 — 2026-08-08] What a send `asset` string resolves to. The rule:
1354
+ * **if it resolves to a Sui coin type, it's sendable** (given balance)
1355
+ * registry symbol (`USDC`, `MANIFEST`) or full `0x…::module::TYPE` both
1356
+ * work. The kind decides the build path:
1357
+ * - `gasless-stable` USDC / USDsui via `0x2::balance::send_funds`
1358
+ * (Sui mainnet protocol allowlist; the ONLY gasless sends).
1359
+ * - `sui` — split from `tx.gas`, gas-paid.
1360
+ * - `coin` — any other coin type via `coinWithBalance` + transferObjects,
1361
+ * gas-paid. `symbol` is display-only (registry or last `::` segment).
1362
+ */
1363
+ type SendAssetClass = {
1364
+ kind: 'gasless-stable';
1365
+ symbol: 'USDC' | 'USDsui';
1366
+ coinType: string;
1367
+ } | {
1368
+ kind: 'sui';
1369
+ symbol: 'SUI';
1370
+ coinType: string;
1371
+ } | {
1372
+ kind: 'coin';
1373
+ symbol: string;
1374
+ coinType: string;
1375
+ };
1376
+ /**
1377
+ * Pure, network-free asset resolution for `send`. Returns `null` for
1378
+ * anything that doesn't resolve to a coin type — unknown bare symbols
1379
+ * (`FOOBAR`) and malformed `::` strings stay hard errors upstream.
1380
+ */
1381
+ declare function classifySendAsset(asset: string): SendAssetClass | null;
1382
+ /** The canonical INVALID_ASSET message for an unresolvable send asset. */
1383
+ declare function invalidSendAssetMessage(asset: string): string;
1384
+ /**
1385
+ * Synchronous, network-free preflight for `send`. Validates asset
1386
+ * resolvability, amount sanity, the gasless stable floor, and recipient
1387
+ * address shape — the cheap checks the v3 host runs before the LLM
1388
+ * round-trip / tap-to-confirm. Returns a `PreflightResult`; never throws.
1389
+ * `buildSendTx` calls this first, then layers the network balance read on top.
1357
1390
  */
1358
1391
  declare function preflightSend(input: {
1359
1392
  to: string;
@@ -1363,25 +1396,25 @@ declare function preflightSend(input: {
1363
1396
  /**
1364
1397
  * Build a PTB that sends `amount` of `asset` from `address` to `to`.
1365
1398
  *
1366
- * [v4.0 Phase A Day 2 SPEC_AGENT_WALLET_GREENFIELD §A]
1367
- *
1368
- * Asset constraint: `'USDC' | 'USDsui' | 'SUI'` only. Other assets throw
1369
- * `INVALID_ASSET` via `assertAllowedAsset('send', asset)`. The constrained
1370
- * set matches Sui mainnet's gasless allowlist (USDC + USDsui) plus SUI
1371
- * for users who want a gas-native transfer.
1399
+ * [S.957 2026-08-08] Widened from the v4 3-asset whitelist to **any held
1400
+ * coin type**: `asset` is a registry symbol (`USDC`, `MANIFEST`) or a full
1401
+ * `0x…::module::TYPE`. Unresolvable strings throw `INVALID_ASSET`.
1372
1402
  *
1373
- * Build paths:
1403
+ * Build paths (`classifySendAsset`):
1374
1404
  * - **USDC / USDsui** — `0x2::balance::send_funds` Move call with a
1375
1405
  * `tx.balance({ type, balance })` input. When built via `SuiGrpcClient`,
1376
1406
  * the gRPC resolver auto-detects gasless eligibility and zeros gas.
1377
- * When built via `SuiJsonRpcClient`, the same PTB still executes but
1378
- * the caller pays normal gas. Minimum 0.01 (protocol allowlist floor).
1407
+ * Minimum 0.01 (protocol allowlist floor). Still the ONLY gasless sends.
1379
1408
  * - **SUI** — `tx.splitCoins(tx.gas, [amount]) → tx.transferObjects()`.
1380
1409
  * Standard gas-native transfer. No minimum.
1410
+ * - **Any other coin type** — `coinWithBalance({ type, balance })` +
1411
+ * `transferObjects`. Gas-paid (sender needs SUI). The resolver sources
1412
+ * coins + address balance together, so post-swap alts held either way
1413
+ * move. Decimals resolve via the registry or on-chain coin metadata
1414
+ * (`resolveCoinDecimals`) — never a silent 9-default guess.
1381
1415
  *
1382
- * Pre-flight balance check stays on JSON-RPC (`client.getBalance`) it
1383
- * sums coin objects + address balance so the legacy `getCoins` page miss
1384
- * doesn't break for users whose stables landed via gasless deposits.
1416
+ * Pre-flight balance check uses `core.getBalance` (sums coin objects +
1417
+ * address balance) for every path.
1385
1418
  *
1386
1419
  * `asset` is REQUIRED (no implicit USDC default — pre-v4 hid LLM intent
1387
1420
  * errors). Callers passing the wrong asset get an explicit error rather
@@ -1392,7 +1425,7 @@ declare function buildSendTx({ client, address, to, amount, asset, }: {
1392
1425
  address: string;
1393
1426
  to: string;
1394
1427
  amount: number;
1395
- asset: SendableAsset;
1428
+ asset: string;
1396
1429
  }): Promise<Transaction>;
1397
1430
  /**
1398
1431
  * Fragment-appender for the chain-mode send leg of SPEC 7 multi-write
@@ -1610,4 +1643,4 @@ declare function putJobSpec(base: string, content: string): Promise<string>;
1610
1643
  * the store is untrusted; the chain hash is the authority). */
1611
1644
  declare function getJobSpec(base: string, hash: string): Promise<string>;
1612
1645
 
1613
- export { type T2000ErrorData as $, A2A_ESCROW_FEE_CONFIG_ID as A, type BalanceResponse as B, CLOCK_ID as C, DEFAULT_ACTIVITY_REPORT_URL as D, ETH_TYPE as E, SUI_TYPE as F, GAS_RESERVE_MIN as G, SUPPORTED_ASSETS as H, IKA_TYPE as I, JOB_STATES as J, KNOWN_TARGETS as K, LABEL_PATTERNS as L, MANIFEST_TYPE as M, NAVX_TYPE as N, OVERLAY_FEE_RATE as O, PREFLIGHT_MAX_AMOUNT as P, type SendResult as Q, type ServiceListing as R, STABLE_ASSETS as S, type SimulationResult as T, type StableAsset as U, type SuiHolding as V, type SuiRpcTxBlock as W, type SupportedAsset as X, type SwapRouteResult as Y, T2000Error as Z, type T2000ErrorCode as _, A2A_ESCROW_PACKAGE_ID as a, suiToMist as a$, T2000_OVERLAY_FEE_WALLET as a0, TOKEN_MAP as a1, type TransactionLeg as a2, type TransactionRecord as a3, type TransactionSigner as a4, type TxDirection as a5, USDC_DECIMALS as a6, USDC_TYPE as a7, USDE_TYPE as a8, USDSUI_TYPE as a9, formatAssetAmount as aA, formatSui as aB, formatUsd as aC, getDecimals as aD, getDecimalsForCoinType as aE, getJob as aF, getJobSpec as aG, jobActionsFor as aH, listServices as aI, mapMoveAbortCode as aJ, mapWalletError as aK, mistToSui as aL, parseSuiRpcTx as aM, payWithX402 as aN, preflightCreateJob as aO, preflightFail as aP, preflightPay as aQ, preflightSend as aR, preflightSwap as aS, putJobSpec as aT, rawToStable as aU, rawToUsdc as aV, refineLendingLabel as aW, reportX402Activity as aX, resolveSymbol as aY, resolveTokenType as aZ, stableToRaw as a_, USDT_TYPE as aa, WAL_TYPE as ab, WBTC_TYPE as ac, type X402ActivityPayload as ad, type ZkLoginProof as ae, ZkLoginSigner as af, buildCreateJobTx as ag, buildDeliverJobTx as ah, buildRefundJobTx as ai, buildRejectJobTx as aj, buildReleaseJobTx as ak, buildSendTx as al, buildSwapTx as am, checkPositiveAmount as an, checkSuiAddress as ao, classifyAction as ap, classifyLabel as aq, classifyTransaction as ar, executeTx as as, extractAllUserLegs as at, extractTransferDetails as au, extractTxCommands as av, extractTxSender as aw, fallbackLabel as ax, fetchService as ay, findSwapRoute as az, type ActivityReportConfig as b, truncateAddress as b0, usdcToRaw as b1, validateAddress as b2, verifyJobForSeller as b3, type T2000Options as b4, type X402Probe as b5, type SerializedCetusRoute as b6, type SwapResult as b7, type SwapQuoteResult as b8, type PaymentRequest as b9, isCetusRouteFresh as bA, isInRegistry as bB, normalizeAsset as bC, normalizeCoinType as bD, probeX402 as bE, queryHistory as bF, queryTransaction as bG, selectAndSplitCoin as bH, selectSuiCoin as bI, serializeCetusRoute as bJ, simulateTransaction as bK, throwIfSimulationFailed as bL, verifyCetusRouteCoinMatch as bM, type SuiCoreClient as ba, type SponsoredCoinMergeCache as bb, type SendableAsset as bc, CETUS_USDC_SUI_POOL as bd, type CoinPage as be, DEFAULT_GRPC_URL as bf, GASLESS_MIN_STABLE_AMOUNT as bg, GASLESS_STABLE_TYPES as bh, MAINNET_A2A_ESCROW_PACKAGE_ID as bi, OPERATION_ASSETS as bj, type Operation as bk, SENDABLE_ASSETS as bl, type SelectAndSplitResult as bm, type SerializedCetusRoutePath as bn, type SerializedRouterDataV3 as bo, addSendToTx as bp, addSwapToTx as bq, assertAllowedAsset as br, assertBuyerRequirements as bs, buildDeclineJobTx as bt, deserializeCetusRoute as bu, fetchAllCoins as bv, getCoinMeta as bw, getSuiClient as bx, getSuiGrpcClient as by, isAllowedAsset as bz, COIN_REGISTRY as c, type ClassifyBalanceChange as d, type ClassifyResult as e, type CoinMeta as f, DEFAULT_COMMERCE_API_BASE as g, DEFAULT_NETWORK as h, type DepositInfo as i, type ExtractedTransfer as j, type Job as k, type JobState as l, type JobTerms as m, type JobVerification as n, KeypairSigner as o, LOFI_TYPE as p, MAX_DELIVER_HORIZON_MS as q, MAX_JOB_USDC as r, MAX_REVIEW_WINDOW_MS as s, MIST_PER_SUI as t, type OverlayFeeConfig as u, PREFLIGHT_OK as v, type PayOptions as w, type PayResult as x, type PreflightResult as y, SUI_DECIMALS as z };
1646
+ export { type T2000ErrorCode as $, A2A_ESCROW_FEE_CONFIG_ID as A, type BalanceResponse as B, CLOCK_ID as C, DEFAULT_ACTIVITY_REPORT_URL as D, ETH_TYPE as E, SUI_TYPE as F, GAS_RESERVE_MIN as G, SUPPORTED_ASSETS as H, IKA_TYPE as I, JOB_STATES as J, KNOWN_TARGETS as K, LABEL_PATTERNS as L, MANIFEST_TYPE as M, NAVX_TYPE as N, OVERLAY_FEE_RATE as O, PREFLIGHT_MAX_AMOUNT as P, type SendAssetClass as Q, type SendResult as R, STABLE_ASSETS as S, type ServiceListing as T, type SimulationResult as U, type StableAsset as V, type SuiHolding as W, type SuiRpcTxBlock as X, type SupportedAsset as Y, type SwapRouteResult as Z, T2000Error as _, A2A_ESCROW_PACKAGE_ID as a, resolveSymbol as a$, type T2000ErrorData as a0, T2000_OVERLAY_FEE_WALLET as a1, TOKEN_MAP as a2, type TransactionLeg as a3, type TransactionRecord as a4, type TransactionSigner as a5, type TxDirection as a6, USDC_DECIMALS as a7, USDC_TYPE as a8, USDE_TYPE as a9, fetchService as aA, findSwapRoute as aB, formatAssetAmount as aC, formatSui as aD, formatUsd as aE, getDecimals as aF, getDecimalsForCoinType as aG, getJob as aH, getJobSpec as aI, invalidSendAssetMessage as aJ, jobActionsFor as aK, listServices as aL, mapMoveAbortCode as aM, mapWalletError as aN, mistToSui as aO, parseSuiRpcTx as aP, payWithX402 as aQ, preflightCreateJob as aR, preflightFail as aS, preflightPay as aT, preflightSend as aU, preflightSwap as aV, putJobSpec as aW, rawToStable as aX, rawToUsdc as aY, refineLendingLabel as aZ, reportX402Activity as a_, USDSUI_TYPE as aa, USDT_TYPE as ab, WAL_TYPE as ac, WBTC_TYPE as ad, type X402ActivityPayload as ae, type ZkLoginProof as af, ZkLoginSigner as ag, buildCreateJobTx as ah, buildDeliverJobTx as ai, buildRefundJobTx as aj, buildRejectJobTx as ak, buildReleaseJobTx as al, buildSendTx as am, buildSwapTx as an, checkPositiveAmount as ao, checkSuiAddress as ap, classifyAction as aq, classifyLabel as ar, classifySendAsset as as, classifyTransaction as at, executeTx as au, extractAllUserLegs as av, extractTransferDetails as aw, extractTxCommands as ax, extractTxSender as ay, fallbackLabel as az, type ActivityReportConfig as b, resolveTokenType as b0, stableToRaw as b1, suiToMist as b2, truncateAddress as b3, usdcToRaw as b4, validateAddress as b5, verifyJobForSeller as b6, type T2000Options as b7, type X402Probe as b8, type SerializedCetusRoute as b9, getSuiClient as bA, getSuiGrpcClient as bB, isAllowedAsset as bC, isCetusRouteFresh as bD, isInRegistry as bE, normalizeAsset as bF, normalizeCoinType as bG, probeX402 as bH, queryHistory as bI, queryTransaction as bJ, selectAndSplitCoin as bK, selectSuiCoin as bL, serializeCetusRoute as bM, simulateTransaction as bN, throwIfSimulationFailed as bO, verifyCetusRouteCoinMatch as bP, type SwapResult as ba, type SwapQuoteResult as bb, type PaymentRequest as bc, type SuiCoreClient as bd, type SponsoredCoinMergeCache as be, type SendableAsset as bf, CETUS_USDC_SUI_POOL as bg, type CoinPage as bh, DEFAULT_GRPC_URL as bi, GASLESS_MIN_STABLE_AMOUNT as bj, GASLESS_STABLE_TYPES as bk, MAINNET_A2A_ESCROW_PACKAGE_ID as bl, OPERATION_ASSETS as bm, type Operation as bn, SENDABLE_ASSETS as bo, type SelectAndSplitResult as bp, type SerializedCetusRoutePath as bq, type SerializedRouterDataV3 as br, addSendToTx as bs, addSwapToTx as bt, assertAllowedAsset as bu, assertBuyerRequirements as bv, buildDeclineJobTx as bw, deserializeCetusRoute as bx, fetchAllCoins as by, getCoinMeta as bz, COIN_REGISTRY as c, type ClassifyBalanceChange as d, type ClassifyResult as e, type CoinMeta as f, DEFAULT_COMMERCE_API_BASE as g, DEFAULT_NETWORK as h, type DepositInfo as i, type ExtractedTransfer as j, type Job as k, type JobState as l, type JobTerms as m, type JobVerification as n, KeypairSigner as o, LOFI_TYPE as p, MAX_DELIVER_HORIZON_MS as q, MAX_JOB_USDC as r, MAX_REVIEW_WINDOW_MS as s, MIST_PER_SUI as t, type OverlayFeeConfig as u, PREFLIGHT_OK as v, type PayOptions as w, type PayResult as x, type PreflightResult as y, SUI_DECIMALS as z };
@@ -1082,7 +1082,7 @@ type SupportedAsset = keyof typeof SUPPORTED_ASSETS;
1082
1082
  type StableAsset = 'USDC' | 'USDsui';
1083
1083
  declare const STABLE_ASSETS: readonly StableAsset[];
1084
1084
  declare const OPERATION_ASSETS: {
1085
- readonly send: readonly ["USDC", "USDsui", "SUI"];
1085
+ readonly send: "*";
1086
1086
  readonly swap: "*";
1087
1087
  };
1088
1088
  type Operation = keyof typeof OPERATION_ASSETS;
@@ -1098,9 +1098,10 @@ declare function isAllowedAsset(op: Operation, asset: string): boolean;
1098
1098
  */
1099
1099
  declare function assertAllowedAsset(op: Operation, asset: string | undefined): void;
1100
1100
  /**
1101
- * [v4.0 Phase A Day 2] Narrow type alias for assets sendable through the
1102
- * Agent Wallet. Matches `OPERATION_ASSETS.send` exactly. Exported so the
1103
- * CLI / SDK / composeTx can share one type without re-declaring it.
1101
+ * [v4.0 Phase A Day 2] Narrow type alias for the composeTx `send_transfer`
1102
+ * appender (sponsored bundles stay stables+SUI) and the gasless docs.
1103
+ * [S.957] No longer the single-step `send` gate that widened to any
1104
+ * resolvable coin type via `classifySendAsset`.
1104
1105
  */
1105
1106
  type SendableAsset = 'USDC' | 'USDsui' | 'SUI';
1106
1107
  declare const SENDABLE_ASSETS: readonly SendableAsset[];
@@ -1349,11 +1350,43 @@ declare function simulateTransaction(client: SuiCoreClient, tx: Transaction, sen
1349
1350
  declare function throwIfSimulationFailed(sim: SimulationResult): void;
1350
1351
 
1351
1352
  /**
1352
- * Synchronous, network-free preflight for `send`. Validates asset membership,
1353
- * amount sanity, the gasless stable floor, and recipient address shape the
1354
- * cheap checks the v3 host runs before the LLM round-trip / tap-to-confirm.
1355
- * Returns a `PreflightResult`; never throws. `buildSendTx` calls this first,
1356
- * then layers the network balance read on top.
1353
+ * [S.957 — 2026-08-08] What a send `asset` string resolves to. The rule:
1354
+ * **if it resolves to a Sui coin type, it's sendable** (given balance)
1355
+ * registry symbol (`USDC`, `MANIFEST`) or full `0x…::module::TYPE` both
1356
+ * work. The kind decides the build path:
1357
+ * - `gasless-stable` USDC / USDsui via `0x2::balance::send_funds`
1358
+ * (Sui mainnet protocol allowlist; the ONLY gasless sends).
1359
+ * - `sui` — split from `tx.gas`, gas-paid.
1360
+ * - `coin` — any other coin type via `coinWithBalance` + transferObjects,
1361
+ * gas-paid. `symbol` is display-only (registry or last `::` segment).
1362
+ */
1363
+ type SendAssetClass = {
1364
+ kind: 'gasless-stable';
1365
+ symbol: 'USDC' | 'USDsui';
1366
+ coinType: string;
1367
+ } | {
1368
+ kind: 'sui';
1369
+ symbol: 'SUI';
1370
+ coinType: string;
1371
+ } | {
1372
+ kind: 'coin';
1373
+ symbol: string;
1374
+ coinType: string;
1375
+ };
1376
+ /**
1377
+ * Pure, network-free asset resolution for `send`. Returns `null` for
1378
+ * anything that doesn't resolve to a coin type — unknown bare symbols
1379
+ * (`FOOBAR`) and malformed `::` strings stay hard errors upstream.
1380
+ */
1381
+ declare function classifySendAsset(asset: string): SendAssetClass | null;
1382
+ /** The canonical INVALID_ASSET message for an unresolvable send asset. */
1383
+ declare function invalidSendAssetMessage(asset: string): string;
1384
+ /**
1385
+ * Synchronous, network-free preflight for `send`. Validates asset
1386
+ * resolvability, amount sanity, the gasless stable floor, and recipient
1387
+ * address shape — the cheap checks the v3 host runs before the LLM
1388
+ * round-trip / tap-to-confirm. Returns a `PreflightResult`; never throws.
1389
+ * `buildSendTx` calls this first, then layers the network balance read on top.
1357
1390
  */
1358
1391
  declare function preflightSend(input: {
1359
1392
  to: string;
@@ -1363,25 +1396,25 @@ declare function preflightSend(input: {
1363
1396
  /**
1364
1397
  * Build a PTB that sends `amount` of `asset` from `address` to `to`.
1365
1398
  *
1366
- * [v4.0 Phase A Day 2 SPEC_AGENT_WALLET_GREENFIELD §A]
1367
- *
1368
- * Asset constraint: `'USDC' | 'USDsui' | 'SUI'` only. Other assets throw
1369
- * `INVALID_ASSET` via `assertAllowedAsset('send', asset)`. The constrained
1370
- * set matches Sui mainnet's gasless allowlist (USDC + USDsui) plus SUI
1371
- * for users who want a gas-native transfer.
1399
+ * [S.957 2026-08-08] Widened from the v4 3-asset whitelist to **any held
1400
+ * coin type**: `asset` is a registry symbol (`USDC`, `MANIFEST`) or a full
1401
+ * `0x…::module::TYPE`. Unresolvable strings throw `INVALID_ASSET`.
1372
1402
  *
1373
- * Build paths:
1403
+ * Build paths (`classifySendAsset`):
1374
1404
  * - **USDC / USDsui** — `0x2::balance::send_funds` Move call with a
1375
1405
  * `tx.balance({ type, balance })` input. When built via `SuiGrpcClient`,
1376
1406
  * the gRPC resolver auto-detects gasless eligibility and zeros gas.
1377
- * When built via `SuiJsonRpcClient`, the same PTB still executes but
1378
- * the caller pays normal gas. Minimum 0.01 (protocol allowlist floor).
1407
+ * Minimum 0.01 (protocol allowlist floor). Still the ONLY gasless sends.
1379
1408
  * - **SUI** — `tx.splitCoins(tx.gas, [amount]) → tx.transferObjects()`.
1380
1409
  * Standard gas-native transfer. No minimum.
1410
+ * - **Any other coin type** — `coinWithBalance({ type, balance })` +
1411
+ * `transferObjects`. Gas-paid (sender needs SUI). The resolver sources
1412
+ * coins + address balance together, so post-swap alts held either way
1413
+ * move. Decimals resolve via the registry or on-chain coin metadata
1414
+ * (`resolveCoinDecimals`) — never a silent 9-default guess.
1381
1415
  *
1382
- * Pre-flight balance check stays on JSON-RPC (`client.getBalance`) it
1383
- * sums coin objects + address balance so the legacy `getCoins` page miss
1384
- * doesn't break for users whose stables landed via gasless deposits.
1416
+ * Pre-flight balance check uses `core.getBalance` (sums coin objects +
1417
+ * address balance) for every path.
1385
1418
  *
1386
1419
  * `asset` is REQUIRED (no implicit USDC default — pre-v4 hid LLM intent
1387
1420
  * errors). Callers passing the wrong asset get an explicit error rather
@@ -1392,7 +1425,7 @@ declare function buildSendTx({ client, address, to, amount, asset, }: {
1392
1425
  address: string;
1393
1426
  to: string;
1394
1427
  amount: number;
1395
- asset: SendableAsset;
1428
+ asset: string;
1396
1429
  }): Promise<Transaction>;
1397
1430
  /**
1398
1431
  * Fragment-appender for the chain-mode send leg of SPEC 7 multi-write
@@ -1610,4 +1643,4 @@ declare function putJobSpec(base: string, content: string): Promise<string>;
1610
1643
  * the store is untrusted; the chain hash is the authority). */
1611
1644
  declare function getJobSpec(base: string, hash: string): Promise<string>;
1612
1645
 
1613
- export { type T2000ErrorData as $, A2A_ESCROW_FEE_CONFIG_ID as A, type BalanceResponse as B, CLOCK_ID as C, DEFAULT_ACTIVITY_REPORT_URL as D, ETH_TYPE as E, SUI_TYPE as F, GAS_RESERVE_MIN as G, SUPPORTED_ASSETS as H, IKA_TYPE as I, JOB_STATES as J, KNOWN_TARGETS as K, LABEL_PATTERNS as L, MANIFEST_TYPE as M, NAVX_TYPE as N, OVERLAY_FEE_RATE as O, PREFLIGHT_MAX_AMOUNT as P, type SendResult as Q, type ServiceListing as R, STABLE_ASSETS as S, type SimulationResult as T, type StableAsset as U, type SuiHolding as V, type SuiRpcTxBlock as W, type SupportedAsset as X, type SwapRouteResult as Y, T2000Error as Z, type T2000ErrorCode as _, A2A_ESCROW_PACKAGE_ID as a, suiToMist as a$, T2000_OVERLAY_FEE_WALLET as a0, TOKEN_MAP as a1, type TransactionLeg as a2, type TransactionRecord as a3, type TransactionSigner as a4, type TxDirection as a5, USDC_DECIMALS as a6, USDC_TYPE as a7, USDE_TYPE as a8, USDSUI_TYPE as a9, formatAssetAmount as aA, formatSui as aB, formatUsd as aC, getDecimals as aD, getDecimalsForCoinType as aE, getJob as aF, getJobSpec as aG, jobActionsFor as aH, listServices as aI, mapMoveAbortCode as aJ, mapWalletError as aK, mistToSui as aL, parseSuiRpcTx as aM, payWithX402 as aN, preflightCreateJob as aO, preflightFail as aP, preflightPay as aQ, preflightSend as aR, preflightSwap as aS, putJobSpec as aT, rawToStable as aU, rawToUsdc as aV, refineLendingLabel as aW, reportX402Activity as aX, resolveSymbol as aY, resolveTokenType as aZ, stableToRaw as a_, USDT_TYPE as aa, WAL_TYPE as ab, WBTC_TYPE as ac, type X402ActivityPayload as ad, type ZkLoginProof as ae, ZkLoginSigner as af, buildCreateJobTx as ag, buildDeliverJobTx as ah, buildRefundJobTx as ai, buildRejectJobTx as aj, buildReleaseJobTx as ak, buildSendTx as al, buildSwapTx as am, checkPositiveAmount as an, checkSuiAddress as ao, classifyAction as ap, classifyLabel as aq, classifyTransaction as ar, executeTx as as, extractAllUserLegs as at, extractTransferDetails as au, extractTxCommands as av, extractTxSender as aw, fallbackLabel as ax, fetchService as ay, findSwapRoute as az, type ActivityReportConfig as b, truncateAddress as b0, usdcToRaw as b1, validateAddress as b2, verifyJobForSeller as b3, type T2000Options as b4, type X402Probe as b5, type SerializedCetusRoute as b6, type SwapResult as b7, type SwapQuoteResult as b8, type PaymentRequest as b9, isCetusRouteFresh as bA, isInRegistry as bB, normalizeAsset as bC, normalizeCoinType as bD, probeX402 as bE, queryHistory as bF, queryTransaction as bG, selectAndSplitCoin as bH, selectSuiCoin as bI, serializeCetusRoute as bJ, simulateTransaction as bK, throwIfSimulationFailed as bL, verifyCetusRouteCoinMatch as bM, type SuiCoreClient as ba, type SponsoredCoinMergeCache as bb, type SendableAsset as bc, CETUS_USDC_SUI_POOL as bd, type CoinPage as be, DEFAULT_GRPC_URL as bf, GASLESS_MIN_STABLE_AMOUNT as bg, GASLESS_STABLE_TYPES as bh, MAINNET_A2A_ESCROW_PACKAGE_ID as bi, OPERATION_ASSETS as bj, type Operation as bk, SENDABLE_ASSETS as bl, type SelectAndSplitResult as bm, type SerializedCetusRoutePath as bn, type SerializedRouterDataV3 as bo, addSendToTx as bp, addSwapToTx as bq, assertAllowedAsset as br, assertBuyerRequirements as bs, buildDeclineJobTx as bt, deserializeCetusRoute as bu, fetchAllCoins as bv, getCoinMeta as bw, getSuiClient as bx, getSuiGrpcClient as by, isAllowedAsset as bz, COIN_REGISTRY as c, type ClassifyBalanceChange as d, type ClassifyResult as e, type CoinMeta as f, DEFAULT_COMMERCE_API_BASE as g, DEFAULT_NETWORK as h, type DepositInfo as i, type ExtractedTransfer as j, type Job as k, type JobState as l, type JobTerms as m, type JobVerification as n, KeypairSigner as o, LOFI_TYPE as p, MAX_DELIVER_HORIZON_MS as q, MAX_JOB_USDC as r, MAX_REVIEW_WINDOW_MS as s, MIST_PER_SUI as t, type OverlayFeeConfig as u, PREFLIGHT_OK as v, type PayOptions as w, type PayResult as x, type PreflightResult as y, SUI_DECIMALS as z };
1646
+ export { type T2000ErrorCode as $, A2A_ESCROW_FEE_CONFIG_ID as A, type BalanceResponse as B, CLOCK_ID as C, DEFAULT_ACTIVITY_REPORT_URL as D, ETH_TYPE as E, SUI_TYPE as F, GAS_RESERVE_MIN as G, SUPPORTED_ASSETS as H, IKA_TYPE as I, JOB_STATES as J, KNOWN_TARGETS as K, LABEL_PATTERNS as L, MANIFEST_TYPE as M, NAVX_TYPE as N, OVERLAY_FEE_RATE as O, PREFLIGHT_MAX_AMOUNT as P, type SendAssetClass as Q, type SendResult as R, STABLE_ASSETS as S, type ServiceListing as T, type SimulationResult as U, type StableAsset as V, type SuiHolding as W, type SuiRpcTxBlock as X, type SupportedAsset as Y, type SwapRouteResult as Z, T2000Error as _, A2A_ESCROW_PACKAGE_ID as a, resolveSymbol as a$, type T2000ErrorData as a0, T2000_OVERLAY_FEE_WALLET as a1, TOKEN_MAP as a2, type TransactionLeg as a3, type TransactionRecord as a4, type TransactionSigner as a5, type TxDirection as a6, USDC_DECIMALS as a7, USDC_TYPE as a8, USDE_TYPE as a9, fetchService as aA, findSwapRoute as aB, formatAssetAmount as aC, formatSui as aD, formatUsd as aE, getDecimals as aF, getDecimalsForCoinType as aG, getJob as aH, getJobSpec as aI, invalidSendAssetMessage as aJ, jobActionsFor as aK, listServices as aL, mapMoveAbortCode as aM, mapWalletError as aN, mistToSui as aO, parseSuiRpcTx as aP, payWithX402 as aQ, preflightCreateJob as aR, preflightFail as aS, preflightPay as aT, preflightSend as aU, preflightSwap as aV, putJobSpec as aW, rawToStable as aX, rawToUsdc as aY, refineLendingLabel as aZ, reportX402Activity as a_, USDSUI_TYPE as aa, USDT_TYPE as ab, WAL_TYPE as ac, WBTC_TYPE as ad, type X402ActivityPayload as ae, type ZkLoginProof as af, ZkLoginSigner as ag, buildCreateJobTx as ah, buildDeliverJobTx as ai, buildRefundJobTx as aj, buildRejectJobTx as ak, buildReleaseJobTx as al, buildSendTx as am, buildSwapTx as an, checkPositiveAmount as ao, checkSuiAddress as ap, classifyAction as aq, classifyLabel as ar, classifySendAsset as as, classifyTransaction as at, executeTx as au, extractAllUserLegs as av, extractTransferDetails as aw, extractTxCommands as ax, extractTxSender as ay, fallbackLabel as az, type ActivityReportConfig as b, resolveTokenType as b0, stableToRaw as b1, suiToMist as b2, truncateAddress as b3, usdcToRaw as b4, validateAddress as b5, verifyJobForSeller as b6, type T2000Options as b7, type X402Probe as b8, type SerializedCetusRoute as b9, getSuiClient as bA, getSuiGrpcClient as bB, isAllowedAsset as bC, isCetusRouteFresh as bD, isInRegistry as bE, normalizeAsset as bF, normalizeCoinType as bG, probeX402 as bH, queryHistory as bI, queryTransaction as bJ, selectAndSplitCoin as bK, selectSuiCoin as bL, serializeCetusRoute as bM, simulateTransaction as bN, throwIfSimulationFailed as bO, verifyCetusRouteCoinMatch as bP, type SwapResult as ba, type SwapQuoteResult as bb, type PaymentRequest as bc, type SuiCoreClient as bd, type SponsoredCoinMergeCache as be, type SendableAsset as bf, CETUS_USDC_SUI_POOL as bg, type CoinPage as bh, DEFAULT_GRPC_URL as bi, GASLESS_MIN_STABLE_AMOUNT as bj, GASLESS_STABLE_TYPES as bk, MAINNET_A2A_ESCROW_PACKAGE_ID as bl, OPERATION_ASSETS as bm, type Operation as bn, SENDABLE_ASSETS as bo, type SelectAndSplitResult as bp, type SerializedCetusRoutePath as bq, type SerializedRouterDataV3 as br, addSendToTx as bs, addSwapToTx as bt, assertAllowedAsset as bu, assertBuyerRequirements as bv, buildDeclineJobTx as bw, deserializeCetusRoute as bx, fetchAllCoins as by, getCoinMeta as bz, COIN_REGISTRY as c, type ClassifyBalanceChange as d, type ClassifyResult as e, type CoinMeta as f, DEFAULT_COMMERCE_API_BASE as g, DEFAULT_NETWORK as h, type DepositInfo as i, type ExtractedTransfer as j, type Job as k, type JobState as l, type JobTerms as m, type JobVerification as n, KeypairSigner as o, LOFI_TYPE as p, MAX_DELIVER_HORIZON_MS as q, MAX_JOB_USDC as r, MAX_REVIEW_WINDOW_MS as s, MIST_PER_SUI as t, type OverlayFeeConfig as u, PREFLIGHT_OK as v, type PayOptions as w, type PayResult as x, type PreflightResult as y, SUI_DECIMALS as z };
package/dist/index.cjs CHANGED
@@ -847,7 +847,7 @@ var SUPPORTED_ASSETS = {
847
847
  };
848
848
  var STABLE_ASSETS = ["USDC", "USDsui"];
849
849
  var OPERATION_ASSETS = {
850
- send: ["USDC", "USDsui", "SUI"],
850
+ send: "*",
851
851
  swap: "*"
852
852
  };
853
853
  function isAllowedAsset(op, asset) {
@@ -1535,19 +1535,42 @@ function normalizeAsset(input) {
1535
1535
  }
1536
1536
 
1537
1537
  // src/wallet/send.ts
1538
+ init_token_registry();
1538
1539
  init_preflight();
1539
- function preflightSend(input) {
1540
+ function classifySendAsset(asset) {
1541
+ const coinType = resolveTokenType(asset.trim());
1542
+ if (!coinType) return null;
1543
+ let normalized;
1540
1544
  try {
1541
- assertAllowedAsset("send", input.asset);
1542
- } catch (e) {
1543
- return preflightFail("INVALID_ASSET", e.message);
1545
+ normalized = utils.normalizeStructTag(coinType);
1546
+ } catch {
1547
+ return null;
1548
+ }
1549
+ if (normalized === utils.normalizeStructTag(GASLESS_STABLE_TYPES.USDC)) {
1550
+ return { kind: "gasless-stable", symbol: "USDC", coinType: GASLESS_STABLE_TYPES.USDC };
1551
+ }
1552
+ if (normalized === utils.normalizeStructTag(GASLESS_STABLE_TYPES.USDsui)) {
1553
+ return { kind: "gasless-stable", symbol: "USDsui", coinType: GASLESS_STABLE_TYPES.USDsui };
1554
+ }
1555
+ if (normalized === utils.normalizeStructTag(exports.SUI_TYPE)) {
1556
+ return { kind: "sui", symbol: "SUI", coinType: exports.SUI_TYPE };
1557
+ }
1558
+ return { kind: "coin", symbol: resolveSymbol(coinType), coinType };
1559
+ }
1560
+ function invalidSendAssetMessage(asset) {
1561
+ return `Unknown asset "${asset}". Use a registry symbol (USDC, USDsui, SUI, MANIFEST, \u2026) or a full coin type (0x\u2026::module::TYPE).`;
1562
+ }
1563
+ function preflightSend(input) {
1564
+ const cls = classifySendAsset(input.asset);
1565
+ if (!cls) {
1566
+ return preflightFail("INVALID_ASSET", invalidSendAssetMessage(input.asset));
1544
1567
  }
1545
1568
  const amountCheck = checkPositiveAmount(input.amount);
1546
1569
  if (!amountCheck.valid) return amountCheck;
1547
- if ((input.asset === "USDC" || input.asset === "USDsui") && input.amount < GASLESS_MIN_STABLE_AMOUNT) {
1570
+ if (cls.kind === "gasless-stable" && input.amount < GASLESS_MIN_STABLE_AMOUNT) {
1548
1571
  return preflightFail(
1549
1572
  "INVALID_AMOUNT",
1550
- `Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${input.asset}. Got ${input.amount}.`
1573
+ `Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${cls.symbol}. Got ${input.amount}.`
1551
1574
  );
1552
1575
  }
1553
1576
  const addressCheck = checkSuiAddress(input.to);
@@ -1564,42 +1587,44 @@ async function buildSendTx({
1564
1587
  const pf = preflightSend({ to, amount, asset });
1565
1588
  if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
1566
1589
  const recipient = validateAddress(to);
1567
- const assetInfo = SUPPORTED_ASSETS[asset];
1568
- if (!assetInfo) throw new exports.T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
1569
- const rawAmount = displayToRaw(amount, assetInfo.decimals);
1590
+ const cls = classifySendAsset(asset);
1591
+ const decimals = cls.kind === "gasless-stable" || cls.kind === "sui" ? SUPPORTED_ASSETS[cls.symbol].decimals : await resolveCoinDecimals(client, cls.coinType);
1592
+ const rawAmount = displayToRaw(amount, decimals);
1570
1593
  const tx = new transactions.Transaction();
1571
1594
  tx.setSender(address);
1572
- const balanceResp = await client.core.getBalance({ owner: address, coinType: assetInfo.type });
1595
+ const balanceResp = await client.core.getBalance({ owner: address, coinType: cls.coinType });
1573
1596
  const totalBalance = BigInt(balanceResp.balance.balance);
1574
1597
  if (totalBalance < rawAmount) {
1575
- throw new exports.T2000Error("INSUFFICIENT_BALANCE", `Insufficient ${asset} balance`, {
1576
- available: Number(totalBalance) / 10 ** assetInfo.decimals,
1598
+ throw new exports.T2000Error("INSUFFICIENT_BALANCE", `Insufficient ${cls.symbol} balance`, {
1599
+ available: Number(totalBalance) / 10 ** decimals,
1577
1600
  required: amount
1578
1601
  });
1579
1602
  }
1580
- if (asset === "USDC" || asset === "USDsui") {
1581
- const rawFloor = displayToRaw(GASLESS_MIN_STABLE_AMOUNT, assetInfo.decimals);
1582
- const remainder = totalBalance - rawAmount;
1583
- if (remainder > 0n && remainder < rawFloor) {
1584
- const total = Number(totalBalance) / 10 ** assetInfo.decimals;
1585
- throw new exports.T2000Error(
1586
- "INVALID_AMOUNT",
1587
- `Gasless ${asset} transfers must send the entire balance or leave at least ${GASLESS_MIN_STABLE_AMOUNT} ${asset}. Sending ${amount} of ${total} leaves ${(total - amount).toFixed(assetInfo.decimals)}. Send ${total} (everything) or at most ${(total - GASLESS_MIN_STABLE_AMOUNT).toFixed(assetInfo.decimals)}.`,
1588
- { available: total, required: amount }
1589
- );
1590
- }
1591
- }
1592
- if (asset === "SUI") {
1603
+ if (cls.kind === "sui") {
1593
1604
  const [sendCoin] = tx.splitCoins(tx.gas, [rawAmount]);
1594
1605
  tx.transferObjects([sendCoin], recipient);
1595
1606
  return tx;
1596
1607
  }
1597
- const coinType = GASLESS_STABLE_TYPES[asset];
1608
+ if (cls.kind === "coin") {
1609
+ const sendCoin = transactions.coinWithBalance({ type: cls.coinType, balance: rawAmount })(tx);
1610
+ tx.transferObjects([sendCoin], recipient);
1611
+ return tx;
1612
+ }
1613
+ const rawFloor = displayToRaw(GASLESS_MIN_STABLE_AMOUNT, decimals);
1614
+ const remainder = totalBalance - rawAmount;
1615
+ if (remainder > 0n && remainder < rawFloor) {
1616
+ const total = Number(totalBalance) / 10 ** decimals;
1617
+ throw new exports.T2000Error(
1618
+ "INVALID_AMOUNT",
1619
+ `Gasless ${cls.symbol} transfers must send the entire balance or leave at least ${GASLESS_MIN_STABLE_AMOUNT} ${cls.symbol}. Sending ${amount} of ${total} leaves ${(total - amount).toFixed(decimals)}. Send ${total} (everything) or at most ${(total - GASLESS_MIN_STABLE_AMOUNT).toFixed(decimals)}.`,
1620
+ { available: total, required: amount }
1621
+ );
1622
+ }
1598
1623
  tx.moveCall({
1599
1624
  target: "0x2::balance::send_funds",
1600
- typeArguments: [coinType],
1625
+ typeArguments: [cls.coinType],
1601
1626
  arguments: [
1602
- tx.balance({ type: coinType, balance: rawAmount }),
1627
+ tx.balance({ type: cls.coinType, balance: rawAmount }),
1603
1628
  tx.pure.address(recipient)
1604
1629
  ]
1605
1630
  });
@@ -2942,11 +2967,21 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
2942
2967
  const rawAmount = BigInt(Math.floor(params.amount * 10 ** fromDecimals));
2943
2968
  let route;
2944
2969
  if (params.serializedRoute) {
2945
- const s = params.serializedRoute;
2970
+ let s = params.serializedRoute;
2971
+ const nested = s.serializedRoute;
2972
+ if (nested && typeof nested === "object" && typeof nested.fromCoinType === "string" && nested.routerData) {
2973
+ s = nested;
2974
+ }
2975
+ if (typeof s.fromCoinType !== "string" || typeof s.toCoinType !== "string") {
2976
+ throw new exports.T2000Error(
2977
+ "SWAP_ROUTE_MISMATCH",
2978
+ "serializedRoute is not the object t2000 quoted \u2014 it is missing fromCoinType/toCoinType. Pass quote.serializedRoute exactly as the quote returned it (not the whole quote response), or omit serializedRoute to discover a fresh route."
2979
+ );
2980
+ }
2946
2981
  if (!verifyCetusRouteCoinMatch2(s, { fromCoinType: fromType, toCoinType: toType })) {
2947
2982
  throw new exports.T2000Error(
2948
2983
  "SWAP_ROUTE_MISMATCH",
2949
- `The quoted route is for ${s.fromCoinType} -> ${s.toCoinType}, not ${params.from} -> ${params.to}. Re-quote and pass the new serializedRoute.`
2984
+ `The quoted route is for ${s.fromCoinType} -> ${s.toCoinType}, not ${fromType} -> ${toType}. Re-quote and pass the new serializedRoute.`
2950
2985
  );
2951
2986
  }
2952
2987
  if (s.byAmountIn !== byAmountIn || BigInt(s.amountIn) !== rawAmount) {
@@ -3090,18 +3125,17 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
3090
3125
  /**
3091
3126
  * Send `amount` of `asset` to `to` (hex address or SuiNS name).
3092
3127
  *
3093
- * [v4.0 Phase A Day 2SPEC_AGENT_WALLET_GREENFIELD §A]
3128
+ * [S.957 2026-08-08] `asset` accepts **any held coin type** a
3129
+ * registry symbol (`USDC`, `MANIFEST`) or a full `0x…::module::TYPE`.
3130
+ * Unresolvable strings throw `INVALID_ASSET`; empty balances throw
3131
+ * `INSUFFICIENT_BALANCE`.
3094
3132
  *
3095
- * **Breaking changes from v3.x:**
3096
- * - `asset` is now REQUIRED (no implicit `?? 'USDC'` default). Callers
3097
- * must specify `'USDC' | 'USDsui' | 'SUI'`. Sending `'USDT'` /
3098
- * `'USDe'` / `'WAL'` / `'ETH'` / `'NAVX'` / `'GOLD'` now errors
3099
- * with `INVALID_ASSET` — swap to a stable first.
3100
3133
  * - USDC + USDsui builds go through `SuiGrpcClient` so the gRPC build
3101
3134
  * resolver auto-detects `0x2::balance::send_funds` eligibility and
3102
- * zeros gas at simulate time. Result: **gasless USDC / USDsui sends
3103
- * from a zero-SUI wallet.** SUI sends stay on the standard gas-paid
3104
- * path.
3135
+ * zeros gas at simulate time **gasless sends from a zero-SUI
3136
+ * wallet.** They remain the ONLY gasless assets.
3137
+ * - SUI and every other coin type are gas-paid (the sender needs SUI).
3138
+ * - `asset` stays REQUIRED (no implicit `?? 'USDC'` default — v4 rule).
3105
3139
  *
3106
3140
  * Submission stays on the JSON-RPC client (the rest of the SDK
3107
3141
  * expects JSON-RPC for read paths, and Sui's docs explicitly support
@@ -3112,30 +3146,31 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
3112
3146
  if (!asset) {
3113
3147
  throw new exports.T2000Error(
3114
3148
  "INVALID_ASSET",
3115
- "send() requires an explicit asset. Use one of: USDC, USDsui, SUI."
3149
+ "send() requires an explicit asset. Use a registry symbol (USDC, USDsui, SUI, MANIFEST, \u2026) or a full coin type (0x\u2026::module::TYPE)."
3116
3150
  );
3117
3151
  }
3118
- assertAllowedAsset("send", asset);
3119
- const sendableAsset = asset;
3152
+ const cls = classifySendAsset(asset);
3153
+ if (!cls) {
3154
+ throw new exports.T2000Error("INVALID_ASSET", invalidSendAssetMessage(asset));
3155
+ }
3120
3156
  this.limits.assert({
3121
3157
  operation: "send",
3122
- amountUsd: approxUsdValue(sendableAsset, params.amount) ?? 0,
3158
+ amountUsd: approxUsdValue(cls.symbol, params.amount) ?? 0,
3123
3159
  force: params.force
3124
3160
  });
3125
3161
  const resolved = await this.resolveRecipient(params.to);
3126
3162
  const sendAmount = params.amount;
3127
3163
  const sendTo = resolved.address;
3128
- const useGrpc = sendableAsset === "USDC" || sendableAsset === "USDsui";
3129
- const buildClient = useGrpc ? getSuiGrpcClient() : void 0;
3164
+ const buildClient = cls.kind === "gasless-stable" ? getSuiGrpcClient() : void 0;
3130
3165
  const gasResult = await executeTx(
3131
3166
  this.client,
3132
3167
  this._signer,
3133
- () => buildSendTx({ client: this.client, address: this._address, to: sendTo, amount: sendAmount, asset: sendableAsset }),
3168
+ () => buildSendTx({ client: this.client, address: this._address, to: sendTo, amount: sendAmount, asset }),
3134
3169
  { buildClient }
3135
3170
  );
3136
- this.limits.record(approxUsdValue(sendableAsset, sendAmount) ?? 0);
3171
+ this.limits.record(approxUsdValue(cls.symbol, sendAmount) ?? 0);
3137
3172
  const balance = await this.balance();
3138
- this.emitBalanceChange(sendableAsset, sendAmount, "send", gasResult.digest);
3173
+ this.emitBalanceChange(cls.symbol, sendAmount, "send", gasResult.digest);
3139
3174
  return {
3140
3175
  success: true,
3141
3176
  tx: gasResult.digest,
@@ -3911,7 +3946,12 @@ var WRITE_APPENDER_REGISTRY = {
3911
3946
  "send_transfer requires an explicit asset. Use one of: USDC, USDsui, SUI."
3912
3947
  );
3913
3948
  }
3914
- assertAllowedAsset("send", input.asset);
3949
+ if (!SENDABLE_ASSETS.some((a) => a.toLowerCase() === input.asset.toLowerCase())) {
3950
+ throw new exports.T2000Error(
3951
+ "INVALID_ASSET",
3952
+ `send_transfer only supports ${SENDABLE_ASSETS.join(", ")}. Cannot use ${input.asset}. Swap to USDC or USDsui first, or send SUI.`
3953
+ );
3954
+ }
3915
3955
  const asset = input.asset;
3916
3956
  const assetInfo = SUPPORTED_ASSETS[asset];
3917
3957
  if (input.amount <= 0) {
@@ -4379,6 +4419,7 @@ exports.checkSuiAddress = checkSuiAddress;
4379
4419
  exports.claimOpenJob = claimOpenJob;
4380
4420
  exports.classifyAction = classifyAction;
4381
4421
  exports.classifyLabel = classifyLabel;
4422
+ exports.classifySendAsset = classifySendAsset;
4382
4423
  exports.classifyTransaction = classifyTransaction;
4383
4424
  exports.clearLimits = clearLimits;
4384
4425
  exports.composeTx = composeTx;
@@ -4415,6 +4456,7 @@ exports.getSuiClient = getSuiClient;
4415
4456
  exports.getSuiGrpcClient = getSuiGrpcClient;
4416
4457
  exports.getSwapQuote = getSwapQuote;
4417
4458
  exports.hasLimits = hasLimits;
4459
+ exports.invalidSendAssetMessage = invalidSendAssetMessage;
4418
4460
  exports.isAllowedAsset = isAllowedAsset;
4419
4461
  exports.isCetusRouteFresh = isCetusRouteFresh;
4420
4462
  exports.isInRegistry = isInRegistry;