@rhea-finance/cross-chain-aggregation-dex 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1275 @@
1
+ import Big2 from 'big.js';
2
+
3
+ // src/types/index.ts
4
+ function requiresRecipient(params) {
5
+ return "sender" in params && "recipient" in params;
6
+ }
7
+ function requiresRecipientInExecute(params) {
8
+ return "sender" in params && "receiveUser" in params;
9
+ }
10
+
11
+ // src/utils/logger.ts
12
+ var LOG_LEVELS = {
13
+ silent: 0,
14
+ error: 1,
15
+ warn: 2,
16
+ info: 3,
17
+ debug: 4
18
+ };
19
+ function getLogLevel() {
20
+ if (typeof process !== "undefined" && process.env?.LOG_LEVEL) {
21
+ const level = process.env.LOG_LEVEL.toLowerCase();
22
+ if (LOG_LEVELS[level] !== void 0) {
23
+ return level;
24
+ }
25
+ }
26
+ return typeof process !== "undefined" && process.env?.NODE_ENV === "production" ? "warn" : "debug";
27
+ }
28
+ var currentLogLevel = getLogLevel();
29
+ var currentLevelValue = LOG_LEVELS[currentLogLevel];
30
+ function shouldLog(level) {
31
+ return LOG_LEVELS[level] <= currentLevelValue;
32
+ }
33
+ var logger = {
34
+ debug: (...args) => {
35
+ if (shouldLog("debug")) {
36
+ console.debug(...args);
37
+ }
38
+ },
39
+ info: (...args) => {
40
+ if (shouldLog("info")) {
41
+ console.info(...args);
42
+ }
43
+ },
44
+ warn: (...args) => {
45
+ if (shouldLog("warn")) {
46
+ console.warn(...args);
47
+ }
48
+ },
49
+ error: (...args) => {
50
+ if (shouldLog("error")) {
51
+ console.error(...args);
52
+ }
53
+ }
54
+ };
55
+
56
+ // src/utils/index.ts
57
+ var bluechipTokensConfig = null;
58
+ function setBluechipTokensConfig(config) {
59
+ bluechipTokensConfig = config;
60
+ }
61
+ function getBluechipTokensConfig() {
62
+ if (!bluechipTokensConfig) {
63
+ logger.warn(
64
+ "getBluechipTokensConfig - Bluechip tokens config not set, returning empty config"
65
+ );
66
+ return {};
67
+ }
68
+ return bluechipTokensConfig;
69
+ }
70
+ function normalizeTokenId(tokenId, wrapNearContractId = "wrap.near") {
71
+ if (!tokenId) {
72
+ logger.error("normalizeTokenId - Empty tokenId:", tokenId);
73
+ return "";
74
+ }
75
+ let normalized = tokenId.replace(/^nep141:/, "");
76
+ if (normalized === "near") {
77
+ normalized = wrapNearContractId;
78
+ }
79
+ if (!normalized) {
80
+ logger.error("normalizeTokenId - Result is empty:", {
81
+ tokenId,
82
+ normalized
83
+ });
84
+ }
85
+ return normalized;
86
+ }
87
+ function isNearIntentsSupportedToken(token, bluechipTokens) {
88
+ if (!token?.symbol || !token?.address) {
89
+ return false;
90
+ }
91
+ const config = bluechipTokens || getBluechipTokensConfig();
92
+ const normalizedSymbol = token.symbol.toUpperCase();
93
+ const symbolKey = normalizedSymbol === "NEAR" || normalizedSymbol === "WNEAR" ? "NEAR" : normalizedSymbol;
94
+ const tokenConfig = config[symbolKey];
95
+ if (!tokenConfig) {
96
+ return false;
97
+ }
98
+ const normalizeAddress = (addr) => addr.replace(/^nep141:/, "").toLowerCase();
99
+ const tokenAddress = normalizeAddress(token.address);
100
+ const configAddress = normalizeAddress(tokenConfig.address || "");
101
+ const configAssetId = tokenConfig.assetId ? normalizeAddress(tokenConfig.assetId) : "";
102
+ return tokenAddress === configAddress || tokenAddress === configAssetId;
103
+ }
104
+ function findBestBluechipToken(bluechipTokens, wrapNearContractId = "wrap.near") {
105
+ const preferredTokens = [];
106
+ if (bluechipTokens.USDT?.address) {
107
+ preferredTokens.push({
108
+ address: bluechipTokens.USDT.address,
109
+ symbol: "USDT",
110
+ decimals: bluechipTokens.USDT.decimals || 6,
111
+ chain: "near"
112
+ });
113
+ }
114
+ if (bluechipTokens.USDC?.address) {
115
+ preferredTokens.push({
116
+ address: bluechipTokens.USDC.address,
117
+ symbol: "USDC",
118
+ decimals: bluechipTokens.USDC.decimals || 6,
119
+ chain: "near"
120
+ });
121
+ }
122
+ if (bluechipTokens.NEAR?.address) {
123
+ preferredTokens.push({
124
+ address: bluechipTokens.NEAR.address,
125
+ symbol: "wNEAR",
126
+ decimals: bluechipTokens.NEAR.decimals || 24,
127
+ chain: "near"
128
+ });
129
+ }
130
+ if (preferredTokens.length === 0) {
131
+ logger.warn(
132
+ "findBestBluechipToken - No preferred tokens found, using wrap.near"
133
+ );
134
+ return {
135
+ address: wrapNearContractId,
136
+ symbol: "wNEAR",
137
+ decimals: 24,
138
+ chain: "near"
139
+ };
140
+ }
141
+ logger.debug("findBestBluechipToken - Selected token:", preferredTokens[0]);
142
+ return preferredTokens[0];
143
+ }
144
+ function convertSlippageToBasisPoints(slippage) {
145
+ if (slippage >= 1) {
146
+ return Math.round(slippage);
147
+ }
148
+ if (slippage > 0 && slippage < 0.01) {
149
+ return Math.round(slippage * 1e4);
150
+ }
151
+ if (slippage >= 0.01 && slippage < 1) {
152
+ return Math.round(slippage * 100);
153
+ }
154
+ return Math.round(slippage);
155
+ }
156
+ function normalizeDestinationAsset(assetId, wrapNearContractId = "wrap.near") {
157
+ if (!assetId) return assetId;
158
+ if (assetId.startsWith("nep141:") || assetId.startsWith("nep245:")) {
159
+ return assetId;
160
+ }
161
+ if (assetId === "near" || assetId === "nep141:near") {
162
+ return `nep141:${wrapNearContractId}`;
163
+ }
164
+ if (assetId.includes(".")) {
165
+ return `nep141:${normalizeTokenId(assetId, wrapNearContractId)}`;
166
+ }
167
+ return assetId;
168
+ }
169
+ function formatGasToTgas(gasInYoctoNEAR) {
170
+ if (!gasInYoctoNEAR) return "0";
171
+ const gasStr = String(gasInYoctoNEAR);
172
+ if (/[eE]/.test(gasStr)) {
173
+ const match = gasStr.match(/^([+-]?\d*\.?\d+)[eE]([+-]?\d+)$/);
174
+ if (match) {
175
+ const base = match[1];
176
+ const exponent = parseInt(match[2], 10);
177
+ const [intPart, fracPart = ""] = base.split(".");
178
+ if (exponent > 0) {
179
+ const newIntPart = intPart + fracPart;
180
+ const zerosToAdd = exponent - fracPart.length;
181
+ if (zerosToAdd > 0) {
182
+ return (newIntPart + "0".repeat(zerosToAdd)).replace(/^0+/, "") || "0";
183
+ } else {
184
+ const pointPos = intPart.length + exponent;
185
+ return (newIntPart.slice(0, pointPos) + "." + newIntPart.slice(pointPos)).replace(/\.?0+$/, "");
186
+ }
187
+ }
188
+ }
189
+ }
190
+ try {
191
+ const gasBigInt = BigInt(gasStr.split(".")[0]);
192
+ const tgasBigInt = gasBigInt / BigInt("1000000000000");
193
+ return tgasBigInt.toString();
194
+ } catch (error) {
195
+ logger.error("formatGasToTgas - Error formatting gas:", {
196
+ gasInYoctoNEAR,
197
+ error
198
+ });
199
+ return "0";
200
+ }
201
+ }
202
+ function formatGasString(gas) {
203
+ if (typeof gas === "bigint") {
204
+ return gas.toString();
205
+ }
206
+ const gasStr = String(gas);
207
+ if (!/[eE]/.test(gasStr) && !gasStr.includes(".")) {
208
+ return gasStr;
209
+ }
210
+ if (/[eE]/.test(gasStr)) {
211
+ const match = gasStr.match(/^([+-]?\d*\.?\d+)[eE]([+-]?\d+)$/);
212
+ if (match) {
213
+ const base = match[1];
214
+ const exponent = parseInt(match[2], 10);
215
+ const [intPart, fracPart = ""] = base.split(".");
216
+ if (exponent > 0) {
217
+ const newIntPart = intPart + fracPart;
218
+ const zerosToAdd = exponent - fracPart.length;
219
+ if (zerosToAdd > 0) {
220
+ return (newIntPart + "0".repeat(zerosToAdd)).replace(/^0+/, "") || "0";
221
+ } else {
222
+ const pointPos = intPart.length + exponent;
223
+ const result = newIntPart.slice(0, pointPos) + "." + newIntPart.slice(pointPos);
224
+ return result.replace(/\.?0+$/, "").replace(/\.$/, "");
225
+ }
226
+ } else if (exponent < 0) {
227
+ const absExp = Math.abs(exponent);
228
+ const zerosToAdd = absExp - intPart.length;
229
+ if (zerosToAdd > 0) {
230
+ return "0." + "0".repeat(zerosToAdd - 1) + intPart.replace(/^-/, "") + fracPart;
231
+ } else {
232
+ const pointPos = intPart.length - absExp;
233
+ return intPart.slice(0, pointPos) + "." + intPart.slice(pointPos) + fracPart;
234
+ }
235
+ }
236
+ }
237
+ }
238
+ if (gasStr.includes(".")) {
239
+ const [intPart, fracPart = ""] = gasStr.split(".");
240
+ return intPart + fracPart;
241
+ }
242
+ return gasStr;
243
+ }
244
+ var NearSmartRouter = class {
245
+ constructor(config) {
246
+ this.findPathAdapter = config.findPathAdapter;
247
+ this.nearChainAdapter = config.nearChainAdapter;
248
+ this.configAdapter = config.configAdapter;
249
+ this.wrapNearContractId = this.configAdapter.getWrapNearContractId();
250
+ this.refExchangeId = this.configAdapter.getRefExchangeId();
251
+ this.tokenStorageDepositRead = this.configAdapter.getTokenStorageDepositRead?.() || "1250000000000000000000";
252
+ }
253
+ /**
254
+ * Get a swap quote (normalizes token ids and queries FindPath for routes).
255
+ */
256
+ async quote(params) {
257
+ try {
258
+ const {
259
+ tokenIn,
260
+ tokenOut,
261
+ amountIn,
262
+ slippage,
263
+ swapType: _swapType = "EXACT_INPUT"
264
+ // Currently not used, reserved for future use
265
+ } = params;
266
+ if (!tokenIn?.address || !tokenOut?.address) {
267
+ return {
268
+ success: false,
269
+ tokenIn: params.tokenIn,
270
+ tokenOut: params.tokenOut,
271
+ amountIn: params.amountIn,
272
+ amountOut: "0",
273
+ minAmountOut: "0",
274
+ routes: [],
275
+ error: "Missing token address"
276
+ };
277
+ }
278
+ const normalizedTokenIn = normalizeTokenId(
279
+ tokenIn.address,
280
+ this.wrapNearContractId
281
+ );
282
+ const normalizedTokenOut = normalizeTokenId(
283
+ tokenOut.address,
284
+ this.wrapNearContractId
285
+ );
286
+ if (!normalizedTokenIn || !normalizedTokenOut) {
287
+ logger.error("SmartRouter quote - Invalid token addresses:", {
288
+ tokenIn: {
289
+ original: tokenIn.address,
290
+ normalized: normalizedTokenIn
291
+ },
292
+ tokenOut: {
293
+ original: tokenOut.address,
294
+ normalized: normalizedTokenOut
295
+ }
296
+ });
297
+ return {
298
+ success: false,
299
+ tokenIn: params.tokenIn,
300
+ tokenOut: params.tokenOut,
301
+ amountIn: params.amountIn,
302
+ amountOut: "0",
303
+ minAmountOut: "0",
304
+ routes: [],
305
+ error: `Invalid token address: tokenIn=${normalizedTokenIn || "empty"}, tokenOut=${normalizedTokenOut || "empty"}`
306
+ };
307
+ }
308
+ const slippageBps = convertSlippageToBasisPoints(slippage);
309
+ const slippageDecimalForApi = slippageBps / 1e4;
310
+ logger.debug("SmartRouter quote - Calling findPath:", {
311
+ tokenIn: normalizedTokenIn,
312
+ tokenOut: normalizedTokenOut,
313
+ amountIn,
314
+ slippage: slippageDecimalForApi,
315
+ slippageBps
316
+ });
317
+ const response = await this.findPathAdapter.findPath({
318
+ tokenIn: normalizedTokenIn,
319
+ tokenOut: normalizedTokenOut,
320
+ amountIn: String(amountIn),
321
+ slippage: slippageDecimalForApi,
322
+ supportLedger: false
323
+ });
324
+ logger.debug("SmartRouter quote - findPath response:", {
325
+ result_code: response?.result_code,
326
+ result_msg: response?.result_msg || response?.result_message,
327
+ hasRoutes: !!response?.result_data?.routes?.length
328
+ });
329
+ if (response?.result_code !== 0 || !response?.result_data?.routes?.length) {
330
+ return {
331
+ success: false,
332
+ tokenIn,
333
+ tokenOut,
334
+ amountIn,
335
+ amountOut: "0",
336
+ minAmountOut: "0",
337
+ routes: [],
338
+ error: response?.result_msg || response?.result_message || "No route found"
339
+ };
340
+ }
341
+ const { routes: serverRoutes, amount_out } = response.result_data;
342
+ const slippageDecimal = new Big2(slippageBps).div(1e4);
343
+ const routes = serverRoutes.map((route) => ({
344
+ pools: route.pools.map((pool) => ({
345
+ pool_id: Number(pool.pool_id),
346
+ token_in: pool.token_in || normalizedTokenIn,
347
+ token_out: pool.token_out || normalizedTokenOut,
348
+ amount_in: pool.amount_in,
349
+ amount_out: pool.amount_out,
350
+ fee: pool.fee
351
+ })),
352
+ amountIn,
353
+ amountOut: route.amount_out || amount_out || "0"
354
+ }));
355
+ const amountOut = new Big2(amount_out || 0);
356
+ const minAmountOut = amountOut.mul(new Big2(1).minus(slippageDecimal)).toFixed(0, Big2.roundDown);
357
+ return {
358
+ success: true,
359
+ tokenIn,
360
+ tokenOut,
361
+ amountIn,
362
+ amountOut: amountOut.toFixed(0),
363
+ minAmountOut,
364
+ routes,
365
+ // Save raw serverRoutes data for executeSwap
366
+ rawRoutes: serverRoutes
367
+ };
368
+ } catch (error) {
369
+ return {
370
+ success: false,
371
+ tokenIn: params.tokenIn,
372
+ tokenOut: params.tokenOut,
373
+ amountIn: params.amountIn,
374
+ amountOut: "0",
375
+ minAmountOut: "0",
376
+ routes: [],
377
+ error: error?.message || "Quote failed"
378
+ };
379
+ }
380
+ }
381
+ /**
382
+ * Execute a swap: optionally adds `storage_deposit` for the recipient, then calls REF via `ft_transfer_call`.
383
+ */
384
+ async executeSwap(params) {
385
+ try {
386
+ const { quote, recipient, depositAddress } = params;
387
+ if (!quote.success || !quote.routes.length) {
388
+ return {
389
+ success: false,
390
+ error: "Invalid quote"
391
+ };
392
+ }
393
+ const swapActions = [];
394
+ const routesToUse = quote.rawRoutes || quote.routes;
395
+ routesToUse.forEach((route) => {
396
+ const pools = route.pools || [];
397
+ pools.forEach((pool) => {
398
+ const poolCopy = { ...pool };
399
+ if (+(poolCopy?.amount_in || 0) == 0) {
400
+ delete poolCopy.amount_in;
401
+ }
402
+ poolCopy.pool_id = Number(poolCopy.pool_id);
403
+ swapActions.push(poolCopy);
404
+ });
405
+ });
406
+ if (!swapActions.length) {
407
+ return {
408
+ success: false,
409
+ error: "No swap actions"
410
+ };
411
+ }
412
+ const finalRecipient = depositAddress || recipient;
413
+ const transactions = [];
414
+ if (finalRecipient && quote.tokenOut?.address) {
415
+ let isRegistered = false;
416
+ try {
417
+ const storageBalance = await this.nearChainAdapter.view({
418
+ contractId: quote.tokenOut.address,
419
+ methodName: "storage_balance_of",
420
+ args: {
421
+ account_id: finalRecipient
422
+ }
423
+ });
424
+ isRegistered = !!storageBalance;
425
+ } catch (err) {
426
+ isRegistered = false;
427
+ }
428
+ if (!isRegistered) {
429
+ logger.debug("SmartRouter - Registering recipient account:", {
430
+ contractId: quote.tokenOut.address,
431
+ accountId: finalRecipient
432
+ });
433
+ transactions.push({
434
+ contractId: quote.tokenOut.address,
435
+ methodName: "storage_deposit",
436
+ args: {
437
+ account_id: finalRecipient,
438
+ registration_only: true
439
+ },
440
+ gas: "50",
441
+ expandDeposit: this.tokenStorageDepositRead
442
+ });
443
+ }
444
+ }
445
+ const swapMsg = {
446
+ force: 0,
447
+ actions: swapActions,
448
+ skip_unwrap_near: false
449
+ };
450
+ if (finalRecipient) {
451
+ swapMsg.swap_out_recipient = finalRecipient;
452
+ }
453
+ logger.debug("SmartRouter - Executing swap:", {
454
+ contractId: quote.tokenIn.address,
455
+ receiver_id: this.refExchangeId,
456
+ amount: quote.amountIn,
457
+ swapMsg,
458
+ swapActionsCount: swapActions.length,
459
+ recipient: finalRecipient,
460
+ tokenOut: quote.tokenOut?.address
461
+ });
462
+ transactions.push({
463
+ contractId: quote.tokenIn.address,
464
+ methodName: "ft_transfer_call",
465
+ args: {
466
+ receiver_id: this.refExchangeId,
467
+ amount: quote.amountIn,
468
+ msg: JSON.stringify(swapMsg)
469
+ },
470
+ gas: "250",
471
+ // NEP-141 requires attaching 1 yoctoNEAR for certain calls.
472
+ expandDeposit: "1"
473
+ });
474
+ const result = await this.nearChainAdapter.call({
475
+ transactions
476
+ });
477
+ if (result.status === "success") {
478
+ return {
479
+ success: true,
480
+ txHash: result.txHash,
481
+ txHashArray: result.txHashArr || (result.txHash ? [result.txHash] : [])
482
+ };
483
+ } else {
484
+ return {
485
+ success: false,
486
+ error: result.message || "Execute swap failed"
487
+ };
488
+ }
489
+ } catch (error) {
490
+ return {
491
+ success: false,
492
+ error: error?.message || "Execute swap failed"
493
+ };
494
+ }
495
+ }
496
+ /**
497
+ * Get Router capabilities
498
+ */
499
+ getCapabilities() {
500
+ return {
501
+ requiresRecipient: false,
502
+ requiresFinalizeQuote: false,
503
+ requiresComplexRegistration: false,
504
+ supportedChain: "near"
505
+ };
506
+ }
507
+ /**
508
+ * Get supported chain
509
+ */
510
+ getSupportedChain() {
511
+ return "near";
512
+ }
513
+ };
514
+ var AggregateDexRouter = class {
515
+ constructor(config) {
516
+ this.NEW_ACCOUNT_STORAGE_COST = "1250000000000000000000";
517
+ // 0.00125 NEAR in yoctoNEAR
518
+ this.ONE_YOCTO_NEAR = "1";
519
+ this.swapMultiDexPathAdapter = config.swapMultiDexPathAdapter;
520
+ this.nearChainAdapter = config.nearChainAdapter;
521
+ this.configAdapter = config.configAdapter;
522
+ this.aggregateDexContractId = this.configAdapter.getAggregateDexContractId?.() || "";
523
+ this.wrapNearContractId = this.configAdapter.getWrapNearContractId();
524
+ if (!this.aggregateDexContractId) {
525
+ logger.error(
526
+ "AggregateDexRouter - AGGREGATE_DEX_CONTRACT_ID not configured"
527
+ );
528
+ }
529
+ }
530
+ /**
531
+ * Get Router capabilities
532
+ */
533
+ getCapabilities() {
534
+ return {
535
+ requiresRecipient: true,
536
+ requiresFinalizeQuote: false,
537
+ requiresComplexRegistration: true,
538
+ supportedChain: "near"
539
+ };
540
+ }
541
+ getSupportedChain() {
542
+ return "near";
543
+ }
544
+ /**
545
+ * Get a swap quote from V2 Router API
546
+ */
547
+ async quote(params) {
548
+ try {
549
+ if (!requiresRecipient(params)) {
550
+ return {
551
+ success: false,
552
+ tokenIn: params.tokenIn,
553
+ tokenOut: params.tokenOut,
554
+ amountIn: params.amountIn,
555
+ amountOut: "0",
556
+ minAmountOut: "0",
557
+ routes: [],
558
+ error: "V2 Router requires sender and recipient parameters"
559
+ };
560
+ }
561
+ const { tokenIn, tokenOut, amountIn, slippage, sender, recipient } = params;
562
+ if (!sender || !recipient) {
563
+ logger.error("AggregateDexRouter quote - Missing sender or recipient:", {
564
+ sender,
565
+ recipient
566
+ });
567
+ return {
568
+ success: false,
569
+ tokenIn: params.tokenIn,
570
+ tokenOut: params.tokenOut,
571
+ amountIn: params.amountIn,
572
+ amountOut: "0",
573
+ minAmountOut: "0",
574
+ routes: [],
575
+ error: `V2 Router requires non-empty sender and recipient. Got sender="${sender}", recipient="${recipient}"`
576
+ };
577
+ }
578
+ if (!tokenIn?.address || !tokenOut?.address) {
579
+ return {
580
+ success: false,
581
+ tokenIn: params.tokenIn,
582
+ tokenOut: params.tokenOut,
583
+ amountIn: params.amountIn,
584
+ amountOut: "0",
585
+ minAmountOut: "0",
586
+ routes: [],
587
+ error: "Missing token address"
588
+ };
589
+ }
590
+ const normalizedTokenIn = normalizeTokenId(
591
+ tokenIn.address,
592
+ this.wrapNearContractId
593
+ );
594
+ const normalizedTokenOut = normalizeTokenId(
595
+ tokenOut.address,
596
+ this.wrapNearContractId
597
+ );
598
+ if (!normalizedTokenIn || !normalizedTokenOut) {
599
+ logger.error("AggregateDexRouter quote - Invalid token addresses:", {
600
+ tokenIn: {
601
+ original: tokenIn.address,
602
+ normalized: normalizedTokenIn
603
+ },
604
+ tokenOut: {
605
+ original: tokenOut.address,
606
+ normalized: normalizedTokenOut
607
+ }
608
+ });
609
+ return {
610
+ success: false,
611
+ tokenIn: params.tokenIn,
612
+ tokenOut: params.tokenOut,
613
+ amountIn: params.amountIn,
614
+ amountOut: "0",
615
+ minAmountOut: "0",
616
+ routes: [],
617
+ error: `Invalid token address: tokenIn=${normalizedTokenIn || "empty"}, tokenOut=${normalizedTokenOut || "empty"}`
618
+ };
619
+ }
620
+ const slippageBps = convertSlippageToBasisPoints(slippage);
621
+ const slippageDecimalForApi = slippageBps / 1e4;
622
+ logger.debug("AggregateDexRouter quote - Calling swapMultiDexPath:", {
623
+ tokenIn: normalizedTokenIn,
624
+ tokenOut: normalizedTokenOut,
625
+ amountIn,
626
+ slippage: slippageDecimalForApi,
627
+ sender,
628
+ recipient
629
+ });
630
+ const response = await this.swapMultiDexPathAdapter.swapMultiDexPath({
631
+ amountIn: String(amountIn),
632
+ tokenIn: normalizedTokenIn,
633
+ tokenOut: normalizedTokenOut,
634
+ slippage: slippageDecimalForApi,
635
+ pathDeep: 2,
636
+ user: sender,
637
+ receiveUser: recipient
638
+ });
639
+ logger.debug("AggregateDexRouter quote - swapMultiDexPath response:", {
640
+ result_code: response?.result_code,
641
+ result_message: response?.result_message,
642
+ hasData: !!response?.result_data
643
+ });
644
+ if (response.result_code !== 0 || !response.result_data) {
645
+ return {
646
+ success: false,
647
+ tokenIn,
648
+ tokenOut,
649
+ amountIn,
650
+ amountOut: "0",
651
+ minAmountOut: "0",
652
+ routes: [],
653
+ error: response.result_message || "V2 Router API call failed"
654
+ };
655
+ }
656
+ const {
657
+ amount_in,
658
+ amount_out,
659
+ min_amount_out,
660
+ msg,
661
+ signature,
662
+ tokens,
663
+ dexs
664
+ } = response.result_data;
665
+ return {
666
+ success: true,
667
+ tokenIn,
668
+ tokenOut,
669
+ amountIn: amount_in || amountIn,
670
+ amountOut: amount_out || "0",
671
+ minAmountOut: min_amount_out || "0",
672
+ routes: [],
673
+ routerMsg: msg,
674
+ signature,
675
+ tokens: tokens || [],
676
+ dexs: dexs || [],
677
+ recipient,
678
+ slippage
679
+ };
680
+ } catch (error) {
681
+ logger.error("AggregateDexRouter quote - Error:", error);
682
+ return {
683
+ success: false,
684
+ tokenIn: params.tokenIn,
685
+ tokenOut: params.tokenOut,
686
+ amountIn: params.amountIn,
687
+ amountOut: "0",
688
+ minAmountOut: "0",
689
+ routes: [],
690
+ error: error?.message || "Quote failed"
691
+ };
692
+ }
693
+ }
694
+ /**
695
+ * Finalize quote with depositAddress (deprecated)
696
+ *
697
+ * @deprecated No longer needed. executeSwap automatically fetches final quote using receiveUser (depositAddress).
698
+ * Kept for interface compatibility only.
699
+ */
700
+ async finalizeQuote(params, depositAddress) {
701
+ if (!requiresRecipient(params)) {
702
+ throw new Error("V2 Router requires recipient parameters");
703
+ }
704
+ return await this.quote({
705
+ ...params,
706
+ recipient: depositAddress
707
+ });
708
+ }
709
+ /**
710
+ * Execute swap with V2 Router
711
+ * Automatically fetches final quote using receiveUser (depositAddress) to ensure correct routerMsg and signature.
712
+ */
713
+ async executeSwap(params) {
714
+ try {
715
+ if (!requiresRecipientInExecute(params)) {
716
+ return {
717
+ success: false,
718
+ error: "V2 Router requires sender and receiveUser parameters"
719
+ };
720
+ }
721
+ const { quote, sender, receiveUser } = params;
722
+ if (!quote.success) {
723
+ return {
724
+ success: false,
725
+ error: "Invalid quote"
726
+ };
727
+ }
728
+ if (!receiveUser || receiveUser.trim() === "") {
729
+ return {
730
+ success: false,
731
+ error: "receiveUser (depositAddress) is required"
732
+ };
733
+ }
734
+ if (receiveUser.startsWith("0x") && receiveUser.length === 42) {
735
+ return {
736
+ success: false,
737
+ error: `receiveUser appears to be an EVM address (${receiveUser}). For NEAR chain swaps, depositAddress must be a NEAR account (64 hex chars or .near format)`
738
+ };
739
+ }
740
+ logger.debug("AggregateDexRouter - executeSwap params:", {
741
+ sender,
742
+ receiveUser,
743
+ tokenIn: quote.tokenIn.address,
744
+ tokenOut: quote.tokenOut.address,
745
+ amountIn: quote.amountIn,
746
+ tokens: quote.tokens,
747
+ dexs: quote.dexs
748
+ });
749
+ const slippage = quote.slippage || 5e-3;
750
+ const finalQuoteParams = {
751
+ tokenIn: quote.tokenIn,
752
+ tokenOut: quote.tokenOut,
753
+ amountIn: quote.amountIn,
754
+ slippage,
755
+ sender,
756
+ recipient: receiveUser
757
+ };
758
+ let finalQuote;
759
+ try {
760
+ finalQuote = await this.quote(finalQuoteParams);
761
+ if (!finalQuote.success) {
762
+ return {
763
+ success: false,
764
+ error: `Failed to fetch quote with receiveUser="${receiveUser}": ${finalQuote.error}`
765
+ };
766
+ }
767
+ } catch (error) {
768
+ logger.error("AggregateDexRouter - Failed to fetch quote with receiveUser:", error);
769
+ return {
770
+ success: false,
771
+ error: `Failed to fetch quote with receiveUser="${receiveUser}": ${error?.message || "Unknown error"}`
772
+ };
773
+ }
774
+ const routerMsg = finalQuote.routerMsg;
775
+ const signature = finalQuote.signature;
776
+ if (!routerMsg || !signature) {
777
+ return {
778
+ success: false,
779
+ error: `Quote fetched with receiveUser="${receiveUser}" is missing routerMsg or signature.`
780
+ };
781
+ }
782
+ logger.debug("AggregateDexRouter - Successfully fetched final quote:", {
783
+ receiveUser,
784
+ quoteRecipient: finalQuote.recipient,
785
+ routerMsgLength: routerMsg.length,
786
+ signatureLength: signature.length
787
+ });
788
+ const tokens = finalQuote.tokens || [];
789
+ const dexs = finalQuote.dexs || [];
790
+ const transactions = [];
791
+ const getStorageBalance = async (tokenId, accountId) => {
792
+ try {
793
+ return await this.nearChainAdapter.view({
794
+ contractId: tokenId,
795
+ methodName: "storage_balance_of",
796
+ args: { account_id: accountId }
797
+ });
798
+ } catch (error) {
799
+ return null;
800
+ }
801
+ };
802
+ const isNativeNear = finalQuote.tokenIn.symbol === "NEAR" || finalQuote.tokenIn.address === "near" || !finalQuote.tokenIn.address && finalQuote.tokenIn.symbol === "NEAR";
803
+ if (isNativeNear) {
804
+ const wrapNearStorageBalance = await getStorageBalance(
805
+ this.wrapNearContractId,
806
+ sender
807
+ ).catch(() => null);
808
+ if (!wrapNearStorageBalance) {
809
+ transactions.push({
810
+ contractId: this.wrapNearContractId,
811
+ methodName: "storage_deposit",
812
+ args: {
813
+ account_id: sender,
814
+ registration_only: true
815
+ },
816
+ gas: "50000000000000",
817
+ expandDeposit: this.NEW_ACCOUNT_STORAGE_COST
818
+ });
819
+ }
820
+ transactions.push({
821
+ contractId: this.wrapNearContractId,
822
+ methodName: "near_deposit",
823
+ args: {},
824
+ gas: "50000000000000",
825
+ expandDeposit: finalQuote.amountIn
826
+ });
827
+ }
828
+ const tokensToCheck = dexs.length > 1 ? tokens : [finalQuote.tokenOut.address];
829
+ const tokenStorageBalances = await Promise.all(
830
+ tokensToCheck.map(
831
+ (tokenId) => getStorageBalance(tokenId, sender).catch(() => null)
832
+ )
833
+ );
834
+ tokensToCheck.forEach((tokenId, index) => {
835
+ if (!tokenStorageBalances[index]) {
836
+ transactions.push({
837
+ contractId: tokenId,
838
+ methodName: "storage_deposit",
839
+ args: {
840
+ account_id: sender,
841
+ registration_only: true
842
+ },
843
+ gas: "50000000000000",
844
+ expandDeposit: this.NEW_ACCOUNT_STORAGE_COST
845
+ });
846
+ }
847
+ });
848
+ if (receiveUser && receiveUser !== sender) {
849
+ logger.debug("AggregateDexRouter - Checking receiveUser registration in tokenOut:", {
850
+ receiveUser,
851
+ tokenOut: finalQuote.tokenOut.address,
852
+ tokenOutSymbol: finalQuote.tokenOut.symbol
853
+ });
854
+ const receiveUserStorageBalance = await getStorageBalance(
855
+ finalQuote.tokenOut.address,
856
+ receiveUser
857
+ ).catch((error) => {
858
+ logger.warn("AggregateDexRouter - Failed to check receiveUser storage balance:", {
859
+ receiveUser,
860
+ tokenOut: finalQuote.tokenOut.address,
861
+ error: error?.message
862
+ });
863
+ return null;
864
+ });
865
+ if (!receiveUserStorageBalance) {
866
+ logger.debug("AggregateDexRouter - receiveUser not registered in tokenOut, adding registration transaction:", {
867
+ receiveUser,
868
+ tokenOut: finalQuote.tokenOut.address,
869
+ tokenOutSymbol: finalQuote.tokenOut.symbol,
870
+ storageCost: this.NEW_ACCOUNT_STORAGE_COST
871
+ });
872
+ transactions.push({
873
+ contractId: finalQuote.tokenOut.address,
874
+ methodName: "storage_deposit",
875
+ args: {
876
+ account_id: receiveUser,
877
+ registration_only: true
878
+ },
879
+ gas: "50000000000000",
880
+ expandDeposit: this.NEW_ACCOUNT_STORAGE_COST
881
+ });
882
+ }
883
+ }
884
+ const aggregateDexStorageBalances = await Promise.all(
885
+ tokens.map(
886
+ (tokenId) => getStorageBalance(tokenId, this.aggregateDexContractId).catch(
887
+ () => null
888
+ )
889
+ )
890
+ );
891
+ tokens.forEach((tokenId, index) => {
892
+ if (!aggregateDexStorageBalances[index]) {
893
+ transactions.push({
894
+ contractId: tokenId,
895
+ methodName: "storage_deposit",
896
+ args: {
897
+ account_id: this.aggregateDexContractId,
898
+ registration_only: true
899
+ },
900
+ gas: "50000000000000",
901
+ expandDeposit: this.NEW_ACCOUNT_STORAGE_COST
902
+ });
903
+ }
904
+ });
905
+ if (tokens.length > 0) {
906
+ const registeredStatus = await this.queryUserTokensRegistered({
907
+ user: sender,
908
+ tokens
909
+ });
910
+ const unregisteredTokens = tokens.filter(
911
+ (_, index) => !registeredStatus[index]
912
+ );
913
+ if (unregisteredTokens.length > 0) {
914
+ const depositPerToken = new Big2("0.005").mul(
915
+ new Big2("1000000000000000000000000")
916
+ );
917
+ const totalDeposit2 = depositPerToken.mul(unregisteredTokens.length);
918
+ transactions.push({
919
+ contractId: this.aggregateDexContractId,
920
+ methodName: "tokens_storage_deposit",
921
+ args: {
922
+ user: sender,
923
+ tokens: unregisteredTokens
924
+ },
925
+ gas: "30000000000000",
926
+ expandDeposit: totalDeposit2.toFixed(0)
927
+ });
928
+ }
929
+ }
930
+ const msgString = JSON.stringify({
931
+ msg: routerMsg,
932
+ signature
933
+ });
934
+ transactions.push({
935
+ contractId: finalQuote.tokenIn.address,
936
+ methodName: "ft_transfer_call",
937
+ args: {
938
+ receiver_id: this.aggregateDexContractId,
939
+ amount: finalQuote.amountIn,
940
+ msg: msgString
941
+ },
942
+ gas: "300000000000000",
943
+ expandDeposit: this.ONE_YOCTO_NEAR
944
+ });
945
+ const totalDeposit = transactions.reduce((sum, tx) => {
946
+ if (tx.expandDeposit) {
947
+ return sum.plus(tx.expandDeposit);
948
+ }
949
+ return sum;
950
+ }, new Big2(0));
951
+ logger.debug("AggregateDexRouter - Executing swap (following mature codebase logic):", {
952
+ contractId: finalQuote.tokenIn.address,
953
+ receiver_id: this.aggregateDexContractId,
954
+ amount: finalQuote.amountIn,
955
+ transactionsCount: transactions.length,
956
+ sender,
957
+ receiveUser,
958
+ tokens: tokens.length,
959
+ dexs: dexs.length,
960
+ totalDepositYocto: totalDeposit.toFixed(0),
961
+ totalDepositNEAR: totalDeposit.div(new Big2("1000000000000000000000000")).toFixed(6),
962
+ transactions: transactions.map((tx, idx) => ({
963
+ index: idx,
964
+ contractId: tx.contractId,
965
+ methodName: tx.methodName,
966
+ expandDeposit: tx.expandDeposit,
967
+ expandDepositNEAR: tx.expandDeposit ? new Big2(tx.expandDeposit).div(new Big2("1000000000000000000000000")).toFixed(6) : "0"
968
+ }))
969
+ });
970
+ const result = await this.nearChainAdapter.call({
971
+ transactions
972
+ });
973
+ if (result.status === "success") {
974
+ return {
975
+ success: true,
976
+ txHash: result.txHash,
977
+ txHashArray: result.txHashArr || (result.txHash ? [result.txHash] : [])
978
+ };
979
+ } else {
980
+ return {
981
+ success: false,
982
+ error: result.message || "Execute swap failed"
983
+ };
984
+ }
985
+ } catch (error) {
986
+ logger.error("AggregateDexRouter executeSwap - Error:", error);
987
+ return {
988
+ success: false,
989
+ error: error?.message || "Execute swap failed"
990
+ };
991
+ }
992
+ }
993
+ /**
994
+ * Query user token registration status in AGGREGATE_DEX contract
995
+ */
996
+ async queryUserTokensRegistered({
997
+ user,
998
+ tokens
999
+ }) {
1000
+ try {
1001
+ return await this.nearChainAdapter.view({
1002
+ contractId: this.aggregateDexContractId,
1003
+ methodName: "query_user_tokens_registered",
1004
+ args: {
1005
+ user,
1006
+ tokens
1007
+ }
1008
+ });
1009
+ } catch (error) {
1010
+ logger.error(
1011
+ "AggregateDexRouter - Failed to query user tokens registered:",
1012
+ error
1013
+ );
1014
+ return tokens.map(() => false);
1015
+ }
1016
+ }
1017
+ };
1018
+ async function completeQuote(params, config) {
1019
+ const {
1020
+ sourceToken,
1021
+ targetToken,
1022
+ sourceChain,
1023
+ targetChain: _targetChain,
1024
+ // Reserved for future use
1025
+ amountIn,
1026
+ slippage,
1027
+ recipient,
1028
+ refundTo
1029
+ } = params;
1030
+ const {
1031
+ intentsQuotationAdapter,
1032
+ dexRouters,
1033
+ dexRouter,
1034
+ bluechipTokens,
1035
+ configAdapter,
1036
+ currentUserAddress
1037
+ } = config;
1038
+ const wrapNearContractId = configAdapter.getWrapNearContractId();
1039
+ const routers = dexRouters || (dexRouter ? [dexRouter] : []);
1040
+ if (routers.length === 0) {
1041
+ throw new Error("At least one DEX router is required");
1042
+ }
1043
+ const userAddress = currentUserAddress || recipient;
1044
+ if (!userAddress) {
1045
+ throw new Error("currentUserAddress or recipient is required for V2 Router");
1046
+ }
1047
+ if (!sourceToken?.address) {
1048
+ throw new Error("Source token address is required");
1049
+ }
1050
+ if (!targetToken?.address) {
1051
+ throw new Error("Target token address is required");
1052
+ }
1053
+ const needsPreSwap = sourceChain === "near" && !isNearIntentsSupportedToken(sourceToken, bluechipTokens);
1054
+ const bluechipToken = findBestBluechipToken(
1055
+ bluechipTokens,
1056
+ wrapNearContractId
1057
+ );
1058
+ if (!bluechipToken?.address) {
1059
+ logger.error("DEX Aggregator - Failed to find bluechip token:", {
1060
+ bluechipToken,
1061
+ bluechipTokens
1062
+ });
1063
+ throw new Error("Failed to find bluechip token address");
1064
+ }
1065
+ logger.debug("DEX Aggregator - Using bluechip token:", {
1066
+ address: bluechipToken.address,
1067
+ symbol: bluechipToken.symbol,
1068
+ decimals: bluechipToken.decimals
1069
+ });
1070
+ let preSwapQuote = null;
1071
+ let bestRouter = null;
1072
+ if (needsPreSwap) {
1073
+ if (!sourceToken?.address) {
1074
+ throw new Error("Source token address is required");
1075
+ }
1076
+ logger.debug("DEX Aggregator - Pre-swap quote params:", {
1077
+ tokenIn: {
1078
+ address: sourceToken.address,
1079
+ symbol: sourceToken.symbol
1080
+ },
1081
+ tokenOut: {
1082
+ address: bluechipToken.address,
1083
+ symbol: bluechipToken.symbol
1084
+ },
1085
+ amountIn,
1086
+ slippage,
1087
+ routersCount: routers.length,
1088
+ userAddress
1089
+ });
1090
+ const quotes = await Promise.allSettled(
1091
+ routers.map((router) => {
1092
+ const capabilities = router.getCapabilities();
1093
+ const quoteParams = capabilities.requiresRecipient ? {
1094
+ tokenIn: sourceToken,
1095
+ tokenOut: bluechipToken,
1096
+ amountIn,
1097
+ slippage,
1098
+ swapType: "EXACT_INPUT",
1099
+ sender: userAddress,
1100
+ recipient: userAddress
1101
+ } : {
1102
+ tokenIn: sourceToken,
1103
+ tokenOut: bluechipToken,
1104
+ amountIn,
1105
+ slippage,
1106
+ swapType: "EXACT_INPUT"
1107
+ };
1108
+ return router.quote(quoteParams);
1109
+ })
1110
+ );
1111
+ const validQuotes = quotes.filter(
1112
+ (r) => r.status === "fulfilled" && r.value.success
1113
+ ).map((r) => r.value);
1114
+ if (validQuotes.length === 0) {
1115
+ const errors = quotes.map((r, index) => {
1116
+ if (r.status === "rejected") {
1117
+ return `Router ${index}: ${r.reason}`;
1118
+ }
1119
+ if (r.status === "fulfilled" && !r.value.success) {
1120
+ return `Router ${index}: ${r.value.error}`;
1121
+ }
1122
+ return null;
1123
+ }).filter(Boolean);
1124
+ logger.error("DEX Aggregator - All router quotes failed:", errors);
1125
+ throw new Error(
1126
+ `All router quotes failed: ${errors.join("; ")}`
1127
+ );
1128
+ }
1129
+ const bestQuote = validQuotes.reduce((best, current) => {
1130
+ const bestAmount = new Big2(best.amountOut);
1131
+ const currentAmount = new Big2(current.amountOut);
1132
+ return currentAmount.gt(bestAmount) ? current : best;
1133
+ });
1134
+ const bestQuoteIndex = validQuotes.indexOf(bestQuote);
1135
+ bestRouter = routers[bestQuoteIndex];
1136
+ preSwapQuote = bestQuote;
1137
+ logger.debug("DEX Aggregator - Selected best router:", {
1138
+ routerIndex: bestQuoteIndex,
1139
+ amountOut: bestQuote.amountOut,
1140
+ routerType: bestRouter.getCapabilities().requiresRecipient ? "V2 (Recipient)" : "V1 (Simple)"
1141
+ });
1142
+ const preSwapAmountOut = preSwapQuote.amountOut;
1143
+ if (!preSwapAmountOut || new Big2(preSwapAmountOut).lte(0)) {
1144
+ logger.error("DEX Aggregator - Pre-swap amountOut is invalid:", {
1145
+ amountOut: preSwapAmountOut,
1146
+ tokenIn: sourceToken,
1147
+ tokenOut: bluechipToken
1148
+ });
1149
+ throw new Error(
1150
+ "Pre-swap returned invalid amount: amount is too small or zero"
1151
+ );
1152
+ }
1153
+ logger.debug("DEX Aggregator - Pre-swap quote success:", {
1154
+ amountOut: preSwapAmountOut,
1155
+ tokenOut: bluechipToken.symbol,
1156
+ decimals: bluechipToken.decimals
1157
+ });
1158
+ }
1159
+ let normalizedSourceAsset;
1160
+ if (needsPreSwap) {
1161
+ const bluechipKey = bluechipToken.symbol?.toUpperCase() === "WNEAR" ? "NEAR" : bluechipToken.symbol?.toUpperCase();
1162
+ const bluechipTokenConfig = bluechipKey && bluechipTokens[bluechipKey] || void 0;
1163
+ if (bluechipTokenConfig?.assetId) {
1164
+ normalizedSourceAsset = bluechipTokenConfig.assetId;
1165
+ logger.debug("Using bluechip token assetId for NearIntents:", {
1166
+ symbol: bluechipToken.symbol,
1167
+ assetId: normalizedSourceAsset,
1168
+ contractAddress: bluechipToken.address
1169
+ });
1170
+ } else {
1171
+ normalizedSourceAsset = `nep141:${bluechipToken.address}`;
1172
+ logger.warn(
1173
+ "Bluechip token assetId not found, using contractAddress with prefix:",
1174
+ {
1175
+ symbol: bluechipToken.symbol,
1176
+ normalizedSourceAsset
1177
+ }
1178
+ );
1179
+ }
1180
+ } else {
1181
+ if (sourceToken.symbol) {
1182
+ const sourceKey = sourceToken.symbol.toUpperCase();
1183
+ const sourceTokenConfig = bluechipTokens[sourceKey];
1184
+ if (sourceTokenConfig?.assetId) {
1185
+ normalizedSourceAsset = sourceTokenConfig.assetId;
1186
+ } else {
1187
+ normalizedSourceAsset = normalizeTokenId(
1188
+ sourceToken.address,
1189
+ wrapNearContractId
1190
+ );
1191
+ if (!normalizedSourceAsset.startsWith("nep141:")) {
1192
+ normalizedSourceAsset = `nep141:${normalizedSourceAsset}`;
1193
+ }
1194
+ }
1195
+ } else {
1196
+ normalizedSourceAsset = normalizeTokenId(
1197
+ sourceToken.address,
1198
+ wrapNearContractId
1199
+ );
1200
+ if (!normalizedSourceAsset.startsWith("nep141:")) {
1201
+ normalizedSourceAsset = `nep141:${normalizedSourceAsset}`;
1202
+ }
1203
+ }
1204
+ }
1205
+ let normalizedTargetAsset = targetToken.address;
1206
+ if (normalizedTargetAsset && !normalizedTargetAsset.startsWith("nep141:") && !normalizedTargetAsset.startsWith("nep245:") && normalizedTargetAsset.includes(".")) {
1207
+ normalizedTargetAsset = `nep141:${normalizeTokenId(
1208
+ normalizedTargetAsset,
1209
+ wrapNearContractId
1210
+ )}`;
1211
+ }
1212
+ normalizedTargetAsset = normalizeDestinationAsset(normalizedTargetAsset, wrapNearContractId) || normalizedTargetAsset;
1213
+ const slippageBps = convertSlippageToBasisPoints(slippage);
1214
+ const intentsAmount = needsPreSwap ? preSwapQuote.amountOut : amountIn;
1215
+ logger.debug("DEX Aggregator - Calling NearIntents quotation:", {
1216
+ originAsset: normalizedSourceAsset,
1217
+ destinationAsset: normalizedTargetAsset,
1218
+ amount: intentsAmount,
1219
+ needsPreSwap,
1220
+ preSwapAmountOut: needsPreSwap ? preSwapQuote.amountOut : void 0
1221
+ });
1222
+ const swapTypeForIntents = needsPreSwap ? "FLEX_INPUT" : void 0;
1223
+ logger.debug("DEX Aggregator - swapType for NearIntents:", {
1224
+ needsPreSwap,
1225
+ swapType: swapTypeForIntents || "EXACT_INPUT (default)"
1226
+ });
1227
+ const intentsQuote = await intentsQuotationAdapter.quote({
1228
+ originAsset: normalizedSourceAsset,
1229
+ destinationAsset: normalizedTargetAsset,
1230
+ amount: intentsAmount,
1231
+ refundTo: refundTo || recipient,
1232
+ recipient,
1233
+ slippageTolerance: slippageBps,
1234
+ swapType: swapTypeForIntents
1235
+ });
1236
+ logger.debug("DEX Aggregator - NearIntents quotation result:", {
1237
+ quoteStatus: intentsQuote.quoteStatus,
1238
+ message: intentsQuote.message,
1239
+ hasDepositAddress: !!intentsQuote.quoteSuccessResult?.quote?.depositAddress
1240
+ });
1241
+ if (intentsQuote.quoteStatus !== "success") {
1242
+ const errorMessage = intentsQuote.message || "Unknown error";
1243
+ logger.error("DEX Aggregator - NearIntents quote failed:", {
1244
+ error: errorMessage,
1245
+ originAsset: normalizedSourceAsset,
1246
+ destinationAsset: normalizedTargetAsset,
1247
+ amount: intentsAmount,
1248
+ needsPreSwap,
1249
+ preSwapAmountOut: needsPreSwap ? preSwapQuote.amountOut : void 0
1250
+ });
1251
+ throw new Error(`Intents quote failed: ${errorMessage}`);
1252
+ }
1253
+ const depositAddress = intentsQuote.quoteSuccessResult?.quote?.depositAddress || "";
1254
+ if (!depositAddress) {
1255
+ throw new Error("Deposit address not found in intents quote");
1256
+ }
1257
+ const finalQuote = preSwapQuote;
1258
+ return {
1259
+ intents: {
1260
+ quote: intentsQuote,
1261
+ depositAddress
1262
+ },
1263
+ preSwap: needsPreSwap && finalQuote && bestRouter ? {
1264
+ quote: finalQuote,
1265
+ tokenIn: sourceToken,
1266
+ tokenOut: bluechipToken,
1267
+ executor: bestRouter
1268
+ } : void 0,
1269
+ finalAmountOut: intentsQuote.quoteSuccessResult?.quote?.amountOut || "0"
1270
+ };
1271
+ }
1272
+
1273
+ export { AggregateDexRouter, NearSmartRouter, completeQuote, convertSlippageToBasisPoints, findBestBluechipToken, formatGasString, formatGasToTgas, getBluechipTokensConfig, isNearIntentsSupportedToken, logger, normalizeDestinationAsset, normalizeTokenId, requiresRecipient, requiresRecipientInExecute, setBluechipTokensConfig };
1274
+ //# sourceMappingURL=index.mjs.map
1275
+ //# sourceMappingURL=index.mjs.map