@txnlab/haystack-router 2.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TxnLab Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,498 @@
1
+ # Haystack Router SDK
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@txnlab/haystack-router.svg)](https://www.npmjs.com/package/@txnlab/haystack-router)
4
+ [![bundle size](https://deno.bundlejs.com/badge?q=@txnlab/haystack-router@latest&treeshake=[*])](https://bundlejs.com/?q=%40txnlab%2Fdeflex%40latest&treeshake=%5B*%5D)
5
+ [![CI](https://github.com/TxnLab/haystack-js/actions/workflows/ci.yml/badge.svg)](https://github.com/TxnLab/haystack-js/actions/workflows/ci.yml)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
8
+
9
+ TypeScript/JavaScript SDK for [Haystack Order Router](https://txnlab.gitbook.io/haystack-router-api) - smart order routing and DEX aggregation on Algorand.
10
+
11
+ ## Prerequisites
12
+
13
+ - **Haystack Router API Key** - Request an API key by emailing [support@txnlab.dev](mailto:support@txnlab.dev)
14
+ - algosdk 3.0.0 or later
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @txnlab/haystack-router algosdk
20
+ ```
21
+
22
+ > **Note**: `algosdk` is a peer dependency and must be installed alongside `@txnlab/haystack-router`.
23
+
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import { RouterClient } from '@txnlab/haystack-router'
28
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
29
+
30
+ const { activeAddress, transactionSigner } = useWallet()
31
+
32
+ // Initialize the client
33
+ const router = new RouterClient({
34
+ apiKey: 'your-api-key',
35
+ })
36
+
37
+ // Get a quote
38
+ const quote = await router.newQuote({
39
+ address: activeAddress,
40
+ fromAssetId: 0, // ALGO
41
+ toAssetId: 31566704, // USDC
42
+ amount: 1_000_000, // 1 ALGO (in microAlgos)
43
+ })
44
+
45
+ // Execute the swap
46
+ const swap = await router.newSwap({
47
+ quote,
48
+ address: activeAddress,
49
+ signer: transactionSigner,
50
+ slippage: 1, // 1% slippage tolerance
51
+ })
52
+ const result = await swap.execute()
53
+
54
+ console.log(`Swap completed in round ${result.confirmedRound}`)
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ### Initialize the Client
60
+
61
+ ```typescript
62
+ import { RouterClient } from '@txnlab/haystack-router'
63
+
64
+ // Basic initialization
65
+ const router = new RouterClient({
66
+ apiKey: 'your-api-key',
67
+ })
68
+
69
+ // Custom Algod configuration
70
+ const router = new RouterClient({
71
+ apiKey: 'your-api-key',
72
+ algodUri: 'https://mainnet-api.4160.nodely.dev/',
73
+ algodToken: '',
74
+ algodPort: 443,
75
+ autoOptIn: true, // Automatically handle asset opt-ins
76
+ })
77
+
78
+ // Earn fees with the referral program
79
+ const router = new RouterClient({
80
+ apiKey: 'your-api-key',
81
+ referrerAddress: 'YOUR_ALGORAND_ADDRESS', // Earns 25% of swap fees
82
+ feeBps: 15, // 0.15% fee (max: 300 = 3%)
83
+ })
84
+ ```
85
+
86
+ By providing your Algorand address as the `referrerAddress` when initializing the client, you can earn 25% of the swap fees generated through your integration. Set the `feeBps` parameter to specify the total fee charged to users (default: 0.15%, max: 3.00%). Learn more about the [Haystack Router Referral Program](https://txnlab.gitbook.io/haystack-router-api/referral-treasury/referral-program).
87
+
88
+ ### Get a Swap Quote
89
+
90
+ The [`newQuote()`](#deflexclientnewquote) method returns a [`SwapQuote`](#deflexquote) object:
91
+
92
+ ```typescript
93
+ // Basic quote
94
+ const quote = await router.newQuote({
95
+ fromASAID: 0, // ALGO
96
+ toASAID: 31566704, // USDC
97
+ amount: 1_000_000, // 1 ALGO
98
+ address: userAddress, // Required for auto opt-in detection
99
+ })
100
+ ```
101
+
102
+ ### Execute a Swap
103
+
104
+ The [`newSwap()`](#deflexclientnewswap) method returns a [`SwapComposer`](#swapcomposer) instance:
105
+
106
+ ```typescript
107
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
108
+
109
+ const { activeAddress, transactionSigner } = useWallet()
110
+
111
+ const swap = await router.newSwap({
112
+ quote,
113
+ address: activeAddress,
114
+ signer: transactionSigner,
115
+ slippage: 1, // 1% slippage tolerance
116
+ })
117
+ const result = await swap.execute()
118
+
119
+ console.log(`Confirmed in round ${result.confirmedRound}`)
120
+ console.log('Transaction IDs:', result.txIds)
121
+ ```
122
+
123
+ ### Transaction Tracking
124
+
125
+ Add a custom note to the input transaction for tracking purposes, and retrieve its transaction ID after execution:
126
+
127
+ ```typescript
128
+ const swap = await router.newSwap({
129
+ quote,
130
+ address: activeAddress,
131
+ signer: transactionSigner,
132
+ slippage: 1,
133
+ note: new TextEncoder().encode('tracking-id-123'), // Custom note for tracking
134
+ })
135
+
136
+ const result = await swap.execute()
137
+
138
+ // Get the transaction ID of the user-signed input transaction
139
+ const inputTxId = swap.getInputTransactionId()
140
+ console.log('Input transaction ID:', inputTxId)
141
+ ```
142
+
143
+ The `note` is applied only to the user-signed payment or asset transfer transaction (not pre-signed or middleware transactions). The transaction ID is available after calling `buildGroup()`, `sign()`, or `execute()`.
144
+
145
+ ### Transaction Signing
146
+
147
+ The SDK supports both standard `algosdk.TransactionSigner` and ARC-1 compliant signer functions.
148
+
149
+ #### 1. use-wallet Signer (Recommended)
150
+
151
+ Use the `@txnlab/use-wallet` library for wallet management in your dApp:
152
+
153
+ ```typescript
154
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
155
+
156
+ const { activeAddress, transactionSigner } = useWallet()
157
+
158
+ const swap = await router.newSwap({
159
+ quote,
160
+ address: activeAddress,
161
+ signer: transactionSigner,
162
+ slippage: 1,
163
+ })
164
+ await swap.execute()
165
+ ```
166
+
167
+ > **Tip**: The [`@txnlab/use-wallet`](https://github.com/TxnLab/use-wallet) library supports multiple wallet providers (Pera, Defly, Lute, WalletConnect, etc.) and provides a unified interface. Choose the framework-specific adapter for your project: `@txnlab/use-wallet-react`, `@txnlab/use-wallet-vue`, `@txnlab/use-wallet-solid`, or `@txnlab/use-wallet-svelte`.
168
+
169
+ #### 2. Custom Signer Function
170
+
171
+ The SDK accepts custom signer functions that receive the complete transaction group and an array of indexes indicating which transactions need signing:
172
+
173
+ ```typescript
174
+ import { Address, encodeUnsignedTransaction, type Transaction } from 'algosdk'
175
+
176
+ // Example: Wrapping an ARC-1 compliant wallet
177
+ const customSigner = async (
178
+ txnGroup: Transaction[],
179
+ indexesToSign: number[],
180
+ ) => {
181
+ // Convert to wallet's expected format
182
+ const walletTxns = txnGroup.map((txn, index) => ({
183
+ txn: Buffer.from(encodeUnsignedTransaction(txn)).toString('base64'),
184
+ signers: indexesToSign.includes(index)
185
+ ? [Address.fromString(activeAddress)]
186
+ : [],
187
+ }))
188
+
189
+ // Sign with wallet provider
190
+ const signedTxns = await walletProvider.signTxns(walletTxns)
191
+
192
+ return signedTxns
193
+ }
194
+
195
+ const swap = await router.newSwap({
196
+ quote,
197
+ address: activeAddress,
198
+ signer: customSigner,
199
+ slippage: 1,
200
+ })
201
+ await swap.execute()
202
+ ```
203
+
204
+ The signer function supports two return patterns:
205
+
206
+ - **Pattern 1** (Pera, Defly, algosdk): Returns only the signed transactions as `Uint8Array[]`
207
+ - **Pattern 2** (Lute, ARC-1 compliant): Returns an array matching the transaction group length with `null` for unsigned transactions as `(Uint8Array | null)[]`
208
+
209
+ Both patterns are automatically handled by the SDK.
210
+
211
+ ### Advanced Transaction Composition
212
+
213
+ Build the transaction group by adding custom transactions and ABI method calls before or after the swap using the [`SwapComposer`](#swapcomposer) instance:
214
+
215
+ ```typescript
216
+ import { ABIMethod, Transaction } from 'algosdk'
217
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
218
+
219
+ const { activeAddress, transactionSigner } = useWallet()
220
+
221
+ // Create your custom transactions
222
+ const customTxn = new Transaction({...})
223
+
224
+ // Define an ABI method call
225
+ const methodCall = {
226
+ appID: 123456,
227
+ method: new ABIMethod({...}),
228
+ methodArgs: [...],
229
+ sender: activeAddress,
230
+ suggestedParams: await algodClient.getTransactionParams().do(),
231
+ }
232
+
233
+ // Build and execute the transaction group
234
+ const swap = await router.newSwap({
235
+ quote,
236
+ address: activeAddress,
237
+ signer: transactionSigner,
238
+ slippage: 1,
239
+ })
240
+
241
+ const result = await swap
242
+ .addTransaction(customTxn) // Add transaction before swap
243
+ .addSwapTransactions() // Add swap transactions
244
+ .addMethodCall(methodCall) // Add ABI method call after swap
245
+ .execute() // Sign and execute entire group
246
+ ```
247
+
248
+ ### Middleware for Custom Asset Requirements
249
+
250
+ Some Algorand assets require additional transactions to be added to swap groups (e.g., assets with transfer restrictions, taxes, or custom smart contract logic). The Haystack Router SDK supports a middleware system that allows these special requirements to be handled by external packages without modifying the core SDK.
251
+
252
+ Middleware can:
253
+ - Adjust quote parameters (e.g., reduce `maxGroupSize` to account for extra transactions)
254
+ - Add transactions before the swap (e.g., unfreeze account, setup calls)
255
+ - Add transactions after the swap (e.g., tax payments, cleanup calls)
256
+
257
+ ```typescript
258
+ import { RouterClient } from '@txnlab/haystack-router'
259
+ import { FirstStageMiddleware } from '@firststage/deflex-middleware' // Example external package
260
+
261
+ // Initialize middleware
262
+ const firstStage = new FirstStageMiddleware({
263
+ contractAppId: 123456,
264
+ })
265
+
266
+ // Pass middleware to RouterClient
267
+ const router = new RouterClient({
268
+ apiKey: 'your-api-key',
269
+ middleware: [firstStage], // Middleware is applied automatically
270
+ })
271
+
272
+ // Use normally - middleware handles everything
273
+ const quote = await router.newQuote({
274
+ fromASAID: 0, // ALGO
275
+ toASAID: 789012, // Custom asset (e.g., MOOJ, DEAL)
276
+ amount: 1_000_000,
277
+ address: userAddress,
278
+ })
279
+
280
+ const swap = await router.newSwap({ quote, address, signer, slippage: 1 })
281
+ await swap.execute() // Middleware transactions are automatically included
282
+ ```
283
+
284
+ #### Built-in Middleware
285
+
286
+ The SDK includes `AutoOptOutMiddleware`, which automatically opts out of assets when swapping your full balance, cleaning up zero balance assets and reducing minimum balance requirements:
287
+
288
+ ```typescript
289
+ import { RouterClient, AutoOptOutMiddleware } from '@txnlab/haystack-router'
290
+
291
+ const autoOptOut = new AutoOptOutMiddleware({
292
+ excludedAssets: [31566704], // Optional: exclude specific assets like USDC
293
+ })
294
+
295
+ const router = new RouterClient({
296
+ apiKey: 'your-api-key',
297
+ middleware: [autoOptOut],
298
+ })
299
+
300
+ // When swapping full balance, opt-out transaction is automatically added
301
+ const quote = await router.newQuote({
302
+ fromASAID: someAssetId,
303
+ toASAID: 0,
304
+ amount: fullBalance, // If this matches your full balance, asset will be opted out
305
+ address: userAddress,
306
+ })
307
+ ```
308
+
309
+ For details on creating your own middleware, see [MIDDLEWARE.md](MIDDLEWARE.md).
310
+
311
+ ### Manual Asset Opt-In Detection
312
+
313
+ If you're not using `autoOptIn: true`, you can manually check if opt-in is needed:
314
+
315
+ ```typescript
316
+ const router = new RouterClient({
317
+ apiKey: 'your-api-key',
318
+ autoOptIn: false, // Default if not provided
319
+ })
320
+
321
+ // Check if user needs to opt into the output asset
322
+ const needsOptIn = await router.needsAssetOptIn(userAddress, toAssetId)
323
+
324
+ // Include opt-in in quote if needed
325
+ const quote = await router.newQuote({
326
+ fromAssetId,
327
+ toAssetId,
328
+ amount,
329
+ optIn: needsOptIn,
330
+ })
331
+ ```
332
+
333
+ ### Error Handling
334
+
335
+ ```typescript
336
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
337
+
338
+ const { activeAddress, transactionSigner } = useWallet()
339
+
340
+ try {
341
+ const quote = await router.newQuote({
342
+ fromAssetId: 0,
343
+ toAssetId: 31566704,
344
+ amount: 1_000_000,
345
+ address: activeAddress,
346
+ })
347
+
348
+ const swap = await router.newSwap({
349
+ quote,
350
+ address: activeAddress,
351
+ signer: transactionSigner,
352
+ slippage: 1,
353
+ })
354
+ const result = await swap.execute()
355
+
356
+ console.log('Swap successful:', result)
357
+ } catch (error) {
358
+ console.error('Swap failed:', error.message)
359
+ }
360
+ ```
361
+
362
+ ## API Reference
363
+
364
+ ### RouterClient
365
+
366
+ The main client for interacting with the Haystack Router API.
367
+
368
+ ```typescript
369
+ new RouterClient(config: ConfigParams)
370
+ ```
371
+
372
+ | Option | Description | Type | Default |
373
+ | ----------------- | ------------------------------------------------------------ | --------------------- | -------------------------------------- |
374
+ | `apiKey` | Your Haystack Router API key | `string` | **required** |
375
+ | `apiBaseUrl` | Base URL for the Haystack Router API | `string` | `https://hayrouter.txnlab.dev` |
376
+ | `algodUri` | Algod node URI | `string` | `https://mainnet-api.4160.nodely.dev/` |
377
+ | `algodToken` | Algod node token | `string` | `''` |
378
+ | `algodPort` | Algod node port | `string \| number` | `443` |
379
+ | `referrerAddress` | Referrer address for fee sharing (receives 25% of swap fees) | `string` | `undefined` |
380
+ | `feeBps` | Fee in basis points (0.15%, max: 300 = 3.00%) | `number` | `15` |
381
+ | `autoOptIn` | Auto-detect and add required opt-in transactions | `boolean` | `false` |
382
+ | `middleware` | Array of middleware for custom asset requirements | `SwapMiddleware[]` | `[]` |
383
+
384
+ > **Referral Program**: By providing a `referrerAddress`, you can earn 25% of the swap fees generated through your integration. The `feeBps` parameter sets the total fee charged (default: 0.15%). Learn more about the [Haystack Router Referral Program](https://txnlab.gitbook.io/haystack-router-api/referral-treasury/referral-program).
385
+
386
+ #### RouterClient.newQuote()
387
+
388
+ Fetch a swap quote and return a [`SwapQuote`](#deflexquote) object.
389
+
390
+ ```typescript
391
+ async newQuote(params: FetchQuoteParams): Promise<SwapQuote>
392
+ ```
393
+
394
+ | Parameter | Description | Type | Default |
395
+ | ------------------- | ------------------------------------------ | --------------------------------- | --------------- |
396
+ | `fromASAID` | Input asset ID | `bigint \| number` | **required** |
397
+ | `toASAID` | Output asset ID | `bigint \| number` | **required** |
398
+ | `amount` | Amount to swap in base units | `bigint \| number` | **required** |
399
+ | `type` | Quote type | `'fixed-input' \| 'fixed-output'` | `'fixed-input'` |
400
+ | `address` | User address (recommended for auto opt-in) | `string` | `undefined` |
401
+ | `disabledProtocols` | Array of protocols to exclude | `Protocol[]` | `[]` |
402
+ | `maxGroupSize` | Maximum transactions in atomic group | `number` | `16` |
403
+ | `maxDepth` | Maximum swap hops | `number` | `4` |
404
+ | `optIn` | Override auto opt-in behavior | `boolean` | `undefined` |
405
+
406
+ #### RouterClient.newSwap()
407
+
408
+ Returns a [`SwapComposer`](#swapcomposer) instance for building and executing swaps.
409
+
410
+ ```typescript
411
+ async newSwap(config: SwapComposerConfig): Promise<SwapComposer>
412
+ ```
413
+
414
+ | Parameter | Description | Type |
415
+ | ---------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
416
+ | `quote` | Quote result or raw API response | `SwapQuote \| FetchQuoteResponse` |
417
+ | `address` | Signer address | `string` |
418
+ | `slippage` | Slippage tolerance as percentage (e.g., 1 for 1%) | `number` |
419
+ | `signer` | Transaction signer function | `algosdk.TransactionSigner \| ((txnGroup: Transaction[], indexesToSign: number[]) => Promise<(Uint8Array \| null)[]>)` |
420
+ | `note` | Optional note for the user-signed input transaction (for tracking purposes) | `Uint8Array` |
421
+
422
+ #### RouterClient.needsAssetOptIn()
423
+
424
+ Checks if an address needs to opt into an asset.
425
+
426
+ ```typescript
427
+ async needsAssetOptIn(address: string, assetId: bigint | number): Promise<boolean>
428
+ ```
429
+
430
+ | Parameter | Description | Type |
431
+ | --------- | ------------------------- | ------------------ |
432
+ | `address` | Algorand address to check | `string` |
433
+ | `assetId` | Asset ID to check | `bigint \| number` |
434
+
435
+ ### SwapQuote
436
+
437
+ Plain object returned by [`newQuote()`](#deflexclientnewquote). Extends the raw API response with additional metadata.
438
+
439
+ **Additional properties added by SDK:**
440
+
441
+ | Property | Description | Type |
442
+ | ----------- | ----------------------------------- | --------------------- |
443
+ | `quote` | Quoted amount (coerced to `bigint`) | `bigint` |
444
+ | `amount` | Original request amount | `bigint` |
445
+ | `address` | User address (if provided) | `string \| undefined` |
446
+ | `createdAt` | Timestamp when quote was created | `number` |
447
+
448
+ **All properties from API response:**
449
+
450
+ | Property | Description | Type |
451
+ | ------------------- | ------------------------------------------------ | ------------------------ |
452
+ | `fromASAID` | Input asset ID | `number` |
453
+ | `toASAID` | Output asset ID | `number` |
454
+ | `type` | Quote type (`'fixed-input'` or `'fixed-output'`) | `string` |
455
+ | `profit` | Profit information | `Profit` |
456
+ | `priceBaseline` | Baseline price without fees | `number` |
457
+ | `userPriceImpact` | Price impact for the user | `number \| undefined` |
458
+ | `marketPriceImpact` | Overall market price impact | `number \| undefined` |
459
+ | `usdIn` | USD value of input | `number` |
460
+ | `usdOut` | USD value of output | `number` |
461
+ | `route` | Routing path information | `Route[]` |
462
+ | `flattenedRoute` | Flattened routing percentages | `Record<string, number>` |
463
+ | `quotes` | Individual DEX quotes | `DexQuote[]` |
464
+ | `requiredAppOptIns` | Required app opt-ins | `number[]` |
465
+ | `txnPayload` | Encrypted transaction payload | `TxnPayload \| null` |
466
+ | `protocolFees` | Fees by protocol | `Record<string, number>` |
467
+ | `timing` | Performance timing data | `unknown \| undefined` |
468
+
469
+ ### SwapComposer
470
+
471
+ Builder for constructing and executing atomic swap transaction groups, returned by [`newSwap()`](#deflexclientnewswap).
472
+
473
+ | Method | Description | Parameters | Returns |
474
+ | -------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
475
+ | `addTransaction(transaction, signer?)` | Add a transaction to the atomic group | `transaction: algosdk.Transaction, signer?: TransactionSigner` | `SwapComposer` |
476
+ | `addMethodCall(methodCall, signer?)` | Add an ABI method call to the atomic group | `methodCall: MethodCall, signer?: TransactionSigner` | `SwapComposer` |
477
+ | `addSwapTransactions()` | Add swap transactions to the group (includes required app opt-ins) | None | `Promise<SwapComposer>` |
478
+ | `buildGroup()` | Build the transaction group and assign group IDs | None | `TransactionWithSigner[]` |
479
+ | `sign()` | Sign the transaction group | None | `Promise<Uint8Array[]>` |
480
+ | `submit()` | Sign and submit the transaction group | None | `Promise<string[]>` (transaction IDs) |
481
+ | `execute(waitRounds?)` | Sign, submit, and wait for confirmation | `waitRounds?: number` (default: 4) | `Promise<{ confirmedRound: bigint, txIds: string[], methodResults: ABIResult[] }>` |
482
+ | `getStatus()` | Get current status: `BUILDING`, `BUILT`, `SIGNED`, `SUBMITTED`, or `COMMITTED` | None | `SwapComposerStatus` |
483
+ | `count()` | Get the number of transactions in the group | None | `number` |
484
+ | `getInputTransactionId()` | Get the transaction ID of the user-signed input transaction (available after `buildGroup()`, `sign()`, or `execute()`) | None | `string \| undefined` |
485
+
486
+ ## Documentation
487
+
488
+ For more information about the Haystack Order Router protocol, visit the [official documentation](https://txnlab.gitbook.io/haystack-router-api).
489
+
490
+ ## License
491
+
492
+ MIT
493
+
494
+ ## Support
495
+
496
+ - [GitHub Issues](https://github.com/TxnLab/haystack-js/issues)
497
+ - [Discord](https://discord.gg/Ek3dNyzG)
498
+ - [TxnLab](https://txnlab.dev)
@@ -0,0 +1,38 @@
1
+ import { t as Logger } from "./logger-DUVOA2Oo.mjs";
2
+
3
+ //#region src/debug.ts
4
+ /**
5
+ * Debug utilities for swap execution failures
6
+ * @internal
7
+ */
8
+ /**
9
+ * Log detailed context when a swap execution fails
10
+ * Only logs when debug level is enabled
11
+ */
12
+ function logSwapExecutionFailure(context, error) {
13
+ Logger.debug("Swap execution failed", {
14
+ error: error instanceof Error ? error.message : String(error),
15
+ quote: {
16
+ fromASAID: context.quote.fromASAID,
17
+ toASAID: context.quote.toASAID,
18
+ type: context.quote.type,
19
+ quote: context.quote.quote.toString(),
20
+ requiredAppOptIns: context.quote.requiredAppOptIns,
21
+ route: context.quote.route?.map((r) => ({
22
+ percentage: r.percentage,
23
+ path: r.path.map((p) => p.name).join(" → ")
24
+ }))
25
+ },
26
+ swap: {
27
+ address: context.address,
28
+ slippage: context.slippage,
29
+ transactionCount: context.transactionCount,
30
+ middlewareCount: context.middlewareCount,
31
+ groupSize: context.groupSize
32
+ }
33
+ });
34
+ }
35
+
36
+ //#endregion
37
+ export { logSwapExecutionFailure };
38
+ //# sourceMappingURL=debug-8aRsrfhx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-8aRsrfhx.mjs","names":[],"sources":["../src/debug.ts"],"sourcesContent":["/**\n * Debug utilities for swap execution failures\n * @internal\n */\n\nimport { Logger } from './logger'\nimport type { SwapQuote, FetchQuoteResponse } from './types'\n\n/**\n * Context for swap execution debugging\n */\nexport interface SwapExecutionContext {\n quote: SwapQuote | FetchQuoteResponse\n address: string\n slippage: number\n transactionCount: number\n middlewareCount: number\n groupSize: number\n}\n\n/**\n * Log detailed context when a swap execution fails\n * Only logs when debug level is enabled\n */\nexport function logSwapExecutionFailure(\n context: SwapExecutionContext,\n error: unknown,\n): void {\n Logger.debug('Swap execution failed', {\n error: error instanceof Error ? error.message : String(error),\n quote: {\n fromASAID: context.quote.fromASAID,\n toASAID: context.quote.toASAID,\n type: context.quote.type,\n quote: context.quote.quote.toString(),\n requiredAppOptIns: context.quote.requiredAppOptIns,\n route: context.quote.route?.map((r) => ({\n percentage: r.percentage,\n path: r.path.map((p) => p.name).join(' → '),\n })),\n },\n swap: {\n address: context.address,\n slippage: context.slippage,\n transactionCount: context.transactionCount,\n middlewareCount: context.middlewareCount,\n groupSize: context.groupSize,\n },\n })\n}\n"],"mappings":";;;;;;;;;;;AAwBA,SAAgB,wBACd,SACA,OACM;AACN,QAAO,MAAM,yBAAyB;EACpC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;EAC7D,OAAO;GACL,WAAW,QAAQ,MAAM;GACzB,SAAS,QAAQ,MAAM;GACvB,MAAM,QAAQ,MAAM;GACpB,OAAO,QAAQ,MAAM,MAAM,UAAU;GACrC,mBAAmB,QAAQ,MAAM;GACjC,OAAO,QAAQ,MAAM,OAAO,KAAK,OAAO;IACtC,YAAY,EAAE;IACd,MAAM,EAAE,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,MAAM;IAC5C,EAAE;GACJ;EACD,MAAM;GACJ,SAAS,QAAQ;GACjB,UAAU,QAAQ;GAClB,kBAAkB,QAAQ;GAC1B,iBAAiB,QAAQ;GACzB,WAAW,QAAQ;GACpB;EACF,CAAC"}