
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@txnlab/deflex
Advanced tools
DEPRECATED: This package has been renamed to @txnlab/haystack-router. TypeScript/JavaScript SDK for Deflex Order Router - smart order routing and DEX aggregation on Algorand
This package has been renamed to @txnlab/haystack-router and will no longer receive updates.
Please migrate to the new package:
npm uninstall @txnlab/deflex
npm install @txnlab/haystack-router
See the migration guide for details.
TypeScript/JavaScript SDK for Deflex Order Router - smart order routing and DEX aggregation on Algorand.
npm install @txnlab/deflex algosdk
Note:
algosdkis a peer dependency and must be installed alongside@txnlab/deflex.
import { DeflexClient } from '@txnlab/deflex'
import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
const { activeAddress, transactionSigner } = useWallet()
// Initialize the client
const deflex = new DeflexClient({
apiKey: 'your-api-key',
})
// Get a quote
const quote = await deflex.newQuote({
address: activeAddress,
fromAssetId: 0, // ALGO
toAssetId: 31566704, // USDC
amount: 1_000_000, // 1 ALGO (in microAlgos)
})
// Execute the swap
const swap = await deflex.newSwap({
quote,
address: activeAddress,
signer: transactionSigner,
slippage: 1, // 1% slippage tolerance
})
const result = await swap.execute()
console.log(`Swap completed in round ${result.confirmedRound}`)
import { DeflexClient } from '@txnlab/deflex'
// Basic initialization
const deflex = new DeflexClient({
apiKey: 'your-api-key',
})
// Custom Algod configuration
const deflex = new DeflexClient({
apiKey: 'your-api-key',
algodUri: 'https://mainnet-api.4160.nodely.dev/',
algodToken: '',
algodPort: 443,
autoOptIn: true, // Automatically handle asset opt-ins
})
// Earn fees with the referral program
const deflex = new DeflexClient({
apiKey: 'your-api-key',
referrerAddress: 'YOUR_ALGORAND_ADDRESS', // Earns 25% of swap fees
feeBps: 15, // 0.15% fee (max: 300 = 3%)
})
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 Deflex Referral Program.
The newQuote() method returns a DeflexQuote object:
// Basic quote
const quote = await deflex.newQuote({
fromASAID: 0, // ALGO
toASAID: 31566704, // USDC
amount: 1_000_000, // 1 ALGO
address: userAddress, // Required for auto opt-in detection
})
The newSwap() method returns a SwapComposer instance:
import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
const { activeAddress, transactionSigner } = useWallet()
const swap = await deflex.newSwap({
quote,
address: activeAddress,
signer: transactionSigner,
slippage: 1, // 1% slippage tolerance
})
const result = await swap.execute()
console.log(`Confirmed in round ${result.confirmedRound}`)
console.log('Transaction IDs:', result.txIds)
Add a custom note to the input transaction for tracking purposes, and retrieve its transaction ID after execution:
const swap = await deflex.newSwap({
quote,
address: activeAddress,
signer: transactionSigner,
slippage: 1,
note: new TextEncoder().encode('tracking-id-123'), // Custom note for tracking
})
const result = await swap.execute()
// Get the transaction ID of the user-signed input transaction
const inputTxId = swap.getInputTransactionId()
console.log('Input transaction ID:', inputTxId)
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().
The SDK supports both standard algosdk.TransactionSigner and ARC-1 compliant signer functions.
Use the @txnlab/use-wallet library for wallet management in your dApp:
import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
const { activeAddress, transactionSigner } = useWallet()
const swap = await deflex.newSwap({
quote,
address: activeAddress,
signer: transactionSigner,
slippage: 1,
})
await swap.execute()
Tip: The
@txnlab/use-walletlibrary 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.
The SDK accepts custom signer functions that receive the complete transaction group and an array of indexes indicating which transactions need signing:
import { Address, encodeUnsignedTransaction, type Transaction } from 'algosdk'
// Example: Wrapping an ARC-1 compliant wallet
const customSigner = async (
txnGroup: Transaction[],
indexesToSign: number[],
) => {
// Convert to wallet's expected format
const walletTxns = txnGroup.map((txn, index) => ({
txn: Buffer.from(encodeUnsignedTransaction(txn)).toString('base64'),
signers: indexesToSign.includes(index)
? [Address.fromString(activeAddress)]
: [],
}))
// Sign with wallet provider
const signedTxns = await walletProvider.signTxns(walletTxns)
return signedTxns
}
const swap = await deflex.newSwap({
quote,
address: activeAddress,
signer: customSigner,
slippage: 1,
})
await swap.execute()
The signer function supports two return patterns:
Uint8Array[]null for unsigned transactions as (Uint8Array | null)[]Both patterns are automatically handled by the SDK.
Build the transaction group by adding custom transactions and ABI method calls before or after the swap using the SwapComposer instance:
import { ABIMethod, Transaction } from 'algosdk'
import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
const { activeAddress, transactionSigner } = useWallet()
// Create your custom transactions
const customTxn = new Transaction({...})
// Define an ABI method call
const methodCall = {
appID: 123456,
method: new ABIMethod({...}),
methodArgs: [...],
sender: activeAddress,
suggestedParams: await algodClient.getTransactionParams().do(),
}
// Build and execute the transaction group
const swap = await deflex.newSwap({
quote,
address: activeAddress,
signer: transactionSigner,
slippage: 1,
})
const result = await swap
.addTransaction(customTxn) // Add transaction before swap
.addSwapTransactions() // Add swap transactions
.addMethodCall(methodCall) // Add ABI method call after swap
.execute() // Sign and execute entire group
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 Deflex SDK supports a middleware system that allows these special requirements to be handled by external packages without modifying the core SDK.
Middleware can:
maxGroupSize to account for extra transactions)import { DeflexClient } from '@txnlab/deflex'
import { FirstStageMiddleware } from '@firststage/deflex-middleware' // Example external package
// Initialize middleware
const firstStage = new FirstStageMiddleware({
contractAppId: 123456,
})
// Pass middleware to DeflexClient
const deflex = new DeflexClient({
apiKey: 'your-api-key',
middleware: [firstStage], // Middleware is applied automatically
})
// Use normally - middleware handles everything
const quote = await deflex.newQuote({
fromASAID: 0, // ALGO
toASAID: 789012, // Custom asset (e.g., MOOJ, DEAL)
amount: 1_000_000,
address: userAddress,
})
const swap = await deflex.newSwap({ quote, address, signer, slippage: 1 })
await swap.execute() // Middleware transactions are automatically included
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:
import { DeflexClient, AutoOptOutMiddleware } from '@txnlab/deflex'
const autoOptOut = new AutoOptOutMiddleware({
excludedAssets: [31566704], // Optional: exclude specific assets like USDC
})
const deflex = new DeflexClient({
apiKey: 'your-api-key',
middleware: [autoOptOut],
})
// When swapping full balance, opt-out transaction is automatically added
const quote = await deflex.newQuote({
fromASAID: someAssetId,
toASAID: 0,
amount: fullBalance, // If this matches your full balance, asset will be opted out
address: userAddress,
})
For details on creating your own middleware, see MIDDLEWARE.md.
If you're not using autoOptIn: true, you can manually check if opt-in is needed:
const deflex = new DeflexClient({
apiKey: 'your-api-key',
autoOptIn: false, // Default if not provided
})
// Check if user needs to opt into the output asset
const needsOptIn = await deflex.needsAssetOptIn(userAddress, toAssetId)
// Include opt-in in quote if needed
const quote = await deflex.newQuote({
fromAssetId,
toAssetId,
amount,
optIn: needsOptIn,
})
import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
const { activeAddress, transactionSigner } = useWallet()
try {
const quote = await deflex.newQuote({
fromAssetId: 0,
toAssetId: 31566704,
amount: 1_000_000,
address: activeAddress,
})
const swap = await deflex.newSwap({
quote,
address: activeAddress,
signer: transactionSigner,
slippage: 1,
})
const result = await swap.execute()
console.log('Swap successful:', result)
} catch (error) {
console.error('Swap failed:', error.message)
}
The main client for interacting with the Deflex API.
new DeflexClient(config: DeflexConfigParams)
| Option | Description | Type | Default |
|---|---|---|---|
apiKey | Your Deflex API key | string | required |
apiBaseUrl | Base URL for the Deflex API | string | https://deflex.txnlab.dev |
algodUri | Algod node URI | string | https://mainnet-api.4160.nodely.dev/ |
algodToken | Algod node token | string | '' |
algodPort | Algod node port | string | number | 443 |
referrerAddress | Referrer address for fee sharing (receives 25% of swap fees) | string | undefined |
feeBps | Fee in basis points (0.15%, max: 300 = 3.00%) | number | 15 |
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. ThefeeBpsparameter sets the total fee charged (default: 0.15%). Learn more about the Deflex Referral Program.
Fetch a swap quote and return a DeflexQuote object.
async newQuote(params: FetchQuoteParams): Promise<DeflexQuote>
| Parameter | Description | Type | Default |
|---|---|---|---|
fromASAID | Input asset ID | bigint | number | required |
toASAID | Output asset ID | bigint | number | required |
amount | Amount to swap in base units | bigint | number | required |
type | Quote type | 'fixed-input' | 'fixed-output' | 'fixed-input' |
address | User address (recommended for auto opt-in) | string | undefined |
disabledProtocols | Array of protocols to exclude | Protocol[] | [] |
maxGroupSize | Maximum transactions in atomic group | number | 16 |
maxDepth | Maximum swap hops | number | 4 |
optIn | Override auto opt-in behavior | boolean | undefined |
Returns a SwapComposer instance for building and executing swaps.
async newSwap(config: SwapComposerConfig): Promise<SwapComposer>
| Parameter | Description | Type |
|---|---|---|
quote | Quote result or raw API response | DeflexQuote | FetchQuoteResponse |
address | Signer address | string |
slippage | Slippage tolerance as percentage (e.g., 1 for 1%) | number |
signer | Transaction signer function | algosdk.TransactionSigner | ((txnGroup: Transaction[], indexesToSign: number[]) => Promise<(Uint8Array | null)[]>) |
note | Optional note for the user-signed input transaction (for tracking purposes) | Uint8Array |
Checks if an address needs to opt into an asset.
async needsAssetOptIn(address: string, assetId: bigint | number): Promise<boolean>
| Parameter | Description | Type |
|---|---|---|
address | Algorand address to check | string |
assetId | Asset ID to check | bigint | number |
Plain object returned by newQuote(). Extends the raw API response with additional metadata.
Additional properties added by SDK:
| Property | Description | Type |
|---|---|---|
quote | Quoted amount (coerced to bigint) | bigint |
amount | Original request amount | bigint |
address | User address (if provided) | string | undefined |
createdAt | Timestamp when quote was created | number |
All properties from API response:
| Property | Description | Type |
|---|---|---|
fromASAID | Input asset ID | number |
toASAID | Output asset ID | number |
type | Quote type ('fixed-input' or 'fixed-output') | string |
profit | Profit information | Profit |
priceBaseline | Baseline price without fees | number |
userPriceImpact | Price impact for the user | number | undefined |
marketPriceImpact | Overall market price impact | number | undefined |
usdIn | USD value of input | number |
usdOut | USD value of output | number |
route | Routing path information | Route[] |
flattenedRoute | Flattened routing percentages | Record<string, number> |
quotes | Individual DEX quotes | DexQuote[] |
requiredAppOptIns | Required app opt-ins | number[] |
txnPayload | Encrypted transaction payload | TxnPayload | null |
protocolFees | Fees by protocol | Record<string, number> |
timing | Performance timing data | unknown | undefined |
Builder for constructing and executing atomic swap transaction groups, returned by newSwap().
| Method | Description | Parameters | Returns |
|---|---|---|---|
addTransaction(transaction, signer?) | Add a transaction to the atomic group | transaction: algosdk.Transaction, signer?: TransactionSigner | SwapComposer |
addMethodCall(methodCall, signer?) | Add an ABI method call to the atomic group | methodCall: MethodCall, signer?: TransactionSigner | SwapComposer |
addSwapTransactions() | Add swap transactions to the group (includes required app opt-ins) | None | Promise<SwapComposer> |
buildGroup() | Build the transaction group and assign group IDs | None | TransactionWithSigner[] |
sign() | Sign the transaction group | None | Promise<Uint8Array[]> |
submit() | Sign and submit the transaction group | None | Promise<string[]> (transaction IDs) |
execute(waitRounds?) | Sign, submit, and wait for confirmation | waitRounds?: number (default: 4) | Promise<{ confirmedRound: bigint, txIds: string[], methodResults: ABIResult[] }> |
getStatus() | Get current status: BUILDING, BUILT, SIGNED, SUBMITTED, or COMMITTED | None | SwapComposerStatus |
count() | Get the number of transactions in the group | None | number |
getInputTransactionId() | Get the transaction ID of the user-signed input transaction (available after buildGroup(), sign(), or execute()) | None | string | undefined |
For more information about the Deflex Order Router protocol, visit the official documentation.
MIT
FAQs
DEPRECATED: This package has been renamed to @txnlab/haystack-router. TypeScript/JavaScript SDK for Deflex Order Router - smart order routing and DEX aggregation on Algorand
We found that @txnlab/deflex demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.