@rhea-finance/cross-chain-aggregation-dex 2.0.5 → 2.0.7

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.
Files changed (42) hide show
  1. package/README.md +148 -71
  2. package/dist/executors/aptos.d.mts +1 -1
  3. package/dist/executors/aptos.d.ts +1 -1
  4. package/dist/executors/aptos.js.map +1 -1
  5. package/dist/executors/aptos.mjs.map +1 -1
  6. package/dist/executors/bitcoin.d.mts +1 -1
  7. package/dist/executors/bitcoin.d.ts +1 -1
  8. package/dist/executors/bitcoin.js.map +1 -1
  9. package/dist/executors/bitcoin.mjs.map +1 -1
  10. package/dist/executors/evm.d.mts +1 -1
  11. package/dist/executors/evm.d.ts +1 -1
  12. package/dist/executors/evm.js.map +1 -1
  13. package/dist/executors/evm.mjs.map +1 -1
  14. package/dist/executors/near.d.mts +1 -1
  15. package/dist/executors/near.d.ts +1 -1
  16. package/dist/executors/near.js.map +1 -1
  17. package/dist/executors/near.mjs.map +1 -1
  18. package/dist/executors/solana.d.mts +1 -1
  19. package/dist/executors/solana.d.ts +1 -1
  20. package/dist/executors/solana.js.map +1 -1
  21. package/dist/executors/solana.mjs.map +1 -1
  22. package/dist/executors/sui.d.mts +1 -1
  23. package/dist/executors/sui.d.ts +1 -1
  24. package/dist/executors/sui.js.map +1 -1
  25. package/dist/executors/sui.mjs.map +1 -1
  26. package/dist/executors/tron.d.mts +1 -1
  27. package/dist/executors/tron.d.ts +1 -1
  28. package/dist/executors/tron.js.map +1 -1
  29. package/dist/executors/tron.mjs.map +1 -1
  30. package/dist/executors/zcash.d.mts +1 -1
  31. package/dist/executors/zcash.d.ts +1 -1
  32. package/dist/executors/zcash.js.map +1 -1
  33. package/dist/executors/zcash.mjs.map +1 -1
  34. package/dist/index.d.mts +40 -6
  35. package/dist/index.d.ts +40 -6
  36. package/dist/index.js +266 -47
  37. package/dist/index.js.map +1 -1
  38. package/dist/index.mjs +265 -48
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/{shared-DmMJXknE.d.mts → shared-COkGiqaz.d.mts} +30 -2
  41. package/dist/{shared-DmMJXknE.d.ts → shared-COkGiqaz.d.ts} +30 -2
  42. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -48,7 +48,7 @@ var ApiClient = class {
48
48
  this.fetchImpl = fetchImpl.bind(globalThis);
49
49
  }
50
50
  quote(body, options = {}) {
51
- return this.request("/api/swap/quote", "quote", {
51
+ return this.request("/api/v2/swap/quote", "quote", {
52
52
  ...options,
53
53
  method: "POST",
54
54
  body,
@@ -56,7 +56,7 @@ var ApiClient = class {
56
56
  });
57
57
  }
58
58
  build(body, options = {}) {
59
- return this.request("/api/swap/swap", "build", {
59
+ return this.request("/api/v2/swap/swap", "build", {
60
60
  ...options,
61
61
  method: "POST",
62
62
  body
@@ -116,6 +116,22 @@ var ApiClient = class {
116
116
  body
117
117
  });
118
118
  }
119
+ getFromTokenRows(chainId, options = {}) {
120
+ return this.request("/get_chain_prices", "tokens", {
121
+ ...options,
122
+ method: "GET",
123
+ retryableOperation: true,
124
+ query: { chain: chainId }
125
+ });
126
+ }
127
+ getCrossChainToTokenRows(chainId, options = {}) {
128
+ return this.request("/api/swap/supported_to_tokens", "tokens", {
129
+ ...options,
130
+ method: "GET",
131
+ retryableOperation: true,
132
+ query: { chain: chainId }
133
+ });
134
+ }
119
135
  async request(path, stage, options) {
120
136
  const url = this.buildUrl(path, options.query);
121
137
  const headers = await this.buildHeaders(
@@ -655,7 +671,7 @@ function normalizeBuild(raw, executionId = createExecutionId(), request) {
655
671
  const lane = laneFromChainType(common.chainType, fromChain);
656
672
  assertLaneMatchesChain(lane, fromChain);
657
673
  const execution = normalizeExecution(raw, lane, fromChain);
658
- const order = normalizeOrder(raw, execution);
674
+ const order = normalizeOrder(raw, execution, request);
659
675
  const deposit = normalizeDeposit(raw.deposit);
660
676
  return {
661
677
  executionId,
@@ -886,11 +902,12 @@ function assertKind(actual, allowed) {
886
902
  );
887
903
  }
888
904
  }
889
- function normalizeOrder(raw, execution) {
905
+ function normalizeOrder(raw, execution, request) {
890
906
  const depositOrderId = readRecordString(raw.deposit, "orderId");
891
- const orderId = raw.orderId ?? depositOrderId;
892
- if (!orderId) return void 0;
893
907
  const router = raw.statusRouter ?? (execution.kind === "evm-signature" ? execution.request.router : void 0) ?? raw.router;
908
+ const confidentialNearIntentsStatusKey = request?.confidentiality === "basic" && router.toLowerCase().includes("nearintents") ? readRecordString(raw.deposit, "depositAddress") : void 0;
909
+ const orderId = raw.orderId ?? depositOrderId ?? confidentialNearIntentsStatusKey;
910
+ if (!orderId) return void 0;
894
911
  const chainId = execution.kind === "evm-signature" ? String(execution.request.chainId) : execution.kind === "evm-transaction" ? String(execution.tx.chainId) : void 0;
895
912
  return { orderId, router, ...chainId ? { chainId } : {} };
896
913
  }
@@ -950,6 +967,8 @@ function assertBaseUnitAmount(value) {
950
967
 
951
968
  // src/normalizers/quote.ts
952
969
  var DEFAULT_QUOTE_WAITING_TIME_MS = 3e3;
970
+ var DEFAULT_SAME_CHAIN_TIMEOUT_MS = 500;
971
+ var DEFAULT_CROSS_CHAIN_TIMEOUT_MS = 3e3;
953
972
  function serializeQuoteRequest(request) {
954
973
  validateQuoteRequest(request);
955
974
  return {
@@ -961,6 +980,8 @@ function serializeQuoteRequest(request) {
961
980
  amountIn: request.amountIn,
962
981
  slippage: request.slippageBps,
963
982
  quoteWaitingTimeMs: request.quoteWaitingTimeMs ?? DEFAULT_QUOTE_WAITING_TIME_MS,
983
+ sameChainTimeoutMs: request.sameChainTimeoutMs ?? DEFAULT_SAME_CHAIN_TIMEOUT_MS,
984
+ crossChainTimeoutMs: request.crossChainTimeoutMs ?? DEFAULT_CROSS_CHAIN_TIMEOUT_MS,
964
985
  ...request.confidentiality ? { confidentiality: request.confidentiality } : {},
965
986
  sender: request.sender.trim(),
966
987
  ...request.recipient?.trim() ? { recipient: request.recipient.trim() } : {}
@@ -972,7 +993,11 @@ function normalizeQuote(request, raw, receivedAt = Date.now()) {
972
993
  throw invalidQuote("Quote response does not contain a valid best route");
973
994
  }
974
995
  const quoteId = readOptionalString(raw.bestQuote.quoteId);
975
- const apiRequest = Object.freeze({ ...serializeQuoteRequest(request) });
996
+ const apiRequest = { ...serializeQuoteRequest(request) };
997
+ delete apiRequest.quoteWaitingTimeMs;
998
+ delete apiRequest.sameChainTimeoutMs;
999
+ delete apiRequest.crossChainTimeoutMs;
1000
+ Object.freeze(apiRequest);
976
1001
  const buildContext = Object.freeze({
977
1002
  request: apiRequest,
978
1003
  router: bestRoute.router,
@@ -1040,6 +1065,14 @@ function validateQuoteRequest(request) {
1040
1065
  "quoteWaitingTimeMs must be a non-negative integer"
1041
1066
  );
1042
1067
  }
1068
+ validateQuoteTimingParameter(
1069
+ request.sameChainTimeoutMs,
1070
+ "sameChainTimeoutMs"
1071
+ );
1072
+ validateQuoteTimingParameter(
1073
+ request.crossChainTimeoutMs,
1074
+ "crossChainTimeoutMs"
1075
+ );
1043
1076
  if (!request.sender.trim()) {
1044
1077
  throw new SwapSdkError(
1045
1078
  "INVALID_REQUEST",
@@ -1062,6 +1095,15 @@ function validateQuoteRequest(request) {
1062
1095
  );
1063
1096
  }
1064
1097
  }
1098
+ function validateQuoteTimingParameter(value, field) {
1099
+ if (value !== void 0 && (!Number.isFinite(value) || !Number.isInteger(value) || value < 0)) {
1100
+ throw new SwapSdkError(
1101
+ "INVALID_REQUEST",
1102
+ "quote",
1103
+ `${field} must be a non-negative integer`
1104
+ );
1105
+ }
1106
+ }
1065
1107
  function normalizeRoute(raw, required) {
1066
1108
  const router = readOptionalString(raw.router);
1067
1109
  const amountOutValue = raw.amountOut ?? raw.estimatedOut;
@@ -1234,6 +1276,137 @@ function normalizeTimestamp(value) {
1234
1276
  return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
1235
1277
  }
1236
1278
 
1279
+ // src/normalizers/tokens.ts
1280
+ var TOKEN_LIST_CHAIN_METADATA = /* @__PURE__ */ new Map([
1281
+ [1, { chain: "1", blockchain: "eth" }],
1282
+ [10, { chain: "10", blockchain: "op" }],
1283
+ [43114, { chain: "43114", blockchain: "avax" }],
1284
+ [4663, { chain: "4663", blockchain: "robinhood" }],
1285
+ [747474, { chain: "747474", blockchain: "katana" }],
1286
+ [146, { chain: "146", blockchain: "sonic" }],
1287
+ [130, { chain: "130", blockchain: "unichain" }],
1288
+ [1672, { chain: "1672", blockchain: "pharos" }],
1289
+ [4217, { chain: "4217", blockchain: "tempo" }],
1290
+ [56, { chain: "56", blockchain: "bsc" }],
1291
+ [100, { chain: "100", blockchain: "gnosis" }],
1292
+ [137, { chain: "137", blockchain: "pol" }],
1293
+ [143, { chain: "143", blockchain: "monad" }],
1294
+ [196, { chain: "196", blockchain: "xlayer" }],
1295
+ [8453, { chain: "8453", blockchain: "base" }],
1296
+ [9745, { chain: "9745", blockchain: "plasma" }],
1297
+ [42161, { chain: "42161", blockchain: "arb" }],
1298
+ [80094, { chain: "80094", blockchain: "bera" }],
1299
+ [195, { chain: "tron", blockchain: "tron" }],
1300
+ [501, { chain: "solana", blockchain: "sol" }],
1301
+ [784, { chain: "sui", blockchain: "sui" }],
1302
+ [900001, { chain: "near", blockchain: "near" }],
1303
+ [900002, { chain: "btc", blockchain: "btc" }],
1304
+ [900010, { chain: "zcash", blockchain: "zec" }],
1305
+ [900012, { chain: "aptos", blockchain: "aptos" }]
1306
+ ]);
1307
+ function normalizeFromTokenList(raw, chainId) {
1308
+ if (!isRecord2(raw) || Array.isArray(raw)) {
1309
+ throw invalidTokenList("From-token response data must be an object");
1310
+ }
1311
+ return normalizeRows(Object.values(raw), chainId);
1312
+ }
1313
+ function normalizeCrossChainToTokenList(raw, chainId) {
1314
+ if (!isRecord2(raw) || !Array.isArray(raw.tokens)) {
1315
+ throw invalidTokenList(
1316
+ "Cross-chain to-token response data must contain a tokens array"
1317
+ );
1318
+ }
1319
+ return normalizeRows(raw.tokens, chainId);
1320
+ }
1321
+ function normalizeRows(rows, chainId) {
1322
+ const tokens = rows.map((row) => normalizeRow(row, chainId)).filter((token) => token !== void 0);
1323
+ if (rows.length > 0 && tokens.length === 0) {
1324
+ throw invalidTokenList("Token-list response contains no valid token rows");
1325
+ }
1326
+ return tokens;
1327
+ }
1328
+ function normalizeRow(value, chainId) {
1329
+ if (!isRecord2(value)) return void 0;
1330
+ const row = value;
1331
+ const assetId = readString(row.assetId) ?? readString(row.address) ?? readString(row.contractAddress) ?? readString(row.coinType);
1332
+ const symbol = readString(row.symbol);
1333
+ const decimals = readDecimals(row.decimals);
1334
+ if (!assetId || !symbol || decimals === void 0) return void 0;
1335
+ const metadata = TOKEN_LIST_CHAIN_METADATA.get(chainId);
1336
+ const chain = metadata?.chain ?? String(chainId);
1337
+ const blockchain = readString(row.blockchain)?.toLowerCase() ?? metadata?.blockchain ?? String(chainId);
1338
+ const rawAddress = readString(row.contractAddress) ?? readString(row.address) ?? readString(row.coinType);
1339
+ const isNative = isNativeToken({
1340
+ row,
1341
+ chain,
1342
+ blockchain,
1343
+ assetId,
1344
+ rawAddress,
1345
+ symbol
1346
+ });
1347
+ const sources = Array.isArray(row.sources) ? row.sources.filter(
1348
+ (source) => typeof source === "string" && source.trim().length > 0
1349
+ ) : readString(row.platform) ? [readString(row.platform)] : [];
1350
+ const price = typeof row.price === "string" || typeof row.price === "number" ? row.price : null;
1351
+ const priceUpdatedAt = typeof row.updated_at === "number" && Number.isFinite(row.updated_at) ? row.updated_at : null;
1352
+ return {
1353
+ chain,
1354
+ address: assetId,
1355
+ symbol,
1356
+ decimals,
1357
+ isNative,
1358
+ tokenListChainId: chainId,
1359
+ blockchain,
1360
+ assetId,
1361
+ contractAddress: isNative ? null : rawAddress ?? null,
1362
+ coinType: readString(row.coinType) ?? null,
1363
+ name: readString(row.name) ?? null,
1364
+ logoURI: readString(row.logoURI) ?? null,
1365
+ price,
1366
+ priceUpdatedAt,
1367
+ sources,
1368
+ raw: { ...row }
1369
+ };
1370
+ }
1371
+ function isNativeToken(input) {
1372
+ if (input.row.isNative === true) return true;
1373
+ const address = (input.rawAddress ?? "").toLowerCase();
1374
+ const assetId = input.assetId.toLowerCase();
1375
+ const coinType = readString(input.row.coinType)?.toLowerCase() ?? "";
1376
+ if (/^[1-9]\d*$/.test(input.chain)) {
1377
+ return address === "0x0000000000000000000000000000000000000000" || address === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" || (input.blockchain === "pol" || input.blockchain === "polygon") && address === "0x0000000000000000000000000000000000001010";
1378
+ }
1379
+ if (input.chain === "solana") {
1380
+ return address === "11111111111111111111111111111111" || assetId === "nep141:sol.omft.near";
1381
+ }
1382
+ if (input.chain === "tron") {
1383
+ return input.symbol.toUpperCase() === "TRX";
1384
+ }
1385
+ if (input.chain === "sui") {
1386
+ return address.endsWith("::sui::sui");
1387
+ }
1388
+ if (input.chain === "aptos") {
1389
+ if (coinType === "0x1::aptos_coin::aptoscoin") return true;
1390
+ if (!/^0x[0-9a-f]+$/.test(address)) return false;
1391
+ const compactAddress = address.slice(2).replace(/^0+/, "") || "0";
1392
+ return compactAddress === "a";
1393
+ }
1394
+ return false;
1395
+ }
1396
+ function readString(value) {
1397
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
1398
+ }
1399
+ function readDecimals(value) {
1400
+ const decimals = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
1401
+ return Number.isInteger(decimals) && decimals >= 0 ? decimals : void 0;
1402
+ }
1403
+ function isRecord2(value) {
1404
+ return typeof value === "object" && value !== null;
1405
+ }
1406
+ function invalidTokenList(message) {
1407
+ return new SwapSdkError("INVALID_API_RESPONSE", "tokens", message);
1408
+ }
1409
+
1237
1410
  // src/mca/collateral.ts
1238
1411
  function resolveMcaWithdrawPolicy(input) {
1239
1412
  const decreaseCollateral = resolveMcaRequiredCollateralDecrease({
@@ -1397,7 +1570,7 @@ function normalizeMcaQuote(request, signer, quote) {
1397
1570
  mca: Object.freeze({ ...mca })
1398
1571
  };
1399
1572
  if (request.flow === "deposit") {
1400
- if (readString(quote.raw.nearDepositTxError)) {
1573
+ if (readString2(quote.raw.nearDepositTxError)) {
1401
1574
  throw invalidResponse(String(quote.raw.nearDepositTxError));
1402
1575
  }
1403
1576
  return {
@@ -1408,7 +1581,7 @@ function normalizeMcaQuote(request, signer, quote) {
1408
1581
  ...quote.raw.nearDepositTx === void 0 ? {} : { nearDepositTx: quote.raw.nearDepositTx }
1409
1582
  };
1410
1583
  }
1411
- if (readString(quote.raw.nearMcaWithdrawTxError)) {
1584
+ if (readString2(quote.raw.nearMcaWithdrawTxError)) {
1412
1585
  throw invalidResponse(String(quote.raw.nearMcaWithdrawTxError));
1413
1586
  }
1414
1587
  const mode = resolveWithdrawMode(request);
@@ -1436,7 +1609,7 @@ function resolveWithdrawMode(request) {
1436
1609
  function isPlainObject(value) {
1437
1610
  return typeof value === "object" && value !== null && !Array.isArray(value);
1438
1611
  }
1439
- function readString(value) {
1612
+ function readString2(value) {
1440
1613
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
1441
1614
  }
1442
1615
  function invalidRequest(message) {
@@ -1738,7 +1911,6 @@ var McaSwapService = class {
1738
1911
  this.client = client;
1739
1912
  this.relayerReports = /* @__PURE__ */ new Map();
1740
1913
  this.now = config.now ?? Date.now;
1741
- this.maxQuoteAgeMs = config.maxQuoteAgeMs === void 0 ? 3e4 : config.maxQuoteAgeMs;
1742
1914
  this.reportMode = config.reportMode ?? "auto";
1743
1915
  this.onEvent = config.onEvent;
1744
1916
  this.resolveSignerIdentity = config.resolveSignerIdentity;
@@ -1760,7 +1932,6 @@ var McaSwapService = class {
1760
1932
  return normalizeMcaQuote(request, signer, quote);
1761
1933
  }
1762
1934
  async build(input) {
1763
- this.assertQuoteFresh(input.quote);
1764
1935
  if (input.quote.executionMode === "withdraw-relayer") {
1765
1936
  throw new SwapSdkError(
1766
1937
  "INVALID_REQUEST",
@@ -1781,7 +1952,6 @@ var McaSwapService = class {
1781
1952
  };
1782
1953
  }
1783
1954
  async swap(input) {
1784
- this.assertQuoteFresh(input.quote);
1785
1955
  if (input.quote.executionMode === "withdraw-relayer") {
1786
1956
  return this.executeRelayerWithdraw({ ...input, quote: input.quote });
1787
1957
  }
@@ -1924,7 +2094,7 @@ var McaSwapService = class {
1924
2094
  "MCA relayer preview is missing business"
1925
2095
  );
1926
2096
  }
1927
- const message = readString2(input.quote.preview.messageToSign);
2097
+ const message = readString3(input.quote.preview.messageToSign);
1928
2098
  if (!message) {
1929
2099
  throw new SwapSdkError(
1930
2100
  "INVALID_API_RESPONSE",
@@ -1933,7 +2103,7 @@ var McaSwapService = class {
1933
2103
  );
1934
2104
  }
1935
2105
  const depositAddress = extractMcaWithdrawDepositAddress({
1936
- snapshotDepositAddress: readString2(input.quote.raw.depositAddress),
2106
+ snapshotDepositAddress: readString3(input.quote.raw.depositAddress),
1937
2107
  preview: input.quote.preview,
1938
2108
  bestQuote: input.quote.raw.bestQuote
1939
2109
  });
@@ -1998,8 +2168,8 @@ var McaSwapService = class {
1998
2168
  signal: input.signal,
1999
2169
  idempotencyKey: input.idempotencyKey
2000
2170
  });
2001
- const orderId = readString2(raw.orderId) ?? readRecordString2(raw.deposit, "orderId");
2002
- const router = readString2(raw.router) ?? input.quote.route.router;
2171
+ const orderId = readString3(raw.orderId) ?? readRecordString2(raw.deposit, "orderId");
2172
+ const router = readString3(raw.router) ?? input.quote.route.router;
2003
2173
  const submittedDepositAddress = readRecordString2(raw.deposit, "depositAddress") ?? depositAddress;
2004
2174
  if (!orderId || !router) {
2005
2175
  throw new SwapSdkError(
@@ -2097,18 +2267,6 @@ var McaSwapService = class {
2097
2267
  this.onEvent?.(event);
2098
2268
  if (local !== this.onEvent) local?.(event);
2099
2269
  }
2100
- assertQuoteFresh(quote) {
2101
- const now = this.now();
2102
- const expiredByApi = quote.expiresAt !== void 0 && now > quote.expiresAt;
2103
- const expiredByAge = this.maxQuoteAgeMs !== null && now - quote.receivedAt > Math.max(0, this.maxQuoteAgeMs);
2104
- if (expiredByApi || expiredByAge) {
2105
- throw new SwapSdkError(
2106
- "QUOTE_EXPIRED",
2107
- "build",
2108
- "Quote has expired; request a fresh quote"
2109
- );
2110
- }
2111
- }
2112
2270
  };
2113
2271
  function buildRequestFromQuote(quote) {
2114
2272
  const context = quote.buildContext;
@@ -2132,14 +2290,14 @@ function assertSignerMatchesQuote(signer, expected) {
2132
2290
  );
2133
2291
  }
2134
2292
  }
2135
- function readString2(value) {
2293
+ function readString3(value) {
2136
2294
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
2137
2295
  }
2138
2296
  function readRecordString2(value, field) {
2139
2297
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
2140
2298
  return void 0;
2141
2299
  }
2142
- return readString2(value[field]);
2300
+ return readString3(value[field]);
2143
2301
  }
2144
2302
 
2145
2303
  // src/client/SwapClient.ts
@@ -2147,6 +2305,8 @@ var SwapClient = class {
2147
2305
  constructor(config) {
2148
2306
  this.inFlight = /* @__PURE__ */ new Set();
2149
2307
  this.reportRequests = /* @__PURE__ */ new Map();
2308
+ this.tokenListCache = /* @__PURE__ */ new Map();
2309
+ this.tokenListInflight = /* @__PURE__ */ new Map();
2150
2310
  this.config = config;
2151
2311
  this.api = new ApiClient(config);
2152
2312
  this.registry = new ExecutorRegistry(config.executors ?? []);
@@ -2154,7 +2314,6 @@ var SwapClient = class {
2154
2314
  this.now = config.now ?? Date.now;
2155
2315
  this.managedSwapFlow = new McaSwapService(this, {
2156
2316
  now: this.now,
2157
- maxQuoteAgeMs: config.maxQuoteAgeMs,
2158
2317
  reportMode: this.reportMode,
2159
2318
  resolveSignerIdentity: (chain) => this.registry.getSigner(chain),
2160
2319
  resolveMessageSigner: (chain) => this.registry.getSigner(chain, true),
@@ -2179,6 +2338,55 @@ var SwapClient = class {
2179
2338
  buildRaw(request, options = {}) {
2180
2339
  return this.api.build(request, options);
2181
2340
  }
2341
+ async getFromTokens(request, options = {}) {
2342
+ return this.loadTokenList("from", request, options, async () => {
2343
+ const raw = await this.api.getFromTokenRows(request.chainId, options);
2344
+ return normalizeFromTokenList(raw, request.chainId);
2345
+ });
2346
+ }
2347
+ async getCrossChainToTokens(request, options = {}) {
2348
+ return this.loadTokenList("cross-chain-to", request, options, async () => {
2349
+ const raw = await this.api.getCrossChainToTokenRows(
2350
+ request.chainId,
2351
+ options
2352
+ );
2353
+ return normalizeCrossChainToTokenList(raw, request.chainId);
2354
+ });
2355
+ }
2356
+ async loadTokenList(direction, request, options, load) {
2357
+ if (!Number.isSafeInteger(request.chainId) || request.chainId <= 0) {
2358
+ throw new SwapSdkError(
2359
+ "INVALID_REQUEST",
2360
+ "tokens",
2361
+ `Token-list chainId must be a positive safe integer: ${String(
2362
+ request.chainId
2363
+ )}`
2364
+ );
2365
+ }
2366
+ const ttlMs = Math.max(0, this.config.tokenListCacheTtlMs ?? 6e5);
2367
+ const key = `${direction}:${request.chainId}`;
2368
+ const cached = this.tokenListCache.get(key);
2369
+ if (ttlMs > 0 && cached && cached.expiresAt > this.now()) {
2370
+ return cloneTokenList(cached.tokens);
2371
+ }
2372
+ const existing = options.signal ? void 0 : this.tokenListInflight.get(key);
2373
+ if (existing) return cloneTokenList(await existing);
2374
+ const pending = load().then((tokens) => {
2375
+ if (ttlMs > 0) {
2376
+ this.tokenListCache.set(key, {
2377
+ expiresAt: this.now() + ttlMs,
2378
+ tokens: cloneTokenList(tokens)
2379
+ });
2380
+ }
2381
+ return tokens;
2382
+ }).finally(() => {
2383
+ if (this.tokenListInflight.get(key) === pending) {
2384
+ this.tokenListInflight.delete(key);
2385
+ }
2386
+ });
2387
+ if (!options.signal) this.tokenListInflight.set(key, pending);
2388
+ return cloneTokenList(await pending);
2389
+ }
2182
2390
  async buildSwap(input) {
2183
2391
  if (isMcaQuote(input.quote)) {
2184
2392
  return this.managedSwapFlow.build({
@@ -2190,7 +2398,6 @@ var SwapClient = class {
2190
2398
  return this.buildStandardSwap(input);
2191
2399
  }
2192
2400
  async buildStandardSwap(input) {
2193
- this.assertQuoteFresh(input.quote);
2194
2401
  const executionId = createExecutionId();
2195
2402
  this.emit({ type: "build-started", executionId });
2196
2403
  const context = input.quote.buildContext;
@@ -2309,7 +2516,23 @@ var SwapClient = class {
2309
2516
  emit({ type: "warning", executionId: build.executionId, warning });
2310
2517
  }
2311
2518
  }
2312
- if ((input.waitFor ?? "submitted") === "completed" && orderId) {
2519
+ const waitsForCompletion = (input.waitFor ?? "submitted") === "completed";
2520
+ const requiresOrderStatus = build.isCrossChain || build.request?.confidentiality === "basic";
2521
+ if (waitsForCompletion && requiresOrderStatus && !orderId) {
2522
+ throw new SwapSdkError(
2523
+ "INVALID_API_RESPONSE",
2524
+ "status",
2525
+ "Swap submitted, but the API did not provide a status key",
2526
+ {
2527
+ details: {
2528
+ executionId: build.executionId,
2529
+ ...result.txHash ? { txHash: result.txHash } : {},
2530
+ router: orderRouter ?? build.router
2531
+ }
2532
+ }
2533
+ );
2534
+ }
2535
+ if (waitsForCompletion && orderId) {
2313
2536
  const status = await this.waitForOrder({
2314
2537
  orderId,
2315
2538
  router: orderRouter ?? build.router,
@@ -2462,19 +2685,6 @@ var SwapClient = class {
2462
2685
  emit(event) {
2463
2686
  this.config.onEvent?.(event);
2464
2687
  }
2465
- assertQuoteFresh(quote) {
2466
- const now = this.now();
2467
- const maxAge = this.config.maxQuoteAgeMs === void 0 ? 3e4 : this.config.maxQuoteAgeMs;
2468
- const expiredByApi = quote.expiresAt !== void 0 && now > quote.expiresAt;
2469
- const expiredByAge = maxAge !== null && now - quote.receivedAt > Math.max(0, maxAge);
2470
- if (expiredByApi || expiredByAge) {
2471
- throw new SwapSdkError(
2472
- "QUOTE_EXPIRED",
2473
- "build",
2474
- "Quote has expired; request a fresh quote"
2475
- );
2476
- }
2477
- }
2478
2688
  createReportRequest(build, result) {
2479
2689
  const request = build.request;
2480
2690
  const reportContext = build.reportContext;
@@ -2544,6 +2754,13 @@ function isMcaQuote(quote) {
2544
2754
  function readNonEmptyString(value) {
2545
2755
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
2546
2756
  }
2757
+ function cloneTokenList(tokens) {
2758
+ return tokens.map((token) => ({
2759
+ ...token,
2760
+ sources: [...token.sources],
2761
+ raw: { ...token.raw }
2762
+ }));
2763
+ }
2547
2764
  function delay(ms, signal) {
2548
2765
  return new Promise((resolve, reject) => {
2549
2766
  if (signal?.aborted) {
@@ -2574,6 +2791,6 @@ function delay(ms, signal) {
2574
2791
  });
2575
2792
  }
2576
2793
 
2577
- export { ApiClient, DEFAULT_MCA_SIGNER_PRIORITY, ExecutorRegistry, SwapClient, SwapSdkError, asSwapSdkError, assertBaseUnitAmount, buildMcaWithdrawRelayerRequest, buildNearMcaWithdrawTransactions, createExecutionId, extractMcaWithdrawBusiness, extractMcaWithdrawDepositAddress, extractMcaWithdrawSignerWallet, formatMcaWallet, formatUnits, fromApiChain, isSameMcaSignerIdentity, normalizeBuild, normalizeHistory, normalizeHistoryStatus, normalizeMcaQuote, normalizeOrderStatus, normalizeQuote, parseUnits, resolveMcaDecreaseCollateral, resolveMcaRequiredCollateralDecrease, resolveMcaWithdrawPolicy, selectMcaSigner, serializeMcaQuoteRequest, serializeQuoteRequest, toApiAssetAddress, toApiChain };
2794
+ export { ApiClient, DEFAULT_MCA_SIGNER_PRIORITY, ExecutorRegistry, SwapClient, SwapSdkError, asSwapSdkError, assertBaseUnitAmount, buildMcaWithdrawRelayerRequest, buildNearMcaWithdrawTransactions, createExecutionId, extractMcaWithdrawBusiness, extractMcaWithdrawDepositAddress, extractMcaWithdrawSignerWallet, formatMcaWallet, formatUnits, fromApiChain, isSameMcaSignerIdentity, normalizeBuild, normalizeCrossChainToTokenList, normalizeFromTokenList, normalizeHistory, normalizeHistoryStatus, normalizeMcaQuote, normalizeOrderStatus, normalizeQuote, parseUnits, resolveMcaDecreaseCollateral, resolveMcaRequiredCollateralDecrease, resolveMcaWithdrawPolicy, selectMcaSigner, serializeMcaQuoteRequest, serializeQuoteRequest, toApiAssetAddress, toApiChain };
2578
2795
  //# sourceMappingURL=index.mjs.map
2579
2796
  //# sourceMappingURL=index.mjs.map