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