@t2000/sdk 5.5.0 → 5.6.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/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var utils = require('@mysten/sui/utils');
3
4
  var transactions = require('@mysten/sui/transactions');
4
5
  var aggregatorSdk = require('@cetusprotocol/aggregator-sdk');
5
6
  var BN = require('bn.js');
@@ -7,7 +8,6 @@ var eventemitter3 = require('eventemitter3');
7
8
  var paymentKit = require('@mysten/payment-kit');
8
9
  var grpc = require('@mysten/sui/grpc');
9
10
  var graphql = require('@mysten/sui/graphql');
10
- var utils = require('@mysten/sui/utils');
11
11
  var ed25519 = require('@mysten/sui/keypairs/ed25519');
12
12
  var cryptography = require('@mysten/sui/cryptography');
13
13
  var promises = require('fs/promises');
@@ -118,6 +118,37 @@ var init_errors = __esm({
118
118
  };
119
119
  }
120
120
  });
121
+ function preflightFail(code, error) {
122
+ return { valid: false, code, error };
123
+ }
124
+ function checkPositiveAmount(amount, label = "Amount", max = exports.PREFLIGHT_MAX_AMOUNT) {
125
+ if (typeof amount !== "number" || !Number.isFinite(amount)) {
126
+ return preflightFail("INVALID_AMOUNT", `${label} must be a finite number`);
127
+ }
128
+ if (amount <= 0) {
129
+ return preflightFail("INVALID_AMOUNT", `${label} must be greater than zero`);
130
+ }
131
+ if (amount > max) {
132
+ return preflightFail("INVALID_AMOUNT", `${label} ${amount} exceeds the sane maximum (${max})`);
133
+ }
134
+ return exports.PREFLIGHT_OK;
135
+ }
136
+ function checkSuiAddress(address, label = "recipient") {
137
+ try {
138
+ if (typeof address === "string" && address.trim() !== "" && utils.isValidSuiAddress(utils.normalizeSuiAddress(address))) {
139
+ return exports.PREFLIGHT_OK;
140
+ }
141
+ } catch {
142
+ }
143
+ return preflightFail("INVALID_ADDRESS", `Invalid ${label} address: ${address}`);
144
+ }
145
+ exports.PREFLIGHT_MAX_AMOUNT = void 0; exports.PREFLIGHT_OK = void 0;
146
+ var init_preflight = __esm({
147
+ "src/preflight.ts"() {
148
+ exports.PREFLIGHT_MAX_AMOUNT = 1e6;
149
+ exports.PREFLIGHT_OK = { valid: true };
150
+ }
151
+ });
121
152
 
122
153
  // src/token-registry.ts
123
154
  var token_registry_exports = {};
@@ -382,10 +413,28 @@ __export(cetus_swap_exports, {
382
413
  findSwapRoute: () => findSwapRoute,
383
414
  isCetusRouteFresh: () => isCetusRouteFresh,
384
415
  isPrecomputedRouteCompatibleWithProviders: () => isPrecomputedRouteCompatibleWithProviders,
416
+ preflightSwap: () => preflightSwap,
385
417
  resolveTokenType: () => resolveTokenType,
386
418
  serializeCetusRoute: () => serializeCetusRoute,
387
419
  verifyCetusRouteCoinMatch: () => verifyCetusRouteCoinMatch
388
420
  });
421
+ function preflightSwap(input) {
422
+ if (typeof input.from !== "string" || input.from.trim() === "") {
423
+ return preflightFail("INVALID_ASSET", "A `from` token is required to swap");
424
+ }
425
+ if (typeof input.to !== "string" || input.to.trim() === "") {
426
+ return preflightFail("INVALID_ASSET", "A `to` token is required to swap");
427
+ }
428
+ const amountCheck = checkPositiveAmount(input.amount, "Amount", Number.POSITIVE_INFINITY);
429
+ if (!amountCheck.valid) return amountCheck;
430
+ const resolvedFrom = resolveTokenType(input.from);
431
+ const resolvedTo = resolveTokenType(input.to);
432
+ const sameToken = input.from.trim() === input.to.trim() || resolvedFrom !== null && resolvedFrom === resolvedTo;
433
+ if (sameToken) {
434
+ return preflightFail("INVALID_ASSET", `Cannot swap ${input.from} to itself`);
435
+ }
436
+ return exports.PREFLIGHT_OK;
437
+ }
389
438
  function serializeCetusRoute(route, context) {
390
439
  return {
391
440
  routerData: serializeRouterDataV3(route.routerData),
@@ -637,6 +686,7 @@ exports.OVERLAY_FEE_RATE = void 0; var clientCache;
637
686
  var init_cetus_swap = __esm({
638
687
  "src/protocols/cetus-swap.ts"() {
639
688
  init_token_registry();
689
+ init_preflight();
640
690
  init_token_registry();
641
691
  exports.OVERLAY_FEE_RATE = 1e-3;
642
692
  clientCache = /* @__PURE__ */ new Map();
@@ -1010,8 +1060,33 @@ async function executeTx(client, signer, buildTx, options = {}) {
1010
1060
 
1011
1061
  // src/wallet/pay.ts
1012
1062
  init_errors();
1063
+ init_preflight();
1064
+ function preflightPay(input) {
1065
+ if (typeof input.url !== "string" || input.url.trim() === "") {
1066
+ return preflightFail("FACILITATOR_REJECTION", "A target URL is required to pay");
1067
+ }
1068
+ let parsed;
1069
+ try {
1070
+ parsed = new URL(input.url);
1071
+ } catch {
1072
+ return preflightFail("FACILITATOR_REJECTION", `Invalid URL: ${input.url}`);
1073
+ }
1074
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
1075
+ return preflightFail(
1076
+ "FACILITATOR_REJECTION",
1077
+ `URL must be http(s): got ${parsed.protocol}//`
1078
+ );
1079
+ }
1080
+ if (input.maxPrice !== void 0) {
1081
+ const priceCheck = checkPositiveAmount(input.maxPrice, "maxPrice");
1082
+ if (!priceCheck.valid) return priceCheck;
1083
+ }
1084
+ return exports.PREFLIGHT_OK;
1085
+ }
1013
1086
  async function payWithMpp(args) {
1014
1087
  const { signer, client, options } = args;
1088
+ const pf = preflightPay({ url: options.url, maxPrice: options.maxPrice });
1089
+ if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
1015
1090
  const method = (options.method ?? "GET").toUpperCase();
1016
1091
  const canHaveBody = method !== "GET" && method !== "HEAD";
1017
1092
  const reqInit = {
@@ -1246,6 +1321,25 @@ function normalizeAsset(input) {
1246
1321
  }
1247
1322
 
1248
1323
  // src/wallet/send.ts
1324
+ init_preflight();
1325
+ function preflightSend(input) {
1326
+ try {
1327
+ assertAllowedAsset("send", input.asset);
1328
+ } catch (e) {
1329
+ return preflightFail("INVALID_ASSET", e.message);
1330
+ }
1331
+ const amountCheck = checkPositiveAmount(input.amount);
1332
+ if (!amountCheck.valid) return amountCheck;
1333
+ if ((input.asset === "USDC" || input.asset === "USDsui") && input.amount < GASLESS_MIN_STABLE_AMOUNT) {
1334
+ return preflightFail(
1335
+ "INVALID_AMOUNT",
1336
+ `Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${input.asset}. Got ${input.amount}.`
1337
+ );
1338
+ }
1339
+ const addressCheck = checkSuiAddress(input.to);
1340
+ if (!addressCheck.valid) return addressCheck;
1341
+ return exports.PREFLIGHT_OK;
1342
+ }
1249
1343
  async function buildSendTx({
1250
1344
  client,
1251
1345
  address,
@@ -1253,17 +1347,11 @@ async function buildSendTx({
1253
1347
  amount,
1254
1348
  asset
1255
1349
  }) {
1256
- assertAllowedAsset("send", asset);
1350
+ const pf = preflightSend({ to, amount, asset });
1351
+ if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
1257
1352
  const recipient = validateAddress(to);
1258
1353
  const assetInfo = SUPPORTED_ASSETS[asset];
1259
1354
  if (!assetInfo) throw new exports.T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
1260
- if (amount <= 0) throw new exports.T2000Error("INVALID_AMOUNT", "Amount must be greater than zero");
1261
- if ((asset === "USDC" || asset === "USDsui") && amount < GASLESS_MIN_STABLE_AMOUNT) {
1262
- throw new exports.T2000Error(
1263
- "INVALID_AMOUNT",
1264
- `Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${asset}. Got ${amount}.`
1265
- );
1266
- }
1267
1355
  const rawAmount = displayToRaw(amount, assetInfo.decimals);
1268
1356
  const tx = new transactions.Transaction();
1269
1357
  tx.setSender(address);
@@ -1558,7 +1646,7 @@ var TX_NODE_FRAGMENT = `
1558
1646
  }
1559
1647
  `;
1560
1648
  var HISTORY_QUERY = `query History($address: SuiAddress!, $last: Int!) {
1561
- transactions(last: $last, filter: { sentAddress: $address }) {
1649
+ transactions(last: $last, filter: { affectedAddress: $address }) {
1562
1650
  nodes {${TX_NODE_FRAGMENT}}
1563
1651
  }
1564
1652
  }`;
@@ -1685,7 +1773,12 @@ function extractCommands(txBlock) {
1685
1773
  init_token_registry();
1686
1774
 
1687
1775
  // src/utils/suins.ts
1688
- var SUI_MAINNET_URL = "https://fullnode.mainnet.sui.io:443";
1776
+ var RESOLVE_NAME_QUERY = `query ResolveSuins($name: String!) {
1777
+ address(name: $name) { address }
1778
+ }`;
1779
+ var REVERSE_NAME_QUERY = `query ReverseSuins($address: SuiAddress!) {
1780
+ address(address: $address) { defaultNameRecord { domain } }
1781
+ }`;
1689
1782
  var SUI_ADDRESS_REGEX = /^0x[a-fA-F0-9]{1,64}$/i;
1690
1783
  var SUI_ADDRESS_STRICT_REGEX = /^0x[a-fA-F0-9]{64}$/i;
1691
1784
  var SUINS_NAME_REGEX = /^[a-z0-9-]+(\.[a-z0-9-]+)*\.sui$/;
@@ -1723,76 +1816,45 @@ async function resolveSuinsViaRpc(rawName, ctx = {}) {
1723
1816
  if (!SUINS_NAME_REGEX.test(name)) {
1724
1817
  throw new InvalidAddressError(rawName);
1725
1818
  }
1726
- const url = ctx.suiRpcUrl || SUI_MAINNET_URL;
1819
+ const gql = getSuiGraphQLClient();
1727
1820
  let res;
1728
1821
  try {
1729
- res = await fetch(url, {
1730
- method: "POST",
1731
- headers: { "Content-Type": "application/json" },
1732
- body: JSON.stringify({
1733
- jsonrpc: "2.0",
1734
- id: 1,
1735
- method: "suix_resolveNameServiceAddress",
1736
- params: [name]
1737
- }),
1738
- signal: ctx.signal ?? AbortSignal.timeout(8e3)
1822
+ res = await gql.query({
1823
+ query: RESOLVE_NAME_QUERY,
1824
+ variables: { name },
1825
+ signal: ctx.signal
1739
1826
  });
1740
1827
  } catch (err) {
1741
1828
  const msg = err instanceof Error ? err.message : String(err);
1742
1829
  throw new SuinsRpcError(name, msg);
1743
1830
  }
1744
- if (!res.ok) {
1745
- throw new SuinsRpcError(name, `HTTP ${res.status}`);
1746
- }
1747
- let body;
1748
- try {
1749
- body = await res.json();
1750
- } catch (err) {
1751
- const msg = err instanceof Error ? err.message : String(err);
1752
- throw new SuinsRpcError(name, `JSON parse failed: ${msg}`);
1753
- }
1754
- if (body.error) {
1755
- throw new SuinsRpcError(name, body.error.message);
1831
+ if (res.errors?.length) {
1832
+ throw new SuinsRpcError(name, res.errors.map((e) => e.message ?? "unknown error").join("; "));
1756
1833
  }
1757
- return body.result ?? null;
1834
+ return res.data?.address?.address ?? null;
1758
1835
  }
1759
1836
  async function resolveAddressToSuinsViaRpc(rawAddress, ctx = {}) {
1760
1837
  const address = rawAddress.trim().toLowerCase();
1761
1838
  if (!SUI_ADDRESS_REGEX.test(address)) {
1762
1839
  throw new InvalidAddressError(rawAddress);
1763
1840
  }
1764
- const url = ctx.suiRpcUrl || SUI_MAINNET_URL;
1841
+ const gql = getSuiGraphQLClient();
1765
1842
  let res;
1766
1843
  try {
1767
- res = await fetch(url, {
1768
- method: "POST",
1769
- headers: { "Content-Type": "application/json" },
1770
- body: JSON.stringify({
1771
- jsonrpc: "2.0",
1772
- id: 1,
1773
- method: "suix_resolveNameServiceNames",
1774
- params: [address]
1775
- }),
1776
- signal: ctx.signal ?? AbortSignal.timeout(8e3)
1844
+ res = await gql.query({
1845
+ query: REVERSE_NAME_QUERY,
1846
+ variables: { address },
1847
+ signal: ctx.signal
1777
1848
  });
1778
1849
  } catch (err) {
1779
1850
  const msg = err instanceof Error ? err.message : String(err);
1780
1851
  throw new SuinsRpcError(address, msg);
1781
1852
  }
1782
- if (!res.ok) {
1783
- throw new SuinsRpcError(address, `HTTP ${res.status}`);
1784
- }
1785
- let body;
1786
- try {
1787
- body = await res.json();
1788
- } catch (err) {
1789
- const msg = err instanceof Error ? err.message : String(err);
1790
- throw new SuinsRpcError(address, `JSON parse failed: ${msg}`);
1791
- }
1792
- if (body.error) {
1793
- throw new SuinsRpcError(address, body.error.message);
1853
+ if (res.errors?.length) {
1854
+ throw new SuinsRpcError(address, res.errors.map((e) => e.message ?? "unknown error").join("; "));
1794
1855
  }
1795
- return body.result?.data ?? [];
1856
+ const domain = res.data?.address?.defaultNameRecord?.domain;
1857
+ return domain ? [domain] : [];
1796
1858
  }
1797
1859
  async function normalizeAddressInput(value, ctx = {}) {
1798
1860
  const trimmed = value.trim();
@@ -2085,7 +2147,9 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
2085
2147
  amountUsd: approxUsdValue(params.from, params.amount) ?? 0,
2086
2148
  force: params.force
2087
2149
  });
2088
- const { findSwapRoute: findSwapRoute2, buildSwapTx: buildSwapTx2, resolveTokenType: resolveTokenType2 } = await Promise.resolve().then(() => (init_cetus_swap(), cetus_swap_exports));
2150
+ const { findSwapRoute: findSwapRoute2, buildSwapTx: buildSwapTx2, resolveTokenType: resolveTokenType2, preflightSwap: preflightSwap2 } = await Promise.resolve().then(() => (init_cetus_swap(), cetus_swap_exports));
2151
+ const pf = preflightSwap2({ from: params.from, to: params.to, amount: params.amount });
2152
+ if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
2089
2153
  const fromType = resolveTokenType2(params.from);
2090
2154
  const toType = resolveTokenType2(params.to);
2091
2155
  if (!fromType) throw new exports.T2000Error("ASSET_NOT_SUPPORTED", `Unknown token: ${params.from}. Provide the full coin type.`);
@@ -2815,6 +2879,9 @@ function displayHandle(label) {
2815
2879
  return `${label}@${parentDisplay}`;
2816
2880
  }
2817
2881
 
2882
+ // src/index.ts
2883
+ init_preflight();
2884
+
2818
2885
  exports.AUDRIC_PARENT_NAME = AUDRIC_PARENT_NAME;
2819
2886
  exports.AUDRIC_PARENT_NFT_ID = AUDRIC_PARENT_NFT_ID;
2820
2887
  exports.CETUS_USDC_SUI_POOL = CETUS_USDC_SUI_POOL;
@@ -2856,6 +2923,8 @@ exports.buildAddLeafTx = buildAddLeafTx;
2856
2923
  exports.buildRevokeLeafTx = buildRevokeLeafTx;
2857
2924
  exports.buildSendTx = buildSendTx;
2858
2925
  exports.buildSwapTx = buildSwapTx;
2926
+ exports.checkPositiveAmount = checkPositiveAmount;
2927
+ exports.checkSuiAddress = checkSuiAddress;
2859
2928
  exports.classifyAction = classifyAction;
2860
2929
  exports.classifyLabel = classifyLabel;
2861
2930
  exports.classifyTransaction = classifyTransaction;
@@ -2903,6 +2972,11 @@ exports.normalizeAsset = normalizeAsset;
2903
2972
  exports.normalizeCoinType = normalizeCoinType;
2904
2973
  exports.parseSuiRpcTx = parseSuiRpcTx;
2905
2974
  exports.payWithMpp = payWithMpp;
2975
+ exports.preflightFail = preflightFail;
2976
+ exports.preflightPay = preflightPay;
2977
+ exports.preflightSend = preflightSend;
2978
+ exports.preflightSwap = preflightSwap;
2979
+ exports.queryBalance = queryBalance;
2906
2980
  exports.queryHistory = queryHistory;
2907
2981
  exports.queryTransaction = queryTransaction;
2908
2982
  exports.rawToStable = rawToStable;