@t2000/sdk 10.27.2 → 10.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/browser.cjs CHANGED
@@ -857,28 +857,6 @@ var SUPPORTED_ASSETS = {
857
857
  }
858
858
  };
859
859
  var STABLE_ASSETS = ["USDC", "USDsui"];
860
- var OPERATION_ASSETS = {
861
- send: ["USDC", "USDsui", "SUI"],
862
- swap: "*"
863
- };
864
- function isAllowedAsset(op, asset) {
865
- const allowed = OPERATION_ASSETS[op];
866
- if (allowed === "*") return true;
867
- const target = asset.toLowerCase();
868
- return allowed.some((a) => a.toLowerCase() === target);
869
- }
870
- function assertAllowedAsset(op, asset) {
871
- if (!asset) return;
872
- if (!isAllowedAsset(op, asset)) {
873
- const allowed = OPERATION_ASSETS[op];
874
- const list = Array.isArray(allowed) ? allowed.join(", ") : "any";
875
- const swapHint = " Swap to USDC or USDsui first, or send SUI." ;
876
- throw new exports.T2000Error(
877
- "INVALID_ASSET",
878
- `${op} only supports ${list}. Cannot use ${asset}.${swapHint}`
879
- );
880
- }
881
- }
882
860
  var GASLESS_STABLE_TYPES = {
883
861
  USDC: SUPPORTED_ASSETS.USDC.type,
884
862
  USDsui: SUPPORTED_ASSETS.USDsui.type
@@ -1249,18 +1227,41 @@ async function buildSwapTx(params) {
1249
1227
  return outputCoin;
1250
1228
  }
1251
1229
  init_errors();
1252
- function preflightSend(input) {
1230
+ init_token_registry();
1231
+ function classifySendAsset(asset) {
1232
+ const coinType = resolveTokenType(asset.trim());
1233
+ if (!coinType) return null;
1234
+ let normalized;
1253
1235
  try {
1254
- assertAllowedAsset("send", input.asset);
1255
- } catch (e) {
1256
- return preflightFail("INVALID_ASSET", e.message);
1236
+ normalized = utils.normalizeStructTag(coinType);
1237
+ } catch {
1238
+ return null;
1239
+ }
1240
+ if (normalized === utils.normalizeStructTag(GASLESS_STABLE_TYPES.USDC)) {
1241
+ return { kind: "gasless-stable", symbol: "USDC", coinType: GASLESS_STABLE_TYPES.USDC };
1242
+ }
1243
+ if (normalized === utils.normalizeStructTag(GASLESS_STABLE_TYPES.USDsui)) {
1244
+ return { kind: "gasless-stable", symbol: "USDsui", coinType: GASLESS_STABLE_TYPES.USDsui };
1245
+ }
1246
+ if (normalized === utils.normalizeStructTag(exports.SUI_TYPE)) {
1247
+ return { kind: "sui", symbol: "SUI", coinType: exports.SUI_TYPE };
1248
+ }
1249
+ return { kind: "coin", symbol: resolveSymbol(coinType), coinType };
1250
+ }
1251
+ function invalidSendAssetMessage(asset) {
1252
+ return `Unknown asset "${asset}". Use a registry symbol (USDC, USDsui, SUI, MANIFEST, \u2026) or a full coin type (0x\u2026::module::TYPE).`;
1253
+ }
1254
+ function preflightSend(input) {
1255
+ const cls = classifySendAsset(input.asset);
1256
+ if (!cls) {
1257
+ return preflightFail("INVALID_ASSET", invalidSendAssetMessage(input.asset));
1257
1258
  }
1258
1259
  const amountCheck = checkPositiveAmount(input.amount);
1259
1260
  if (!amountCheck.valid) return amountCheck;
1260
- if ((input.asset === "USDC" || input.asset === "USDsui") && input.amount < GASLESS_MIN_STABLE_AMOUNT) {
1261
+ if (cls.kind === "gasless-stable" && input.amount < GASLESS_MIN_STABLE_AMOUNT) {
1261
1262
  return preflightFail(
1262
1263
  "INVALID_AMOUNT",
1263
- `Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${input.asset}. Got ${input.amount}.`
1264
+ `Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${cls.symbol}. Got ${input.amount}.`
1264
1265
  );
1265
1266
  }
1266
1267
  const addressCheck = checkSuiAddress(input.to);
@@ -1277,42 +1278,44 @@ async function buildSendTx({
1277
1278
  const pf = preflightSend({ to, amount, asset });
1278
1279
  if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
1279
1280
  const recipient = validateAddress(to);
1280
- const assetInfo = SUPPORTED_ASSETS[asset];
1281
- if (!assetInfo) throw new exports.T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
1282
- const rawAmount = displayToRaw(amount, assetInfo.decimals);
1281
+ const cls = classifySendAsset(asset);
1282
+ const decimals = cls.kind === "gasless-stable" || cls.kind === "sui" ? SUPPORTED_ASSETS[cls.symbol].decimals : await resolveCoinDecimals(client, cls.coinType);
1283
+ const rawAmount = displayToRaw(amount, decimals);
1283
1284
  const tx = new transactions.Transaction();
1284
1285
  tx.setSender(address);
1285
- const balanceResp = await client.core.getBalance({ owner: address, coinType: assetInfo.type });
1286
+ const balanceResp = await client.core.getBalance({ owner: address, coinType: cls.coinType });
1286
1287
  const totalBalance = BigInt(balanceResp.balance.balance);
1287
1288
  if (totalBalance < rawAmount) {
1288
- throw new exports.T2000Error("INSUFFICIENT_BALANCE", `Insufficient ${asset} balance`, {
1289
- available: Number(totalBalance) / 10 ** assetInfo.decimals,
1289
+ throw new exports.T2000Error("INSUFFICIENT_BALANCE", `Insufficient ${cls.symbol} balance`, {
1290
+ available: Number(totalBalance) / 10 ** decimals,
1290
1291
  required: amount
1291
1292
  });
1292
1293
  }
1293
- if (asset === "USDC" || asset === "USDsui") {
1294
- const rawFloor = displayToRaw(GASLESS_MIN_STABLE_AMOUNT, assetInfo.decimals);
1295
- const remainder = totalBalance - rawAmount;
1296
- if (remainder > 0n && remainder < rawFloor) {
1297
- const total = Number(totalBalance) / 10 ** assetInfo.decimals;
1298
- throw new exports.T2000Error(
1299
- "INVALID_AMOUNT",
1300
- `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)}.`,
1301
- { available: total, required: amount }
1302
- );
1303
- }
1304
- }
1305
- if (asset === "SUI") {
1294
+ if (cls.kind === "sui") {
1306
1295
  const [sendCoin] = tx.splitCoins(tx.gas, [rawAmount]);
1307
1296
  tx.transferObjects([sendCoin], recipient);
1308
1297
  return tx;
1309
1298
  }
1310
- const coinType = GASLESS_STABLE_TYPES[asset];
1299
+ if (cls.kind === "coin") {
1300
+ const sendCoin = transactions.coinWithBalance({ type: cls.coinType, balance: rawAmount })(tx);
1301
+ tx.transferObjects([sendCoin], recipient);
1302
+ return tx;
1303
+ }
1304
+ const rawFloor = displayToRaw(GASLESS_MIN_STABLE_AMOUNT, decimals);
1305
+ const remainder = totalBalance - rawAmount;
1306
+ if (remainder > 0n && remainder < rawFloor) {
1307
+ const total = Number(totalBalance) / 10 ** decimals;
1308
+ throw new exports.T2000Error(
1309
+ "INVALID_AMOUNT",
1310
+ `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)}.`,
1311
+ { available: total, required: amount }
1312
+ );
1313
+ }
1311
1314
  tx.moveCall({
1312
1315
  target: "0x2::balance::send_funds",
1313
- typeArguments: [coinType],
1316
+ typeArguments: [cls.coinType],
1314
1317
  arguments: [
1315
- tx.balance({ type: coinType, balance: rawAmount }),
1318
+ tx.balance({ type: cls.coinType, balance: rawAmount }),
1316
1319
  tx.pure.address(recipient)
1317
1320
  ]
1318
1321
  });
@@ -1662,6 +1665,7 @@ exports.checkPositiveAmount = checkPositiveAmount;
1662
1665
  exports.checkSuiAddress = checkSuiAddress;
1663
1666
  exports.classifyAction = classifyAction;
1664
1667
  exports.classifyLabel = classifyLabel;
1668
+ exports.classifySendAsset = classifySendAsset;
1665
1669
  exports.classifyTransaction = classifyTransaction;
1666
1670
  exports.executeTx = executeTx;
1667
1671
  exports.extractAllUserLegs = extractAllUserLegs;
@@ -1679,6 +1683,7 @@ exports.getDecimals = getDecimals;
1679
1683
  exports.getDecimalsForCoinType = getDecimalsForCoinType;
1680
1684
  exports.getJob = getJob;
1681
1685
  exports.getJobSpec = getJobSpec;
1686
+ exports.invalidSendAssetMessage = invalidSendAssetMessage;
1682
1687
  exports.jobActionsFor = jobActionsFor;
1683
1688
  exports.listServices = listServices;
1684
1689
  exports.mapMoveAbortCode = mapMoveAbortCode;