@shogun-sdk/swap 0.0.2-test.24 → 0.0.2-test.26

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.js CHANGED
@@ -1,17 +1,16 @@
1
- // src/core/token-list.ts
2
- import { getTokenList as intentsGetTokenList } from "@shogun-sdk/intents-sdk";
3
- async function getTokenList(params) {
4
- return intentsGetTokenList(params);
5
- }
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
4
 
7
5
  // src/core/getQuote.ts
8
6
  import { QuoteProvider } from "@shogun-sdk/intents-sdk";
9
7
  import { parseUnits } from "viem";
10
8
 
11
- // src/core/executeOrder/normalizeNative.ts
12
- import { isEvmChain } from "@shogun-sdk/intents-sdk";
9
+ // src/core/execute/normalizeNative.ts
10
+ import { isEvmChain as isEvmChain2 } from "@shogun-sdk/intents-sdk";
13
11
 
14
12
  // src/utils/address.ts
13
+ import { zeroAddress } from "viem";
15
14
  var NATIVE_TOKEN = {
16
15
  ETH: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
17
16
  SOL: "So11111111111111111111111111111111111111111",
@@ -22,13 +21,31 @@ var isNativeAddress = (tokenAddress) => {
22
21
  const normalizedTokenAddress = tokenAddress.toLowerCase();
23
22
  return !!tokenAddress && NATIVE_ADDRESSES.includes(normalizedTokenAddress);
24
23
  };
24
+ function normalizeEvmTokenAddress(address) {
25
+ const lower = address.toLowerCase();
26
+ return lower === NATIVE_TOKEN.ETH.toLowerCase() ? zeroAddress : address;
27
+ }
25
28
 
26
29
  // src/utils/chain.ts
27
- import { ChainID } from "@shogun-sdk/intents-sdk";
28
- var SOLANA_CHAIN_ID = ChainID.Solana;
29
- var SupportedChains = [
30
+ import { ChainID as BaseChainID, isEvmChain as isEvmChainIntent } from "@shogun-sdk/intents-sdk";
31
+ var SOLANA_CHAIN_ID = BaseChainID.Solana;
32
+ var CURRENT_SUPPORTED = [
33
+ BaseChainID.Solana,
34
+ BaseChainID.BSC,
35
+ BaseChainID.Base
36
+ ];
37
+ var ChainId = Object.entries(BaseChainID).reduce(
38
+ (acc, [key, value]) => {
39
+ if (typeof value === "number" && CURRENT_SUPPORTED.includes(value)) {
40
+ acc[key] = value;
41
+ }
42
+ return acc;
43
+ },
44
+ {}
45
+ );
46
+ var SupportedChainsInternal = [
30
47
  {
31
- id: ChainID.Arbitrum,
48
+ id: BaseChainID.Arbitrum,
32
49
  name: "Arbitrum",
33
50
  isEVM: true,
34
51
  wrapped: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
@@ -37,7 +54,7 @@ var SupportedChains = [
37
54
  tokenAddress: NATIVE_TOKEN.ETH
38
55
  },
39
56
  {
40
- id: ChainID.Optimism,
57
+ id: BaseChainID.Optimism,
41
58
  name: "Optimism",
42
59
  isEVM: true,
43
60
  wrapped: "0x4200000000000000000000000000000000000006",
@@ -46,7 +63,7 @@ var SupportedChains = [
46
63
  tokenAddress: NATIVE_TOKEN.ETH
47
64
  },
48
65
  {
49
- id: ChainID.Base,
66
+ id: BaseChainID.Base,
50
67
  name: "Base",
51
68
  isEVM: true,
52
69
  wrapped: "0x4200000000000000000000000000000000000006",
@@ -55,7 +72,7 @@ var SupportedChains = [
55
72
  tokenAddress: NATIVE_TOKEN.ETH
56
73
  },
57
74
  {
58
- id: ChainID.Hyperliquid,
75
+ id: BaseChainID.Hyperliquid,
59
76
  name: "Hyperliquid",
60
77
  isEVM: true,
61
78
  wrapped: "0x5555555555555555555555555555555555555555",
@@ -64,7 +81,7 @@ var SupportedChains = [
64
81
  tokenAddress: NATIVE_TOKEN.ETH
65
82
  },
66
83
  {
67
- id: ChainID.BSC,
84
+ id: BaseChainID.BSC,
68
85
  name: "BSC",
69
86
  isEVM: true,
70
87
  wrapped: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
@@ -82,6 +99,10 @@ var SupportedChains = [
82
99
  tokenAddress: NATIVE_TOKEN.SOL
83
100
  }
84
101
  ];
102
+ var SupportedChains = SupportedChainsInternal.filter(
103
+ (c) => CURRENT_SUPPORTED.includes(c.id)
104
+ );
105
+ var isEvmChain = isEvmChainIntent;
85
106
 
86
107
  // src/utils/viem.ts
87
108
  function isViemWalletClient(wallet) {
@@ -109,9 +130,9 @@ function serializeBigIntsToStrings(obj) {
109
130
  return obj;
110
131
  }
111
132
 
112
- // src/core/executeOrder/normalizeNative.ts
133
+ // src/core/execute/normalizeNative.ts
113
134
  function normalizeNative(chainId, address) {
114
- if (isEvmChain(chainId) && isNativeAddress(address)) {
135
+ if (isEvmChain2(chainId) && isNativeAddress(address)) {
115
136
  const chain = SupportedChains.find((c) => c.id === chainId);
116
137
  if (!chain?.wrapped)
117
138
  throw new Error(`Wrapped token not found for chainId ${chainId}`);
@@ -122,13 +143,14 @@ function normalizeNative(chainId, address) {
122
143
 
123
144
  // src/core/getQuote.ts
124
145
  async function getQuote(params) {
146
+ const amount = BigInt(params.amount);
125
147
  if (!params.tokenIn?.address || !params.tokenOut?.address) {
126
148
  throw new Error("Both tokenIn and tokenOut must include an address.");
127
149
  }
128
150
  if (!params.sourceChainId || !params.destChainId) {
129
151
  throw new Error("Both sourceChainId and destChainId are required.");
130
152
  }
131
- if (params.amount <= 0n) {
153
+ if (amount <= 0n) {
132
154
  throw new Error("Amount must be greater than 0.");
133
155
  }
134
156
  const normalizedTokenIn = normalizeNative(params.sourceChainId, params.tokenIn.address);
@@ -137,7 +159,7 @@ async function getQuote(params) {
137
159
  destChainId: params.destChainId,
138
160
  tokenIn: normalizedTokenIn,
139
161
  tokenOut: params.tokenOut.address,
140
- amount: params.amount
162
+ amount
141
163
  });
142
164
  const slippagePercent = Math.min(Math.max(params.slippage ?? 0.5, 0), 50);
143
165
  let warning;
@@ -168,7 +190,7 @@ async function getQuote(params) {
168
190
  decimals: params.tokenOut.decimals ?? 18,
169
191
  chainId: params.destChainId
170
192
  },
171
- amountIn: params.amount,
193
+ amountIn: BigInt(params.amount),
172
194
  pricePerInputToken,
173
195
  slippage: slippagePercent,
174
196
  internal: {
@@ -192,7 +214,7 @@ function buildQuoteParams({
192
214
  tokenOut,
193
215
  sourceChainId,
194
216
  destChainId,
195
- amount: parseUnits(amount.toString(), tokenIn.decimals ?? 18),
217
+ amount: parseUnits(amount.toString(), tokenIn.decimals ?? 18).toString(),
196
218
  slippage
197
219
  };
198
220
  }
@@ -239,59 +261,66 @@ async function getBalances(params, options) {
239
261
  const evmItems = data.evm?.items ?? [];
240
262
  const svmItems = data.svm?.items ?? [];
241
263
  const combined = [...evmItems, ...svmItems];
264
+ const filtered = combined.filter(
265
+ (b) => CURRENT_SUPPORTED.includes(b.chainId)
266
+ );
242
267
  return {
243
- results: combined,
268
+ results: filtered,
244
269
  nextCursorEvm: data.evm?.cursor ?? null,
245
270
  nextCursorSvm: data.svm?.cursor ?? null
246
271
  };
247
272
  }
248
273
 
249
- // src/core/executeOrder/execute.ts
250
- import { ChainID as ChainID3, isEvmChain as isEvmChain2 } from "@shogun-sdk/intents-sdk";
251
- import { BaseError } from "viem";
252
-
253
- // src/wallet-adapter/svm-wallet-adapter/adapter.ts
254
- import {
255
- Connection
256
- } from "@solana/web3.js";
257
- var adaptSolanaWallet = (walletAddress, chainId, rpcUrl, signAndSendTransaction) => {
258
- let _chainId = chainId;
259
- const connection = new Connection(rpcUrl, { commitment: "confirmed" });
260
- const getChainId = async () => _chainId;
261
- const sendTransaction = async (transaction) => {
262
- const txHash = await signAndSendTransaction(transaction);
263
- console.debug(`\u{1F6F0} Sent transaction: ${txHash}`);
264
- const maxRetries = 20;
265
- const delayMs = 2e3;
266
- for (let attempt = 0; attempt < maxRetries; attempt++) {
267
- const res = await connection.getSignatureStatus(txHash, { searchTransactionHistory: true });
268
- if (res?.value?.confirmationStatus === "confirmed" || res?.value?.confirmationStatus === "finalized") {
269
- return txHash;
270
- }
271
- await new Promise((resolve) => setTimeout(resolve, delayMs));
272
- }
273
- throw new Error(`Transaction not confirmed after ${maxRetries * (delayMs / 1e3)}s`);
274
- };
275
- const signTypedData = async () => {
276
- throw new Error("signTypedData not implemented for Solana");
277
- };
278
- const switchChain = async (newChainId) => {
279
- _chainId = newChainId;
280
- };
274
+ // src/core/token-list.ts
275
+ import { TOKEN_SEARCH_API_BASE_URL as TOKEN_SEARCH_API_BASE_URL2 } from "@shogun-sdk/intents-sdk";
276
+ async function getTokenList(params) {
277
+ const url = new URL(`${TOKEN_SEARCH_API_BASE_URL2}/tokens/search`);
278
+ if (params.q) url.searchParams.append("q", params.q);
279
+ if (params.networkId) url.searchParams.append("networkId", String(params.networkId));
280
+ if (params.page) url.searchParams.append("page", String(params.page));
281
+ if (params.limit) url.searchParams.append("limit", String(params.limit));
282
+ const res = await fetch(url.toString(), {
283
+ signal: params.signal
284
+ });
285
+ if (!res.ok) {
286
+ throw new Error(`Failed to fetch tokens: ${res.status} ${res.statusText}`);
287
+ }
288
+ const data = await res.json();
289
+ const filteredResults = data.results.filter(
290
+ (token) => CURRENT_SUPPORTED.includes(token.chainId)
291
+ );
281
292
  return {
282
- vmType: "SVM" /* SVM */,
283
- getChainId,
284
- address: async () => walletAddress,
285
- sendTransaction,
286
- switchChain,
287
- signTypedData,
288
- rpcUrl
293
+ ...data,
294
+ results: filteredResults,
295
+ count: filteredResults.length
289
296
  };
290
- };
297
+ }
298
+
299
+ // src/core/token.ts
300
+ import { TOKEN_SEARCH_API_BASE_URL as TOKEN_SEARCH_API_BASE_URL3 } from "@shogun-sdk/intents-sdk";
301
+ async function getTokensData(addresses) {
302
+ if (!addresses?.length) return [];
303
+ const response = await fetch(`${TOKEN_SEARCH_API_BASE_URL3}/tokens/tokens`, {
304
+ method: "POST",
305
+ headers: {
306
+ "Content-Type": "application/json",
307
+ accept: "*/*"
308
+ },
309
+ body: JSON.stringify({ addresses })
310
+ });
311
+ if (!response.ok) {
312
+ throw new Error(`Failed to fetch token data: ${response.statusText}`);
313
+ }
314
+ const data = await response.json();
315
+ const filtered = data.filter((t) => CURRENT_SUPPORTED.includes(Number(t.chainId)));
316
+ return filtered;
317
+ }
318
+
319
+ // src/core/execute/execute.ts
320
+ import { ChainID as ChainID2, isEvmChain as isEvmChain3 } from "@shogun-sdk/intents-sdk";
321
+ import "viem";
291
322
 
292
323
  // src/wallet-adapter/evm-wallet-adapter/adapter.ts
293
- import { utils as ethersUtils } from "ethers/lib/ethers.js";
294
- import { hexValue } from "ethers/lib/utils.js";
295
324
  import {
296
325
  custom,
297
326
  publicActions
@@ -299,64 +328,6 @@ import {
299
328
  function isEVMTransaction(tx) {
300
329
  return typeof tx.from === "string";
301
330
  }
302
- var adaptEthersSigner = (signer, transport) => {
303
- const signTypedData = async (signData) => {
304
- const typedSigner = signer;
305
- return await typedSigner._signTypedData(
306
- signData.domain,
307
- signData.types,
308
- signData.value
309
- );
310
- };
311
- const sendTransaction = async (transaction) => {
312
- if (!isEVMTransaction(transaction)) {
313
- throw new Error("Expected EVMTransaction but got SolanaTransaction");
314
- }
315
- const tx = await signer.sendTransaction({
316
- from: transaction.from,
317
- to: transaction.to,
318
- data: transaction.data,
319
- value: transaction.value
320
- });
321
- return tx.hash;
322
- };
323
- const switchChain = async (chainId) => {
324
- try {
325
- await window.ethereum.request({
326
- method: "wallet_switchEthereumChain",
327
- params: [{ chainId: hexValue(chainId) }]
328
- });
329
- } catch (error) {
330
- console.error("Failed to switch chain:", error);
331
- throw error;
332
- }
333
- };
334
- const readContract = async ({
335
- address,
336
- abi,
337
- functionName,
338
- args = []
339
- }) => {
340
- const iface = new ethersUtils.Interface(abi);
341
- const fnArgs = Array.isArray(args) ? args : [];
342
- const data = iface.encodeFunctionData(functionName, fnArgs);
343
- const provider = signer.provider;
344
- if (!provider) throw new Error("Signer has no provider");
345
- const result = await provider.call({ to: address, data });
346
- const decoded = iface.decodeFunctionResult(functionName, result);
347
- return decoded[0];
348
- };
349
- return {
350
- vmType: "EVM" /* EVM */,
351
- transport,
352
- getChainId: async () => signer.getChainId(),
353
- address: async () => signer.getAddress(),
354
- sendTransaction,
355
- signTypedData,
356
- switchChain,
357
- readContract
358
- };
359
- };
360
331
  var adaptViemWallet = (wallet) => {
361
332
  const signTypedData = async (signData) => {
362
333
  return await wallet.signTypedData({
@@ -439,14 +410,14 @@ var adaptViemWallet = (wallet) => {
439
410
  };
440
411
  };
441
412
 
442
- // src/core/executeOrder/handleEvmExecution.ts
413
+ // src/core/execute/handleEvmExecution.ts
443
414
  import {
444
415
  getEVMSingleChainOrderTypedData,
445
416
  getEVMCrossChainOrderTypedData
446
417
  } from "@shogun-sdk/intents-sdk";
447
418
  import { encodeFunctionData as encodeFunctionData2 } from "viem";
448
419
 
449
- // src/core/executeOrder/stageMessages.ts
420
+ // src/core/execute/stageMessages.ts
450
421
  var DEFAULT_STAGE_MESSAGES = {
451
422
  processing: "Preparing transaction for execution",
452
423
  approving: "Approving token allowance",
@@ -455,20 +426,44 @@ var DEFAULT_STAGE_MESSAGES = {
455
426
  submitting: "Submitting transaction",
456
427
  initiated: "Transaction initiated.",
457
428
  success: "Transaction Executed successfully",
429
+ success_limit: "Limit order has been submitted successfully.",
458
430
  shogun_processing: "Shogun is processing your transaction",
459
431
  error: "Transaction failed during submission"
460
432
  };
461
433
 
462
- // src/core/executeOrder/buildOrder.ts
434
+ // src/core/execute/buildOrder.ts
463
435
  import { CrossChainOrder, SingleChainOrder } from "@shogun-sdk/intents-sdk";
436
+ import { formatUnits, parseUnits as parseUnits2 } from "viem";
437
+
438
+ // src/utils/order.ts
439
+ var OrderExecutionType = /* @__PURE__ */ ((OrderExecutionType2) => {
440
+ OrderExecutionType2["LIMIT"] = "limit";
441
+ OrderExecutionType2["MARKET"] = "market";
442
+ return OrderExecutionType2;
443
+ })(OrderExecutionType || {});
444
+
445
+ // src/core/execute/buildOrder.ts
464
446
  async function buildOrder({
465
447
  quote,
466
448
  accountAddress,
467
449
  destination,
468
450
  deadline,
469
- isSingleChain
451
+ isSingleChain,
452
+ orderType,
453
+ options
470
454
  }) {
471
455
  const { tokenIn, tokenOut } = quote;
456
+ let amountOutMin = BigInt(quote.internal.estimatedAmountOutReduced);
457
+ if (orderType === "limit" /* LIMIT */ && options && "executionPrice" in options) {
458
+ const executionPrice = Number(options.executionPrice);
459
+ if (Number.isFinite(executionPrice) && executionPrice > 0) {
460
+ const decimalsIn = tokenIn.decimals ?? 18;
461
+ const decimalsOut = tokenOut.decimals ?? 18;
462
+ const formattedAmountIn = Number(formatUnits(BigInt(quote.amountIn.toString()), decimalsIn));
463
+ const rawAmountOut = formattedAmountIn * executionPrice;
464
+ amountOutMin = parseUnits2(rawAmountOut.toString(), decimalsOut);
465
+ }
466
+ }
472
467
  if (isSingleChain) {
473
468
  return await SingleChainOrder.create({
474
469
  user: accountAddress,
@@ -476,7 +471,7 @@ async function buildOrder({
476
471
  tokenIn: tokenIn.address,
477
472
  tokenOut: tokenOut.address,
478
473
  amountIn: quote.amountIn,
479
- amountOutMin: quote.internal.estimatedAmountOutReduced,
474
+ amountOutMin,
480
475
  deadline,
481
476
  destinationAddress: destination
482
477
  });
@@ -490,7 +485,7 @@ async function buildOrder({
490
485
  destinationTokenAddress: tokenOut.address,
491
486
  destinationAddress: destination,
492
487
  deadline,
493
- destinationTokenMinAmount: quote.internal.estimatedAmountOutReduced,
488
+ destinationTokenMinAmount: amountOutMin,
494
489
  minStablecoinAmount: quote.minStablecoinsAmount
495
490
  });
496
491
  }
@@ -561,7 +556,7 @@ async function pollOrderStatus(address, orderId, options = {}) {
561
556
  });
562
557
  }
563
558
 
564
- // src/core/executeOrder/handleOrderPollingResult.ts
559
+ // src/core/execute/handleOrderPollingResult.ts
565
560
  async function handleOrderPollingResult({
566
561
  status,
567
562
  orderId,
@@ -599,7 +594,7 @@ async function handleOrderPollingResult({
599
594
  };
600
595
  }
601
596
 
602
- // src/core/executeOrder/ensurePermit2Allowance.ts
597
+ // src/core/execute/ensurePermit2Allowance.ts
603
598
  import { encodeFunctionData, erc20Abi, maxUint256 } from "viem";
604
599
  import { PERMIT2_ADDRESS } from "@shogun-sdk/intents-sdk";
605
600
  async function ensurePermit2Allowance({
@@ -644,7 +639,7 @@ async function ensurePermit2Allowance({
644
639
  );
645
640
  }
646
641
 
647
- // src/core/executeOrder/handleEvmExecution.ts
642
+ // src/core/execute/handleEvmExecution.ts
648
643
  async function handleEvmExecution({
649
644
  recipientAddress,
650
645
  quote,
@@ -652,15 +647,19 @@ async function handleEvmExecution({
652
647
  accountAddress,
653
648
  wallet,
654
649
  isSingleChain,
655
- deadline,
656
- update
650
+ update,
651
+ orderType,
652
+ options
657
653
  }) {
658
- const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage];
654
+ const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage] ?? "";
655
+ const deadline = options?.deadline ?? Math.floor(Date.now() / 1e3) + 20 * 60;
659
656
  await wallet.switchChain(chainId);
660
657
  const tokenIn = normalizeNative(chainId, quote.tokenIn.address);
658
+ quote.tokenOut.address = normalizeEvmTokenAddress(quote.tokenOut.address);
661
659
  const shouldWrapNative = isNativeAddress(quote.tokenIn.address);
662
660
  update("processing", shouldWrapNative ? `${messageFor("processing")} (wrapping native token)` : messageFor("processing"));
663
661
  if (shouldWrapNative) {
662
+ quote.tokenIn.address === tokenIn;
664
663
  await wallet.sendTransaction({
665
664
  to: tokenIn,
666
665
  data: encodeFunctionData2({
@@ -687,7 +686,9 @@ async function handleEvmExecution({
687
686
  accountAddress,
688
687
  destination,
689
688
  deadline,
690
- isSingleChain
689
+ isSingleChain,
690
+ orderType,
691
+ options
691
692
  });
692
693
  console.debug(`order`, order);
693
694
  update("processing", messageFor("signing"));
@@ -711,22 +712,33 @@ async function handleEvmExecution({
711
712
  update("initiated", messageFor("initiated"));
712
713
  const { intentId: orderId } = res.data;
713
714
  update("initiated", messageFor("shogun_processing"));
714
- const status = await pollOrderStatus(accountAddress, orderId);
715
- return await handleOrderPollingResult({
716
- status,
717
- orderId,
718
- chainId,
719
- update,
720
- messageFor
721
- });
715
+ if (orderType === "limit" /* LIMIT */) {
716
+ update("success", messageFor("success_limit"));
717
+ return {
718
+ status: true,
719
+ orderId,
720
+ chainId,
721
+ finalStatus: "OrderPlaced",
722
+ stage: "success"
723
+ };
724
+ } else {
725
+ const status = await pollOrderStatus(accountAddress, orderId);
726
+ return await handleOrderPollingResult({
727
+ status,
728
+ orderId,
729
+ chainId,
730
+ update,
731
+ messageFor
732
+ });
733
+ }
722
734
  }
723
735
 
724
- // src/core/executeOrder/handleSolanaExecution.ts
736
+ // src/core/execute/handleSolanaExecution.ts
725
737
  import {
726
738
  getSolanaSingleChainOrderInstructions,
727
739
  getSolanaCrossChainOrderInstructions
728
740
  } from "@shogun-sdk/intents-sdk";
729
- import { VersionedTransaction as VersionedTransaction2 } from "@solana/web3.js";
741
+ import { VersionedTransaction } from "@solana/web3.js";
730
742
  async function handleSolanaExecution({
731
743
  recipientAddress,
732
744
  quote,
@@ -734,12 +746,14 @@ async function handleSolanaExecution({
734
746
  isSingleChain,
735
747
  update,
736
748
  accountAddress,
737
- deadline
749
+ orderType,
750
+ options
738
751
  }) {
739
752
  if (!wallet.rpcUrl) {
740
753
  throw new Error("Solana wallet is missing rpcUrl");
741
754
  }
742
- const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage];
755
+ const deadline = options?.deadline ?? Math.floor(Date.now() / 1e3) + 20 * 60;
756
+ const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage] ?? "";
743
757
  update("processing", messageFor("processing"));
744
758
  const destination = recipientAddress ?? accountAddress;
745
759
  const order = await buildOrder({
@@ -747,14 +761,16 @@ async function handleSolanaExecution({
747
761
  accountAddress,
748
762
  destination,
749
763
  deadline,
750
- isSingleChain
764
+ isSingleChain,
765
+ orderType,
766
+ options
751
767
  });
752
768
  const txData = await getSolanaOrderInstructions({
753
769
  order,
754
770
  isSingleChain,
755
771
  rpcUrl: wallet.rpcUrl
756
772
  });
757
- const transaction = VersionedTransaction2.deserialize(Uint8Array.from(txData.txBytes));
773
+ const transaction = VersionedTransaction.deserialize(Uint8Array.from(txData.txBytes));
758
774
  update("processing", messageFor("signing"));
759
775
  await wallet.sendTransaction(transaction);
760
776
  update("processing", messageFor("submitting"));
@@ -769,14 +785,25 @@ async function handleSolanaExecution({
769
785
  update("initiated", messageFor("initiated"));
770
786
  const { jwt, intentId: orderId } = response.data;
771
787
  update("initiated", messageFor("shogun_processing"));
772
- const status = await pollOrderStatus(jwt, orderId);
773
- return await handleOrderPollingResult({
774
- status,
775
- orderId,
776
- chainId: SOLANA_CHAIN_ID,
777
- update,
778
- messageFor
779
- });
788
+ if (orderType === "limit" /* LIMIT */) {
789
+ update("success", messageFor("success_limit"));
790
+ return {
791
+ status: true,
792
+ orderId,
793
+ chainId: SOLANA_CHAIN_ID,
794
+ finalStatus: "OrderPlaced",
795
+ stage: "success"
796
+ };
797
+ } else {
798
+ const status = await pollOrderStatus(jwt, orderId);
799
+ return await handleOrderPollingResult({
800
+ status,
801
+ orderId,
802
+ chainId: SOLANA_CHAIN_ID,
803
+ update,
804
+ messageFor
805
+ });
806
+ }
780
807
  }
781
808
  async function getSolanaOrderInstructions({
782
809
  order,
@@ -809,13 +836,14 @@ async function submitToAuctioneer({
809
836
  });
810
837
  }
811
838
 
812
- // src/core/executeOrder/execute.ts
839
+ // src/core/execute/execute.ts
813
840
  async function executeOrder({
814
841
  quote,
815
842
  accountAddress,
816
843
  recipientAddress,
817
844
  wallet,
818
845
  onStatus,
846
+ orderType = "market" /* MARKET */,
819
847
  options = {}
820
848
  }) {
821
849
  const isDev = process.env.NODE_ENV !== "production";
@@ -828,21 +856,31 @@ async function executeOrder({
828
856
  onStatus?.(stage, message ?? messageFor(stage));
829
857
  };
830
858
  try {
831
- const deadline = options.deadline ?? Math.floor(Date.now() / 1e3) + 20 * 60;
832
859
  log("Starting execution:", {
833
860
  accountAddress,
834
861
  recipientAddress,
835
- deadline,
836
862
  tokenIn: quote?.tokenIn,
837
863
  tokenOut: quote?.tokenOut
838
864
  });
839
865
  const adapter = normalizeWallet(wallet);
840
866
  if (!adapter) throw new Error("No wallet provided");
841
867
  const { tokenIn, tokenOut } = quote;
868
+ const srcChain = Number(tokenIn.chainId);
869
+ const destChain = Number(tokenOut.chainId);
870
+ if (!CURRENT_SUPPORTED.includes(srcChain) || !CURRENT_SUPPORTED.includes(destChain)) {
871
+ const unsupportedChains = [
872
+ !CURRENT_SUPPORTED.includes(srcChain) ? srcChain : null,
873
+ !CURRENT_SUPPORTED.includes(destChain) ? destChain : null
874
+ ].filter(Boolean).join(", ");
875
+ const errorMsg = `Unsupported chain(s): ${unsupportedChains}`;
876
+ update("error", errorMsg);
877
+ log("Error:", errorMsg);
878
+ throw new Error(errorMsg);
879
+ }
842
880
  const isSingleChain = tokenIn.chainId === tokenOut.chainId;
843
881
  const chainId = Number(tokenIn.chainId);
844
882
  update("processing");
845
- if (isEvmChain2(chainId)) {
883
+ if (isEvmChain3(chainId)) {
846
884
  log("Detected EVM chain:", chainId);
847
885
  const result = await handleEvmExecution({
848
886
  recipientAddress,
@@ -851,13 +889,14 @@ async function executeOrder({
851
889
  accountAddress,
852
890
  wallet: adapter,
853
891
  isSingleChain,
854
- deadline,
855
- update
892
+ update,
893
+ orderType,
894
+ options
856
895
  });
857
896
  log("EVM execution result:", result);
858
897
  return result;
859
898
  }
860
- if (chainId === ChainID3.Solana) {
899
+ if (chainId === ChainID2.Solana) {
861
900
  log("Detected Solana chain");
862
901
  const result = await handleSolanaExecution({
863
902
  recipientAddress,
@@ -865,8 +904,9 @@ async function executeOrder({
865
904
  accountAddress,
866
905
  wallet: adapter,
867
906
  isSingleChain,
868
- deadline,
869
- update
907
+ update,
908
+ orderType,
909
+ options
870
910
  });
871
911
  log("Solana execution result:", result);
872
912
  return result;
@@ -876,8 +916,13 @@ async function executeOrder({
876
916
  log("Error:", unsupported);
877
917
  return { status: false, message: unsupported, stage: "error" };
878
918
  } catch (error) {
879
- const message = error instanceof BaseError ? error.shortMessage : error instanceof Error ? error.message : String(error);
880
- log("Execution failed:", { message, error });
919
+ let message = "An unknown error occurred";
920
+ if (error && typeof error === "object") {
921
+ const err = error;
922
+ message = err.details ?? err.message ?? message;
923
+ } else if (typeof error === "string") {
924
+ message = error;
925
+ }
881
926
  update("error", message);
882
927
  return { status: false, message, stage: "error" };
883
928
  }
@@ -888,319 +933,147 @@ function normalizeWallet(wallet) {
888
933
  return wallet;
889
934
  }
890
935
 
891
- // src/react/useTokenList.ts
892
- import { useEffect, useMemo, useRef, useState } from "react";
893
- var tokenCache = /* @__PURE__ */ new Map();
894
- function useTokenList(params) {
895
- const [data, setData] = useState(null);
896
- const [loading, setLoading] = useState(false);
897
- const [error, setError] = useState(null);
898
- const controllerRef = useRef(null);
899
- const debounceRef = useRef(null);
900
- const debounceMs = params.debounceMs ?? 250;
901
- const cacheKey = useMemo(() => {
902
- return JSON.stringify({
903
- q: params.q?.trim().toLowerCase() ?? "",
904
- networkId: params.networkId ?? "all",
905
- page: params.page ?? 1,
906
- limit: params.limit ?? 50
907
- });
908
- }, [params.q, params.networkId, params.page, params.limit]);
909
- async function fetchTokens(signal) {
910
- if (tokenCache.has(cacheKey)) {
911
- setData(tokenCache.get(cacheKey));
912
- setLoading(false);
913
- setError(null);
914
- return;
915
- }
916
- try {
917
- setLoading(true);
918
- const result = await getTokenList({ ...params, signal });
919
- tokenCache.set(cacheKey, result);
920
- setData(result);
921
- setError(null);
922
- } catch (err) {
923
- if (err.name !== "AbortError") {
924
- const e = err instanceof Error ? err : new Error("Unknown error while fetching tokens");
925
- setError(e);
926
- }
927
- } finally {
928
- setLoading(false);
936
+ // src/core/client.ts
937
+ var SwapSDK = class {
938
+ constructor(config) {
939
+ __publicField(this, "apiKey");
940
+ /**
941
+ * Fetches metadata for one or more tokens from the Shogun Token Search API.
942
+ *
943
+ * ---
944
+ * ### Overview
945
+ * `getTokensData` retrieves normalized token information — such as symbol, name,
946
+ * decimals, logo URI, and verified status — for a given list of token addresses.
947
+ *
948
+ * It supports both **EVM** and **SVM (Solana)** tokens, returning metadata from
949
+ * Shogun’s unified token registry.
950
+ *
951
+ * ---
952
+ * @example
953
+ * ```ts
954
+ * const tokens = await getTokensData([
955
+ * "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
956
+ * "So11111111111111111111111111111111111111112", // SOL
957
+ * ]);
958
+ *
959
+ * console.log(tokens);
960
+ * [
961
+ * { symbol: "USDC", name: "USD Coin", chainId: 1, decimals: 6, ... },
962
+ * { symbol: "SOL", name: "Solana", chainId: 101, decimals: 9, ... }
963
+ * ]
964
+ * ```
965
+ *
966
+ * @param addresses - An array of token addresses (EVM or SVM) to fetch metadata for.
967
+ * @returns A promise resolving to an array of {@link TokenInfo} objects.
968
+ *
969
+ * @throws Will throw an error if the network request fails or the API responds with a non-OK status.
970
+ */
971
+ __publicField(this, "getTokensData", getTokensData.bind(this));
972
+ if (!config.apiKey) {
973
+ throw new Error("SwapSDK: Missing API key");
929
974
  }
975
+ this.apiKey = config.apiKey;
976
+ if (this.apiKey) void this.apiKey;
930
977
  }
931
- useEffect(() => {
932
- if (!params.q && !params.networkId) return;
933
- if (debounceRef.current) clearTimeout(debounceRef.current);
934
- if (controllerRef.current) controllerRef.current.abort();
935
- const controller = new AbortController();
936
- controllerRef.current = controller;
937
- debounceRef.current = setTimeout(() => {
938
- fetchTokens(controller.signal);
939
- }, debounceMs);
940
- return () => {
941
- controller.abort();
942
- if (debounceRef.current) clearTimeout(debounceRef.current);
943
- };
944
- }, [cacheKey, debounceMs]);
945
- return useMemo(
946
- () => ({
947
- /** Current fetched data (cached when possible) */
948
- data,
949
- /** Whether a request is in progress */
950
- loading,
951
- /** Error object if a request failed */
952
- error,
953
- /** Manually refetch the token list */
954
- refetch: () => fetchTokens(),
955
- /** Clear all cached token results (shared across hook instances) */
956
- clearCache: () => tokenCache.clear()
957
- }),
958
- [data, loading, error]
959
- );
960
- }
961
-
962
- // src/react/useExecuteOrder.ts
963
- import { useState as useState2, useCallback, useRef as useRef2, useEffect as useEffect2 } from "react";
964
- function useExecuteOrder() {
965
- const [status, setStatus] = useState2("processing");
966
- const [message, setMessage] = useState2(null);
967
- const [loading, setLoading] = useState2(false);
968
- const [data, setData] = useState2(null);
969
- const [error, setError] = useState2(null);
970
- const isMounted = useRef2(true);
971
- useEffect2(() => {
972
- return () => {
973
- isMounted.current = false;
974
- };
975
- }, []);
976
- const execute = useCallback(
977
- async ({
978
+ /**
979
+ * Retrieves a swap quote for the given input and output tokens.
980
+ *
981
+ * @param params - Quote parameters including source/destination tokens and amount.
982
+ * @returns A normalized `SwapQuoteResponse` containing output amount, route, and metadata.
983
+ */
984
+ async getQuote(params) {
985
+ return getQuote(params);
986
+ }
987
+ /**
988
+ * Fetches token balances for the specified user wallet(s).
989
+ *
990
+ * Supports both EVM and SVM (Solana) wallet addresses.
991
+ *
992
+ * @param params - Wallet address and optional chain filters.
993
+ * @param options - Optional abort signal for cancellation.
994
+ * @returns A unified balance response with per-chain token details.
995
+ */
996
+ async getBalances(params, options) {
997
+ return getBalances(params, options);
998
+ }
999
+ /**
1000
+ * Retrieves a list of verified tokens based on search query or chain filter.
1001
+ *
1002
+ * @param params - Search parameters (query, chain ID, pagination options).
1003
+ * @returns Paginated `TokenSearchResponse` containing token metadata.
1004
+ */
1005
+ async getTokenList(params) {
1006
+ return getTokenList(params);
1007
+ }
1008
+ /**
1009
+ * Executes a prepared swap quote using the provided wallet and configuration.
1010
+ *
1011
+ * Handles:
1012
+ * - Token approval (if required)
1013
+ * - Transaction signing and broadcasting
1014
+ * - Confirmation polling and stage-based status updates
1015
+ *
1016
+ * Supports both:
1017
+ * - Market orders (with optional deadline)
1018
+ * - Limit orders (requires executionPrice and deadline)
1019
+ *
1020
+ * @param quote - The swap quote to execute, containing route and metadata.
1021
+ * @param accountAddress - The user's wallet address executing the swap.
1022
+ * @param recipientAddress - Optional recipient address for the output tokens (defaults to sender).
1023
+ * @param wallet - Adapted wallet instance (EVM/Solana) or a standard Viem `WalletClient`.
1024
+ * @param onStatus - Optional callback for receiving execution stage updates and messages.
1025
+ * @param orderType - Defines whether this is a market or limit order.
1026
+ * @param options - Execution parameters (different per order type).
1027
+ *
1028
+ * @returns A finalized execution result containing transaction hash, status, and any returned data.
1029
+ *
1030
+ * @example
1031
+ * ```ts
1032
+ * * Market order
1033
+ * const result = await sdk.executeTransaction({
1034
+ * quote,
1035
+ * accountAddress: "0x123...",
1036
+ * wallet,
1037
+ * orderType: OrderExecutionType.MARKET,
1038
+ * options: { deadline: 1800 },
1039
+ * onStatus: (stage, msg) => console.log(stage, msg),
1040
+ * });
1041
+ *
1042
+ * * Limit order
1043
+ * const result = await sdk.executeTransaction({
1044
+ * quote,
1045
+ * accountAddress: "0x123...",
1046
+ * wallet,
1047
+ * orderType: OrderExecutionType.LIMIT,
1048
+ * options: { executionPrice: "0.0021", deadline: 3600 },
1049
+ * });
1050
+ * ```
1051
+ */
1052
+ async executeTransaction({
1053
+ quote,
1054
+ accountAddress,
1055
+ recipientAddress,
1056
+ wallet,
1057
+ onStatus,
1058
+ orderType,
1059
+ options
1060
+ }) {
1061
+ return executeOrder({
978
1062
  quote,
1063
+ wallet,
979
1064
  accountAddress,
980
1065
  recipientAddress,
981
- wallet,
982
- deadline
983
- }) => {
984
- if (!quote || !wallet) {
985
- throw new Error("Quote and wallet are required for order execution.");
986
- }
987
- setLoading(true);
988
- setError(null);
989
- setData(null);
990
- setMessage(null);
991
- try {
992
- const effectiveDeadline = deadline ?? Math.floor(Date.now() / 1e3) + 20 * 60;
993
- const onStatus = (stage, msg) => {
994
- if (!isMounted.current) return;
995
- setStatus(stage);
996
- if (msg) setMessage(msg);
997
- };
998
- const result = await executeOrder({
999
- quote,
1000
- accountAddress,
1001
- recipientAddress,
1002
- wallet,
1003
- onStatus,
1004
- options: { deadline: effectiveDeadline }
1005
- });
1006
- if (!isMounted.current) return result;
1007
- setData(result);
1008
- setStatus(result.stage);
1009
- setMessage("Order executed successfully");
1010
- return result;
1011
- } catch (err) {
1012
- const errorObj = err instanceof Error ? err : new Error(String(err));
1013
- if (isMounted.current) {
1014
- setError(errorObj);
1015
- setStatus("error");
1016
- setMessage(errorObj.message);
1017
- setData({
1018
- status: false,
1019
- stage: "error",
1020
- message: errorObj.message
1021
- });
1022
- }
1023
- return {
1024
- status: false,
1025
- stage: "error",
1026
- message: errorObj.message
1027
- };
1028
- } finally {
1029
- if (isMounted.current) setLoading(false);
1030
- }
1031
- },
1032
- []
1033
- );
1034
- return {
1035
- /** Executes the swap order. */
1036
- execute,
1037
- /** Current execution stage. */
1038
- status,
1039
- /** Human-readable status message. */
1040
- message,
1041
- /** Whether execution is ongoing. */
1042
- loading,
1043
- /** Raw SDK response data. */
1044
- data,
1045
- /** Captured error (if execution failed). */
1046
- error
1047
- };
1048
- }
1049
-
1050
- // src/react/useQuote.ts
1051
- import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState3 } from "react";
1052
- function useQuote(params, options) {
1053
- const [data, setData] = useState3(null);
1054
- const [loading, setLoading] = useState3(false);
1055
- const [error, setError] = useState3(null);
1056
- const [warning, setWarning] = useState3(null);
1057
- const debounceMs = options?.debounceMs ?? 250;
1058
- const autoRefreshMs = options?.autoRefreshMs;
1059
- const abortRef = useRef3(null);
1060
- const debounceRef = useRef3(null);
1061
- const mounted = useRef3(false);
1062
- const paramsKey = useMemo2(
1063
- () => params ? JSON.stringify(serializeBigIntsToStrings(params)) : null,
1064
- [params]
1065
- );
1066
- useEffect3(() => {
1067
- mounted.current = true;
1068
- return () => {
1069
- mounted.current = false;
1070
- abortRef.current?.abort();
1071
- if (debounceRef.current) clearTimeout(debounceRef.current);
1072
- };
1073
- }, []);
1074
- const fetchQuote = useCallback2(async () => {
1075
- if (!params) return;
1076
- try {
1077
- setLoading(true);
1078
- setWarning(null);
1079
- const result = await getQuote(params);
1080
- const serializeResult = serializeBigIntsToStrings(result);
1081
- if (!mounted.current) return;
1082
- setData((prev) => {
1083
- if (JSON.stringify(prev) === JSON.stringify(serializeResult)) return prev;
1084
- return serializeResult;
1085
- });
1086
- setWarning(result.warning ?? null);
1087
- setError(null);
1088
- } catch (err) {
1089
- if (err.name === "AbortError") return;
1090
- console.error("[useQuote] fetch error:", err);
1091
- if (mounted.current) setError(err instanceof Error ? err : new Error(String(err)));
1092
- } finally {
1093
- if (mounted.current) setLoading(false);
1094
- }
1095
- }, [paramsKey]);
1096
- useEffect3(() => {
1097
- if (!paramsKey) return;
1098
- if (debounceRef.current) clearTimeout(debounceRef.current);
1099
- debounceRef.current = setTimeout(() => {
1100
- fetchQuote();
1101
- }, debounceMs);
1102
- return () => {
1103
- if (debounceRef.current) clearTimeout(debounceRef.current);
1104
- abortRef.current?.abort();
1105
- };
1106
- }, [paramsKey, debounceMs, fetchQuote]);
1107
- useEffect3(() => {
1108
- if (!autoRefreshMs || !paramsKey) return;
1109
- const interval = setInterval(() => fetchQuote(), autoRefreshMs);
1110
- return () => clearInterval(interval);
1111
- }, [autoRefreshMs, paramsKey, fetchQuote]);
1112
- return useMemo2(
1113
- () => ({
1114
- data,
1115
- loading,
1116
- error,
1117
- warning,
1118
- refetch: fetchQuote
1119
- }),
1120
- [data, loading, error, warning, fetchQuote]
1121
- );
1122
- }
1123
-
1124
- // src/react/useBalances.ts
1125
- import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState4 } from "react";
1126
- function useBalances(params) {
1127
- const [data, setData] = useState4(null);
1128
- const [loading, setLoading] = useState4(false);
1129
- const [error, setError] = useState4(null);
1130
- const abortRef = useRef4(null);
1131
- const stableParams = useMemo3(() => {
1132
- if (!params) return null;
1133
- const { addresses, cursorEvm, cursorSvm } = params;
1134
- return {
1135
- addresses: {
1136
- evm: addresses?.evm ?? void 0,
1137
- svm: addresses?.svm ?? void 0
1138
- },
1139
- cursorEvm,
1140
- cursorSvm
1141
- };
1142
- }, [params?.addresses?.evm, params?.addresses?.svm, params?.cursorEvm, params?.cursorSvm]);
1143
- const fetchBalances = useCallback3(async () => {
1144
- if (!stableParams) return;
1145
- if (abortRef.current) abortRef.current.abort();
1146
- const controller = new AbortController();
1147
- abortRef.current = controller;
1148
- setLoading(true);
1149
- setError(null);
1150
- try {
1151
- const result = await getBalances(stableParams, { signal: controller.signal });
1152
- setData((prev) => {
1153
- if (JSON.stringify(prev) === JSON.stringify(result)) return prev;
1154
- return result;
1155
- });
1156
- return result;
1157
- } catch (err) {
1158
- if (err.name === "AbortError") return;
1159
- const e = err instanceof Error ? err : new Error(String(err));
1160
- setError(e);
1161
- throw e;
1162
- } finally {
1163
- setLoading(false);
1164
- }
1165
- }, [stableParams]);
1166
- useEffect4(() => {
1167
- if (stableParams) fetchBalances().catch(() => {
1066
+ onStatus,
1067
+ orderType,
1068
+ options
1168
1069
  });
1169
- return () => {
1170
- if (abortRef.current) abortRef.current.abort();
1171
- };
1172
- }, [fetchBalances]);
1173
- return useMemo3(
1174
- () => ({
1175
- /** Latest fetched balance data */
1176
- data,
1177
- /** Whether the hook is currently fetching */
1178
- loading,
1179
- /** Error object if fetching failed */
1180
- error,
1181
- /** Manually trigger a refresh */
1182
- refetch: fetchBalances
1183
- }),
1184
- [data, loading, error, fetchBalances]
1185
- );
1186
- }
1070
+ }
1071
+ };
1187
1072
  export {
1188
- NATIVE_TOKEN,
1189
- SOLANA_CHAIN_ID,
1073
+ ChainId,
1074
+ OrderExecutionType,
1190
1075
  SupportedChains,
1191
- adaptEthersSigner,
1192
- adaptSolanaWallet,
1193
- adaptViemWallet,
1076
+ SwapSDK,
1194
1077
  buildQuoteParams,
1195
- executeOrder,
1196
- getBalances,
1197
- getQuote,
1198
- getTokenList,
1199
- isNativeAddress,
1200
- isViemWalletClient,
1201
- serializeBigIntsToStrings,
1202
- useBalances,
1203
- useExecuteOrder,
1204
- useQuote,
1205
- useTokenList
1078
+ isEvmChain
1206
1079
  };