@txnlab/deflex 1.1.0 → 1.3.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
@@ -1,5 +1,11 @@
1
1
  # Deflex SDK
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@txnlab/deflex.svg)](https://www.npmjs.com/package/@txnlab/deflex)
4
+ [![bundle size](https://deno.bundlejs.com/badge?q=@txnlab/deflex@latest&treeshake=[*])](https://bundlejs.com/?q=%40txnlab%2Fdeflex%40latest&treeshake=%5B*%5D)
5
+ [![CI](https://github.com/TxnLab/deflex-js/actions/workflows/ci.yml/badge.svg)](https://github.com/TxnLab/deflex-js/actions/workflows/ci.yml)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
8
+
3
9
  TypeScript/JavaScript SDK for [Deflex Order Router](https://txnlab.gitbook.io/deflex-api) - smart order routing and DEX aggregation on Algorand.
4
10
 
5
11
  ## Prerequisites
@@ -174,6 +180,7 @@ await swap.execute()
174
180
  ```
175
181
 
176
182
  The signer function supports two return patterns:
183
+
177
184
  - **Pattern 1** (Pera, Defly, algosdk): Returns only the signed transactions as `Uint8Array[]`
178
185
  - **Pattern 2** (Lute, ARC-1 compliant): Returns an array matching the transaction group length with `null` for unsigned transactions as `(Uint8Array | null)[]`
179
186
 
@@ -181,17 +188,25 @@ Both patterns are automatically handled by the SDK.
181
188
 
182
189
  ### Advanced Transaction Composition
183
190
 
184
- Build the transaction group by adding custom transactions before or after the swap using the [`SwapComposer`](#swapcomposer) instance:
191
+ Build the transaction group by adding custom transactions and ABI method calls before or after the swap using the [`SwapComposer`](#swapcomposer) instance:
185
192
 
186
193
  ```typescript
187
- import { Transaction } from 'algosdk'
194
+ import { ABIMethod, Transaction } from 'algosdk'
188
195
  import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
189
196
 
190
197
  const { activeAddress, transactionSigner } = useWallet()
191
198
 
192
199
  // Create your custom transactions
193
- const customTxn1 = new Transaction({...})
194
- const customTxn2 = new Transaction({...})
200
+ const customTxn = new Transaction({...})
201
+
202
+ // Define an ABI method call
203
+ const methodCall = {
204
+ appID: 123456,
205
+ method: new ABIMethod({...}),
206
+ methodArgs: [...],
207
+ sender: activeAddress,
208
+ suggestedParams: await algodClient.getTransactionParams().do(),
209
+ }
195
210
 
196
211
  // Build and execute the transaction group
197
212
  const swap = await deflex.newSwap({
@@ -202,12 +217,50 @@ const swap = await deflex.newSwap({
202
217
  })
203
218
 
204
219
  const result = await swap
205
- .addTransaction(customTxn1) // Add transaction before swap
220
+ .addTransaction(customTxn) // Add transaction before swap
206
221
  .addSwapTransactions() // Add swap transactions
207
- .addTransaction(customTxn2) // Add transaction after swap
222
+ .addMethodCall(methodCall) // Add ABI method call after swap
208
223
  .execute() // Sign and execute entire group
209
224
  ```
210
225
 
226
+ ### Middleware for Custom Asset Requirements
227
+
228
+ 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.
229
+
230
+ Middleware can:
231
+ - Adjust quote parameters (e.g., reduce `maxGroupSize` to account for extra transactions)
232
+ - Add transactions before the swap (e.g., unfreeze account, setup calls)
233
+ - Add transactions after the swap (e.g., tax payments, cleanup calls)
234
+
235
+ ```typescript
236
+ import { DeflexClient } from '@txnlab/deflex'
237
+ import { FirstStageMiddleware } from '@firststage/deflex-middleware' // Example external package
238
+
239
+ // Initialize middleware
240
+ const firstStage = new FirstStageMiddleware({
241
+ contractAppId: 123456,
242
+ })
243
+
244
+ // Pass middleware to DeflexClient
245
+ const deflex = new DeflexClient({
246
+ apiKey: 'your-api-key',
247
+ middleware: [firstStage], // Middleware is applied automatically
248
+ })
249
+
250
+ // Use normally - middleware handles everything
251
+ const quote = await deflex.newQuote({
252
+ fromASAID: 0, // ALGO
253
+ toASAID: 789012, // Custom asset (e.g., MOOJ, DEAL)
254
+ amount: 1_000_000,
255
+ address: userAddress,
256
+ })
257
+
258
+ const swap = await deflex.newSwap({ quote, address, signer, slippage: 1 })
259
+ await swap.execute() // Middleware transactions are automatically included
260
+ ```
261
+
262
+ For details on creating your own middleware, see [MIDDLEWARE.md](MIDDLEWARE.md).
263
+
211
264
  ### Manual Asset Opt-In Detection
212
265
 
213
266
  If you're not using `autoOptIn: true`, you can manually check if opt-in is needed:
@@ -269,16 +322,17 @@ The main client for interacting with the Deflex API.
269
322
  new DeflexClient(config: DeflexConfigParams)
270
323
  ```
271
324
 
272
- | Option | Description | Type | Default |
273
- | ----------------- | ------------------------------------------------------------ | ------------------ | -------------------------------------- |
274
- | `apiKey` | Your Deflex API key | `string` | **required** |
275
- | `apiBaseUrl` | Base URL for the Deflex API | `string` | `https://deflex.txnlab.dev` |
276
- | `algodUri` | Algod node URI | `string` | `https://mainnet-api.4160.nodely.dev/` |
277
- | `algodToken` | Algod node token | `string` | `''` |
278
- | `algodPort` | Algod node port | `string \| number` | `443` |
279
- | `referrerAddress` | Referrer address for fee sharing (receives 25% of swap fees) | `string` | `undefined` |
280
- | `feeBps` | Fee in basis points (0.15%, max: 300 = 3.00%) | `number` | `15` |
281
- | `autoOptIn` | Auto-detect and add required opt-in transactions | `boolean` | `false` |
325
+ | Option | Description | Type | Default |
326
+ | ----------------- | ------------------------------------------------------------ | --------------------- | -------------------------------------- |
327
+ | `apiKey` | Your Deflex API key | `string` | **required** |
328
+ | `apiBaseUrl` | Base URL for the Deflex API | `string` | `https://deflex.txnlab.dev` |
329
+ | `algodUri` | Algod node URI | `string` | `https://mainnet-api.4160.nodely.dev/` |
330
+ | `algodToken` | Algod node token | `string` | `''` |
331
+ | `algodPort` | Algod node port | `string \| number` | `443` |
332
+ | `referrerAddress` | Referrer address for fee sharing (receives 25% of swap fees) | `string` | `undefined` |
333
+ | `feeBps` | Fee in basis points (0.15%, max: 300 = 3.00%) | `number` | `15` |
334
+ | `autoOptIn` | Auto-detect and add required opt-in transactions | `boolean` | `false` |
335
+ | `middleware` | Array of middleware for custom asset requirements | `SwapMiddleware[]` | `[]` |
282
336
 
283
337
  > **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).
284
338
 
@@ -310,11 +364,11 @@ Returns a [`SwapComposer`](#swapcomposer) instance for building and executing sw
310
364
  async newSwap(config: SwapComposerConfig): Promise<SwapComposer>
311
365
  ```
312
366
 
313
- | Parameter | Description | Type |
314
- | ---------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
315
- | `quote` | Quote result or raw API response | `DeflexQuote \| FetchQuoteResponse` |
316
- | `address` | Signer address | `string` |
317
- | `slippage` | Slippage tolerance as percentage (e.g., 1 for 1%) | `number` |
367
+ | Parameter | Description | Type |
368
+ | ---------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
369
+ | `quote` | Quote result or raw API response | `DeflexQuote \| FetchQuoteResponse` |
370
+ | `address` | Signer address | `string` |
371
+ | `slippage` | Slippage tolerance as percentage (e.g., 1 for 1%) | `number` |
318
372
  | `signer` | Transaction signer function | `algosdk.TransactionSigner \| ((txnGroup: Transaction[], indexesToSign: number[]) => Promise<(Uint8Array \| null)[]>)` |
319
373
 
320
374
  #### DeflexClient.needsAssetOptIn()
@@ -368,15 +422,17 @@ Plain object returned by [`newQuote()`](#deflexclientnewquote). Extends the raw
368
422
 
369
423
  Builder for constructing and executing atomic swap transaction groups, returned by [`newSwap()`](#deflexclientnewswap).
370
424
 
371
- | Method | Description | Parameters | Returns |
372
- | ----------------------------- | ------------------------------------------------------------------------------ | ---------------------------------- | ------------------------------------- |
373
- | `addTransaction(transaction)` | Add a transaction to the atomic group | `transaction: algosdk.Transaction` | `SwapComposer` |
374
- | `addSwapTransactions()` | Add swap transactions to the group (includes required app opt-ins) | None | `Promise<SwapComposer>` |
375
- | `sign()` | Sign the transaction group | None | `Promise<Uint8Array[]>` |
376
- | `submit()` | Sign and submit the transaction group | None | `Promise<string[]>` |
377
- | `execute(waitRounds?)` | Sign, submit, and wait for confirmation | `waitRounds?: number` (default: 4) | `Promise<PendingTransactionResponse>` |
378
- | `getStatus()` | Get current status: `BUILDING`, `BUILT`, `SIGNED`, `SUBMITTED`, or `COMMITTED` | None | `ComposerStatus` |
379
- | `count()` | Get the number of transactions in the group | None | `number` |
425
+ | Method | Description | Parameters | Returns |
426
+ | -------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
427
+ | `addTransaction(transaction, signer?)` | Add a transaction to the atomic group | `transaction: algosdk.Transaction, signer?: TransactionSigner` | `SwapComposer` |
428
+ | `addMethodCall(methodCall, signer?)` | Add an ABI method call to the atomic group | `methodCall: MethodCall, signer?: TransactionSigner` | `SwapComposer` |
429
+ | `addSwapTransactions()` | Add swap transactions to the group (includes required app opt-ins) | None | `Promise<SwapComposer>` |
430
+ | `buildGroup()` | Build the transaction group and assign group IDs | None | `TransactionWithSigner[]` |
431
+ | `sign()` | Sign the transaction group | None | `Promise<Uint8Array[]>` |
432
+ | `submit()` | Sign and submit the transaction group | None | `Promise<string[]>` (transaction IDs) |
433
+ | `execute(waitRounds?)` | Sign, submit, and wait for confirmation | `waitRounds?: number` (default: 4) | `Promise<{ confirmedRound: bigint, txIds: string[], methodResults: ABIResult[] }>` |
434
+ | `getStatus()` | Get current status: `BUILDING`, `BUILT`, `SIGNED`, `SUBMITTED`, or `COMMITTED` | None | `SwapComposerStatus` |
435
+ | `count()` | Get the number of transactions in the group | None | `number` |
380
436
 
381
437
  ## Documentation
382
438
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import algosdk, { Algodv2, Transaction, TransactionSigner } from "algosdk";
1
+ import { ABIArgument, ABIMethod, ABIResult, Address, Algodv2, BoxReference, OnApplicationComplete, ResourceReference, SuggestedParams, Transaction, TransactionSigner, TransactionWithSigner } from "algosdk";
2
2
 
3
3
  //#region src/constants.d.ts
4
4
  /**
@@ -281,14 +281,270 @@ interface FetchSwapTxnsResponse {
281
281
  /**
282
282
  * Processed transaction with optional pre-signature
283
283
  *
284
+ * @deprecated This type is no longer used internally. Use algosdk.TransactionWithSigner instead.
284
285
  * @internal
285
286
  */
286
287
  interface SwapTransaction {
287
288
  /** The Algorand transaction */
288
- readonly txn: algosdk.Transaction;
289
+ readonly txn: Transaction;
289
290
  /** Pre-signature from Deflex (if applicable) */
290
291
  readonly deflexSignature?: DeflexSignature;
291
292
  }
293
+ /**
294
+ * Method call to be executed as part of the swap
295
+ */
296
+ interface MethodCall {
297
+ /** The ID of the smart contract to call. Set this to 0 to indicate an application creation call. */
298
+ appID: number | bigint;
299
+ /** The method to call on the smart contract */
300
+ method: ABIMethod;
301
+ /** The arguments to include in the method call. If omitted, no arguments will be passed to the method. */
302
+ methodArgs?: ABIArgument[];
303
+ /** The address of the sender of this application call */
304
+ sender: string | Address;
305
+ /** Transactions params to use for this application call */
306
+ suggestedParams: SuggestedParams;
307
+ /** The OnComplete action to take for this application call. If omitted, OnApplicationComplete.NoOpOC will be used. */
308
+ onComplete?: OnApplicationComplete;
309
+ /** The approval program for this application call. Only set this if this is an application creation call, or if onComplete is OnApplicationComplete.UpdateApplicationOC */
310
+ approvalProgram?: Uint8Array;
311
+ /** The clear program for this application call. Only set this if this is an application creation call, or if onComplete is OnApplicationComplete.UpdateApplicationOC */
312
+ clearProgram?: Uint8Array;
313
+ /** The global integer schema size. Only set this if this is an application creation call. */
314
+ numGlobalInts?: number;
315
+ /** The global byte slice schema size. Only set this if this is an application creation call. */
316
+ numGlobalByteSlices?: number;
317
+ /** The local integer schema size. Only set this if this is an application creation call. */
318
+ numLocalInts?: number;
319
+ /** The local byte slice schema size. Only set this if this is an application creation call. */
320
+ numLocalByteSlices?: number;
321
+ /** The number of extra pages to allocate for the application's programs. Only set this if this is an application creation call. If omitted, defaults to 0. */
322
+ extraPages?: number;
323
+ /** Array of Address strings that represent external accounts supplied to this application. If accounts are provided here, the accounts specified in the method args will appear after these. */
324
+ appAccounts?: Array<string | Address>;
325
+ /** Array of App ID numbers that represent external apps supplied to this application. If apps are provided here, the apps specified in the method args will appear after these. */
326
+ appForeignApps?: Array<number | bigint>;
327
+ /** Array of Asset ID numbers that represent external assets supplied to this application. If assets are provided here, the assets specified in the method args will appear after these. */
328
+ appForeignAssets?: Array<number | bigint>;
329
+ /** The box references for this application call */
330
+ boxes?: BoxReference[];
331
+ /** The resource references for this application call */
332
+ access?: ResourceReference[];
333
+ /** The note value for this application call */
334
+ note?: Uint8Array;
335
+ /** The lease value for this application call */
336
+ lease?: Uint8Array;
337
+ /** If provided, the address that the sender will be rekeyed to at the conclusion of this application call */
338
+ rekeyTo?: string | Address;
339
+ /** The lowest application version for which this transaction should immediately fail. 0 indicates that no version check should be performed. */
340
+ rejectVersion?: number | bigint;
341
+ /** A transaction signer that can authorize this application call from sender */
342
+ signer?: TransactionSigner;
343
+ }
344
+ //#endregion
345
+ //#region src/middleware.d.ts
346
+ /**
347
+ * Context provided to middleware hooks during swap composition
348
+ */
349
+ interface SwapContext {
350
+ /** The quote result from newQuote() */
351
+ readonly quote: DeflexQuote;
352
+ /** The address of the account performing the swap */
353
+ readonly address: string;
354
+ /** Algodv2 client instance for making additional queries/transactions */
355
+ readonly algodClient: Algodv2;
356
+ /** Suggested transaction parameters from the network */
357
+ readonly suggestedParams: SuggestedParams;
358
+ /** Input asset ID (always bigint for precision and future-proofing) */
359
+ readonly fromASAID: bigint;
360
+ /** Output asset ID (always bigint for precision and future-proofing) */
361
+ readonly toASAID: bigint;
362
+ /** Transaction signer for transactions that need to be signed by the user */
363
+ readonly signer: TransactionSigner;
364
+ }
365
+ /**
366
+ * Middleware interface for extending Deflex swap functionality
367
+ *
368
+ * Middleware allows you to modify quote parameters and inject additional transactions
369
+ * into the atomic swap group. This is useful for assets that require special handling,
370
+ * such as those with transfer restrictions, taxes, or custom smart contract logic.
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * class CustomAssetMiddleware implements SwapMiddleware {
375
+ * readonly name = 'CustomAsset'
376
+ * readonly version = '1.0.0'
377
+ *
378
+ * async shouldApply(params) {
379
+ * return params.fromASAID === CUSTOM_ASSET_ID || params.toASAID === CUSTOM_ASSET_ID
380
+ * }
381
+ *
382
+ * async adjustQuoteParams(params) {
383
+ * // Reduce maxGroupSize to account for extra transactions
384
+ * return { ...params, maxGroupSize: params.maxGroupSize - 3 }
385
+ * }
386
+ *
387
+ * async beforeSwap(context) {
388
+ * // Return transactions to add before the swap
389
+ * return [unfreezeTransaction]
390
+ * }
391
+ *
392
+ * async afterSwap(context) {
393
+ * // Return transactions to add after the swap
394
+ * return [taxTransaction, refreezeTransaction]
395
+ * }
396
+ * }
397
+ * ```
398
+ */
399
+ interface SwapMiddleware {
400
+ /** Unique identifier for the middleware */
401
+ readonly name: string;
402
+ /** Semantic version of the middleware */
403
+ readonly version: string;
404
+ /**
405
+ * Determines if this middleware should be applied to the given swap
406
+ *
407
+ * Called during both quote and swap phases. Use this to check if either
408
+ * the input or output asset requires special handling.
409
+ *
410
+ * @param params - Asset IDs being swapped
411
+ * @returns True if middleware should be applied
412
+ *
413
+ * @example
414
+ * ```typescript
415
+ * async shouldApply(params) {
416
+ * // Check if asset is registered in our smart contract
417
+ * const assetInfo = await this.getAssetInfo(params.fromASAID)
418
+ * return assetInfo !== null
419
+ * }
420
+ * ```
421
+ */
422
+ shouldApply(params: {
423
+ fromASAID: bigint;
424
+ toASAID: bigint;
425
+ }): Promise<boolean>;
426
+ /**
427
+ * Modify quote parameters before fetching the quote
428
+ *
429
+ * **IMPORTANT**: If your middleware adds transactions via `beforeSwap` or `afterSwap`,
430
+ * you MUST reduce `maxGroupSize` accordingly to prevent failures. The Deflex API may
431
+ * return routes that use all 16 available transaction slots.
432
+ *
433
+ * Use this to adjust the quote request based on your asset's requirements.
434
+ * Common adjustments include:
435
+ * - Reducing `maxGroupSize` to account for additional transactions (REQUIRED if adding txns)
436
+ * - Adjusting `amount` to account for fees/taxes
437
+ * - Modifying `disabledProtocols` if certain DEXs are incompatible
438
+ *
439
+ * @param params - Original quote parameters
440
+ * @returns Modified quote parameters
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * async adjustQuoteParams(params) {
445
+ * const [fromTaxed, toTaxed] = await Promise.all([
446
+ * this.isAssetTaxed(params.fromASAID),
447
+ * this.isAssetTaxed(params.toASAID),
448
+ * ])
449
+ *
450
+ * // 3 extra transactions per taxed asset
451
+ * let maxGroupSize = params.maxGroupSize ?? 16
452
+ * if (fromTaxed) maxGroupSize -= 3
453
+ * if (toTaxed) maxGroupSize -= 3
454
+ *
455
+ * // Adjust amount for input tax
456
+ * let amount = params.amount
457
+ * if (fromTaxed) {
458
+ * const taxRate = await this.getTaxRate(params.fromASAID)
459
+ * amount = this.applyTax(amount, taxRate)
460
+ * }
461
+ *
462
+ * return { ...params, maxGroupSize, amount }
463
+ * }
464
+ * ```
465
+ */
466
+ adjustQuoteParams?(params: FetchQuoteParams): Promise<FetchQuoteParams>;
467
+ /**
468
+ * Add transactions before the swap transactions
469
+ *
470
+ * Called when building the swap transaction group. Transactions are added
471
+ * to the group in the order they appear in the returned array.
472
+ *
473
+ * Transaction order in final group: [beforeSwap] → [swap txns] → [afterSwap]
474
+ *
475
+ * @param context - Swap context with quote, address, and algod client
476
+ * @returns Array of transactions with signers to add before swap
477
+ *
478
+ * @example
479
+ * ```typescript
480
+ * async beforeSwap(context) {
481
+ * const txns: TransactionWithSigner[] = []
482
+ *
483
+ * // Unfreeze user account before swap
484
+ * if (await this.needsUnfreeze(context.fromASAID)) {
485
+ * const unfreezeCall = makeApplicationNoOpTxn(
486
+ * context.address,
487
+ * this.appId,
488
+ * ...,
489
+ * context.suggestedParams
490
+ * )
491
+ *
492
+ * txns.push({
493
+ * txn: unfreezeCall,
494
+ * signer: context.signer, // Use the signer from context
495
+ * })
496
+ * }
497
+ *
498
+ * return txns
499
+ * }
500
+ * ```
501
+ */
502
+ beforeSwap?(context: SwapContext): Promise<TransactionWithSigner[]>;
503
+ /**
504
+ * Add transactions after the swap transactions
505
+ *
506
+ * Called when building the swap transaction group. Transactions are added
507
+ * to the group in the order they appear in the returned array.
508
+ *
509
+ * Transaction order in final group: [beforeSwap] → [swap txns] → [afterSwap]
510
+ *
511
+ * @param context - Swap context with quote, address, and algod client
512
+ * @returns Array of transactions with signers to add after swap
513
+ *
514
+ * @example
515
+ * ```typescript
516
+ * async afterSwap(context) {
517
+ * const txns: TransactionWithSigner[] = []
518
+ *
519
+ * // Pay tax and refreeze account
520
+ * if (await this.isTaxed(context.fromASAID)) {
521
+ * const taxAmount = await this.calculateTax(context)
522
+ * const taxPayment = makeAssetTransferTxn(
523
+ * context.address,
524
+ * this.taxReceiver,
525
+ * taxAmount,
526
+ * context.fromASAID,
527
+ * context.suggestedParams
528
+ * )
529
+ * const refreezeCall = makeApplicationNoOpTxn(
530
+ * context.address,
531
+ * this.appId,
532
+ * ...,
533
+ * context.suggestedParams
534
+ * )
535
+ *
536
+ * txns.push(
537
+ * { txn: taxPayment, signer: context.signer },
538
+ * { txn: refreezeCall, signer: context.signer },
539
+ * )
540
+ * }
541
+ *
542
+ * return txns
543
+ * }
544
+ * ```
545
+ */
546
+ afterSwap?(context: SwapContext): Promise<TransactionWithSigner[]>;
547
+ }
292
548
  //#endregion
293
549
  //#region src/composer.d.ts
294
550
  /**
@@ -329,6 +585,8 @@ interface SwapComposerConfig {
329
585
  readonly address: string;
330
586
  /** Transaction signer function */
331
587
  readonly signer: TransactionSigner | SignerFunction;
588
+ /** Middleware to apply during swap composition */
589
+ readonly middleware?: SwapMiddleware[];
332
590
  }
333
591
  /**
334
592
  * Composer for building and executing atomic swap transaction groups
@@ -340,27 +598,28 @@ interface SwapComposerConfig {
340
598
  * @example
341
599
  * ```typescript
342
600
  * const quote = await deflex.fetchQuote({ ... })
343
- * const composer = await deflex.newSwap({ quote, address, slippage })
601
+ * const composer = await deflex.newSwap({ quote, address, slippage, signer })
344
602
  *
345
603
  * await composer
346
604
  * .addTransaction(customTxn)
347
605
  * .addSwapTransactions()
348
- * .execute(signer)
606
+ * .execute()
349
607
  * ```
350
608
  */
351
609
  declare class SwapComposer {
610
+ /** The ATC used to compose the group */
611
+ private atc;
352
612
  /** The maximum size of an atomic transaction group. */
353
613
  static MAX_GROUP_SIZE: number;
354
- private status;
355
- private transactions;
614
+ /** Whether the swap transactions have been added to the atomic group. */
356
615
  private swapTransactionsAdded;
357
- private signedTxns;
358
- private txIds;
616
+ private readonly quote;
359
617
  private readonly requiredAppOptIns;
360
618
  private readonly deflexTxns;
361
619
  private readonly algodClient;
362
620
  private readonly address;
363
621
  private readonly signer;
622
+ private readonly middleware;
364
623
  /**
365
624
  * Create a new SwapComposer instance
366
625
  *
@@ -368,11 +627,12 @@ declare class SwapComposer {
368
627
  * this directly, as the factory method handles fetching swap transactions automatically.
369
628
  *
370
629
  * @param config - Configuration for the composer
371
- * @param config.requiredAppOptIns - The quote response from fetchQuote()
630
+ * @param config.quote - The quote response from fetchQuote()
372
631
  * @param config.deflexTxns - The swap transactions from fetchSwapTransactions()
373
632
  * @param config.algodClient - Algodv2 client instance
374
633
  * @param config.address - The address of the account that will sign transactions
375
634
  * @param config.signer - Transaction signer function
635
+ * @param config.middleware - Middleware to apply during swap composition
376
636
  */
377
637
  constructor(config: SwapComposerConfig);
378
638
  /**
@@ -403,12 +663,29 @@ declare class SwapComposer {
403
663
  * @throws Error if the composer is not in the BUILDING status
404
664
  * @throws Error if the maximum group size is exceeded
405
665
  */
406
- addTransaction(transaction: Transaction): this;
666
+ addTransaction(transaction: Transaction, signer?: TransactionSigner): this;
667
+ /**
668
+ * Add a method call to the atomic group
669
+ *
670
+ * The `signer` property in the `methodCall` parameter is optional. If not provided,
671
+ * the signer will default to the one passed as the second parameter, or the
672
+ * configured signer from the constructor if no second parameter is provided.
673
+ *
674
+ * @param methodCall - The method call to add
675
+ * @param signer - The signer to use for the method call (defaults to constructor signer)
676
+ * @returns This composer instance for chaining
677
+ */
678
+ addMethodCall(methodCall: MethodCall, signer?: TransactionSigner): this;
407
679
  /**
408
680
  * Add swap transactions to the atomic group
409
681
  *
410
- * This method automatically processes required app opt-ins and adds all swap
411
- * transactions from the quote. Can only be called once per composer instance.
682
+ * This method automatically processes required app opt-ins, executes middleware hooks,
683
+ * and adds all swap transactions from the quote. Can only be called once per composer instance.
684
+ *
685
+ * Middleware hooks are executed in this order:
686
+ * 1. beforeSwap() - Add transactions before swap transactions
687
+ * 2. Swap transactions (from API)
688
+ * 3. afterSwap() - Add transactions after swap transactions
412
689
  *
413
690
  * @returns This composer instance for chaining
414
691
  * @throws Error if the swap transactions have already been added
@@ -416,6 +693,30 @@ declare class SwapComposer {
416
693
  * @throws Error if the maximum group size is exceeded
417
694
  */
418
695
  addSwapTransactions(): Promise<this>;
696
+ /**
697
+ * Finalize the transaction group by assigning group IDs
698
+ *
699
+ * This method builds the atomic transaction group, assigning group IDs to all transactions
700
+ * if there is more than one transaction. After calling this method, the composer's status
701
+ * will be at least BUILT.
702
+ *
703
+ * @returns Array of transactions with their associated signers
704
+ *
705
+ * @throws Error if the group contains 0 transactions
706
+ *
707
+ * @example
708
+ * ```typescript
709
+ * const composer = await deflex.newSwap({ quote, address, slippage, signer })
710
+ * composer.addTransaction(customTxn)
711
+ *
712
+ * // Build the group to inspect transactions before signing
713
+ * const txnsWithSigners = composer.buildGroup()
714
+ * console.log('Group ID:', txnsWithSigners[0].txn.group)
715
+ * console.log('Group length:', txnsWithSigners.length)
716
+ * console.log('Status:', composer.getStatus()) // BUILT
717
+ * ```
718
+ */
719
+ buildGroup(): TransactionWithSigner[];
419
720
  /**
420
721
  * Sign the transaction group
421
722
  *
@@ -467,6 +768,7 @@ declare class SwapComposer {
467
768
  execute(waitRounds?: number): Promise<{
468
769
  confirmedRound: bigint;
469
770
  txIds: string[];
771
+ methodResults: ABIResult[];
470
772
  }>;
471
773
  /**
472
774
  * Validates an Algorand address
@@ -481,15 +783,25 @@ declare class SwapComposer {
481
783
  */
482
784
  private processRequiredAppOptIns;
483
785
  /**
484
- * Finalizes the transaction group by assigning group IDs
485
- *
486
- * The composer's status will be at least BUILT after executing this method.
786
+ * The default signer function that uses the configured signer
487
787
  */
488
- private buildGroup;
788
+ private defaultSigner;
789
+ /**
790
+ * Creates a TransactionSigner function for Deflex pre-signed transactions
791
+ */
792
+ private createDeflexSigner;
489
793
  /**
490
794
  * Re-signs a Deflex transaction using the provided logic signature or secret key
491
795
  */
492
796
  private signDeflexTransaction;
797
+ /**
798
+ * Execute middleware hooks (beforeSwap or afterSwap)
799
+ */
800
+ private executeMiddlewareHooks;
801
+ /**
802
+ * Create SwapContext for middleware hooks
803
+ */
804
+ private createSwapContext;
493
805
  }
494
806
  //#endregion
495
807
  //#region src/client.d.ts
@@ -524,6 +836,7 @@ declare class SwapComposer {
524
836
  declare class DeflexClient {
525
837
  private readonly config;
526
838
  private readonly algodClient;
839
+ private readonly middleware;
527
840
  /**
528
841
  * Create a new DeflexClient instance
529
842
  *
@@ -536,8 +849,11 @@ declare class DeflexClient {
536
849
  * @param config.referrerAddress - Referrer address for fee sharing (receives 25% of swap fees)
537
850
  * @param config.feeBps - Fee in basis points (default: 15 = 0.15%, max: 300 = 3.00%)
538
851
  * @param config.autoOptIn - Automatically detect and add required opt-in transactions (default: false)
852
+ * @param config.middleware - Array of middleware to apply to swaps (default: [])
539
853
  */
540
- constructor(config: DeflexConfigParams);
854
+ constructor(config: DeflexConfigParams & {
855
+ middleware?: SwapMiddleware[];
856
+ });
541
857
  /**
542
858
  * Fetch a swap quote from the Deflex API
543
859
  *
@@ -737,5 +1053,5 @@ declare class HTTPError extends Error {
737
1053
  */
738
1054
  declare function request<T>(url: string, options?: RequestInit): Promise<T>;
739
1055
  //#endregion
740
- export { Asset, DEFAULT_ALGOD_PORT, DEFAULT_ALGOD_TOKEN, DEFAULT_ALGOD_URI, DEFAULT_API_BASE_URL, DEFAULT_AUTO_OPT_IN, DEFAULT_CONFIRMATION_ROUNDS, DEFAULT_FEE_BPS, DEFAULT_MAX_DEPTH, DEFAULT_MAX_GROUP_SIZE, DEPRECATED_PROTOCOLS, DeflexClient, DeflexConfig, DeflexConfigParams, DeflexQuote, DeflexSignature, DeflexTransaction, DexQuote, FetchQuoteParams, FetchQuoteResponse, FetchSwapTxnsBody, FetchSwapTxnsParams, FetchSwapTxnsResponse, HTTPError, MAX_FEE_BPS, PathElement, Profit, Protocol, QuoteType, Route, SignerFunction, SwapComposer, SwapComposerConfig, SwapComposerStatus, SwapTransaction, TxnPayload, request };
1056
+ export { Asset, DEFAULT_ALGOD_PORT, DEFAULT_ALGOD_TOKEN, DEFAULT_ALGOD_URI, DEFAULT_API_BASE_URL, DEFAULT_AUTO_OPT_IN, DEFAULT_CONFIRMATION_ROUNDS, DEFAULT_FEE_BPS, DEFAULT_MAX_DEPTH, DEFAULT_MAX_GROUP_SIZE, DEPRECATED_PROTOCOLS, DeflexClient, DeflexConfig, DeflexConfigParams, DeflexQuote, DeflexSignature, DeflexTransaction, DexQuote, FetchQuoteParams, FetchQuoteResponse, FetchSwapTxnsBody, FetchSwapTxnsParams, FetchSwapTxnsResponse, HTTPError, MAX_FEE_BPS, MethodCall, PathElement, Profit, Protocol, QuoteType, Route, SignerFunction, SwapComposer, SwapComposerConfig, SwapComposerStatus, SwapContext, SwapMiddleware, SwapTransaction, TxnPayload, request };
741
1057
  //# sourceMappingURL=index.d.ts.map