@txnlab/deflex 1.0.0-beta.1

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,384 @@
1
+ # Deflex SDK
2
+
3
+ TypeScript/JavaScript SDK for [Deflex Order Router](https://txnlab.gitbook.io/deflex-api) - smart order routing and DEX aggregation on Algorand.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @txnlab/deflex
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { DeflexClient } from '@txnlab/deflex'
15
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
16
+
17
+ const { activeAddress, transactionSigner } = useWallet()
18
+
19
+ // Initialize the client
20
+ const deflex = new DeflexClient({
21
+ apiKey: 'your-api-key',
22
+ })
23
+
24
+ // Get a quote
25
+ const quote = await deflex.newQuote({
26
+ address: activeAddress,
27
+ fromAssetId: 0, // ALGO
28
+ toAssetId: 31566704, // USDC
29
+ amount: 1_000_000, // 1 ALGO (in microAlgos)
30
+ })
31
+
32
+ // Execute the swap
33
+ const swap = await deflex.newSwap({
34
+ quote,
35
+ address: activeAddress,
36
+ signer: transactionSigner,
37
+ slippage: 1, // 1% slippage tolerance
38
+ })
39
+ const result = await swap.execute()
40
+
41
+ console.log(`Swap completed in round ${result.confirmedRound}`)
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ ### Initialize the Client
47
+
48
+ ```typescript
49
+ import { DeflexClient } from '@txnlab/deflex'
50
+
51
+ // Basic initialization
52
+ const deflex = new DeflexClient({
53
+ apiKey: 'your-api-key',
54
+ })
55
+
56
+ // Advanced configuration
57
+ const deflex = new DeflexClient({
58
+ apiKey: 'your-api-key',
59
+ algodUri: 'https://mainnet-api.4160.nodely.dev/',
60
+ algodToken: '',
61
+ algodPort: 443,
62
+ referrerAddress: '<referrer_address>', // Earns 25% of swap fees
63
+ feeBps: 15, // 0.15% fee (max: 300 = 3%)
64
+ autoOptIn: true, // Automatically handle asset opt-ins
65
+ })
66
+ ```
67
+
68
+ ### Get a Swap Quote
69
+
70
+ The [`newQuote()`](#deflexclientnewquote) method returns a [`DeflexQuote`](#deflexquote) instance:
71
+
72
+ ```typescript
73
+ // Basic quote
74
+ const quote = await deflex.newQuote({
75
+ fromAssetId: 0, // ALGO
76
+ toAssetId: 31566704, // USDC
77
+ amount: 1_000_000, // 1 ALGO
78
+ address: userAddress, // Required for auto opt-in detection
79
+ })
80
+ ```
81
+
82
+ ### Execute a Swap
83
+
84
+ The [`newSwap()`](#deflexclientnewswap) method returns a [`SwapComposer`](#swapcomposer) instance:
85
+
86
+ ```typescript
87
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
88
+
89
+ const { activeAddress, transactionSigner } = useWallet()
90
+
91
+ const swap = await deflex.newSwap({
92
+ quote,
93
+ address: activeAddress,
94
+ signer: transactionSigner,
95
+ slippage: 1, // 1% slippage tolerance
96
+ })
97
+ const result = await swap.execute()
98
+
99
+ console.log(`Confirmed in round ${result.confirmedRound}`)
100
+ console.log('Transaction IDs:', result.txIds)
101
+ ```
102
+
103
+ ### Transaction Signing
104
+
105
+ The SDK supports two types of transaction signers that must be passed to `newSwap()`:
106
+
107
+ #### 1. use-wallet Signer (Recommended)
108
+
109
+ Use the `@txnlab/use-wallet` library for wallet management in your dApp:
110
+
111
+ ```typescript
112
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
113
+
114
+ const { activeAddress, transactionSigner } = useWallet()
115
+
116
+ const swap = await deflex.newSwap({
117
+ quote,
118
+ address: activeAddress,
119
+ signer: transactionSigner,
120
+ slippage: 1,
121
+ })
122
+ await swap.execute()
123
+ ```
124
+
125
+ > **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`.
126
+
127
+ #### 2. Custom Signer Function
128
+
129
+ ```typescript
130
+ // Custom signer function signature:
131
+ // (txns: Transaction[]) => Promise<Uint8Array[]>
132
+
133
+ const customSigner = async (txns) => {
134
+ // Your custom signing logic here
135
+ const signedTxns = await yourWalletProvider.signTransactions(txns)
136
+
137
+ return signedTxns
138
+ }
139
+
140
+ const swap = await deflex.newSwap({
141
+ quote,
142
+ address: activeAddress,
143
+ signer: customSigner,
144
+ slippage: 1,
145
+ })
146
+ await swap.execute()
147
+ ```
148
+
149
+ > **Note**: The custom signer function must return an array of `Uint8Array` where each element is a signed transaction.
150
+
151
+ ### Advanced Transaction Composition
152
+
153
+ Build the transaction group by adding custom transactions before or after the swap using the [`SwapComposer`](#swapcomposer) instance:
154
+
155
+ ```typescript
156
+ import { Transaction } from 'algosdk'
157
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
158
+
159
+ const { activeAddress, transactionSigner } = useWallet()
160
+
161
+ // Create your custom transactions
162
+ const customTxn1 = new Transaction({...})
163
+ const customTxn2 = new Transaction({...})
164
+
165
+ // Build and execute the transaction group
166
+ const swap = await deflex.newSwap({
167
+ quote,
168
+ address: activeAddress,
169
+ signer: transactionSigner,
170
+ slippage: 1,
171
+ })
172
+
173
+ const result = await swap
174
+ .addTransaction(customTxn1) // Add transaction before swap
175
+ .addSwapTransactions() // Add swap transactions
176
+ .addTransaction(customTxn2) // Add transaction after swap
177
+ .execute() // Sign and execute entire group
178
+ ```
179
+
180
+ ### Manual Asset Opt-In Detection
181
+
182
+ If you're not using `autoOptIn: true`, you can manually check if opt-in is needed:
183
+
184
+ ```typescript
185
+ const deflex = new DeflexClient({
186
+ apiKey: 'your-api-key',
187
+ autoOptIn: false, // Default if not provided
188
+ })
189
+
190
+ // Check if user needs to opt into the output asset
191
+ const needsOptIn = await deflex.needsAssetOptIn(userAddress, toAssetId)
192
+
193
+ // Include opt-in in quote if needed
194
+ const quote = await deflex.newQuote({
195
+ fromAssetId,
196
+ toAssetId,
197
+ amount,
198
+ optIn: needsOptIn,
199
+ })
200
+ ```
201
+
202
+ ### Error Handling
203
+
204
+ ```typescript
205
+ import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
206
+
207
+ const { activeAddress, transactionSigner } = useWallet()
208
+
209
+ try {
210
+ const quote = await deflex.newQuote({
211
+ fromAssetId: 0,
212
+ toAssetId: 31566704,
213
+ amount: 1_000_000,
214
+ address: activeAddress,
215
+ })
216
+
217
+ const swap = await deflex.newSwap({
218
+ quote,
219
+ address: activeAddress,
220
+ signer: transactionSigner,
221
+ slippage: 1,
222
+ })
223
+ const result = await swap.execute()
224
+
225
+ console.log('Swap successful:', result)
226
+ } catch (error) {
227
+ console.error('Swap failed:', error.message)
228
+ }
229
+ ```
230
+
231
+ ## API Reference
232
+
233
+ ### DeflexClient
234
+
235
+ The main client for interacting with the Deflex API.
236
+
237
+ ```typescript
238
+ new DeflexClient(config: DeflexConfigParams)
239
+ ```
240
+
241
+ | Option | Description | Type | Default |
242
+ | ----------------- | ------------------------------------------------------------ | ------------------ | -------------------------------------- |
243
+ | `apiKey` | Your Deflex API key | `string` | **required** |
244
+ | `algodUri` | Algod node URI | `string` | `https://mainnet-api.4160.nodely.dev/` |
245
+ | `algodToken` | Algod node token | `string` | `''` |
246
+ | `algodPort` | Algod node port | `string \| number` | `443` |
247
+ | `referrerAddress` | Referrer address for fee sharing (receives 25% of swap fees) | `string` | `undefined` |
248
+ | `feeBps` | Fee in basis points (0.15%, max: 300 = 3.00%) | `number` | `15` |
249
+ | `autoOptIn` | Auto-detect and add required opt-in transactions | `boolean` | `false` |
250
+
251
+ > **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 [Deflex Referral Program](https://txnlab.gitbook.io/deflex-api/referral-treasury/referral-program).
252
+
253
+ #### DeflexClient.newQuote()
254
+
255
+ Fetch a swap quote and return a [`DeflexQuote`](#deflexquote) instance.
256
+
257
+ ```typescript
258
+ async newQuote(params: QuoteParams): Promise<DeflexQuote>
259
+ ```
260
+
261
+ | Parameter | Description | Type | Default |
262
+ | ------------------- | ------------------------------------------ | --------------------------------- | --------------- |
263
+ | `fromAssetId` | Input asset ID | `bigint \| number` | **required** |
264
+ | `toAssetId` | Output asset ID | `bigint \| number` | **required** |
265
+ | `amount` | Amount to swap in base units | `bigint \| number` | **required** |
266
+ | `type` | Quote type | `'fixed-input' \| 'fixed-output'` | `'fixed-input'` |
267
+ | `address` | User address (recommended for auto opt-in) | `string` | `undefined` |
268
+ | `disabledProtocols` | Array of protocols to exclude | `Protocol[]` | `[]` |
269
+ | `maxGroupSize` | Maximum transactions in atomic group | `number` | `16` |
270
+ | `maxDepth` | Maximum swap hops | `number` | `4` |
271
+ | `optIn` | Override auto opt-in behavior | `boolean` | `undefined` |
272
+
273
+ #### DeflexClient.newSwap()
274
+
275
+ Returns a [`SwapComposer`](#swapcomposer) instance for building and executing swaps.
276
+
277
+ ```typescript
278
+ async newSwap(config: SwapComposerConfig): Promise<SwapComposer>
279
+ ```
280
+
281
+ | Parameter | Description | Type |
282
+ | ---------- | ------------------------------------------------- | --------------------------------------------------------------------------------------- |
283
+ | `quote` | Quote instance or response object | `DeflexQuote \| FetchQuoteResponse` |
284
+ | `address` | Signer address | `string` |
285
+ | `slippage` | Slippage tolerance as percentage (e.g., 1 for 1%) | `number` |
286
+ | `signer` | Transaction signer function | `algosdk.TransactionSigner \| ((txns: algosdk.Transaction[]) => Promise<Uint8Array[]>)` |
287
+
288
+ #### DeflexClient.needsAssetOptIn()
289
+
290
+ Checks if an address needs to opt into an asset.
291
+
292
+ ```typescript
293
+ async needsAssetOptIn(address: string, assetId: bigint | number): Promise<boolean>
294
+ ```
295
+
296
+ | Parameter | Description | Type |
297
+ | --------- | ------------------------- | ------------------ |
298
+ | `address` | Algorand address to check | `string` |
299
+ | `assetId` | Asset ID to check | `bigint \| number` |
300
+
301
+ ### DeflexQuote
302
+
303
+ Wrapper class for quote responses returned by [`newQuote()`](#deflexclientnewquote).
304
+
305
+ | Property | Description | Type |
306
+ | ------------------- | ------------------------------------------------ | ------------------------ |
307
+ | `quote` | Quoted amount | `bigint` |
308
+ | `amount` | Original request amount | `bigint` |
309
+ | `address` | User address (if provided) | `string \| undefined` |
310
+ | `createdAt` | Timestamp when quote was created | `number` |
311
+ | `fromAssetId` | Input asset ID | `number` |
312
+ | `toAssetId` | Output asset ID | `number` |
313
+ | `type` | Quote type (`'fixed-input'` or `'fixed-output'`) | `string` |
314
+ | `profit` | Profit information | `Profit` |
315
+ | `priceBaseline` | Baseline price without fees | `number` |
316
+ | `userPriceImpact` | Price impact for the user | `number \| undefined` |
317
+ | `marketPriceImpact` | Overall market price impact | `number \| undefined` |
318
+ | `usdIn` | USD value of input | `number` |
319
+ | `usdOut` | USD value of output | `number` |
320
+ | `route` | Routing path information | `Route[]` |
321
+ | `flattenedRoute` | Flattened routing percentages | `Record<string, number>` |
322
+ | `quotes` | Individual DEX quotes | `DexQuote[]` |
323
+ | `requiredAppOptIns` | Required app opt-ins | `number[]` |
324
+ | `txnPayload` | Encrypted transaction payload | `TxnPayload \| null` |
325
+ | `protocolFees` | Fees by protocol | `Record<string, number>` |
326
+ | `response` | Raw API response | `FetchQuoteResponse` |
327
+
328
+ #### DeflexQuote.getSlippageAmount()
329
+
330
+ Calculates the slippage-adjusted amount.
331
+
332
+ - For **fixed-input** swaps: Returns minimum output amount
333
+ - For **fixed-output** swaps: Returns maximum input amount
334
+
335
+ ```typescript
336
+ getSlippageAmount(slippage: number): bigint
337
+ ```
338
+
339
+ | Parameter | Description | Type |
340
+ | ---------- | ------------------------------------------------- | -------- |
341
+ | `slippage` | Slippage tolerance as percentage (e.g., 1 for 1%) | `number` |
342
+
343
+ **Example:**
344
+
345
+ ```typescript
346
+ const quote = await deflex.newQuote({
347
+ fromAssetId: 0,
348
+ toAssetId: 31566704,
349
+ amount: 1_000_000,
350
+ type: 'fixed-input',
351
+ })
352
+
353
+ // Get minimum output with 1% slippage
354
+ const minOutput = quote.getSlippageAmount(1)
355
+ console.log(`Minimum you'll receive: ${minOutput}`)
356
+ ```
357
+
358
+ ### SwapComposer
359
+
360
+ Builder for constructing and executing atomic swap transaction groups, returned by [`newSwap()`](#deflexclientnewswap).
361
+
362
+ | Method | Description | Parameters | Returns |
363
+ | ----------------------------- | ------------------------------------------------------------------------------ | ---------------------------------- | ------------------------------------- |
364
+ | `addTransaction(transaction)` | Add a transaction to the atomic group | `transaction: algosdk.Transaction` | `SwapComposer` |
365
+ | `addSwapTransactions()` | Add swap transactions to the group (includes required app opt-ins) | None | `Promise<SwapComposer>` |
366
+ | `sign()` | Sign the transaction group | None | `Promise<Uint8Array[]>` |
367
+ | `submit()` | Sign and submit the transaction group | None | `Promise<string[]>` |
368
+ | `execute(waitRounds?)` | Sign, submit, and wait for confirmation | `waitRounds?: number` (default: 4) | `Promise<PendingTransactionResponse>` |
369
+ | `getStatus()` | Get current status: `BUILDING`, `BUILT`, `SIGNED`, `SUBMITTED`, or `COMMITTED` | None | `ComposerStatus` |
370
+ | `count()` | Get the number of transactions in the group | None | `number` |
371
+
372
+ ## Documentation
373
+
374
+ For more information about the Deflex Order Router protocol, visit the [official documentation](https://txnlab.gitbook.io/deflex-api).
375
+
376
+ ## License
377
+
378
+ MIT
379
+
380
+ ## Support
381
+
382
+ - [GitHub Issues](https://github.com/TxnLab/deflex-js/issues)
383
+ - [Discord](https://discord.gg/Ek3dNyzG)
384
+ - [TxnLab](https://txnlab.dev)