@txnlab/haystack-router 2.0.4 → 3.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/README.md CHANGED
@@ -10,16 +10,23 @@ TypeScript/JavaScript SDK for [Haystack Order Router](https://txnlab.gitbook.io/
10
10
 
11
11
  ## Prerequisites
12
12
 
13
- - **Haystack Router API Key** - Request an API key by emailing [support@txnlab.dev](mailto:support@txnlab.dev)
13
+ - **Haystack Router API Key** - A free tier key is included below for development and testing (60 requests/min). For production rate limits, request a dedicated key from [support@txnlab.dev](mailto:support@txnlab.dev).
14
14
  - algosdk 3.0.0 or later
15
15
 
16
+ ### API Key Tiers
17
+
18
+ | Tier | Key | Rate Limit | Use Case |
19
+ | --- | --- | --- | --- |
20
+ | **Free** | `1b72df7e-1131-4449-8ce1-29b79dd3f51e` | 60 requests/min | Development, testing, low-volume integrations |
21
+ | **Production** | Request from [support@txnlab.dev](mailto:support@txnlab.dev) | Higher limits | Production applications |
22
+
16
23
  ## Installation
17
24
 
18
25
  ```bash
19
26
  npm install @txnlab/haystack-router algosdk
20
27
  ```
21
28
 
22
- > **Note**: `algosdk` is a peer dependency and must be installed alongside `@txnlab/haystack-router`.
29
+ > **Note**: Requires Node.js 22 or later. `algosdk` is a peer dependency and must be installed alongside `@txnlab/haystack-router`.
23
30
 
24
31
  ## Quick Start
25
32
 
@@ -31,7 +38,7 @@ const { activeAddress, transactionSigner } = useWallet()
31
38
 
32
39
  // Initialize the client
33
40
  const router = new RouterClient({
34
- apiKey: 'your-api-key',
41
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
35
42
  })
36
43
 
37
44
  // Get a quote
@@ -63,12 +70,12 @@ import { RouterClient } from '@txnlab/haystack-router'
63
70
 
64
71
  // Basic initialization
65
72
  const router = new RouterClient({
66
- apiKey: 'your-api-key',
73
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
67
74
  })
68
75
 
69
76
  // Custom Algod configuration
70
77
  const router = new RouterClient({
71
- apiKey: 'your-api-key',
78
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
72
79
  algodUri: 'https://mainnet-api.4160.nodely.dev/',
73
80
  algodToken: '',
74
81
  algodPort: 443,
@@ -77,7 +84,7 @@ const router = new RouterClient({
77
84
 
78
85
  // Earn fees with the referral program
79
86
  const router = new RouterClient({
80
- apiKey: 'your-api-key',
87
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
81
88
  referrerAddress: 'YOUR_ALGORAND_ADDRESS', // Earns 25% of swap fees
82
89
  feeBps: 15, // 0.15% fee (max: 300 = 3%)
83
90
  })
@@ -142,6 +149,41 @@ console.log('Input transaction ID:', inputTxId)
142
149
 
143
150
  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
151
 
152
+ ### Launch Tokens (Pre-Bonding)
153
+
154
+ API keys with launch-token access can swap any asset into or out of a HayLaunch token that is still on its bonding curve. Quote it like any other asset, as a `fixed-input` swap, and pass the same `slippage` you will execute with:
155
+
156
+ ```typescript
157
+ const quote = await router.newQuote({
158
+ fromASAID: 31566704, // USDC
159
+ toASAID: launchTokenAssetId, // pre-bonding launch token
160
+ amount: 10_000_000,
161
+ slippage: 1, // same value as newSwap() below
162
+ address: activeAddress,
163
+ })
164
+
165
+ if (quote.launch) {
166
+ // quote.quote: launch tokens out (buy) or output asset (sell)
167
+ // quote.launch.bondingSurplus: bonding asset left in the wallet
168
+ // quote.launch.refund: bonding asset refunded when a buy completes bonding
169
+ }
170
+
171
+ const swap = await router.newSwap({
172
+ quote,
173
+ address: activeAddress,
174
+ signer: transactionSigner,
175
+ slippage: 1,
176
+ })
177
+ await swap.execute()
178
+
179
+ const summary = swap.getSummary()
180
+ // summary.outputAmount: launch tokens credited (buy)
181
+ // summary.inputAmount: launch tokens sold (sell)
182
+ // summary.launch: the curve call's ID, bonding amount and refund
183
+ ```
184
+
185
+ Without `slippage`, a launch quote overstates the output by about the slippage; `newSwap()` logs a warning when the two don't match. Fixed-output launch buys and launch-token-to-launch-token swaps aren't supported yet and return a 400.
186
+
145
187
  ### Transaction Signing
146
188
 
147
189
  The SDK supports both standard `algosdk.TransactionSigner` and ARC-1 compliant signer functions.
@@ -265,7 +307,7 @@ const firstStage = new FirstStageMiddleware({
265
307
 
266
308
  // Pass middleware to RouterClient
267
309
  const router = new RouterClient({
268
- apiKey: 'your-api-key',
310
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
269
311
  middleware: [firstStage], // Middleware is applied automatically
270
312
  })
271
313
 
@@ -293,7 +335,7 @@ const autoOptOut = new AutoOptOutMiddleware({
293
335
  })
294
336
 
295
337
  const router = new RouterClient({
296
- apiKey: 'your-api-key',
338
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
297
339
  middleware: [autoOptOut],
298
340
  })
299
341
 
@@ -314,7 +356,7 @@ If you're not using `autoOptIn: true`, you can manually check if opt-in is neede
314
356
 
315
357
  ```typescript
316
358
  const router = new RouterClient({
317
- apiKey: 'your-api-key',
359
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
318
360
  autoOptIn: false, // Default if not provided
319
361
  })
320
362
 
@@ -402,6 +444,7 @@ async newQuote(params: FetchQuoteParams): Promise<SwapQuote>
402
444
  | `maxGroupSize` | Maximum transactions in atomic group | `number` | `16` |
403
445
  | `maxDepth` | Maximum swap hops | `number` | `4` |
404
446
  | `optIn` | Override auto opt-in behavior | `boolean` | `undefined` |
447
+ | `slippage` | Slippage % you will execute with, in [0, 100); required for accurate launch token quotes | `number` | `undefined` |
405
448
 
406
449
  #### RouterClient.newSwap()
407
450
 
@@ -443,6 +486,8 @@ Plain object returned by [`newQuote()`](#routerclientnewquote). Extends the raw
443
486
  | `quote` | Quoted amount (coerced to `bigint`) | `bigint` |
444
487
  | `amount` | Original request amount | `bigint` |
445
488
  | `address` | User address (if provided) | `string \| undefined` |
489
+ | `slippage` | Slippage sent with the quote request (if provided) | `number \| undefined` |
490
+ | `launch` | Bonding-curve details for a pre-bonding launch token (amounts as `bigint`) | `SwapLaunchQuote \| undefined` |
446
491
  | `createdAt` | Timestamp when quote was created | `number` |
447
492
 
448
493
  **All properties from API response:**
@@ -1,5 +1,4 @@
1
- import { t as Logger } from "./logger-DUVOA2Oo.mjs";
2
-
1
+ import { t as Logger } from "./logger-BelK6H0R.mjs";
3
2
  //#region src/debug.ts
4
3
  /**
5
4
  * Debug utilities for swap execution failures
@@ -16,6 +15,7 @@ function logSwapExecutionFailure(context, error) {
16
15
  fromASAID: context.quote.fromASAID,
17
16
  toASAID: context.quote.toASAID,
18
17
  type: context.quote.type,
18
+ amount: "amount" in context.quote ? context.quote.amount.toString() : void 0,
19
19
  quote: context.quote.quote.toString(),
20
20
  requiredAppOptIns: context.quote.requiredAppOptIns,
21
21
  route: context.quote.route?.map((r) => ({
@@ -32,7 +32,7 @@ function logSwapExecutionFailure(context, error) {
32
32
  }
33
33
  });
34
34
  }
35
-
36
35
  //#endregion
37
36
  export { logSwapExecutionFailure };
38
- //# sourceMappingURL=debug-8aRsrfhx.mjs.map
37
+
38
+ //# sourceMappingURL=debug-CU-Ps4nm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-CU-Ps4nm.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 amount:\n 'amount' in context.quote ? context.quote.amount.toString() : undefined,\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;CACN,OAAO,MAAM,yBAAyB;EACpC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC5D,OAAO;GACL,WAAW,QAAQ,MAAM;GACzB,SAAS,QAAQ,MAAM;GACvB,MAAM,QAAQ,MAAM;GACpB,QACE,YAAY,QAAQ,QAAQ,QAAQ,MAAM,OAAO,SAAS,IAAI,KAAA;GAChE,OAAO,QAAQ,MAAM,MAAM,SAAS;GACpC,mBAAmB,QAAQ,MAAM;GACjC,OAAO,QAAQ,MAAM,OAAO,KAAK,OAAO;IACtC,YAAY,EAAE;IACd,MAAM,EAAE,KAAK,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK;GAC5C,EAAE;EACJ;EACA,MAAM;GACJ,SAAS,QAAQ;GACjB,UAAU,QAAQ;GAClB,kBAAkB,QAAQ;GAC1B,iBAAiB,QAAQ;GACzB,WAAW,QAAQ;EACrB;CACF,CAAC;AACH"}