Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

Haystack Router SDK is a TypeScript/JavaScript SDK for the Haystack Order Router - smart order routing and DEX aggregation on Algorand. This is a pnpm workspace monorepo containing the SDK package and example implementations.

> **Note:** This SDK was migrated from `@txnlab/deflex` (TxnLab/deflex-js) to `@txnlab/haystack-router` (TxnLab/haystack-js) as part of a rebranding effort. See [MIGRATION.md](../MIGRATION.md) for details on migrating from the old package.

## Commands

```bash
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This repository contains the Haystack Router SDK and example implementations for

### [@txnlab/haystack-router](./packages/haystack)

TypeScript/JavaScript SDK for [Haystack Order Router](https://txnlab.gitbook.io/haystack-router-api) - smart order routing and DEX aggregation on Algorand.
TypeScript/JavaScript SDK for [Haystack Order Router](https://txnlab.gitbook.io/deflex-api) - smart order routing and DEX aggregation on Algorand.

- **Documentation**: [packages/haystack/README.md](./packages/haystack/README.md)
- **npm**: [@txnlab/haystack-router](https://www.npmjs.com/package/@txnlab/haystack-router)
Expand Down Expand Up @@ -160,7 +160,7 @@ Root-level scripts:

- **SDK Documentation**: [packages/haystack/README.md](./packages/haystack/README.md)
- **Examples Guide**: [examples/README.md](./examples/README.md)
- **Haystack Router API Docs**: [https://txnlab.gitbook.io/haystack-router-api](https://txnlab.gitbook.io/haystack-router-api)
- **API Docs**: [https://txnlab.gitbook.io/deflex-api](https://txnlab.gitbook.io/deflex-api) _(Haystack Router documentation coming soon)_

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,4 @@ The monorepo structure enables a smooth development workflow:

- [GitHub Issues](https://github.com/TxnLab/haystack-js/issues)
- [Discord](https://discord.gg/Ek3dNyzG)
- [Documentation](https://txnlab.gitbook.io/haystack-router-api)
- [Documentation](https://txnlab.gitbook.io/deflex-api)
2 changes: 1 addition & 1 deletion examples/node-cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ async function executeSwap() {
)
console.log(` Slippage: ${config.slippage}%\n`)

// Initialize Deflex client
// Initialize Haystack Router client
const router = new RouterClient({
apiKey: config.apiKey,
autoOptIn: true,
Expand Down
6 changes: 3 additions & 3 deletions packages/haystack/MIDDLEWARE.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ async beforeSwap(context: SwapContext): Promise<TransactionWithSigner[]> {
"default": "./dist/index.js"
}
},
"keywords": ["deflex", "algorand", "dex", "middleware"],
"keywords": ["haystack-router", "algorand", "dex", "middleware"],
"peerDependencies": {
"@txnlab/haystack-router": "^1.2.0",
"algosdk": "^3.0.0"
Expand All @@ -351,7 +351,7 @@ Include clear usage instructions:
````markdown
# CustomAsset Haystack Router Middleware

Middleware for swapping CustomAsset tokens via Deflex.
Middleware for swapping CustomAsset tokens via Haystack Router.

## Installation

Expand Down Expand Up @@ -392,7 +392,7 @@ If your middleware adds ANY transactions via `beforeSwap()` or `afterSwap()`, yo
**Why this is critical:**
- Algorand has a hard limit of 16 transactions per atomic group
- Haystack Router API will optimize routes to use as many transactions as the `maxGroupSize` allows
- If Deflex returns a 16-transaction route and you try to add more, the transaction will **fail**
- If Haystack Router returns a 16-transaction route and you try to add more, the transaction will **fail**

**Example:**
```typescript
Expand Down
20 changes: 10 additions & 10 deletions packages/haystack/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Haystack Router SDK

[![npm version](https://img.shields.io/npm/v/@txnlab/haystack-router.svg)](https://www.npmjs.com/package/@txnlab/haystack-router)
[![bundle size](https://deno.bundlejs.com/badge?q=@txnlab/haystack-router@latest&treeshake=[*])](https://bundlejs.com/?q=%40txnlab%2Fdeflex%40latest&treeshake=%5B*%5D)
[![bundle size](https://deno.bundlejs.com/badge?q=@txnlab/haystack-router@latest&treeshake=[*])](https://bundlejs.com/?q=%40txnlab%2Fhaystack-router%40latest&treeshake=%5B*%5D)
[![CI](https://github.com/TxnLab/haystack-js/actions/workflows/ci.yml/badge.svg)](https://github.com/TxnLab/haystack-js/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)

TypeScript/JavaScript SDK for [Haystack Order Router](https://txnlab.gitbook.io/haystack-router-api) - smart order routing and DEX aggregation on Algorand.
TypeScript/JavaScript SDK for [Haystack Order Router](https://txnlab.gitbook.io/deflex-api) - smart order routing and DEX aggregation on Algorand.

## Prerequisites

Expand Down Expand Up @@ -83,11 +83,11 @@ const router = new RouterClient({
})
```

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).
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/deflex-api/referral-treasury/referral-program).

### Get a Swap Quote

The [`newQuote()`](#deflexclientnewquote) method returns a [`SwapQuote`](#deflexquote) object:
The [`newQuote()`](#routerclientnewquote) method returns a [`SwapQuote`](#swapquote) object:

```typescript
// Basic quote
Expand All @@ -101,7 +101,7 @@ const quote = await router.newQuote({

### Execute a Swap

The [`newSwap()`](#deflexclientnewswap) method returns a [`SwapComposer`](#swapcomposer) instance:
The [`newSwap()`](#routerclientnewswap) method returns a [`SwapComposer`](#swapcomposer) instance:

```typescript
import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
Expand Down Expand Up @@ -381,11 +381,11 @@ new RouterClient(config: ConfigParams)
| `autoOptIn` | Auto-detect and add required opt-in transactions | `boolean` | `false` |
| `middleware` | Array of middleware for custom asset requirements | `SwapMiddleware[]` | `[]` |

> **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).
> **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/deflex-api/referral-treasury/referral-program).

#### RouterClient.newQuote()

Fetch a swap quote and return a [`SwapQuote`](#deflexquote) object.
Fetch a swap quote and return a [`SwapQuote`](#swapquote) object.

```typescript
async newQuote(params: FetchQuoteParams): Promise<SwapQuote>
Expand Down Expand Up @@ -434,7 +434,7 @@ async needsAssetOptIn(address: string, assetId: bigint | number): Promise<boolea

### SwapQuote

Plain object returned by [`newQuote()`](#deflexclientnewquote). Extends the raw API response with additional metadata.
Plain object returned by [`newQuote()`](#routerclientnewquote). Extends the raw API response with additional metadata.

**Additional properties added by SDK:**

Expand Down Expand Up @@ -468,7 +468,7 @@ Plain object returned by [`newQuote()`](#deflexclientnewquote). Extends the raw

### SwapComposer

Builder for constructing and executing atomic swap transaction groups, returned by [`newSwap()`](#deflexclientnewswap).
Builder for constructing and executing atomic swap transaction groups, returned by [`newSwap()`](#routerclientnewswap).

| Method | Description | Parameters | Returns |
| -------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
Expand All @@ -485,7 +485,7 @@ Builder for constructing and executing atomic swap transaction groups, returned

## Documentation

For more information about the Haystack Order Router protocol, visit the [official documentation](https://txnlab.gitbook.io/haystack-router-api).
For more information about the Haystack Order Router protocol, visit the [official documentation](https://txnlab.gitbook.io/deflex-api).

## License

Expand Down
6 changes: 3 additions & 3 deletions packages/haystack/src/composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ export class SwapComposer {
delete txn.group

if (swapTxn.signature !== false) {
// Pre-signed transaction - use custom Deflex signer
// Pre-signed transaction - use custom Haystack Router signer
swapTxns.push({
txn,
signer: this.createSwapSigner(swapTxn.signature),
Expand Down Expand Up @@ -728,7 +728,7 @@ export class SwapComposer {
}

/**
* Creates a TransactionSigner function for Deflex pre-signed transactions
* Creates a TransactionSigner function for Haystack Router pre-signed transactions
*/
private createSwapSigner(signature: Signature): TransactionSigner {
return async (
Expand All @@ -744,7 +744,7 @@ export class SwapComposer {
}

/**
* Re-signs a Deflex transaction using the provided logic signature or secret key
* Re-signs a Haystack Router transaction using the provided logic signature or secret key
*/
private signSwapTransaction(
transaction: Transaction,
Expand Down
2 changes: 1 addition & 1 deletion packages/haystack/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export interface SwapContext {
}

/**
* Middleware interface for extending Deflex swap functionality
* Middleware interface for extending Haystack Router swap functionality
*
* Middleware allows you to modify quote parameters and inject additional transactions
* into the atomic swap group. This is useful for assets that require special handling,
Expand Down
44 changes: 18 additions & 26 deletions packages/haystack/tests/composer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ describe('SwapComposer', () => {
logicSig,
)

const mockPreSignedDeflexTxn: SwapTransaction = {
const mockPreSignedSwapTxn: SwapTransaction = {
data: Buffer.from(
algosdk.encodeUnsignedTransaction(preSignedTxn),
).toString('base64'),
Expand All @@ -981,15 +981,11 @@ describe('SwapComposer', () => {
logicSigBlob: false,
}

const mockUserDeflexTxn: SwapTransaction = createMockSwapTxn()
const mockUserSwapTxn: SwapTransaction = createMockSwapTxn()

const composer = new SwapComposer({
quote: createMockQuote() as FetchQuoteResponse,
swapTxns: [
mockUserDeflexTxn,
mockPreSignedDeflexTxn,
mockUserDeflexTxn,
],
swapTxns: [mockUserSwapTxn, mockPreSignedSwapTxn, mockUserSwapTxn],
algodClient: mockAlgodClient,
address: validAddress,
signer: async (
Expand Down Expand Up @@ -1024,7 +1020,7 @@ describe('SwapComposer', () => {
logicSig,
)

const mockPreSignedDeflexTxn: SwapTransaction = {
const mockPreSignedSwapTxn: SwapTransaction = {
data: Buffer.from(
algosdk.encodeUnsignedTransaction(preSignedTxn),
).toString('base64'),
Expand All @@ -1038,15 +1034,11 @@ describe('SwapComposer', () => {
logicSigBlob: false,
}

const mockUserDeflexTxn: SwapTransaction = createMockSwapTxn()
const mockUserSwapTxn: SwapTransaction = createMockSwapTxn()

const composer = new SwapComposer({
quote: createMockQuote() as FetchQuoteResponse,
swapTxns: [
mockUserDeflexTxn,
mockPreSignedDeflexTxn,
mockUserDeflexTxn,
],
swapTxns: [mockUserSwapTxn, mockPreSignedSwapTxn, mockUserSwapTxn],
algodClient: mockAlgodClient,
address: validAddress,
signer: async (
Expand Down Expand Up @@ -1552,7 +1544,7 @@ describe('SwapComposer', () => {
const txn = createMockTransaction(appAddress.toString())
const signedTxn = algosdk.signLogicSigTransactionObject(txn, logicSig)

const mockDeflexLsigTxn: SwapTransaction = {
const mockLsigSwapTxn: SwapTransaction = {
data: Buffer.from(algosdk.encodeUnsignedTransaction(txn)).toString(
'base64',
),
Expand All @@ -1568,7 +1560,7 @@ describe('SwapComposer', () => {

const composer = new SwapComposer({
quote: createMockQuote() as FetchQuoteResponse,
swapTxns: [mockDeflexLsigTxn],
swapTxns: [mockLsigSwapTxn],
algodClient: mockAlgodClient,
address: validAddress,
signer: async (txns: algosdk.Transaction[]) =>
Expand All @@ -1586,7 +1578,7 @@ describe('SwapComposer', () => {
const account = algosdk.generateAccount()
const txn = createMockTransaction(account.addr.toString())

const mockDeflexSkTxn: SwapTransaction = {
const mockSkSwapTxn: SwapTransaction = {
data: Buffer.from(algosdk.encodeUnsignedTransaction(txn)).toString(
'base64',
),
Expand All @@ -1602,7 +1594,7 @@ describe('SwapComposer', () => {

const composer = new SwapComposer({
quote: createMockQuote() as FetchQuoteResponse,
swapTxns: [mockDeflexSkTxn],
swapTxns: [mockSkSwapTxn],
algodClient: mockAlgodClient,
address: validAddress,
signer: async (txns: algosdk.Transaction[]) =>
Expand Down Expand Up @@ -1661,7 +1653,7 @@ describe('SwapComposer', () => {

await composer.addSwapTransactions()

// Error happens during signing when the Deflex signer is called
// Error happens during signing when the swap signer is called
await expect(composer.sign()).rejects.toThrow(
'Logic signature structure missing lsig field',
)
Expand Down Expand Up @@ -1693,7 +1685,7 @@ describe('SwapComposer', () => {

await composer.addSwapTransactions()

// Error happens during signing when the Deflex signer is called
// Error happens during signing when the swap signer is called
await expect(composer.sign()).rejects.toThrow(
'Unsupported signature type',
)
Expand Down Expand Up @@ -1770,7 +1762,7 @@ describe('SwapComposer', () => {
logicSig,
)

const mockPreSignedDeflexTxn: SwapTransaction = {
const mockPreSignedSwapTxn: SwapTransaction = {
data: Buffer.from(
algosdk.encodeUnsignedTransaction(preSignedTxn),
).toString('base64'),
Expand All @@ -1784,7 +1776,7 @@ describe('SwapComposer', () => {
logicSigBlob: false,
}

const mockUserDeflexTxn: SwapTransaction = {
const mockUserSwapTxn: SwapTransaction = {
data: Buffer.from(
algosdk.encodeUnsignedTransaction(createMockTransaction()),
).toString('base64'),
Expand All @@ -1797,7 +1789,7 @@ describe('SwapComposer', () => {

const composer = new SwapComposer({
quote: createMockQuote() as FetchQuoteResponse,
swapTxns: [mockPreSignedDeflexTxn, mockUserDeflexTxn],
swapTxns: [mockPreSignedSwapTxn, mockUserSwapTxn],
algodClient: mockAlgodClient,
address: validAddress,
signer: async (txns: algosdk.Transaction[]) =>
Expand Down Expand Up @@ -2023,7 +2015,7 @@ describe('SwapComposer', () => {
logicSig,
)

const mockPreSignedDeflexTxn: SwapTransaction = {
const mockPreSignedSwapTxn: SwapTransaction = {
data: Buffer.from(
algosdk.encodeUnsignedTransaction(preSignedTxn),
).toString('base64'),
Expand All @@ -2037,7 +2029,7 @@ describe('SwapComposer', () => {
logicSigBlob: false,
}

const mockUserDeflexTxn: SwapTransaction = {
const mockUserSwapTxn: SwapTransaction = {
data: Buffer.from(
algosdk.encodeUnsignedTransaction(createMockTransaction()),
).toString('base64'),
Expand All @@ -2048,7 +2040,7 @@ describe('SwapComposer', () => {

const composer = new SwapComposer({
quote: createMockQuote() as FetchQuoteResponse,
swapTxns: [mockPreSignedDeflexTxn, mockUserDeflexTxn],
swapTxns: [mockPreSignedSwapTxn, mockUserSwapTxn],
algodClient: mockAlgodClient,
address: validAddress,
signer: async (txns: algosdk.Transaction[]) =>
Expand Down