@shogun-sdk/swap 0.0.2-test.4 → 0.0.2-test.41

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/core.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,32 @@ 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
+ BaseChainID.MONAD
37
+ ];
38
+ var ChainId = Object.entries(BaseChainID).reduce(
39
+ (acc, [key, value]) => {
40
+ if (typeof value === "number" && CURRENT_SUPPORTED.includes(value)) {
41
+ acc[key] = value;
42
+ }
43
+ return acc;
44
+ },
45
+ {}
46
+ );
47
+ var SupportedChainsInternal = [
30
48
  {
31
- id: ChainID.Arbitrum,
49
+ id: BaseChainID.Arbitrum,
32
50
  name: "Arbitrum",
33
51
  isEVM: true,
34
52
  wrapped: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
@@ -37,7 +55,7 @@ var SupportedChains = [
37
55
  tokenAddress: NATIVE_TOKEN.ETH
38
56
  },
39
57
  {
40
- id: ChainID.Optimism,
58
+ id: BaseChainID.Optimism,
41
59
  name: "Optimism",
42
60
  isEVM: true,
43
61
  wrapped: "0x4200000000000000000000000000000000000006",
@@ -46,7 +64,7 @@ var SupportedChains = [
46
64
  tokenAddress: NATIVE_TOKEN.ETH
47
65
  },
48
66
  {
49
- id: ChainID.Base,
67
+ id: BaseChainID.Base,
50
68
  name: "Base",
51
69
  isEVM: true,
52
70
  wrapped: "0x4200000000000000000000000000000000000006",
@@ -55,7 +73,7 @@ var SupportedChains = [
55
73
  tokenAddress: NATIVE_TOKEN.ETH
56
74
  },
57
75
  {
58
- id: ChainID.Hyperliquid,
76
+ id: BaseChainID.Hyperliquid,
59
77
  name: "Hyperliquid",
60
78
  isEVM: true,
61
79
  wrapped: "0x5555555555555555555555555555555555555555",
@@ -64,7 +82,7 @@ var SupportedChains = [
64
82
  tokenAddress: NATIVE_TOKEN.ETH
65
83
  },
66
84
  {
67
- id: ChainID.BSC,
85
+ id: BaseChainID.BSC,
68
86
  name: "BSC",
69
87
  isEVM: true,
70
88
  wrapped: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
@@ -80,8 +98,21 @@ var SupportedChains = [
80
98
  symbol: "SOL",
81
99
  decimals: 9,
82
100
  tokenAddress: NATIVE_TOKEN.SOL
101
+ },
102
+ {
103
+ id: BaseChainID.MONAD,
104
+ name: "Monad",
105
+ isEVM: true,
106
+ wrapped: "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
107
+ symbol: "MON",
108
+ decimals: 18,
109
+ tokenAddress: NATIVE_TOKEN.ETH
83
110
  }
84
111
  ];
112
+ var SupportedChains = SupportedChainsInternal.filter(
113
+ (c) => CURRENT_SUPPORTED.includes(c.id)
114
+ );
115
+ var isEvmChain = isEvmChainIntent;
85
116
 
86
117
  // src/utils/viem.ts
87
118
  function isViemWalletClient(wallet) {
@@ -109,9 +140,9 @@ function serializeBigIntsToStrings(obj) {
109
140
  return obj;
110
141
  }
111
142
 
112
- // src/core/executeOrder/normalizeNative.ts
143
+ // src/core/execute/normalizeNative.ts
113
144
  function normalizeNative(chainId, address) {
114
- if (isEvmChain(chainId) && isNativeAddress(address)) {
145
+ if (isEvmChain2(chainId) && isNativeAddress(address)) {
115
146
  const chain = SupportedChains.find((c) => c.id === chainId);
116
147
  if (!chain?.wrapped)
117
148
  throw new Error(`Wrapped token not found for chainId ${chainId}`);
@@ -122,39 +153,72 @@ function normalizeNative(chainId, address) {
122
153
 
123
154
  // src/core/getQuote.ts
124
155
  async function getQuote(params) {
156
+ const amount = BigInt(params.amount);
125
157
  if (!params.tokenIn?.address || !params.tokenOut?.address) {
126
158
  throw new Error("Both tokenIn and tokenOut must include an address.");
127
159
  }
128
160
  if (!params.sourceChainId || !params.destChainId) {
129
161
  throw new Error("Both sourceChainId and destChainId are required.");
130
162
  }
131
- if (params.amount <= 0n) {
163
+ if (amount <= 0n) {
132
164
  throw new Error("Amount must be greater than 0.");
133
165
  }
134
- const normalizedTokenIn = normalizeNative(params.sourceChainId, params.tokenIn.address);
135
- const data = await QuoteProvider.getQuote({
136
- sourceChainId: params.sourceChainId,
137
- destChainId: params.destChainId,
138
- tokenIn: normalizedTokenIn,
139
- tokenOut: params.tokenOut.address,
140
- amount: params.amount
141
- });
142
- const inputSlippage = params.slippage ?? 5;
143
- const slippageDecimal = inputSlippage / 100;
144
- const slippage = Math.min(Math.max(slippageDecimal, 0), 0.5);
166
+ const slippagePercent = Math.min(Math.max(params.slippage ?? 0.5, 0), 50);
167
+ const slippageBps = BigInt(Math.round(slippagePercent * 100));
168
+ const applyUserSlippage = (value) => value * (10000n - slippageBps) / 10000n;
145
169
  let warning;
146
- if (slippage > 0.1) {
147
- warning = `\u26A0\uFE0F High slippage tolerance (${(slippage * 100).toFixed(2)}%) \u2014 price may vary significantly.`;
170
+ if (slippagePercent > 10) {
171
+ warning = `\u26A0\uFE0F High slippage tolerance (${slippagePercent.toFixed(2)}%) \u2014 price may vary significantly.`;
172
+ }
173
+ const normalizedTokenIn = normalizeNative(params.sourceChainId, params.tokenIn.address);
174
+ const isSingleChain = params.sourceChainId === params.destChainId;
175
+ let data;
176
+ let netFloor;
177
+ let minStablecoinsAmount;
178
+ if (isSingleChain) {
179
+ const { quote, netAmountOut } = await QuoteProvider.getSingleChainNetQuote({
180
+ chainId: params.sourceChainId,
181
+ amount,
182
+ tokenIn: normalizedTokenIn,
183
+ tokenOut: params.tokenOut.address
184
+ });
185
+ netFloor = netAmountOut;
186
+ minStablecoinsAmount = 0n;
187
+ data = {
188
+ amountInUsd: quote.amountInUsd,
189
+ estimatedAmountInAsMinStablecoinAmount: 0n,
190
+ estimatedAmountOut: quote.amountOut,
191
+ estimatedAmountOutUsd: quote.amountOutUsd,
192
+ // filled in below once the user slippage buffer is known
193
+ estimatedAmountOutReduced: netAmountOut,
194
+ estimatedAmountOutUsdReduced: quote.amountOutUsd,
195
+ tokenIn: { address: params.tokenIn.address, chainId: params.sourceChainId },
196
+ tokenOut: { address: params.tokenOut.address, chainId: params.destChainId }
197
+ };
198
+ } else {
199
+ const crossChainQuote = await QuoteProvider.getCrossChainNetQuote({
200
+ sourceChainId: params.sourceChainId,
201
+ destChainId: params.destChainId,
202
+ tokenIn: normalizedTokenIn,
203
+ tokenOut: params.tokenOut.address,
204
+ amount
205
+ });
206
+ data = crossChainQuote;
207
+ netFloor = BigInt(crossChainQuote.estimatedAmountOutReduced);
208
+ minStablecoinsAmount = applyUserSlippage(
209
+ BigInt(crossChainQuote.estimatedAmountInAsMinStablecoinAmount)
210
+ );
148
211
  }
149
- const estimatedAmountOut = BigInt(data.estimatedAmountOutReduced);
150
- const slippageBps = BigInt(Math.round(slippage * 1e4));
151
- const estimatedAmountOutAfterSlippage = estimatedAmountOut * (10000n - slippageBps) / 10000n;
152
- const pricePerInputToken = estimatedAmountOut * 10n ** BigInt(params.tokenIn.decimals ?? 18) / BigInt(params.amount);
212
+ const amountOut = applyUserSlippage(netFloor);
213
+ const grossAmountOut = BigInt(data.estimatedAmountOut);
214
+ const pricePerTokenOutInUsd = grossAmountOut > 0n ? data.estimatedAmountOutUsd / Number(grossAmountOut) : 0;
215
+ const amountOutUsd = Number(amountOut) * pricePerTokenOutInUsd;
216
+ const pricePerInputToken = grossAmountOut * 10n ** BigInt(params.tokenIn.decimals ?? 18) / amount;
153
217
  return {
154
- amountOut: estimatedAmountOut,
155
- amountOutUsd: data.estimatedAmountOutUsd,
218
+ amountOut,
219
+ amountOutUsd,
156
220
  amountInUsd: data.amountInUsd,
157
- minStablecoinsAmount: data.estimatedAmountInAsMinStablecoinAmount,
221
+ minStablecoinsAmount,
158
222
  tokenIn: {
159
223
  address: params.tokenIn.address,
160
224
  decimals: params.tokenIn.decimals ?? 18,
@@ -165,12 +229,13 @@ async function getQuote(params) {
165
229
  decimals: params.tokenOut.decimals ?? 18,
166
230
  chainId: params.destChainId
167
231
  },
168
- amountIn: params.amount,
232
+ amountIn: amount,
169
233
  pricePerInputToken,
170
- slippage,
234
+ slippage: slippagePercent,
171
235
  internal: {
172
236
  ...data,
173
- estimatedAmountOutReduced: estimatedAmountOutAfterSlippage
237
+ estimatedAmountOutReduced: amountOut,
238
+ estimatedAmountOutUsdReduced: amountOutUsd
174
239
  },
175
240
  warning
176
241
  };
@@ -188,7 +253,7 @@ function buildQuoteParams({
188
253
  tokenOut,
189
254
  sourceChainId,
190
255
  destChainId,
191
- amount: parseUnits(amount.toString(), tokenIn.decimals ?? 18),
256
+ amount: parseUnits(amount.toString(), tokenIn.decimals ?? 18).toString(),
192
257
  slippage
193
258
  };
194
259
  }
@@ -235,22 +300,69 @@ async function getBalances(params, options) {
235
300
  const evmItems = data.evm?.items ?? [];
236
301
  const svmItems = data.svm?.items ?? [];
237
302
  const combined = [...evmItems, ...svmItems];
303
+ const filtered = combined.filter(
304
+ (b) => CURRENT_SUPPORTED.includes(b.chainId)
305
+ );
238
306
  return {
239
- results: combined,
307
+ results: filtered,
240
308
  nextCursorEvm: data.evm?.cursor ?? null,
241
309
  nextCursorSvm: data.svm?.cursor ?? null
242
310
  };
243
311
  }
244
312
 
245
- // src/core/executeOrder/execute.ts
246
- import { ChainID as ChainID4, isEvmChain as isEvmChain2 } from "@shogun-sdk/intents-sdk";
247
- import { BaseError } from "viem";
313
+ // src/core/token-list.ts
314
+ import { TOKEN_SEARCH_API_BASE_URL as TOKEN_SEARCH_API_BASE_URL2 } from "@shogun-sdk/intents-sdk";
315
+ async function getTokenList(params) {
316
+ const url = new URL(`${TOKEN_SEARCH_API_BASE_URL2}/tokens/search`);
317
+ if (params.q) url.searchParams.append("q", params.q);
318
+ if (params.networkId) url.searchParams.append("networkId", String(params.networkId));
319
+ if (params.page) url.searchParams.append("page", String(params.page));
320
+ if (params.limit) url.searchParams.append("limit", String(params.limit));
321
+ const res = await fetch(url.toString(), {
322
+ signal: params.signal
323
+ });
324
+ if (!res.ok) {
325
+ throw new Error(`Failed to fetch tokens: ${res.status} ${res.statusText}`);
326
+ }
327
+ const data = await res.json();
328
+ const filteredResults = data.results.filter(
329
+ (token) => CURRENT_SUPPORTED.includes(token.chainId)
330
+ );
331
+ return {
332
+ ...data,
333
+ results: filteredResults,
334
+ count: filteredResults.length
335
+ };
336
+ }
337
+
338
+ // src/core/token.ts
339
+ import { TOKEN_SEARCH_API_BASE_URL as TOKEN_SEARCH_API_BASE_URL3 } from "@shogun-sdk/intents-sdk";
340
+ async function getTokensData(addresses) {
341
+ if (!addresses?.length) return [];
342
+ const response = await fetch(`${TOKEN_SEARCH_API_BASE_URL3}/tokens/tokens`, {
343
+ method: "POST",
344
+ headers: {
345
+ "Content-Type": "application/json",
346
+ accept: "*/*"
347
+ },
348
+ body: JSON.stringify({ addresses })
349
+ });
350
+ if (!response.ok) {
351
+ throw new Error(`Failed to fetch token data: ${response.statusText}`);
352
+ }
353
+ const data = await response.json();
354
+ const filtered = data.filter((t) => CURRENT_SUPPORTED.includes(Number(t.chainId)));
355
+ return filtered;
356
+ }
357
+
358
+ // src/core/execute/execute.ts
359
+ import { ChainID as ChainID2, isEvmChain as isEvmChain3 } from "@shogun-sdk/intents-sdk";
360
+ import "viem";
248
361
 
249
362
  // src/wallet-adapter/evm-wallet-adapter/adapter.ts
250
- import "ethers/lib/ethers.js";
251
- import { hexValue } from "ethers/lib/utils.js";
252
363
  import {
253
- custom
364
+ custom,
365
+ publicActions
254
366
  } from "viem";
255
367
  function isEVMTransaction(tx) {
256
368
  return typeof tx.from === "string";
@@ -269,15 +381,26 @@ var adaptViemWallet = (wallet) => {
269
381
  if (!isEVMTransaction(transaction)) {
270
382
  throw new Error("Expected EVMTransaction but got SolanaTransaction");
271
383
  }
272
- const tx = await wallet.sendTransaction({
273
- from: transaction.from,
274
- to: transaction.to,
275
- data: transaction.data,
276
- value: transaction.value,
277
- account: wallet.account?.address,
278
- chain: wallet.chain
279
- });
280
- return tx;
384
+ if (wallet.transport.type === "http") {
385
+ const request = await wallet.prepareTransactionRequest({
386
+ to: transaction.to,
387
+ data: transaction.data,
388
+ value: transaction.value,
389
+ chain: wallet.chain
390
+ });
391
+ const serializedTransaction = await wallet.signTransaction(request);
392
+ const tx = await wallet.sendRawTransaction({ serializedTransaction });
393
+ return tx;
394
+ } else {
395
+ const hash = await wallet.sendTransaction({
396
+ to: transaction.to,
397
+ data: transaction.data,
398
+ value: transaction.value,
399
+ chain: wallet.chain,
400
+ account: wallet.account
401
+ });
402
+ return hash;
403
+ }
281
404
  };
282
405
  const switchChain = async (chainId) => {
283
406
  try {
@@ -300,6 +423,20 @@ var adaptViemWallet = (wallet) => {
300
423
  if (!addr) throw new Error("No address found");
301
424
  return addr;
302
425
  };
426
+ const readContract = async ({
427
+ address: address2,
428
+ abi,
429
+ functionName,
430
+ args = []
431
+ }) => {
432
+ const publicClient = wallet.extend(publicActions);
433
+ return await publicClient.readContract({
434
+ address: address2,
435
+ abi,
436
+ functionName,
437
+ args
438
+ });
439
+ };
303
440
  return {
304
441
  vmType: "EVM" /* EVM */,
305
442
  transport: custom(wallet.transport),
@@ -307,39 +444,65 @@ var adaptViemWallet = (wallet) => {
307
444
  address,
308
445
  sendTransaction,
309
446
  signTypedData,
310
- switchChain
447
+ switchChain,
448
+ readContract
311
449
  };
312
450
  };
313
451
 
314
- // src/core/executeOrder/handleEvmExecution.ts
452
+ // src/core/execute/handleEvmExecution.ts
315
453
  import {
316
454
  getEVMSingleChainOrderTypedData,
317
- getEVMCrossChainOrderTypedData,
318
- PERMIT2_ADDRESS
455
+ getEVMCrossChainOrderTypedData
319
456
  } from "@shogun-sdk/intents-sdk";
320
- import { encodeFunctionData, erc20Abi } from "viem";
457
+ import { encodeFunctionData as encodeFunctionData2 } from "viem";
321
458
 
322
- // src/core/executeOrder/stageMessages.ts
459
+ // src/core/execute/stageMessages.ts
323
460
  var DEFAULT_STAGE_MESSAGES = {
324
461
  processing: "Preparing transaction for execution",
325
462
  approving: "Approving token allowance",
326
463
  approved: "Token approved successfully",
327
- signing: "Signing order for submission",
328
- submitting: "Submitting order to Auctioneer",
329
- success: "Order executed successfully",
330
- error: "Order execution failed"
464
+ signing: "Signing transaction for submission",
465
+ submitting: "Submitting transaction",
466
+ initiated: "Transaction initiated.",
467
+ success: "Transaction Executed successfully",
468
+ success_limit: "Limit order has been submitted successfully.",
469
+ shogun_processing: "Shogun is processing your transaction",
470
+ error: "Transaction failed during submission"
331
471
  };
332
472
 
333
- // src/core/executeOrder/buildOrder.ts
473
+ // src/core/execute/buildOrder.ts
334
474
  import { CrossChainOrder, SingleChainOrder } from "@shogun-sdk/intents-sdk";
475
+ import { formatUnits, parseUnits as parseUnits2 } from "viem";
476
+
477
+ // src/utils/order.ts
478
+ var OrderExecutionType = /* @__PURE__ */ ((OrderExecutionType2) => {
479
+ OrderExecutionType2["LIMIT"] = "limit";
480
+ OrderExecutionType2["MARKET"] = "market";
481
+ return OrderExecutionType2;
482
+ })(OrderExecutionType || {});
483
+
484
+ // src/core/execute/buildOrder.ts
335
485
  async function buildOrder({
336
486
  quote,
337
487
  accountAddress,
338
488
  destination,
339
489
  deadline,
340
- isSingleChain
490
+ isSingleChain,
491
+ orderType,
492
+ options
341
493
  }) {
342
494
  const { tokenIn, tokenOut } = quote;
495
+ let amountOutMin = BigInt(quote.internal.estimatedAmountOutReduced);
496
+ if (orderType === "limit" /* LIMIT */ && options && "executionPrice" in options) {
497
+ const executionPrice = Number(options.executionPrice);
498
+ if (Number.isFinite(executionPrice) && executionPrice > 0) {
499
+ const decimalsIn = tokenIn.decimals ?? 18;
500
+ const decimalsOut = tokenOut.decimals ?? 18;
501
+ const formattedAmountIn = Number(formatUnits(BigInt(quote.amountIn.toString()), decimalsIn));
502
+ const rawAmountOut = formattedAmountIn * executionPrice;
503
+ amountOutMin = parseUnits2(rawAmountOut.toString(), decimalsOut);
504
+ }
505
+ }
343
506
  if (isSingleChain) {
344
507
  return await SingleChainOrder.create({
345
508
  user: accountAddress,
@@ -347,7 +510,7 @@ async function buildOrder({
347
510
  tokenIn: tokenIn.address,
348
511
  tokenOut: tokenOut.address,
349
512
  amountIn: quote.amountIn,
350
- amountOutMin: quote.internal.estimatedAmountOutReduced,
513
+ amountOutMin,
351
514
  deadline,
352
515
  destinationAddress: destination
353
516
  });
@@ -361,12 +524,166 @@ async function buildOrder({
361
524
  destinationTokenAddress: tokenOut.address,
362
525
  destinationAddress: destination,
363
526
  deadline,
364
- destinationTokenMinAmount: quote.internal.estimatedAmountOutReduced,
527
+ destinationTokenMinAmount: amountOutMin,
365
528
  minStablecoinAmount: quote.minStablecoinsAmount
366
529
  });
367
530
  }
368
531
 
369
- // src/core/executeOrder/handleEvmExecution.ts
532
+ // src/utils/pollOrderStatus.ts
533
+ import { AUCTIONEER_URL } from "@shogun-sdk/intents-sdk";
534
+ async function pollOrderStatus(address, orderId, options = {}) {
535
+ const { intervalMs = 2e3, timeoutMs = 3e5, authToken } = options;
536
+ const startTime = Date.now();
537
+ const isDebug = process.env.NODE_ENV !== "production";
538
+ const isEvmAddress = /^0x[a-fA-F0-9]{40}$/.test(address);
539
+ const isSuiAddress = /^0x[a-fA-F0-9]{64}$/.test(address);
540
+ const isSolanaAddress = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
541
+ let queryParam;
542
+ if (isEvmAddress) queryParam = `evmWallets=${address}`;
543
+ else if (isSuiAddress) queryParam = `suiWallets=${address}`;
544
+ else if (isSolanaAddress) queryParam = `solanaWallets=${address}`;
545
+ else throw new Error(`Unrecognized wallet address format: ${address}`);
546
+ const queryUrl = `${AUCTIONEER_URL}/user_intent?${queryParam}`;
547
+ return new Promise((resolve, reject) => {
548
+ const pollInterval = setInterval(async () => {
549
+ try {
550
+ if (Date.now() - startTime > timeoutMs) {
551
+ clearInterval(pollInterval);
552
+ return resolve("Timeout");
553
+ }
554
+ const res = await fetch(queryUrl, {
555
+ method: "GET",
556
+ headers: {
557
+ "Content-Type": "application/json",
558
+ // The /user_intent status endpoint requires the SIWE JWT; without it
559
+ // the request 401s after the order has already been submitted.
560
+ ...authToken ? { Authorization: `Bearer ${authToken}` } : {}
561
+ }
562
+ });
563
+ if (!res.ok) {
564
+ clearInterval(pollInterval);
565
+ return reject(
566
+ new Error(`Failed to fetch orders: ${res.status} ${res.statusText}`)
567
+ );
568
+ }
569
+ const json = await res.json();
570
+ const data = json?.data ?? {};
571
+ const allOrders = [
572
+ ...data.crossChainDcaOrders ?? [],
573
+ ...data.crossChainLimitOrders ?? [],
574
+ ...data.singleChainDcaOrders ?? [],
575
+ ...data.singleChainLimitOrders ?? []
576
+ ];
577
+ const targetOrder = allOrders.find((o) => o.orderId === orderId);
578
+ if (!targetOrder) {
579
+ if (isDebug)
580
+ console.debug(`[pollOrderStatus] [${orderId}] Not found yet`);
581
+ return;
582
+ }
583
+ const { orderStatus } = targetOrder;
584
+ if (isDebug) {
585
+ const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
586
+ console.debug(`targetOrder`, targetOrder);
587
+ console.debug(
588
+ `[pollOrderStatus] [${orderId}] status=${orderStatus} (elapsed ${elapsed}s)`
589
+ );
590
+ }
591
+ if (["Fulfilled", "Cancelled", "Outdated"].includes(orderStatus)) {
592
+ clearInterval(pollInterval);
593
+ return resolve(orderStatus);
594
+ }
595
+ } catch (error) {
596
+ clearInterval(pollInterval);
597
+ return reject(error);
598
+ }
599
+ }, intervalMs);
600
+ });
601
+ }
602
+
603
+ // src/core/execute/handleOrderPollingResult.ts
604
+ async function handleOrderPollingResult({
605
+ status,
606
+ orderId,
607
+ chainId,
608
+ update,
609
+ messageFor
610
+ }) {
611
+ switch (status) {
612
+ case "Fulfilled":
613
+ update("success", messageFor("success"));
614
+ return {
615
+ status: true,
616
+ orderId,
617
+ chainId,
618
+ finalStatus: status,
619
+ stage: "success"
620
+ };
621
+ case "Cancelled":
622
+ update("error", "Order was cancelled before fulfillment");
623
+ break;
624
+ case "Timeout":
625
+ update("error", "Order polling timed out");
626
+ break;
627
+ case "NotFound":
628
+ default:
629
+ update("error", "Order not found");
630
+ break;
631
+ }
632
+ return {
633
+ status: false,
634
+ orderId,
635
+ chainId,
636
+ finalStatus: status,
637
+ stage: "error"
638
+ };
639
+ }
640
+
641
+ // src/core/execute/ensurePermit2Allowance.ts
642
+ import { encodeFunctionData, erc20Abi, maxUint256 } from "viem";
643
+ import { PERMIT2_ADDRESS } from "@shogun-sdk/intents-sdk";
644
+ async function ensurePermit2Allowance({
645
+ chainId,
646
+ tokenIn,
647
+ wallet,
648
+ accountAddress,
649
+ requiredAmount,
650
+ increaseByDelta = false
651
+ }) {
652
+ const spender = PERMIT2_ADDRESS[chainId];
653
+ let currentAllowance = 0n;
654
+ try {
655
+ if (!wallet.readContract) {
656
+ throw new Error("Wallet does not implement readContract()");
657
+ }
658
+ currentAllowance = await wallet.readContract({
659
+ address: tokenIn,
660
+ abi: erc20Abi,
661
+ functionName: "allowance",
662
+ args: [accountAddress, spender]
663
+ });
664
+ } catch (error) {
665
+ console.warn(`[Permit2] Failed to read allowance for ${tokenIn}`, error);
666
+ }
667
+ const approvalAmount = increaseByDelta ? currentAllowance + requiredAmount : maxUint256;
668
+ console.debug(
669
+ `[Permit2] Approving ${approvalAmount} for ${tokenIn} (current: ${currentAllowance}, required: ${requiredAmount})`
670
+ );
671
+ await wallet.sendTransaction({
672
+ to: tokenIn,
673
+ from: accountAddress,
674
+ data: encodeFunctionData({
675
+ abi: erc20Abi,
676
+ functionName: "approve",
677
+ args: [spender, approvalAmount]
678
+ }),
679
+ value: 0n
680
+ });
681
+ console.info(
682
+ `[Permit2] Approval transaction sent for ${tokenIn} on chain ${chainId}`
683
+ );
684
+ }
685
+
686
+ // src/core/execute/handleEvmExecution.ts
370
687
  async function handleEvmExecution({
371
688
  recipientAddress,
372
689
  quote,
@@ -374,18 +691,22 @@ async function handleEvmExecution({
374
691
  accountAddress,
375
692
  wallet,
376
693
  isSingleChain,
377
- deadline,
378
- update
694
+ update,
695
+ orderType,
696
+ options
379
697
  }) {
380
- const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage];
698
+ const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage] ?? "";
699
+ const deadline = options?.deadline ?? Math.floor(Date.now() / 1e3) + 20 * 60;
381
700
  await wallet.switchChain(chainId);
382
701
  const tokenIn = normalizeNative(chainId, quote.tokenIn.address);
702
+ quote.tokenOut.address = normalizeEvmTokenAddress(quote.tokenOut.address);
383
703
  const shouldWrapNative = isNativeAddress(quote.tokenIn.address);
384
704
  update("processing", shouldWrapNative ? `${messageFor("processing")} (wrapping native token)` : messageFor("processing"));
385
705
  if (shouldWrapNative) {
706
+ quote.tokenIn.address === tokenIn;
386
707
  await wallet.sendTransaction({
387
708
  to: tokenIn,
388
- data: encodeFunctionData({
709
+ data: encodeFunctionData2({
389
710
  abi: [{ type: "function", name: "deposit", stateMutability: "payable", inputs: [], outputs: [] }],
390
711
  functionName: "deposit",
391
712
  args: []
@@ -394,44 +715,70 @@ async function handleEvmExecution({
394
715
  from: accountAddress
395
716
  });
396
717
  }
397
- update("approving", messageFor("approving"));
398
- await wallet.sendTransaction({
399
- to: tokenIn,
400
- data: encodeFunctionData({
401
- abi: erc20Abi,
402
- functionName: "approve",
403
- args: [PERMIT2_ADDRESS[chainId], BigInt(quote.amountIn)]
404
- }),
405
- value: 0n,
406
- from: accountAddress
718
+ update("processing", messageFor("approving"));
719
+ await ensurePermit2Allowance({
720
+ chainId,
721
+ tokenIn,
722
+ wallet,
723
+ accountAddress,
724
+ requiredAmount: BigInt(quote.amountIn)
407
725
  });
408
- update("approved", messageFor("approved"));
726
+ update("processing", messageFor("approved"));
409
727
  const destination = recipientAddress ?? accountAddress;
410
728
  const order = await buildOrder({
411
729
  quote,
412
730
  accountAddress,
413
731
  destination,
414
732
  deadline,
415
- isSingleChain
733
+ isSingleChain,
734
+ orderType,
735
+ options
416
736
  });
417
- update("signing", messageFor("signing"));
737
+ console.debug(`order`, order);
738
+ update("processing", messageFor("signing"));
418
739
  const { orderTypedData, nonce } = isSingleChain ? await getEVMSingleChainOrderTypedData(order) : await getEVMCrossChainOrderTypedData(order);
740
+ const typedData = serializeBigIntsToStrings(orderTypedData);
419
741
  if (!wallet.signTypedData) {
420
742
  throw new Error("Wallet does not support EIP-712 signing");
421
743
  }
422
- const signature = await wallet.signTypedData(serializeBigIntsToStrings(orderTypedData));
423
- update("submitting", messageFor("submitting"));
744
+ const signature = await wallet.signTypedData({
745
+ domain: typedData.domain,
746
+ types: typedData.types,
747
+ primaryType: typedData.primaryType,
748
+ value: typedData.message,
749
+ message: typedData.message
750
+ });
751
+ update("processing", messageFor("submitting"));
424
752
  const res = await order.sendToAuctioneer({ signature, nonce: nonce.toString() });
425
753
  if (!res.success) {
426
754
  throw new Error("Auctioneer submission failed");
427
755
  }
428
- update("success", messageFor("success"));
429
- return { status: true, txHash: res.data, chainId, stage: "success" };
756
+ update("initiated", messageFor("initiated"));
757
+ const { intentId: orderId } = res.data;
758
+ update("initiated", messageFor("shogun_processing"));
759
+ if (orderType === "limit" /* LIMIT */) {
760
+ update("success", messageFor("success_limit"));
761
+ return {
762
+ status: true,
763
+ orderId,
764
+ chainId,
765
+ finalStatus: "OrderPlaced",
766
+ stage: "success"
767
+ };
768
+ } else {
769
+ const status = await pollOrderStatus(accountAddress, orderId, { authToken: options?.authToken });
770
+ return await handleOrderPollingResult({
771
+ status,
772
+ orderId,
773
+ chainId,
774
+ update,
775
+ messageFor
776
+ });
777
+ }
430
778
  }
431
779
 
432
- // src/core/executeOrder/handleSolanaExecution.ts
780
+ // src/core/execute/handleSolanaExecution.ts
433
781
  import {
434
- ChainID as ChainID3,
435
782
  getSolanaSingleChainOrderInstructions,
436
783
  getSolanaCrossChainOrderInstructions
437
784
  } from "@shogun-sdk/intents-sdk";
@@ -443,12 +790,14 @@ async function handleSolanaExecution({
443
790
  isSingleChain,
444
791
  update,
445
792
  accountAddress,
446
- deadline
793
+ orderType,
794
+ options
447
795
  }) {
448
796
  if (!wallet.rpcUrl) {
449
797
  throw new Error("Solana wallet is missing rpcUrl");
450
798
  }
451
- const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage];
799
+ const deadline = options?.deadline ?? Math.floor(Date.now() / 1e3) + 20 * 60;
800
+ const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage] ?? "";
452
801
  update("processing", messageFor("processing"));
453
802
  const destination = recipientAddress ?? accountAddress;
454
803
  const order = await buildOrder({
@@ -456,7 +805,9 @@ async function handleSolanaExecution({
456
805
  accountAddress,
457
806
  destination,
458
807
  deadline,
459
- isSingleChain
808
+ isSingleChain,
809
+ orderType,
810
+ options
460
811
  });
461
812
  const txData = await getSolanaOrderInstructions({
462
813
  order,
@@ -464,10 +815,9 @@ async function handleSolanaExecution({
464
815
  rpcUrl: wallet.rpcUrl
465
816
  });
466
817
  const transaction = VersionedTransaction.deserialize(Uint8Array.from(txData.txBytes));
467
- update("signing", messageFor("signing"));
468
- console.log({ order });
469
- const txSignature = await wallet.sendTransaction(transaction);
470
- update("submitting", messageFor("submitting"));
818
+ update("processing", messageFor("signing"));
819
+ await wallet.sendTransaction(transaction);
820
+ update("processing", messageFor("submitting"));
471
821
  const response = await submitToAuctioneer({
472
822
  order,
473
823
  isSingleChain,
@@ -476,13 +826,28 @@ async function handleSolanaExecution({
476
826
  if (!response.success) {
477
827
  throw new Error("Auctioneer submission failed");
478
828
  }
479
- update("success", messageFor("success"));
480
- return {
481
- status: true,
482
- txHash: txSignature,
483
- chainId: ChainID3.Solana,
484
- stage: "success"
485
- };
829
+ update("initiated", messageFor("initiated"));
830
+ const { intentId: orderId } = response.data;
831
+ update("initiated", messageFor("shogun_processing"));
832
+ if (orderType === "limit" /* LIMIT */) {
833
+ update("success", messageFor("success_limit"));
834
+ return {
835
+ status: true,
836
+ orderId,
837
+ chainId: SOLANA_CHAIN_ID,
838
+ finalStatus: "OrderPlaced",
839
+ stage: "success"
840
+ };
841
+ } else {
842
+ const status = await pollOrderStatus(accountAddress, orderId, { authToken: options?.authToken });
843
+ return await handleOrderPollingResult({
844
+ status,
845
+ orderId,
846
+ chainId: SOLANA_CHAIN_ID,
847
+ update,
848
+ messageFor
849
+ });
850
+ }
486
851
  }
487
852
  async function getSolanaOrderInstructions({
488
853
  order,
@@ -515,52 +880,93 @@ async function submitToAuctioneer({
515
880
  });
516
881
  }
517
882
 
518
- // src/core/executeOrder/execute.ts
883
+ // src/core/execute/execute.ts
519
884
  async function executeOrder({
520
885
  quote,
521
886
  accountAddress,
522
887
  recipientAddress,
523
888
  wallet,
524
889
  onStatus,
890
+ orderType = "market" /* MARKET */,
525
891
  options = {}
526
892
  }) {
527
- const deadline = options.deadline ?? Math.floor(Date.now() / 1e3) + 20 * 60;
893
+ const isDev = process.env.NODE_ENV !== "production";
894
+ const log = (...args) => {
895
+ if (isDev) console.debug("[OneShot::executeOrder]", ...args);
896
+ };
528
897
  const messageFor = (stage) => DEFAULT_STAGE_MESSAGES[stage];
529
- const update = (stage, message) => onStatus?.(stage, message ?? messageFor(stage));
898
+ const update = (stage, message) => {
899
+ log("Stage:", stage, "| Message:", message ?? messageFor(stage));
900
+ onStatus?.(stage, message ?? messageFor(stage));
901
+ };
530
902
  try {
903
+ log("Starting execution:", {
904
+ accountAddress,
905
+ recipientAddress,
906
+ tokenIn: quote?.tokenIn,
907
+ tokenOut: quote?.tokenOut
908
+ });
531
909
  const adapter = normalizeWallet(wallet);
532
910
  if (!adapter) throw new Error("No wallet provided");
533
911
  const { tokenIn, tokenOut } = quote;
912
+ const srcChain = Number(tokenIn.chainId);
913
+ const destChain = Number(tokenOut.chainId);
914
+ if (!CURRENT_SUPPORTED.includes(srcChain) || !CURRENT_SUPPORTED.includes(destChain)) {
915
+ const unsupportedChains = [
916
+ !CURRENT_SUPPORTED.includes(srcChain) ? srcChain : null,
917
+ !CURRENT_SUPPORTED.includes(destChain) ? destChain : null
918
+ ].filter(Boolean).join(", ");
919
+ const errorMsg = `Unsupported chain(s): ${unsupportedChains}`;
920
+ update("error", errorMsg);
921
+ log("Error:", errorMsg);
922
+ throw new Error(errorMsg);
923
+ }
534
924
  const isSingleChain = tokenIn.chainId === tokenOut.chainId;
535
925
  const chainId = Number(tokenIn.chainId);
536
- update("processing", messageFor("processing"));
537
- if (isEvmChain2(chainId)) {
538
- return await handleEvmExecution({
926
+ update("processing");
927
+ if (isEvmChain3(chainId)) {
928
+ log("Detected EVM chain:", chainId);
929
+ const result = await handleEvmExecution({
539
930
  recipientAddress,
540
931
  quote,
541
932
  chainId,
542
933
  accountAddress,
543
934
  wallet: adapter,
544
935
  isSingleChain,
545
- deadline,
546
- update
936
+ update,
937
+ orderType,
938
+ options
547
939
  });
940
+ log("EVM execution result:", result);
941
+ return result;
548
942
  }
549
- if (chainId === ChainID4.Solana) {
550
- return await handleSolanaExecution({
943
+ if (chainId === ChainID2.Solana) {
944
+ log("Detected Solana chain");
945
+ const result = await handleSolanaExecution({
551
946
  recipientAddress,
552
947
  quote,
553
948
  accountAddress,
554
949
  wallet: adapter,
555
950
  isSingleChain,
556
- deadline,
557
- update
951
+ update,
952
+ orderType,
953
+ options
558
954
  });
955
+ log("Solana execution result:", result);
956
+ return result;
559
957
  }
560
- update("error", "Unsupported chain");
561
- return { status: false, message: "Unsupported chain", stage: "error" };
958
+ const unsupported = `Unsupported chain: ${chainId}`;
959
+ update("error", unsupported);
960
+ log("Error:", unsupported);
961
+ return { status: false, message: unsupported, stage: "error" };
562
962
  } catch (error) {
563
- const message = error instanceof BaseError ? error.shortMessage : error instanceof Error ? error.message : String(error);
963
+ let message = "An unknown error occurred";
964
+ if (error && typeof error === "object") {
965
+ const err = error;
966
+ message = err.details ?? err.message ?? message;
967
+ } else if (typeof error === "string") {
968
+ message = error;
969
+ }
564
970
  update("error", message);
565
971
  return { status: false, message, stage: "error" };
566
972
  }
@@ -571,20 +977,526 @@ function normalizeWallet(wallet) {
571
977
  return wallet;
572
978
  }
573
979
 
574
- // src/core/index.ts
575
- import { ChainID as ChainID5, isEvmChain as isEvmChain3 } from "@shogun-sdk/intents-sdk";
980
+ // src/core/orders/getOrders.ts
981
+ import { fetchUserOrders } from "@shogun-sdk/intents-sdk";
982
+ async function getOrders({
983
+ evmAddress,
984
+ solAddress
985
+ }) {
986
+ const wallets = [evmAddress, solAddress].filter(
987
+ (wallet) => Boolean(wallet)
988
+ );
989
+ if (wallets.length === 0) {
990
+ throw new Error("At least one wallet address (EVM, Solana) must be provided.");
991
+ }
992
+ const results = await Promise.all(
993
+ wallets.map((wallet) => fetchUserOrders({ wallet }))
994
+ );
995
+ return results.reduce(
996
+ (merged, orders) => {
997
+ merged.singleChainLimitOrders.push(...orders.singleChainLimitOrders);
998
+ merged.crossChainLimitOrders.push(...orders.crossChainLimitOrders);
999
+ return merged;
1000
+ },
1001
+ { singleChainLimitOrders: [], crossChainLimitOrders: [] }
1002
+ );
1003
+ }
1004
+
1005
+ // src/core/orders/cancelOrder.ts
1006
+ import {
1007
+ cancelCrossChainOrderInstructionsAsBytes,
1008
+ cancelSingleChainOrderInstructionsAsBytes,
1009
+ ChainID as ChainID3,
1010
+ CROSS_CHAIN_GUARD_ADDRESSES,
1011
+ PERMIT2_ADDRESS as PERMIT2_ADDRESS2,
1012
+ SINGLE_CHAIN_GUARD_ADDRESSES
1013
+ } from "@shogun-sdk/intents-sdk";
1014
+ import {
1015
+ VersionedMessage,
1016
+ VersionedTransaction as VersionedTransaction2
1017
+ } from "@solana/web3.js";
1018
+ import { encodeFunctionData as encodeFunctionData3 } from "viem";
1019
+ var inFlightCancels = /* @__PURE__ */ new Map();
1020
+ function cancelIntentsOrder(args) {
1021
+ const srcChain = "srcChainId" in args.order ? args.order.srcChainId : args.order.chainId;
1022
+ const key = `${srcChain}:${args.order.orderId}`;
1023
+ const existing = inFlightCancels.get(key);
1024
+ if (existing) return existing;
1025
+ const pending = performCancel(args).finally(() => {
1026
+ inFlightCancels.delete(key);
1027
+ });
1028
+ inFlightCancels.set(key, pending);
1029
+ return pending;
1030
+ }
1031
+ async function performCancel({
1032
+ order,
1033
+ wallet,
1034
+ sol_rpc
1035
+ }) {
1036
+ const isCrossChain = "srcChainId" in order && "destChainId" in order && order.srcChainId !== order.destChainId;
1037
+ const srcChain = "srcChainId" in order ? order.srcChainId : order.chainId;
1038
+ const isSolanaOrder = srcChain === ChainID3.Solana;
1039
+ if (isSolanaOrder) {
1040
+ if (!isCrossChain) {
1041
+ const { versionedMessageBytes: versionedMessageBytes2 } = await cancelSingleChainOrderInstructionsAsBytes(
1042
+ order.orderId,
1043
+ order.user,
1044
+ { rpcUrl: sol_rpc }
1045
+ );
1046
+ const message2 = VersionedMessage.deserialize(
1047
+ versionedMessageBytes2
1048
+ );
1049
+ const tx2 = new VersionedTransaction2(message2);
1050
+ return await wallet.sendTransaction(tx2);
1051
+ }
1052
+ const { versionedMessageBytes } = await cancelCrossChainOrderInstructionsAsBytes(
1053
+ order.orderId,
1054
+ order.user,
1055
+ { rpcUrl: sol_rpc }
1056
+ );
1057
+ const message = VersionedMessage.deserialize(
1058
+ versionedMessageBytes
1059
+ );
1060
+ const tx = new VersionedTransaction2(message);
1061
+ return await wallet.sendTransaction(tx);
1062
+ }
1063
+ const chainId = srcChain;
1064
+ const { readContract } = wallet;
1065
+ if (!readContract) {
1066
+ throw new Error("Wallet does not support readContract");
1067
+ }
1068
+ const nonce = BigInt(order.nonce ?? "0");
1069
+ const nonceWordPos = nonce >> 8n;
1070
+ const nonceBitPos = nonce - nonceWordPos * 256n;
1071
+ if (isCrossChain) {
1072
+ const [orderData = [false, false], currentNonceBitmap = 0n] = await Promise.all([
1073
+ readContract({
1074
+ address: CROSS_CHAIN_GUARD_ADDRESSES[chainId],
1075
+ abi: [
1076
+ {
1077
+ inputs: [{ name: "orderId", type: "bytes32" }],
1078
+ name: "orderData",
1079
+ outputs: [
1080
+ { name: "initialized", type: "bool" },
1081
+ { name: "deactivated", type: "bool" }
1082
+ ],
1083
+ stateMutability: "view",
1084
+ type: "function"
1085
+ }
1086
+ ],
1087
+ functionName: "orderData",
1088
+ args: [order.orderId]
1089
+ }),
1090
+ readContract({
1091
+ address: PERMIT2_ADDRESS2[chainId],
1092
+ abi: [
1093
+ {
1094
+ inputs: [
1095
+ { name: "owner", type: "address" },
1096
+ { name: "wordPos", type: "uint256" }
1097
+ ],
1098
+ name: "nonceBitmap",
1099
+ outputs: [{ name: "", type: "uint256" }],
1100
+ stateMutability: "view",
1101
+ type: "function"
1102
+ }
1103
+ ],
1104
+ functionName: "nonceBitmap",
1105
+ args: [order.user, nonceWordPos]
1106
+ })
1107
+ ]);
1108
+ const [initialized, deactivated] = orderData;
1109
+ if (initialized) {
1110
+ if (deactivated) {
1111
+ throw new Error("Order is already deactivated");
1112
+ }
1113
+ return await wallet.sendTransaction({
1114
+ to: CROSS_CHAIN_GUARD_ADDRESSES[order.srcChainId],
1115
+ data: encodeFunctionData3({
1116
+ abi: [
1117
+ {
1118
+ inputs: [
1119
+ {
1120
+ components: [
1121
+ { name: "user", type: "address" },
1122
+ { name: "tokenIn", type: "address" },
1123
+ { name: "srcChainId", type: "uint256" },
1124
+ { name: "deadline", type: "uint256" },
1125
+ { name: "amountIn", type: "uint256" },
1126
+ { name: "minStablecoinsAmount", type: "uint256" },
1127
+ { name: "executionDetailsHash", type: "bytes32" },
1128
+ { name: "nonce", type: "uint256" }
1129
+ ],
1130
+ name: "orderInfo",
1131
+ type: "tuple"
1132
+ }
1133
+ ],
1134
+ name: "cancelOrder",
1135
+ outputs: [],
1136
+ stateMutability: "nonpayable",
1137
+ type: "function"
1138
+ }
1139
+ ],
1140
+ functionName: "cancelOrder",
1141
+ args: [
1142
+ {
1143
+ user: order.user,
1144
+ tokenIn: order.tokenIn,
1145
+ srcChainId: BigInt(order.srcChainId),
1146
+ deadline: BigInt(order.deadline),
1147
+ amountIn: BigInt(order.amountIn),
1148
+ minStablecoinsAmount: BigInt(order.minStablecoinsAmount),
1149
+ executionDetailsHash: order.executionDetailsHash,
1150
+ nonce
1151
+ }
1152
+ ]
1153
+ }),
1154
+ value: BigInt(0),
1155
+ from: order.user
1156
+ });
1157
+ } else {
1158
+ if ((currentNonceBitmap & 1n << nonceBitPos) !== 0n) {
1159
+ throw new Error("Nonce is already invalidated");
1160
+ }
1161
+ const mask2 = 1n << nonceBitPos;
1162
+ return await wallet.sendTransaction({
1163
+ to: PERMIT2_ADDRESS2[order.srcChainId],
1164
+ data: encodeFunctionData3({
1165
+ abi: [
1166
+ {
1167
+ inputs: [
1168
+ { name: "wordPos", type: "uint256" },
1169
+ { name: "mask", type: "uint256" }
1170
+ ],
1171
+ name: "invalidateUnorderedNonces",
1172
+ outputs: [],
1173
+ stateMutability: "nonpayable",
1174
+ type: "function"
1175
+ }
1176
+ ],
1177
+ functionName: "invalidateUnorderedNonces",
1178
+ args: [nonceWordPos, mask2]
1179
+ }),
1180
+ value: BigInt(0),
1181
+ from: order.user
1182
+ });
1183
+ }
1184
+ }
1185
+ const [wasManuallyInitialized, currentBitmap = 0n] = await Promise.all([
1186
+ readContract({
1187
+ address: SINGLE_CHAIN_GUARD_ADDRESSES[chainId],
1188
+ abi: [
1189
+ {
1190
+ inputs: [{ name: "orderHash", type: "bytes32" }],
1191
+ name: "orderManuallyInitialized",
1192
+ outputs: [{ name: "", type: "bool" }],
1193
+ stateMutability: "view",
1194
+ type: "function"
1195
+ }
1196
+ ],
1197
+ functionName: "orderManuallyInitialized",
1198
+ args: [order.orderId]
1199
+ }),
1200
+ readContract({
1201
+ address: PERMIT2_ADDRESS2[chainId],
1202
+ abi: [
1203
+ {
1204
+ inputs: [
1205
+ { name: "owner", type: "address" },
1206
+ { name: "wordPos", type: "uint256" }
1207
+ ],
1208
+ name: "nonceBitmap",
1209
+ outputs: [{ name: "", type: "uint256" }],
1210
+ stateMutability: "view",
1211
+ type: "function"
1212
+ }
1213
+ ],
1214
+ functionName: "nonceBitmap",
1215
+ args: [order.user, nonceWordPos]
1216
+ })
1217
+ ]);
1218
+ if (wasManuallyInitialized) {
1219
+ return await wallet.sendTransaction({
1220
+ to: SINGLE_CHAIN_GUARD_ADDRESSES[chainId],
1221
+ data: encodeFunctionData3({
1222
+ abi: [
1223
+ {
1224
+ inputs: [
1225
+ {
1226
+ name: "order",
1227
+ type: "tuple",
1228
+ components: [
1229
+ { name: "amountIn", type: "uint256" },
1230
+ { name: "tokenIn", type: "address" },
1231
+ { name: "deadline", type: "uint256" },
1232
+ { name: "nonce", type: "uint256" },
1233
+ { name: "encodedExternalCallData", type: "bytes" },
1234
+ {
1235
+ name: "extraTransfers",
1236
+ type: "tuple[]",
1237
+ components: [
1238
+ { name: "amount", type: "uint256" },
1239
+ { name: "receiver", type: "address" },
1240
+ { name: "token", type: "address" }
1241
+ ]
1242
+ },
1243
+ {
1244
+ name: "requestedOutput",
1245
+ type: "tuple",
1246
+ components: [
1247
+ { name: "amount", type: "uint256" },
1248
+ { name: "receiver", type: "address" },
1249
+ { name: "token", type: "address" }
1250
+ ]
1251
+ },
1252
+ { name: "user", type: "address" }
1253
+ ]
1254
+ }
1255
+ ],
1256
+ name: "cancelManuallyCreatedOrder",
1257
+ outputs: [],
1258
+ stateMutability: "nonpayable",
1259
+ type: "function"
1260
+ }
1261
+ ],
1262
+ functionName: "cancelManuallyCreatedOrder",
1263
+ args: [
1264
+ {
1265
+ amountIn: BigInt(order.amountIn),
1266
+ tokenIn: order.tokenIn,
1267
+ deadline: BigInt(order.deadline),
1268
+ nonce,
1269
+ encodedExternalCallData: "0x",
1270
+ extraTransfers: (order.extraTransfers || []).map((t) => ({
1271
+ amount: BigInt(t.amount),
1272
+ receiver: t.receiver,
1273
+ token: t.token
1274
+ })),
1275
+ requestedOutput: {
1276
+ amount: BigInt(order.amountOutMin),
1277
+ receiver: order.destinationAddress,
1278
+ token: order.tokenOut
1279
+ },
1280
+ user: order.user
1281
+ }
1282
+ ]
1283
+ }),
1284
+ value: 0n,
1285
+ from: order.user
1286
+ });
1287
+ }
1288
+ const mask = 1n << nonceBitPos;
1289
+ if ((currentBitmap & mask) !== 0n) {
1290
+ throw new Error("Nonce is already invalidated");
1291
+ }
1292
+ return await wallet.sendTransaction({
1293
+ to: PERMIT2_ADDRESS2[chainId],
1294
+ data: encodeFunctionData3({
1295
+ abi: [
1296
+ {
1297
+ inputs: [
1298
+ { name: "wordPos", type: "uint256" },
1299
+ { name: "mask", type: "uint256" }
1300
+ ],
1301
+ name: "invalidateUnorderedNonces",
1302
+ outputs: [],
1303
+ stateMutability: "nonpayable",
1304
+ type: "function"
1305
+ }
1306
+ ],
1307
+ functionName: "invalidateUnorderedNonces",
1308
+ args: [nonceWordPos, mask]
1309
+ }),
1310
+ value: 0n,
1311
+ from: order.user
1312
+ });
1313
+ }
1314
+
1315
+ // src/core/client.ts
1316
+ var SwapSDK = class {
1317
+ constructor(config) {
1318
+ __publicField(this, "apiKey");
1319
+ /**
1320
+ * Fetches metadata for one or more tokens from the Shogun Token Search API.
1321
+ *
1322
+ * ---
1323
+ * ### Overview
1324
+ * `getTokensData` retrieves normalized token information — such as symbol, name,
1325
+ * decimals, logo URI, and verified status — for a given list of token addresses.
1326
+ *
1327
+ * It supports both **EVM** and **SVM (Solana)** tokens, returning metadata from
1328
+ * Shogun’s unified token registry.
1329
+ *
1330
+ * ---
1331
+ * @example
1332
+ * ```ts
1333
+ * const tokens = await getTokensData([
1334
+ * "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
1335
+ * "So11111111111111111111111111111111111111112", // SOL
1336
+ * ]);
1337
+ *
1338
+ * console.log(tokens);
1339
+ * [
1340
+ * { symbol: "USDC", name: "USD Coin", chainId: 1, decimals: 6, ... },
1341
+ * { symbol: "SOL", name: "Solana", chainId: 101, decimals: 9, ... }
1342
+ * ]
1343
+ * ```
1344
+ *
1345
+ * @param addresses - An array of token addresses (EVM or SVM) to fetch metadata for.
1346
+ * @returns A promise resolving to an array of {@link TokenInfo} objects.
1347
+ *
1348
+ * @throws Will throw an error if the network request fails or the API responds with a non-OK status.
1349
+ */
1350
+ __publicField(this, "getTokensData", getTokensData.bind(this));
1351
+ if (!config.apiKey) {
1352
+ throw new Error("SwapSDK: Missing API key");
1353
+ }
1354
+ this.apiKey = config.apiKey;
1355
+ if (this.apiKey) void this.apiKey;
1356
+ }
1357
+ /**
1358
+ * Retrieves a swap quote for the given input and output tokens.
1359
+ *
1360
+ * @param params - Quote parameters including source/destination tokens and amount.
1361
+ * @returns A normalized `SwapQuoteResponse` containing output amount, route, and metadata.
1362
+ */
1363
+ async getQuote(params) {
1364
+ return getQuote(params);
1365
+ }
1366
+ /**
1367
+ * Fetches token balances for the specified user wallet(s).
1368
+ *
1369
+ * Supports both EVM and SVM (Solana) wallet addresses.
1370
+ *
1371
+ * @param params - Wallet address and optional chain filters.
1372
+ * @param options - Optional abort signal for cancellation.
1373
+ * @returns A unified balance response with per-chain token details.
1374
+ */
1375
+ async getBalances(params, options) {
1376
+ return getBalances(params, options);
1377
+ }
1378
+ /**
1379
+ * Retrieves a list of verified tokens based on search query or chain filter.
1380
+ *
1381
+ * @param params - Search parameters (query, chain ID, pagination options).
1382
+ * @returns Paginated `TokenSearchResponse` containing token metadata.
1383
+ */
1384
+ async getTokenList(params) {
1385
+ return getTokenList(params);
1386
+ }
1387
+ /**
1388
+ * Executes a prepared swap quote using the provided wallet and configuration.
1389
+ *
1390
+ * Handles:
1391
+ * - Token approval (if required)
1392
+ * - Transaction signing and broadcasting
1393
+ * - Confirmation polling and stage-based status updates
1394
+ *
1395
+ * Supports both:
1396
+ * - Market orders (with optional deadline)
1397
+ * - Limit orders (requires executionPrice and deadline)
1398
+ *
1399
+ * @param quote - The swap quote to execute, containing route and metadata.
1400
+ * @param accountAddress - The user's wallet address executing the swap.
1401
+ * @param recipientAddress - Optional recipient address for the output tokens (defaults to sender).
1402
+ * @param wallet - Adapted wallet instance (EVM/Solana) or a standard Viem `WalletClient`.
1403
+ * @param onStatus - Optional callback for receiving execution stage updates and messages.
1404
+ * @param orderType - Defines whether this is a market or limit order.
1405
+ * @param options - Execution parameters (different per order type).
1406
+ *
1407
+ * @returns A finalized execution result containing transaction hash, status, and any returned data.
1408
+ *
1409
+ * @example
1410
+ * ```ts
1411
+ * * Market order
1412
+ * const result = await sdk.executeTransaction({
1413
+ * quote,
1414
+ * accountAddress: "0x123...",
1415
+ * wallet,
1416
+ * orderType: OrderExecutionType.MARKET,
1417
+ * options: { deadline: 1800 },
1418
+ * onStatus: (stage, msg) => console.log(stage, msg),
1419
+ * });
1420
+ *
1421
+ * * Limit order
1422
+ * const result = await sdk.executeTransaction({
1423
+ * quote,
1424
+ * accountAddress: "0x123...",
1425
+ * wallet,
1426
+ * orderType: OrderExecutionType.LIMIT,
1427
+ * options: { executionPrice: "0.0021", deadline: 3600 },
1428
+ * });
1429
+ * ```
1430
+ */
1431
+ async executeTransaction({
1432
+ quote,
1433
+ accountAddress,
1434
+ recipientAddress,
1435
+ wallet,
1436
+ onStatus,
1437
+ orderType,
1438
+ options
1439
+ }) {
1440
+ return executeOrder({
1441
+ quote,
1442
+ wallet,
1443
+ accountAddress,
1444
+ recipientAddress,
1445
+ onStatus,
1446
+ orderType,
1447
+ options
1448
+ });
1449
+ }
1450
+ /**
1451
+ * Fetches all user orders (Market, Limit, Cross-chain) for connected wallets.
1452
+ *
1453
+ * ---
1454
+ * ### Overview
1455
+ * Retrieves both **single-chain** and **cross-chain** orders from the Shogun Intents API.
1456
+ * Works across EVM, Solana
1457
+ *
1458
+ * ---
1459
+ * @example
1460
+ * ```ts
1461
+ * const orders = await sdk.getOrders({
1462
+ * evmAddress: "0x123...",
1463
+ * solAddress: "9d12hF...abc",
1464
+ * });
1465
+ *
1466
+ * console.log(orders.singleChainLimitOrders);
1467
+ * ```
1468
+ *
1469
+ * @param params - Wallet addresses to fetch orders for (EVM, Solana).
1470
+ * @returns A structured {@link ApiUserOrders} object containing all user orders.
1471
+ */
1472
+ async getOrders(params) {
1473
+ return getOrders(params);
1474
+ }
1475
+ /**
1476
+ * Cancels an order (single-chain or cross-chain) on EVM or Solana.
1477
+ *
1478
+ * Internally routes to the correct guard contract or Solana program to
1479
+ * deactivate the order or invalidate its nonce.
1480
+ *
1481
+ * @param params.order - Order payload returned from the Intents API.
1482
+ * @param params.wallet - Adapted wallet used to submit the cancellation transaction.
1483
+ * @param params.solRpc - Solana RPC URL used for SVM cancellations.
1484
+ *
1485
+ * @returns A transaction signature or hash from the underlying wallet.
1486
+ */
1487
+ async cancelOrder(params) {
1488
+ return cancelIntentsOrder({
1489
+ order: params.order,
1490
+ wallet: params.wallet,
1491
+ sol_rpc: params.solRpc
1492
+ });
1493
+ }
1494
+ };
576
1495
  export {
577
- ChainID5 as ChainID,
578
- NATIVE_TOKEN,
579
- SOLANA_CHAIN_ID,
1496
+ ChainId,
1497
+ OrderExecutionType,
580
1498
  SupportedChains,
1499
+ SwapSDK,
581
1500
  buildQuoteParams,
582
- executeOrder,
583
- getBalances,
584
- getQuote,
585
- getTokenList,
586
- isEvmChain3 as isEvmChain,
587
- isNativeAddress,
588
- isViemWalletClient,
589
- serializeBigIntsToStrings
1501
+ isEvmChain
590
1502
  };