@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 +54 -9
- package/dist/{debug-8aRsrfhx.mjs → debug-CU-Ps4nm.mjs} +4 -4
- package/dist/debug-CU-Ps4nm.mjs.map +1 -0
- package/dist/index.d.mts +160 -57
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +214 -78
- package/dist/index.mjs.map +1 -1
- package/dist/{logger-DUVOA2Oo.mjs → logger-BelK6H0R.mjs} +17 -26
- package/dist/{logger-DUVOA2Oo.mjs.map → logger-BelK6H0R.mjs.map} +1 -1
- package/package.json +10 -10
- package/dist/debug-8aRsrfhx.mjs.map +0 -1
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** -
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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-
|
|
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
|
-
|
|
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"}
|