@txnlab/deflex 1.3.0 → 1.4.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/README.md CHANGED
@@ -259,6 +259,31 @@ const swap = await deflex.newSwap({ quote, address, signer, slippage: 1 })
259
259
  await swap.execute() // Middleware transactions are automatically included
260
260
  ```
261
261
 
262
+ #### Built-in Middleware
263
+
264
+ 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:
265
+
266
+ ```typescript
267
+ import { DeflexClient, AutoOptOutMiddleware } from '@txnlab/deflex'
268
+
269
+ const autoOptOut = new AutoOptOutMiddleware({
270
+ excludedAssets: [31566704], // Optional: exclude specific assets like USDC
271
+ })
272
+
273
+ const deflex = new DeflexClient({
274
+ apiKey: 'your-api-key',
275
+ middleware: [autoOptOut],
276
+ })
277
+
278
+ // When swapping full balance, opt-out transaction is automatically added
279
+ const quote = await deflex.newQuote({
280
+ fromASAID: someAssetId,
281
+ toASAID: 0,
282
+ amount: fullBalance, // If this matches your full balance, asset will be opted out
283
+ address: userAddress,
284
+ })
285
+ ```
286
+
262
287
  For details on creating your own middleware, see [MIDDLEWARE.md](MIDDLEWARE.md).
263
288
 
264
289
  ### Manual Asset Opt-In Detection
@@ -26,8 +26,8 @@ declare const DEFAULT_ALGOD_TOKEN = "";
26
26
  declare const DEFAULT_ALGOD_PORT = 443;
27
27
  /** Default Deflex API base URL */
28
28
  declare const DEFAULT_API_BASE_URL = "https://deflex.txnlab.dev/api";
29
- /** Default fee in basis points (0.15%) */
30
- declare const DEFAULT_FEE_BPS = 15;
29
+ /** Default fee in basis points (0.10%) */
30
+ declare const DEFAULT_FEE_BPS = 10;
31
31
  /** Maximum allowed fee in basis points (3.00%) */
32
32
  declare const MAX_FEE_BPS = 300;
33
33
  /** Default maximum transaction group size */
@@ -37,7 +37,7 @@ declare const DEFAULT_MAX_DEPTH = 4;
37
37
  /** Default auto opt-in setting (automatic asset/app opt-in detection) */
38
38
  declare const DEFAULT_AUTO_OPT_IN = false;
39
39
  /** Default number of rounds to wait for transaction confirmation */
40
- declare const DEFAULT_CONFIRMATION_ROUNDS = 4;
40
+ declare const DEFAULT_CONFIRMATION_ROUNDS = 10;
41
41
  //#endregion
42
42
  //#region src/types.d.ts
43
43
  /**
@@ -343,6 +343,23 @@ interface MethodCall {
343
343
  }
344
344
  //#endregion
345
345
  //#region src/middleware.d.ts
346
+ /**
347
+ * Context provided to middleware shouldApply hook
348
+ */
349
+ interface QuoteContext {
350
+ /** Input asset ID (always bigint for precision and future-proofing) */
351
+ readonly fromASAID: bigint;
352
+ /** Output asset ID (always bigint for precision and future-proofing) */
353
+ readonly toASAID: bigint;
354
+ /** Amount to swap (always bigint for precision and future-proofing) */
355
+ readonly amount: bigint;
356
+ /** Quote type */
357
+ readonly type: QuoteType;
358
+ /** Address of the account that will perform the swap (if provided) */
359
+ readonly address?: string;
360
+ /** Algodv2 client instance for making additional queries */
361
+ readonly algodClient: Algodv2;
362
+ }
346
363
  /**
347
364
  * Context provided to middleware hooks during swap composition
348
365
  */
@@ -375,8 +392,8 @@ interface SwapContext {
375
392
  * readonly name = 'CustomAsset'
376
393
  * readonly version = '1.0.0'
377
394
  *
378
- * async shouldApply(params) {
379
- * return params.fromASAID === CUSTOM_ASSET_ID || params.toASAID === CUSTOM_ASSET_ID
395
+ * async shouldApply(context) {
396
+ * return context.fromASAID === CUSTOM_ASSET_ID || context.toASAID === CUSTOM_ASSET_ID
380
397
  * }
381
398
  *
382
399
  * async adjustQuoteParams(params) {
@@ -407,22 +424,19 @@ interface SwapMiddleware {
407
424
  * Called during both quote and swap phases. Use this to check if either
408
425
  * the input or output asset requires special handling.
409
426
  *
410
- * @param params - Asset IDs being swapped
427
+ * @param context - Quote context with asset IDs, amount, type, address, and algod client
411
428
  * @returns True if middleware should be applied
412
429
  *
413
430
  * @example
414
431
  * ```typescript
415
- * async shouldApply(params) {
432
+ * async shouldApply(context) {
416
433
  * // Check if asset is registered in our smart contract
417
- * const assetInfo = await this.getAssetInfo(params.fromASAID)
434
+ * const assetInfo = await this.getAssetInfo(context.fromASAID)
418
435
  * return assetInfo !== null
419
436
  * }
420
437
  * ```
421
438
  */
422
- shouldApply(params: {
423
- fromASAID: bigint;
424
- toASAID: bigint;
425
- }): Promise<boolean>;
439
+ shouldApply(context: QuoteContext): Promise<boolean>;
426
440
  /**
427
441
  * Modify quote parameters before fetching the quote
428
442
  *
@@ -545,6 +559,52 @@ interface SwapMiddleware {
545
559
  */
546
560
  afterSwap?(context: SwapContext): Promise<TransactionWithSigner[]>;
547
561
  }
562
+ /**
563
+ * Configuration options for AutoOptOutMiddleware
564
+ */
565
+ interface AutoOptOutConfig {
566
+ /**
567
+ * Array of asset IDs that should be excluded from automatic opt-out behavior
568
+ * @default []
569
+ */
570
+ readonly excludedAssets?: readonly (number | bigint)[];
571
+ }
572
+ /**
573
+ * Middleware that automatically adds an asset opt-out transaction when swapping
574
+ * the full balance of an input asset, leaving it with a zero balance.
575
+ *
576
+ * @example
577
+ * ```typescript
578
+ * import { DeflexClient, AutoOptOutMiddleware } from '@txnlab/deflex'
579
+ *
580
+ * const autoOptOut = new AutoOptOutMiddleware({
581
+ * excludedAssets: [31566704], // Don't auto-opt-out of USDC
582
+ * })
583
+ *
584
+ * const deflex = new DeflexClient({
585
+ * apiKey: 'your-api-key',
586
+ * middleware: [autoOptOut],
587
+ * })
588
+ *
589
+ * // When swapping full balance, opt-out transaction is automatically added
590
+ * const quote = await deflex.newQuote({
591
+ * address: userAddress,
592
+ * fromASAID: someAssetId,
593
+ * toASAID: 0,
594
+ * amount: fullBalance, // If this equals account's full balance, opt-out is added
595
+ * type: 'fixed-input',
596
+ * })
597
+ * ```
598
+ */
599
+ declare class AutoOptOutMiddleware implements SwapMiddleware {
600
+ readonly name = "AutoOptOut";
601
+ readonly version = "1.0.0";
602
+ private readonly excludedAssets;
603
+ constructor(config?: AutoOptOutConfig);
604
+ shouldApply(context: QuoteContext): Promise<boolean>;
605
+ adjustQuoteParams(params: FetchQuoteParams): Promise<FetchQuoteParams>;
606
+ afterSwap(context: SwapContext): Promise<TransactionWithSigner[]>;
607
+ }
548
608
  //#endregion
549
609
  //#region src/composer.d.ts
550
610
  /**
@@ -754,7 +814,7 @@ declare class SwapComposer {
754
814
  * This is the primary method for executing swaps and combines sign(), submit(), and
755
815
  * waitForConfirmation() into a single call.
756
816
  *
757
- * @param waitRounds - The number of rounds to wait for confirmation (default: 4)
817
+ * @param waitRounds - The number of rounds to wait for confirmation (default: 10)
758
818
  * @returns Object containing the confirmed round and transaction IDs
759
819
  * @throws Error if the transaction group has already been committed
760
820
  *
@@ -798,10 +858,6 @@ declare class SwapComposer {
798
858
  * Execute middleware hooks (beforeSwap or afterSwap)
799
859
  */
800
860
  private executeMiddlewareHooks;
801
- /**
802
- * Create SwapContext for middleware hooks
803
- */
804
- private createSwapContext;
805
861
  }
806
862
  //#endregion
807
863
  //#region src/client.d.ts
@@ -1053,5 +1109,5 @@ declare class HTTPError extends Error {
1053
1109
  */
1054
1110
  declare function request<T>(url: string, options?: RequestInit): Promise<T>;
1055
1111
  //#endregion
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 };
1057
- //# sourceMappingURL=index.d.ts.map
1112
+ export { Asset, AutoOptOutConfig, AutoOptOutMiddleware, 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, QuoteContext, QuoteType, Route, SignerFunction, SwapComposer, SwapComposerConfig, SwapComposerStatus, SwapContext, SwapMiddleware, SwapTransaction, TxnPayload, request };
1113
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/constants.ts","../src/types.ts","../src/middleware.ts","../src/composer.ts","../src/client.ts","../src/utils.ts"],"sourcesContent":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Algodv2, AtomicTransactionComposer, LogicSigAccount, Transaction, decodeUnsignedTransaction, isValidAddress, makeApplicationOptInTxnFromObject, msgpackRawDecode, signLogicSigTransactionObject, signTransaction } from "algosdk";
1
+ import { Algodv2, AtomicTransactionComposer, LogicSigAccount, Transaction, decodeUnsignedTransaction, isValidAddress, makeApplicationOptInTxnFromObject, makeAssetTransferTxnWithSuggestedParamsFromObject, msgpackRawDecode, signLogicSigTransactionObject, signTransaction } from "algosdk";
2
2
 
3
3
  //#region src/constants.ts
4
4
  /**
@@ -27,8 +27,8 @@ const DEFAULT_ALGOD_TOKEN = "";
27
27
  const DEFAULT_ALGOD_PORT = 443;
28
28
  /** Default Deflex API base URL */
29
29
  const DEFAULT_API_BASE_URL = "https://deflex.txnlab.dev/api";
30
- /** Default fee in basis points (0.15%) */
31
- const DEFAULT_FEE_BPS = 15;
30
+ /** Default fee in basis points (0.10%) */
31
+ const DEFAULT_FEE_BPS = 10;
32
32
  /** Maximum allowed fee in basis points (3.00%) */
33
33
  const MAX_FEE_BPS = 300;
34
34
  /** Default maximum transaction group size */
@@ -38,7 +38,7 @@ const DEFAULT_MAX_DEPTH = 4;
38
38
  /** Default auto opt-in setting (automatic asset/app opt-in detection) */
39
39
  const DEFAULT_AUTO_OPT_IN = false;
40
40
  /** Default number of rounds to wait for transaction confirmation */
41
- const DEFAULT_CONFIRMATION_ROUNDS = 4;
41
+ const DEFAULT_CONFIRMATION_ROUNDS = 10;
42
42
 
43
43
  //#endregion
44
44
  //#region src/composer.ts
@@ -275,7 +275,7 @@ var SwapComposer = class SwapComposer {
275
275
  * This is the primary method for executing swaps and combines sign(), submit(), and
276
276
  * waitForConfirmation() into a single call.
277
277
  *
278
- * @param waitRounds - The number of rounds to wait for confirmation (default: 4)
278
+ * @param waitRounds - The number of rounds to wait for confirmation (default: 10)
279
279
  * @returns Object containing the confirmed round and transaction IDs
280
280
  * @throws Error if the transaction group has already been committed
281
281
  *
@@ -288,7 +288,7 @@ var SwapComposer = class SwapComposer {
288
288
  */
289
289
  async execute(waitRounds = DEFAULT_CONFIRMATION_ROUNDS) {
290
290
  if (!this.swapTransactionsAdded) await this.addSwapTransactions();
291
- const { txIDs,...result } = await this.atc.execute(this.algodClient, waitRounds);
291
+ const { txIDs, ...result } = await this.atc.execute(this.algodClient, waitRounds);
292
292
  return {
293
293
  ...result,
294
294
  txIds: txIDs
@@ -386,37 +386,37 @@ var SwapComposer = class SwapComposer {
386
386
  */
387
387
  async executeMiddlewareHooks(hookName) {
388
388
  const allTxns = [];
389
+ const quote = "createdAt" in this.quote ? this.quote : {
390
+ ...this.quote,
391
+ quote: this.quote.quote === "" ? 0n : BigInt(this.quote.quote),
392
+ amount: 0n,
393
+ createdAt: Date.now()
394
+ };
395
+ const quoteContext = {
396
+ fromASAID: BigInt(this.quote.fromASAID),
397
+ toASAID: BigInt(this.quote.toASAID),
398
+ amount: quote.amount,
399
+ type: this.quote.type,
400
+ address: quote.address,
401
+ algodClient: this.algodClient
402
+ };
389
403
  for (const mw of this.middleware) {
390
- if (!await mw.shouldApply({
404
+ if (!await mw.shouldApply(quoteContext) || !mw[hookName]) continue;
405
+ const suggestedParams = await this.algodClient.getTransactionParams().do();
406
+ const swapContext = {
407
+ quote,
408
+ address: this.address,
409
+ algodClient: this.algodClient,
410
+ suggestedParams,
391
411
  fromASAID: BigInt(this.quote.fromASAID),
392
- toASAID: BigInt(this.quote.toASAID)
393
- }) || !mw[hookName]) continue;
394
- const context = await this.createSwapContext();
395
- const txns = await mw[hookName](context);
412
+ toASAID: BigInt(this.quote.toASAID),
413
+ signer: this.defaultSigner
414
+ };
415
+ const txns = await mw[hookName](swapContext);
396
416
  allTxns.push(...txns);
397
417
  }
398
418
  return allTxns;
399
419
  }
400
- /**
401
- * Create SwapContext for middleware hooks
402
- */
403
- async createSwapContext() {
404
- const suggestedParams = await this.algodClient.getTransactionParams().do();
405
- return {
406
- quote: "createdAt" in this.quote ? this.quote : {
407
- ...this.quote,
408
- quote: this.quote.quote === "" ? 0n : BigInt(this.quote.quote),
409
- amount: 0n,
410
- createdAt: Date.now()
411
- },
412
- address: this.address,
413
- algodClient: this.algodClient,
414
- suggestedParams,
415
- fromASAID: BigInt(this.quote.fromASAID),
416
- toASAID: BigInt(this.quote.toASAID),
417
- signer: this.defaultSigner
418
- };
419
- }
420
420
  };
421
421
 
422
422
  //#endregion
@@ -673,10 +673,15 @@ var DeflexClient = class {
673
673
  */
674
674
  async newQuote(params) {
675
675
  let adjustedParams = { ...params };
676
- for (const mw of this.middleware) if (await mw.shouldApply({
676
+ const quoteContext = {
677
677
  fromASAID: BigInt(params.fromASAID),
678
- toASAID: BigInt(params.toASAID)
679
- }) && mw.adjustQuoteParams) adjustedParams = await mw.adjustQuoteParams(adjustedParams);
678
+ toASAID: BigInt(params.toASAID),
679
+ amount: BigInt(params.amount),
680
+ type: params.type ?? "fixed-input",
681
+ address: params.address ?? void 0,
682
+ algodClient: this.algodClient
683
+ };
684
+ for (const mw of this.middleware) if (await mw.shouldApply(quoteContext) && mw.adjustQuoteParams) adjustedParams = await mw.adjustQuoteParams(adjustedParams);
680
685
  const response = await this.fetchQuote(adjustedParams);
681
686
  return {
682
687
  ...response,
@@ -773,5 +778,77 @@ var DeflexClient = class {
773
778
  };
774
779
 
775
780
  //#endregion
776
- export { 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, HTTPError, MAX_FEE_BPS, Protocol, SwapComposer, SwapComposerStatus, request };
777
- //# sourceMappingURL=index.js.map
781
+ //#region src/middleware.ts
782
+ /**
783
+ * Middleware that automatically adds an asset opt-out transaction when swapping
784
+ * the full balance of an input asset, leaving it with a zero balance.
785
+ *
786
+ * @example
787
+ * ```typescript
788
+ * import { DeflexClient, AutoOptOutMiddleware } from '@txnlab/deflex'
789
+ *
790
+ * const autoOptOut = new AutoOptOutMiddleware({
791
+ * excludedAssets: [31566704], // Don't auto-opt-out of USDC
792
+ * })
793
+ *
794
+ * const deflex = new DeflexClient({
795
+ * apiKey: 'your-api-key',
796
+ * middleware: [autoOptOut],
797
+ * })
798
+ *
799
+ * // When swapping full balance, opt-out transaction is automatically added
800
+ * const quote = await deflex.newQuote({
801
+ * address: userAddress,
802
+ * fromASAID: someAssetId,
803
+ * toASAID: 0,
804
+ * amount: fullBalance, // If this equals account's full balance, opt-out is added
805
+ * type: 'fixed-input',
806
+ * })
807
+ * ```
808
+ */
809
+ var AutoOptOutMiddleware = class {
810
+ name = "AutoOptOut";
811
+ version = "1.0.0";
812
+ excludedAssets;
813
+ constructor(config = {}) {
814
+ this.excludedAssets = new Set((config.excludedAssets ?? []).map((id) => BigInt(id)));
815
+ }
816
+ async shouldApply(context) {
817
+ if (context.type !== "fixed-input") return false;
818
+ if (!context.address) return false;
819
+ if (context.fromASAID === 0n) return false;
820
+ if (this.excludedAssets.has(context.fromASAID)) return false;
821
+ try {
822
+ const assetHolding = (await context.algodClient.accountInformation(context.address).do()).assets?.find((asset) => asset.assetId === context.fromASAID);
823
+ if (!assetHolding) return false;
824
+ return assetHolding.amount === context.amount;
825
+ } catch (error) {
826
+ console.warn(`AutoOptOutMiddleware: Failed to fetch account info for ${context.address}:`, error);
827
+ return false;
828
+ }
829
+ }
830
+ async adjustQuoteParams(params) {
831
+ const maxGroupSize = (params.maxGroupSize ?? 16) - 1;
832
+ return {
833
+ ...params,
834
+ maxGroupSize
835
+ };
836
+ }
837
+ async afterSwap(context) {
838
+ return [{
839
+ txn: makeAssetTransferTxnWithSuggestedParamsFromObject({
840
+ sender: context.address,
841
+ receiver: context.address,
842
+ amount: 0n,
843
+ assetIndex: context.fromASAID,
844
+ closeRemainderTo: context.address,
845
+ suggestedParams: context.suggestedParams
846
+ }),
847
+ signer: context.signer
848
+ }];
849
+ }
850
+ };
851
+
852
+ //#endregion
853
+ export { AutoOptOutMiddleware, 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, HTTPError, MAX_FEE_BPS, Protocol, SwapComposer, SwapComposerStatus, request };
854
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["swapTxns: TransactionWithSigner[]","allTxns: TransactionWithSigner[]","quote: DeflexQuote","quoteContext: QuoteContext","swapContext: SwapContext","status: number","statusText: string","data: unknown","errorData: unknown","body: FetchSwapTxnsBody"],"sources":["../src/constants.ts","../src/composer.ts","../src/utils.ts","../src/client.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Supported DEX protocols for swap routing\n */\nexport enum Protocol {\n TinymanV2 = 'TinymanV2',\n Algofi = 'Algofi',\n Algomint = 'Algomint',\n Pact = 'Pact',\n Folks = 'Folks',\n TAlgo = 'TAlgo',\n}\n\n/**\n * Deprecated protocols that are automatically excluded from routing\n *\n * @internal\n */\nexport const DEPRECATED_PROTOCOLS = ['Humble', 'Tinyman'] as const\n\n/** Default Algod node URI for mainnet */\nexport const DEFAULT_ALGOD_URI = 'https://mainnet-api.4160.nodely.dev/'\n\n/** Default Algod node token (empty for public nodes) */\nexport const DEFAULT_ALGOD_TOKEN = ''\n\n/** Default Algod node port */\nexport const DEFAULT_ALGOD_PORT = 443\n\n/** Default Deflex API base URL */\nexport const DEFAULT_API_BASE_URL = 'https://deflex.txnlab.dev/api'\n\n/** Default fee in basis points (0.10%) */\nexport const DEFAULT_FEE_BPS = 10\n\n/** Maximum allowed fee in basis points (3.00%) */\nexport const MAX_FEE_BPS = 300\n\n/** Default maximum transaction group size */\nexport const DEFAULT_MAX_GROUP_SIZE = 16\n\n/** Default maximum routing depth (number of hops) */\nexport const DEFAULT_MAX_DEPTH = 4\n\n/** Default auto opt-in setting (automatic asset/app opt-in detection) */\nexport const DEFAULT_AUTO_OPT_IN = false\n\n/** Default number of rounds to wait for transaction confirmation */\nexport const DEFAULT_CONFIRMATION_ROUNDS = 10\n","import {\n AtomicTransactionComposer,\n decodeUnsignedTransaction,\n isValidAddress,\n LogicSigAccount,\n makeApplicationOptInTxnFromObject,\n msgpackRawDecode,\n signLogicSigTransactionObject,\n signTransaction,\n Transaction,\n type ABIResult,\n type Algodv2,\n type TransactionSigner,\n type TransactionWithSigner,\n} from 'algosdk'\nimport { DEFAULT_CONFIRMATION_ROUNDS } from './constants'\nimport type { SwapMiddleware, SwapContext, QuoteContext } from './middleware'\nimport type {\n FetchQuoteResponse,\n DeflexTransaction,\n DeflexSignature,\n DeflexQuote,\n MethodCall,\n QuoteType,\n} from './types'\n\n/**\n * A transaction signer function that supports both standard algosdk.TransactionSigner\n * and ARC-1 compliant signers that may return null for unsigned transactions.\n *\n * @param txnGroup - The complete transaction group to sign\n * @param indexesToSign - Array of indexes indicating which transactions need signing\n * @returns Array of signed transactions (may include nulls for ARC-1 compliant wallets)\n */\nexport type SignerFunction = (\n txnGroup: Transaction[],\n indexesToSign: number[],\n) => Promise<(Uint8Array | null)[]>\n\n/**\n * Status of the SwapComposer transaction group lifecycle\n */\nexport enum SwapComposerStatus {\n /** The atomic group is still under construction. */\n BUILDING,\n\n /** The atomic group has been finalized, but not yet signed. */\n BUILT,\n\n /** The atomic group has been finalized and signed, but not yet submitted to the network. */\n SIGNED,\n\n /** The atomic group has been finalized, signed, and submitted to the network. */\n SUBMITTED,\n\n /** The atomic group has been finalized, signed, submitted, and successfully committed to a block. */\n COMMITTED,\n}\n\n/**\n * Configuration for creating a SwapComposer instance\n */\nexport interface SwapComposerConfig {\n /** The quote response from fetchQuote() or newQuote() */\n readonly quote: FetchQuoteResponse | DeflexQuote\n /** The swap transactions from fetchSwapTransactions() */\n readonly deflexTxns: DeflexTransaction[]\n /** Algodv2 client instance */\n readonly algodClient: Algodv2\n /** The address of the account that will sign transactions */\n readonly address: string\n /** Transaction signer function */\n readonly signer: TransactionSigner | SignerFunction\n /** Middleware to apply during swap composition */\n readonly middleware?: SwapMiddleware[]\n}\n\n/**\n * Composer for building and executing atomic swap transaction groups\n *\n * The SwapComposer allows you to build complex transaction groups by adding custom\n * transactions before and after swap transactions. It handles pre-signed transactions,\n * automatic app opt-ins, and provides a fluent API for transaction group construction.\n *\n * @example\n * ```typescript\n * const quote = await deflex.fetchQuote({ ... })\n * const composer = await deflex.newSwap({ quote, address, slippage, signer })\n *\n * await composer\n * .addTransaction(customTxn)\n * .addSwapTransactions()\n * .execute()\n * ```\n */\nexport class SwapComposer {\n /** The ATC used to compose the group */\n private atc = new AtomicTransactionComposer()\n\n /** The maximum size of an atomic transaction group. */\n static MAX_GROUP_SIZE: number = AtomicTransactionComposer.MAX_GROUP_SIZE\n\n /** Whether the swap transactions have been added to the atomic group. */\n private swapTransactionsAdded = false\n\n private readonly quote: FetchQuoteResponse | DeflexQuote\n private readonly requiredAppOptIns: number[]\n private readonly deflexTxns: DeflexTransaction[]\n private readonly algodClient: Algodv2\n private readonly address: string\n private readonly signer: TransactionSigner | SignerFunction\n private readonly middleware: SwapMiddleware[]\n\n /**\n * Create a new SwapComposer instance\n *\n * Note: Most developers should use DeflexClient.newSwap() instead of constructing\n * this directly, as the factory method handles fetching swap transactions automatically.\n *\n * @param config - Configuration for the composer\n * @param config.quote - The quote response from fetchQuote()\n * @param config.deflexTxns - The swap transactions from fetchSwapTransactions()\n * @param config.algodClient - Algodv2 client instance\n * @param config.address - The address of the account that will sign transactions\n * @param config.signer - Transaction signer function\n * @param config.middleware - Middleware to apply during swap composition\n */\n constructor(config: SwapComposerConfig) {\n // Validate required parameters\n if (!config.quote) {\n throw new Error('Quote is required')\n }\n if (!config.deflexTxns) {\n throw new Error('Swap transactions are required')\n }\n if (config.deflexTxns.length === 0) {\n throw new Error('Swap transactions array cannot be empty')\n }\n if (!config.algodClient) {\n throw new Error('Algodv2 client instance is required')\n }\n if (!config.signer) {\n throw new Error('Signer is required')\n }\n\n this.quote = config.quote\n this.requiredAppOptIns = config.quote.requiredAppOptIns\n this.deflexTxns = config.deflexTxns\n this.algodClient = config.algodClient\n this.address = this.validateAddress(config.address)\n this.signer = config.signer\n this.middleware = config.middleware ?? []\n }\n\n /**\n * Get the status of this composer's transaction group\n *\n * @returns The current status of the transaction group\n */\n getStatus(): SwapComposerStatus {\n return this.atc.getStatus() as unknown as SwapComposerStatus\n }\n\n /**\n * Get the number of transactions currently in this atomic group\n *\n * @returns The number of transactions in the group\n */\n count(): number {\n return this.atc.count()\n }\n\n /**\n * Add a transaction to the atomic group\n *\n * Transactions are added in the order methods are called. For example:\n * ```typescript\n * composer\n * .addTransaction(txn1) // Added first\n * .addSwapTransactions() // Added second\n * .addTransaction(txn2) // Added third\n * ```\n *\n * @param transaction - The transaction to add\n * @returns This composer instance for chaining\n * @throws Error if the composer is not in the BUILDING status\n * @throws Error if the maximum group size is exceeded\n */\n addTransaction(transaction: Transaction, signer = this.defaultSigner): this {\n this.atc.addTransaction({ txn: transaction, signer })\n return this\n }\n\n /**\n * Add a method call to the atomic group\n *\n * The `signer` property in the `methodCall` parameter is optional. If not provided,\n * the signer will default to the one passed as the second parameter, or the\n * configured signer from the constructor if no second parameter is provided.\n *\n * @param methodCall - The method call to add\n * @param signer - The signer to use for the method call (defaults to constructor signer)\n * @returns This composer instance for chaining\n */\n addMethodCall(methodCall: MethodCall, signer = this.defaultSigner): this {\n this.atc.addMethodCall({\n ...methodCall,\n signer: methodCall.signer ?? signer,\n })\n return this\n }\n\n /**\n * Add swap transactions to the atomic group\n *\n * This method automatically processes required app opt-ins, executes middleware hooks,\n * and adds all swap transactions from the quote. Can only be called once per composer instance.\n *\n * Middleware hooks are executed in this order:\n * 1. beforeSwap() - Add transactions before swap transactions\n * 2. Swap transactions (from API)\n * 3. afterSwap() - Add transactions after swap transactions\n *\n * @returns This composer instance for chaining\n * @throws Error if the swap transactions have already been added\n * @throws Error if the composer is not in the BUILDING status\n * @throws Error if the maximum group size is exceeded\n */\n async addSwapTransactions(): Promise<this> {\n if (this.swapTransactionsAdded) {\n throw new Error('Swap transactions have already been added')\n }\n\n if (this.getStatus() !== SwapComposerStatus.BUILDING) {\n throw new Error(\n 'Cannot add swap transactions when composer status is not BUILDING',\n )\n }\n\n // Execute beforeSwap middleware hooks\n const beforeTxns = await this.executeMiddlewareHooks('beforeSwap')\n\n // Check total length before adding beforeSwap transactions\n if (this.atc.count() + beforeTxns.length > SwapComposer.MAX_GROUP_SIZE) {\n throw new Error(\n `Adding beforeSwap transactions exceeds the maximum atomic group size of ${SwapComposer.MAX_GROUP_SIZE}`,\n )\n }\n\n for (const txnWithSigner of beforeTxns) {\n this.atc.addTransaction(txnWithSigner)\n }\n\n // Process swap transactions and execute afterSwap hooks\n const processedTxns = await this.processSwapTransactions()\n const afterTxns = await this.executeMiddlewareHooks('afterSwap')\n\n // Check total length before adding swap and afterSwap transactions\n const totalLength =\n this.atc.count() + processedTxns.length + afterTxns.length\n\n if (totalLength > SwapComposer.MAX_GROUP_SIZE) {\n throw new Error(\n `Adding swap transactions exceeds the maximum atomic group size of ${SwapComposer.MAX_GROUP_SIZE}`,\n )\n }\n\n // Add swap transactions\n for (const txnWithSigner of processedTxns) {\n this.atc.addTransaction(txnWithSigner)\n }\n\n // Add afterSwap middleware transactions\n for (const txnWithSigner of afterTxns) {\n this.atc.addTransaction(txnWithSigner)\n }\n\n this.swapTransactionsAdded = true\n return this\n }\n\n /**\n * Finalize the transaction group by assigning group IDs\n *\n * This method builds the atomic transaction group, assigning group IDs to all transactions\n * if there is more than one transaction. After calling this method, the composer's status\n * will be at least BUILT.\n *\n * @returns Array of transactions with their associated signers\n *\n * @throws Error if the group contains 0 transactions\n *\n * @example\n * ```typescript\n * const composer = await deflex.newSwap({ quote, address, slippage, signer })\n * composer.addTransaction(customTxn)\n *\n * // Build the group to inspect transactions before signing\n * const txnsWithSigners = composer.buildGroup()\n * console.log('Group ID:', txnsWithSigners[0].txn.group)\n * console.log('Group length:', txnsWithSigners.length)\n * console.log('Status:', composer.getStatus()) // BUILT\n * ```\n */\n buildGroup(): TransactionWithSigner[] {\n return this.atc.buildGroup()\n }\n\n /**\n * Sign the transaction group\n *\n * Automatically adds swap transactions if not already added, builds the atomic group,\n * and signs all transactions using the configured signer.\n *\n * @returns A promise that resolves to an array of signed transaction blobs\n *\n * @example\n * ```typescript\n * const signedTxns = await composer.sign()\n * ```\n */\n async sign(): Promise<Uint8Array[]> {\n if (this.getStatus() >= SwapComposerStatus.SIGNED) {\n return this.atc.gatherSignatures()\n }\n\n // Auto-add swap transactions if needed\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n return await this.atc.gatherSignatures()\n }\n\n /**\n * Submit the signed transactions to the network\n *\n * This method signs the transaction group (if not already signed) and submits\n * it to the Algorand network. Does not wait for confirmation.\n *\n * @returns The transaction IDs\n * @throws Error if the transaction group has already been submitted\n *\n * @example\n * ```typescript\n * const txIds = await composer.submit()\n * console.log('Submitted transactions:', txIds)\n * ```\n */\n async submit(): Promise<string[]> {\n // Auto-add swap transactions if needed (maintains backward compatibility)\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n return this.atc.submit(this.algodClient)\n }\n\n /**\n * Execute the swap\n *\n * Signs the transaction group, submits it to the network, and waits for confirmation.\n * This is the primary method for executing swaps and combines sign(), submit(), and\n * waitForConfirmation() into a single call.\n *\n * @param waitRounds - The number of rounds to wait for confirmation (default: 10)\n * @returns Object containing the confirmed round and transaction IDs\n * @throws Error if the transaction group has already been committed\n *\n * @example\n * ```typescript\n * const result = await composer.execute()\n * console.log(`Confirmed in round ${result.confirmedRound}`)\n * console.log('Transaction IDs:', result.txIds)\n * ```\n */\n async execute(waitRounds: number = DEFAULT_CONFIRMATION_ROUNDS): Promise<{\n confirmedRound: bigint\n txIds: string[]\n methodResults: ABIResult[]\n }> {\n // Auto-add swap transactions if needed (maintains backward compatibility)\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n const { txIDs, ...result } = await this.atc.execute(\n this.algodClient,\n waitRounds,\n )\n\n return {\n ...result,\n txIds: txIDs,\n }\n }\n\n /**\n * Validates an Algorand address\n */\n private validateAddress(address: string): string {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid Algorand address: ${address}`)\n }\n return address\n }\n\n /**\n * Processes app opt-ins and decodes swap transactions from API response\n */\n private async processSwapTransactions(): Promise<TransactionWithSigner[]> {\n const appOptIns = await this.processRequiredAppOptIns()\n\n const swapTxns: TransactionWithSigner[] = []\n for (let i = 0; i < this.deflexTxns.length; i++) {\n const deflexTxn = this.deflexTxns[i]\n if (!deflexTxn) continue\n\n try {\n const txnBytes = Buffer.from(deflexTxn.data, 'base64')\n const txn = decodeUnsignedTransaction(txnBytes)\n delete txn.group\n\n if (deflexTxn.signature !== false) {\n // Pre-signed transaction - use custom Deflex signer\n swapTxns.push({\n txn,\n signer: this.createDeflexSigner(deflexTxn.signature),\n })\n } else {\n // User transaction - use configured signer\n swapTxns.push({\n txn,\n signer: this.defaultSigner,\n })\n }\n } catch (error) {\n throw new Error(\n `Failed to process swap transaction at index ${i}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n return [...appOptIns, ...swapTxns]\n }\n\n /**\n * Creates opt-in transactions for apps the user hasn't opted into yet\n */\n private async processRequiredAppOptIns(): Promise<TransactionWithSigner[]> {\n // Fetch account information\n const accountInfo = await this.algodClient\n .accountInformation(this.address)\n .do()\n\n // Check app opt-ins\n const userApps =\n accountInfo?.appsLocalState?.map((app) => Number(app.id)) || []\n const appsToOptIn = this.requiredAppOptIns.filter(\n (appId) => !userApps.includes(appId),\n )\n\n if (appsToOptIn.length === 0) return []\n\n const suggestedParams = await this.algodClient.getTransactionParams().do()\n\n return appsToOptIn.map((appId) => ({\n txn: makeApplicationOptInTxnFromObject({\n sender: this.address,\n appIndex: appId,\n suggestedParams,\n }),\n signer: this.defaultSigner,\n }))\n }\n\n /**\n * The default signer function that uses the configured signer\n */\n private defaultSigner: TransactionSigner = async (\n txnGroup: Transaction[],\n indexesToSign: number[],\n ) => {\n const result = await this.signer(txnGroup, indexesToSign)\n return result.filter((txn): txn is Uint8Array => txn !== null)\n }\n\n /**\n * Creates a TransactionSigner function for Deflex pre-signed transactions\n */\n private createDeflexSigner(signature: DeflexSignature): TransactionSigner {\n return async (\n txnGroup: Transaction[],\n indexesToSign: number[],\n ): Promise<Uint8Array[]> => {\n return indexesToSign.map((i) => {\n const txn = txnGroup[i]\n if (!txn) throw new Error(`Transaction at index ${i} not found`)\n return this.signDeflexTransaction(txn, signature)\n })\n }\n }\n\n /**\n * Re-signs a Deflex transaction using the provided logic signature or secret key\n */\n private signDeflexTransaction(\n transaction: Transaction,\n signature: DeflexSignature,\n ): Uint8Array {\n try {\n if (signature.type === 'logic_signature') {\n // Decode the signature value to extract the logic signature\n const valueArray = signature.value as Record<string, number>\n const valueBytes = new Uint8Array(Object.values(valueArray))\n const decoded = msgpackRawDecode(valueBytes) as {\n lsig?: { l: Uint8Array; arg?: Uint8Array[] }\n }\n\n if (!decoded.lsig) {\n throw new Error('Logic signature structure missing lsig field')\n }\n\n const lsig = decoded.lsig\n const logicSigAccount = new LogicSigAccount(lsig.l, lsig.arg)\n\n const signedTxn = signLogicSigTransactionObject(\n transaction,\n logicSigAccount,\n )\n return signedTxn.blob\n } else if (signature.type === 'secret_key') {\n // Convert signature.value (Record<string, number>) to Uint8Array\n const valueArray = signature.value as Record<string, number>\n const secretKey = new Uint8Array(Object.values(valueArray))\n const signedTxn = signTransaction(transaction, secretKey)\n return signedTxn.blob\n } else {\n throw new Error(`Unsupported signature type: ${signature.type}`)\n }\n } catch (error) {\n throw new Error(\n `Failed to re-sign transaction: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n /**\n * Execute middleware hooks (beforeSwap or afterSwap)\n */\n private async executeMiddlewareHooks(\n hookName: 'beforeSwap' | 'afterSwap',\n ): Promise<TransactionWithSigner[]> {\n const allTxns: TransactionWithSigner[] = []\n\n // Convert to DeflexQuote if needed\n const quote: DeflexQuote =\n 'createdAt' in this.quote\n ? this.quote\n : {\n ...this.quote,\n quote: this.quote.quote === '' ? 0n : BigInt(this.quote.quote),\n amount: 0n, // Not available in FetchQuoteResponse\n createdAt: Date.now(),\n }\n\n // Create quote context for middleware shouldApply checks\n const quoteContext: QuoteContext = {\n fromASAID: BigInt(this.quote.fromASAID),\n toASAID: BigInt(this.quote.toASAID),\n amount: quote.amount,\n type: this.quote.type as QuoteType,\n address: quote.address,\n algodClient: this.algodClient,\n }\n\n for (const mw of this.middleware) {\n const shouldApply = await mw.shouldApply(quoteContext)\n\n if (!shouldApply || !mw[hookName]) {\n continue\n }\n\n // Create swap context for middleware hooks (only when needed)\n const suggestedParams = await this.algodClient.getTransactionParams().do()\n const swapContext: SwapContext = {\n quote,\n address: this.address,\n algodClient: this.algodClient,\n suggestedParams,\n fromASAID: BigInt(this.quote.fromASAID),\n toASAID: BigInt(this.quote.toASAID),\n signer: this.defaultSigner,\n }\n\n const txns = await mw[hookName](swapContext)\n allTxns.push(...txns)\n }\n\n return allTxns\n }\n}\n","/**\n * HTTP error with status code and response data\n */\nexport class HTTPError extends Error {\n constructor(\n public status: number,\n public statusText: string,\n public data: unknown,\n ) {\n super(`HTTP ${status} ${statusText}`)\n this.name = 'HTTPError'\n }\n}\n\n/**\n * Make an HTTP request and parse JSON response\n *\n * Simple wrapper around native fetch for API calls. Throws HTTPError for\n * non-2xx responses.\n *\n * @param url - The URL to request\n * @param options - Fetch options\n * @returns Parsed JSON response\n * @throws HTTPError if the response status is not ok\n */\nexport async function request<T>(\n url: string,\n options?: RequestInit,\n): Promise<T> {\n const response = await fetch(url, options)\n\n if (!response.ok) {\n let errorData: unknown\n\n try {\n errorData = await response.json()\n } catch {\n try {\n errorData = await response.text()\n } catch {\n errorData = 'Failed to parse error response'\n }\n }\n\n throw new HTTPError(\n response.status,\n response.statusText,\n JSON.stringify(errorData),\n )\n }\n\n return response.json() as Promise<T>\n}\n","import { Algodv2, isValidAddress, type TransactionSigner } from 'algosdk'\nimport { SwapComposer, type SignerFunction } from './composer'\nimport {\n DEFAULT_ALGOD_PORT,\n DEFAULT_ALGOD_TOKEN,\n DEFAULT_ALGOD_URI,\n DEFAULT_API_BASE_URL,\n DEFAULT_AUTO_OPT_IN,\n DEFAULT_FEE_BPS,\n DEFAULT_MAX_DEPTH,\n DEFAULT_MAX_GROUP_SIZE,\n DEPRECATED_PROTOCOLS,\n MAX_FEE_BPS,\n} from './constants'\nimport { request } from './utils'\nimport type { SwapMiddleware } from './middleware'\nimport type {\n FetchQuoteResponse,\n FetchSwapTxnsResponse,\n DeflexConfig,\n DeflexConfigParams,\n FetchSwapTxnsParams,\n FetchSwapTxnsBody,\n FetchQuoteParams,\n DeflexQuote,\n} from './types'\n\n/**\n * Client for interacting with the Deflex order router API\n *\n * The DeflexClient provides methods to fetch swap quotes and create transaction composers\n * for executing swaps on the Algorand blockchain. It handles API communication, transaction\n * validation, and automatic asset/app opt-in detection.\n *\n * @example\n * ```typescript\n * const deflex = new DeflexClient({\n * apiKey: 'your-api-key',\n * })\n * ```\n *\n * @example\n * ```typescript\n * const deflex = new DeflexClient({\n * apiKey: 'your-api-key',\n * apiBaseUrl: 'https://deflex.txnlab.dev',\n * algodUri: 'https://mainnet-api.4160.nodely.dev/',\n * algodToken: '',\n * algodPort: 443,\n * referrerAddress: 'REFERRER_ADDRESS...',\n * feeBps: 15,\n * autoOptIn: false,\n * })\n * ```\n */\nexport class DeflexClient {\n private readonly config: DeflexConfig\n private readonly algodClient: Algodv2\n private readonly middleware: SwapMiddleware[]\n\n /**\n * Create a new DeflexClient instance\n *\n * @param config - Configuration parameters\n * @param config.apiKey - API key for Deflex API (required)\n * @param config.apiBaseUrl - Base URL for the Deflex API (default: https://deflex.txnlab.dev)\n * @param config.algodUri - Algod node URI (default: https://mainnet-api.4160.nodely.dev/)\n * @param config.algodToken - Algod node token (default: '')\n * @param config.algodPort - Algod node port (default: 443)\n * @param config.referrerAddress - Referrer address for fee sharing (receives 25% of swap fees)\n * @param config.feeBps - Fee in basis points (default: 15 = 0.15%, max: 300 = 3.00%)\n * @param config.autoOptIn - Automatically detect and add required opt-in transactions (default: false)\n * @param config.middleware - Array of middleware to apply to swaps (default: [])\n */\n constructor(config: DeflexConfigParams & { middleware?: SwapMiddleware[] }) {\n // Validate and set config\n this.config = {\n apiKey: this.validateApiKey(config.apiKey),\n apiBaseUrl: config.apiBaseUrl ?? DEFAULT_API_BASE_URL,\n algodUri: config.algodUri ?? DEFAULT_ALGOD_URI,\n algodToken: config.algodToken ?? DEFAULT_ALGOD_TOKEN,\n algodPort: config.algodPort ?? DEFAULT_ALGOD_PORT,\n referrerAddress: config.referrerAddress\n ? this.validateAddress(config.referrerAddress)\n : undefined,\n feeBps: this.validateFeeBps(config.feeBps ?? DEFAULT_FEE_BPS),\n autoOptIn: config.autoOptIn ?? DEFAULT_AUTO_OPT_IN,\n }\n\n // Create Algodv2 client\n this.algodClient = new Algodv2(\n this.config.algodToken,\n this.config.algodUri,\n this.config.algodPort,\n )\n\n // Store middleware\n this.middleware = config.middleware ?? []\n }\n\n /**\n * Fetch a swap quote from the Deflex API\n *\n * Requests optimal swap routing from the Deflex API. The quote includes routing\n * information, price impact, required opt-ins, and an encrypted transaction payload.\n *\n * @param params - Parameters for the quote request\n * @param params.fromASAID - The ID of the asset to swap from\n * @param params.toASAID - The ID of the asset to swap to\n * @param params.amount - The amount of the asset to swap in base units\n * @param params.type - The type of the quote (default: 'fixed-input')\n * @param params.disabledProtocols - List of protocols to disable (default: [])\n * @param params.maxGroupSize - The maximum group size (default: 16)\n * @param params.maxDepth - The maximum depth (default: 4)\n * @param params.address - The address of the account that will perform the swap (recommended when using `config.autoOptIn` or `params.optIn`)\n * @param params.optIn - Whether to include asset opt-in transaction\n * - If true: API reduces maxGroupSize by 1 and includes opt-in (always included, even if not needed)\n * - If false: No opt-in transaction included\n * - If undefined: Falls back to `config.autoOptIn` behavior with account check (if `params.address` is provided)\n * @returns A FetchQuoteResponse object with routing information\n *\n * @example\n * ```typescript\n * const quote = await deflex.fetchQuote({\n * address: 'ABC...',\n * fromASAID: 0, // ALGO\n * toASAID: 31566704, // USDC\n * amount: 1_000_000, // 1 ALGO\n * })\n * ```\n */\n async fetchQuote(params: FetchQuoteParams): Promise<FetchQuoteResponse> {\n const {\n fromASAID,\n toASAID,\n amount,\n type = 'fixed-input',\n disabledProtocols = [],\n maxGroupSize = DEFAULT_MAX_GROUP_SIZE,\n maxDepth = DEFAULT_MAX_DEPTH,\n optIn,\n address,\n } = params\n\n // Always include deprecated protocols in disabled list\n const allDisabledProtocols = [\n ...new Set([...DEPRECATED_PROTOCOLS, ...disabledProtocols]),\n ]\n\n let includeOptIn = optIn\n if (includeOptIn === undefined && this.config.autoOptIn) {\n if (address) {\n includeOptIn = await this.needsAssetOptIn(\n this.validateAddress(address),\n toASAID,\n )\n } else {\n console.warn(\n 'autoOptIn is enabled but no address provided to fetchQuote(). Asset opt-in check skipped.',\n )\n }\n }\n\n const url = new URL(`${this.config.apiBaseUrl}/fetchQuote`)\n\n url.searchParams.append('apiKey', this.config.apiKey)\n url.searchParams.append('algodUri', this.config.algodUri)\n url.searchParams.append('algodToken', this.config.algodToken)\n url.searchParams.append('algodPort', String(this.config.algodPort))\n url.searchParams.append('feeBps', this.config.feeBps.toString())\n url.searchParams.append('fromASAID', BigInt(fromASAID).toString())\n url.searchParams.append('toASAID', BigInt(toASAID).toString())\n url.searchParams.append('amount', BigInt(amount).toString())\n url.searchParams.append('type', type)\n url.searchParams.append('disabledProtocols', allDisabledProtocols.join(','))\n url.searchParams.append('maxGroupSize', maxGroupSize.toString())\n url.searchParams.append('maxDepth', maxDepth.toString())\n\n if (typeof includeOptIn === 'boolean') {\n url.searchParams.append('optIn', String(includeOptIn))\n }\n\n if (this.config.referrerAddress) {\n url.searchParams.append('referrerAddress', this.config.referrerAddress)\n }\n\n return request<FetchQuoteResponse>(url.toString())\n }\n\n /**\n * Check if asset opt-in is required for the output asset\n *\n * Convenience method to determine if an address needs to opt into the output asset\n * of a swap. This is useful when you want to get a quote without requiring wallet\n * connection upfront, but need to know whether to set `optIn: true` in fetchQuote()\n * to ensure proper routing (as opt-ins reduce maxGroupSize by 1).\n *\n * Note: If you enable `config.autoOptIn`, this check is handled automatically when\n * an address is provided to fetchQuote().\n *\n * @param address - The address to check\n * @param assetId - The output asset ID to check\n * @returns True if asset opt-in is required, false otherwise (always false for ALGO)\n *\n * @example\n * ```typescript\n * // Check if opt-in needed for output asset before fetching quote\n * const needsOptIn = await deflex.needsAssetOptIn(userAddress, toAssetId)\n * const quote = await deflex.fetchQuote({\n * fromAssetId,\n * toAssetId,\n * amount,\n * optIn: needsOptIn,\n * })\n * ```\n */\n async needsAssetOptIn(\n address: string,\n assetId: number | bigint,\n ): Promise<boolean> {\n // Fetch account information\n const accountInfo = await this.algodClient.accountInformation(address).do()\n\n // Check if asset opt-in is required\n return (\n BigInt(assetId) !== 0n &&\n accountInfo?.assets?.find(\n (asset) => asset.assetId === BigInt(assetId),\n ) === undefined\n )\n }\n\n /**\n * Fetch swap transactions from the Deflex API\n *\n * Decrypts the quote payload and generates executable swap transactions for the\n * specified signer address with the given slippage tolerance.\n *\n * @param params - Parameters for the swap transaction request\n * @param params.quote - The quote response from fetchQuote()\n * @param params.address - The address of the signer\n * @param params.slippage - The slippage tolerance as a percentage (e.g., 1 for 1%)\n * @returns A FetchSwapTxnsResponse object with transaction data\n */\n async fetchSwapTransactions(\n params: FetchSwapTxnsParams,\n ): Promise<FetchSwapTxnsResponse> {\n const { quote, address, slippage } = params\n\n // Validate signer address\n this.validateAddress(address)\n\n const url = new URL(`${this.config.apiBaseUrl}/fetchExecuteSwapTxns`)\n\n const body: FetchSwapTxnsBody = {\n apiKey: this.config.apiKey,\n address,\n txnPayloadJSON: quote.txnPayload,\n slippage,\n }\n\n return request<FetchSwapTxnsResponse>(url.toString(), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n }\n\n /**\n * Fetch a quote and return an enhanced quote result\n *\n * This is the recommended way to fetch quotes. It returns an object that\n * extends the raw API response with additional metadata and type normalization.\n *\n * @param params - Parameters for the quote request\n * @param params.fromASAID - The ID of the asset to swap from\n * @param params.toASAID - The ID of the asset to swap to\n * @param params.amount - The amount of the asset to swap in base units\n * @param params.type - The type of the quote (default: 'fixed-input')\n * @param params.disabledProtocols - List of protocols to disable (default: [])\n * @param params.maxGroupSize - The maximum group size (default: 16)\n * @param params.maxDepth - The maximum depth (default: 4)\n * @param params.address - The address of the account that will perform the swap (recommended when using `config.autoOptIn` or `params.optIn`)\n * @param params.optIn - Whether to include asset opt-in transaction\n * @returns A DeflexQuote enhanced quote result\n *\n * @example\n * ```typescript\n * const quote = await deflex.newQuote({\n * address: 'ABC...',\n * fromASAID: 0,\n * toASAID: 31566704,\n * amount: 1_000_000,\n * })\n *\n * console.log(quote.quote) // bigint - quoted amount\n * console.log(quote.fromASAID) // number - input asset ID\n * console.log(quote.toASAID) // number - output asset ID\n * console.log(quote.amount) // bigint - original request amount\n * console.log(quote.createdAt) // number - timestamp\n * ```\n */\n async newQuote(params: FetchQuoteParams): Promise<DeflexQuote> {\n // Apply middleware transformations to quote params\n let adjustedParams = { ...params }\n\n // Create quote context for middleware\n const quoteContext = {\n fromASAID: BigInt(params.fromASAID),\n toASAID: BigInt(params.toASAID),\n amount: BigInt(params.amount),\n type: params.type ?? ('fixed-input' as const),\n address: params.address ?? undefined,\n algodClient: this.algodClient,\n }\n\n for (const mw of this.middleware) {\n const shouldApply = await mw.shouldApply(quoteContext)\n\n if (shouldApply && mw.adjustQuoteParams) {\n adjustedParams = await mw.adjustQuoteParams(adjustedParams)\n }\n }\n\n const response = await this.fetchQuote(adjustedParams)\n\n return {\n ...response,\n quote: response.quote === '' ? 0n : BigInt(response.quote),\n amount: BigInt(params.amount),\n address: params.address ?? undefined,\n createdAt: Date.now(),\n }\n }\n\n /**\n * Create a SwapComposer instance\n *\n * This factory method creates a composer that allows you to add custom transactions\n * before and after the swap transactions, with automatic handling of pre-signed transactions\n * and opt-ins.\n *\n * @param config.quote - The quote result from newQuote() or raw API response from fetchQuote()\n * @param config.address - The address of the signer\n * @param config.slippage - The slippage tolerance\n * @param config.signer - Transaction signer function\n * @returns A SwapComposer instance ready for building transaction groups\n *\n * @example\n * ```typescript\n * // Basic swap\n * const quote = await deflex.newQuote({ ... })\n * await deflex.newSwap({ quote, address, slippage, signer })\n * .execute()\n * ```\n *\n * @example\n * ```typescript\n * // Advanced swap with custom transactions\n * const quote = await deflex.newQuote({ ... })\n * const swap = await deflex.newSwap({\n * quote,\n * address,\n * slippage,\n * signer,\n * })\n *\n * console.log(swap.getStatus()) // BUILDING\n *\n * const signedTxns = await swap\n * .addTransaction(beforeTxn)\n * .addSwapTransactions() // Adds swap transactions to the group\n * .addTransaction(afterTxn)\n * .sign()\n *\n * console.log(swap.getStatus()) // SIGNED\n *\n * const result = await swap.execute(waitRounds)\n * console.log(result.confirmedRound, result.txIds)\n *\n * console.log(swap.getStatus()) // COMMITTED\n * ```\n */\n async newSwap(config: {\n quote: DeflexQuote | FetchQuoteResponse\n address: string\n slippage: number\n signer: TransactionSigner | SignerFunction\n }): Promise<SwapComposer> {\n const { quote, address, slippage, signer } = config\n\n const swapResponse = await this.fetchSwapTransactions({\n quote,\n address,\n slippage,\n })\n\n // Create the composer\n const composer = new SwapComposer({\n quote,\n deflexTxns: swapResponse.txns,\n algodClient: this.algodClient,\n address,\n signer,\n middleware: this.middleware,\n })\n\n return composer\n }\n\n /**\n * Validates the API key\n */\n private validateApiKey(apiKey: string): string {\n if (!apiKey) {\n throw new Error('API key is required')\n }\n return apiKey\n }\n\n /**\n * Validates an Algorand address\n */\n private validateAddress(address: string): string {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid Algorand address: ${address}`)\n }\n return address\n }\n\n /**\n * Validates the fee in basis points (max 300 = 3.00%)\n */\n private validateFeeBps(feeBps: number): number {\n if (feeBps < 0 || feeBps > MAX_FEE_BPS) {\n throw new Error(\n `Invalid fee: ${feeBps} basis points (must be between 0 and ${MAX_FEE_BPS})`,\n )\n }\n return feeBps\n }\n}\n","import {\n makeAssetTransferTxnWithSuggestedParamsFromObject,\n type Algodv2,\n type SuggestedParams,\n type TransactionSigner,\n type TransactionWithSigner,\n} from 'algosdk'\nimport type { DeflexQuote, FetchQuoteParams, QuoteType } from './types'\n\n/**\n * Context provided to middleware shouldApply hook\n */\nexport interface QuoteContext {\n /** Input asset ID (always bigint for precision and future-proofing) */\n readonly fromASAID: bigint\n /** Output asset ID (always bigint for precision and future-proofing) */\n readonly toASAID: bigint\n /** Amount to swap (always bigint for precision and future-proofing) */\n readonly amount: bigint\n /** Quote type */\n readonly type: QuoteType\n /** Address of the account that will perform the swap (if provided) */\n readonly address?: string\n /** Algodv2 client instance for making additional queries */\n readonly algodClient: Algodv2\n}\n\n/**\n * Context provided to middleware hooks during swap composition\n */\nexport interface SwapContext {\n /** The quote result from newQuote() */\n readonly quote: DeflexQuote\n /** The address of the account performing the swap */\n readonly address: string\n /** Algodv2 client instance for making additional queries/transactions */\n readonly algodClient: Algodv2\n /** Suggested transaction parameters from the network */\n readonly suggestedParams: SuggestedParams\n /** Input asset ID (always bigint for precision and future-proofing) */\n readonly fromASAID: bigint\n /** Output asset ID (always bigint for precision and future-proofing) */\n readonly toASAID: bigint\n /** Transaction signer for transactions that need to be signed by the user */\n readonly signer: TransactionSigner\n}\n\n/**\n * Middleware interface for extending Deflex swap functionality\n *\n * Middleware allows you to modify quote parameters and inject additional transactions\n * into the atomic swap group. This is useful for assets that require special handling,\n * such as those with transfer restrictions, taxes, or custom smart contract logic.\n *\n * @example\n * ```typescript\n * class CustomAssetMiddleware implements SwapMiddleware {\n * readonly name = 'CustomAsset'\n * readonly version = '1.0.0'\n *\n * async shouldApply(context) {\n * return context.fromASAID === CUSTOM_ASSET_ID || context.toASAID === CUSTOM_ASSET_ID\n * }\n *\n * async adjustQuoteParams(params) {\n * // Reduce maxGroupSize to account for extra transactions\n * return { ...params, maxGroupSize: params.maxGroupSize - 3 }\n * }\n *\n * async beforeSwap(context) {\n * // Return transactions to add before the swap\n * return [unfreezeTransaction]\n * }\n *\n * async afterSwap(context) {\n * // Return transactions to add after the swap\n * return [taxTransaction, refreezeTransaction]\n * }\n * }\n * ```\n */\nexport interface SwapMiddleware {\n /** Unique identifier for the middleware */\n readonly name: string\n\n /** Semantic version of the middleware */\n readonly version: string\n\n /**\n * Determines if this middleware should be applied to the given swap\n *\n * Called during both quote and swap phases. Use this to check if either\n * the input or output asset requires special handling.\n *\n * @param context - Quote context with asset IDs, amount, type, address, and algod client\n * @returns True if middleware should be applied\n *\n * @example\n * ```typescript\n * async shouldApply(context) {\n * // Check if asset is registered in our smart contract\n * const assetInfo = await this.getAssetInfo(context.fromASAID)\n * return assetInfo !== null\n * }\n * ```\n */\n shouldApply(context: QuoteContext): Promise<boolean>\n\n /**\n * Modify quote parameters before fetching the quote\n *\n * **IMPORTANT**: If your middleware adds transactions via `beforeSwap` or `afterSwap`,\n * you MUST reduce `maxGroupSize` accordingly to prevent failures. The Deflex API may\n * return routes that use all 16 available transaction slots.\n *\n * Use this to adjust the quote request based on your asset's requirements.\n * Common adjustments include:\n * - Reducing `maxGroupSize` to account for additional transactions (REQUIRED if adding txns)\n * - Adjusting `amount` to account for fees/taxes\n * - Modifying `disabledProtocols` if certain DEXs are incompatible\n *\n * @param params - Original quote parameters\n * @returns Modified quote parameters\n *\n * @example\n * ```typescript\n * async adjustQuoteParams(params) {\n * const [fromTaxed, toTaxed] = await Promise.all([\n * this.isAssetTaxed(params.fromASAID),\n * this.isAssetTaxed(params.toASAID),\n * ])\n *\n * // 3 extra transactions per taxed asset\n * let maxGroupSize = params.maxGroupSize ?? 16\n * if (fromTaxed) maxGroupSize -= 3\n * if (toTaxed) maxGroupSize -= 3\n *\n * // Adjust amount for input tax\n * let amount = params.amount\n * if (fromTaxed) {\n * const taxRate = await this.getTaxRate(params.fromASAID)\n * amount = this.applyTax(amount, taxRate)\n * }\n *\n * return { ...params, maxGroupSize, amount }\n * }\n * ```\n */\n adjustQuoteParams?(params: FetchQuoteParams): Promise<FetchQuoteParams>\n\n /**\n * Add transactions before the swap transactions\n *\n * Called when building the swap transaction group. Transactions are added\n * to the group in the order they appear in the returned array.\n *\n * Transaction order in final group: [beforeSwap] → [swap txns] → [afterSwap]\n *\n * @param context - Swap context with quote, address, and algod client\n * @returns Array of transactions with signers to add before swap\n *\n * @example\n * ```typescript\n * async beforeSwap(context) {\n * const txns: TransactionWithSigner[] = []\n *\n * // Unfreeze user account before swap\n * if (await this.needsUnfreeze(context.fromASAID)) {\n * const unfreezeCall = makeApplicationNoOpTxn(\n * context.address,\n * this.appId,\n * ...,\n * context.suggestedParams\n * )\n *\n * txns.push({\n * txn: unfreezeCall,\n * signer: context.signer, // Use the signer from context\n * })\n * }\n *\n * return txns\n * }\n * ```\n */\n beforeSwap?(context: SwapContext): Promise<TransactionWithSigner[]>\n\n /**\n * Add transactions after the swap transactions\n *\n * Called when building the swap transaction group. Transactions are added\n * to the group in the order they appear in the returned array.\n *\n * Transaction order in final group: [beforeSwap] → [swap txns] → [afterSwap]\n *\n * @param context - Swap context with quote, address, and algod client\n * @returns Array of transactions with signers to add after swap\n *\n * @example\n * ```typescript\n * async afterSwap(context) {\n * const txns: TransactionWithSigner[] = []\n *\n * // Pay tax and refreeze account\n * if (await this.isTaxed(context.fromASAID)) {\n * const taxAmount = await this.calculateTax(context)\n * const taxPayment = makeAssetTransferTxn(\n * context.address,\n * this.taxReceiver,\n * taxAmount,\n * context.fromASAID,\n * context.suggestedParams\n * )\n * const refreezeCall = makeApplicationNoOpTxn(\n * context.address,\n * this.appId,\n * ...,\n * context.suggestedParams\n * )\n *\n * txns.push(\n * { txn: taxPayment, signer: context.signer },\n * { txn: refreezeCall, signer: context.signer },\n * )\n * }\n *\n * return txns\n * }\n * ```\n */\n afterSwap?(context: SwapContext): Promise<TransactionWithSigner[]>\n}\n\n/**\n * Configuration options for AutoOptOutMiddleware\n */\nexport interface AutoOptOutConfig {\n /**\n * Array of asset IDs that should be excluded from automatic opt-out behavior\n * @default []\n */\n readonly excludedAssets?: readonly (number | bigint)[]\n}\n\n/**\n * Middleware that automatically adds an asset opt-out transaction when swapping\n * the full balance of an input asset, leaving it with a zero balance.\n *\n * @example\n * ```typescript\n * import { DeflexClient, AutoOptOutMiddleware } from '@txnlab/deflex'\n *\n * const autoOptOut = new AutoOptOutMiddleware({\n * excludedAssets: [31566704], // Don't auto-opt-out of USDC\n * })\n *\n * const deflex = new DeflexClient({\n * apiKey: 'your-api-key',\n * middleware: [autoOptOut],\n * })\n *\n * // When swapping full balance, opt-out transaction is automatically added\n * const quote = await deflex.newQuote({\n * address: userAddress,\n * fromASAID: someAssetId,\n * toASAID: 0,\n * amount: fullBalance, // If this equals account's full balance, opt-out is added\n * type: 'fixed-input',\n * })\n * ```\n */\nexport class AutoOptOutMiddleware implements SwapMiddleware {\n readonly name = 'AutoOptOut'\n readonly version = '1.0.0'\n\n private readonly excludedAssets: Set<bigint>\n\n constructor(config: AutoOptOutConfig = {}) {\n this.excludedAssets = new Set(\n (config.excludedAssets ?? []).map((id) => BigInt(id)),\n )\n }\n\n async shouldApply(context: QuoteContext): Promise<boolean> {\n // Only apply for fixed-input swaps\n if (context.type !== 'fixed-input') {\n return false\n }\n\n // Must have an address to check balance\n if (!context.address) {\n return false\n }\n\n // Don't opt-out of ALGO (asset ID 0)\n if (context.fromASAID === 0n) {\n return false\n }\n\n // Check if asset is in excluded list\n if (this.excludedAssets.has(context.fromASAID)) {\n return false\n }\n\n try {\n // Get account info to check current balance\n const accountInfo = await context.algodClient\n .accountInformation(context.address)\n .do()\n\n // Find the asset in account's holdings\n const assetHolding = accountInfo.assets?.find(\n (asset) => asset.assetId === context.fromASAID,\n )\n\n // If asset not found, don't opt-out\n if (!assetHolding) {\n return false\n }\n\n // Check if swap amount equals current balance\n return assetHolding.amount === context.amount\n } catch (error) {\n // If we can't fetch account info, don't apply middleware\n console.warn(\n `AutoOptOutMiddleware: Failed to fetch account info for ${context.address}:`,\n error,\n )\n return false\n }\n }\n\n async adjustQuoteParams(params: FetchQuoteParams): Promise<FetchQuoteParams> {\n // Reduce maxGroupSize by 1 to make room for the opt-out transaction\n const maxGroupSize = (params.maxGroupSize ?? 16) - 1\n\n return {\n ...params,\n maxGroupSize,\n }\n }\n\n async afterSwap(context: SwapContext): Promise<TransactionWithSigner[]> {\n // Create asset opt-out transaction (send 0 amount with closeRemainderTo = sender)\n const optOutTxn = makeAssetTransferTxnWithSuggestedParamsFromObject({\n sender: context.address,\n receiver: context.address,\n amount: 0n,\n assetIndex: context.fromASAID,\n closeRemainderTo: context.address,\n suggestedParams: context.suggestedParams,\n })\n\n return [\n {\n txn: optOutTxn,\n signer: context.signer,\n },\n ]\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@txnlab/deflex",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "TypeScript/JavaScript SDK for Deflex Order Router - smart order routing and DEX aggregation on Algorand",
5
5
  "keywords": [
6
6
  "algorand",
@@ -33,18 +33,18 @@
33
33
  "type": "module",
34
34
  "exports": {
35
35
  ".": {
36
- "types": "./dist/index.d.ts",
37
- "import": "./dist/index.js"
36
+ "types": "./dist/index.d.mts",
37
+ "import": "./dist/index.mjs"
38
38
  }
39
39
  },
40
- "types": "./dist/index.d.ts",
40
+ "types": "./dist/index.d.mts",
41
41
  "publishConfig": {
42
42
  "access": "public"
43
43
  },
44
44
  "engines": {
45
45
  "node": ">=20"
46
46
  },
47
- "packageManager": "pnpm@10.20.0",
47
+ "packageManager": "pnpm@10.22.0",
48
48
  "scripts": {
49
49
  "build": "tsdown && publint --strict",
50
50
  "test": "vitest run",
@@ -53,13 +53,13 @@
53
53
  "typecheck": "tsc --noEmit"
54
54
  },
55
55
  "devDependencies": {
56
- "@types/node": "22.19.0",
57
- "@vitest/coverage-v8": "4.0.6",
56
+ "@types/node": "22.19.1",
57
+ "@vitest/coverage-v8": "4.0.13",
58
58
  "algosdk": "3.5.2",
59
59
  "publint": "0.3.15",
60
- "tsdown": "0.15.12",
60
+ "tsdown": "0.16.6",
61
61
  "typescript": "5.9.3",
62
- "vitest": "4.0.6"
62
+ "vitest": "4.0.13"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "algosdk": "^3.0.0"
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/constants.ts","../src/types.ts","../src/middleware.ts","../src/composer.ts","../src/client.ts","../src/utils.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["swapTxns: TransactionWithSigner[]","allTxns: TransactionWithSigner[]","status: number","statusText: string","data: unknown","errorData: unknown","body: FetchSwapTxnsBody"],"sources":["../src/constants.ts","../src/composer.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["/**\n * Supported DEX protocols for swap routing\n */\nexport enum Protocol {\n TinymanV2 = 'TinymanV2',\n Algofi = 'Algofi',\n Algomint = 'Algomint',\n Pact = 'Pact',\n Folks = 'Folks',\n TAlgo = 'TAlgo',\n}\n\n/**\n * Deprecated protocols that are automatically excluded from routing\n *\n * @internal\n */\nexport const DEPRECATED_PROTOCOLS = ['Humble', 'Tinyman'] as const\n\n/** Default Algod node URI for mainnet */\nexport const DEFAULT_ALGOD_URI = 'https://mainnet-api.4160.nodely.dev/'\n\n/** Default Algod node token (empty for public nodes) */\nexport const DEFAULT_ALGOD_TOKEN = ''\n\n/** Default Algod node port */\nexport const DEFAULT_ALGOD_PORT = 443\n\n/** Default Deflex API base URL */\nexport const DEFAULT_API_BASE_URL = 'https://deflex.txnlab.dev/api'\n\n/** Default fee in basis points (0.15%) */\nexport const DEFAULT_FEE_BPS = 15\n\n/** Maximum allowed fee in basis points (3.00%) */\nexport const MAX_FEE_BPS = 300\n\n/** Default maximum transaction group size */\nexport const DEFAULT_MAX_GROUP_SIZE = 16\n\n/** Default maximum routing depth (number of hops) */\nexport const DEFAULT_MAX_DEPTH = 4\n\n/** Default auto opt-in setting (automatic asset/app opt-in detection) */\nexport const DEFAULT_AUTO_OPT_IN = false\n\n/** Default number of rounds to wait for transaction confirmation */\nexport const DEFAULT_CONFIRMATION_ROUNDS = 4\n","import {\n AtomicTransactionComposer,\n decodeUnsignedTransaction,\n isValidAddress,\n LogicSigAccount,\n makeApplicationOptInTxnFromObject,\n msgpackRawDecode,\n signLogicSigTransactionObject,\n signTransaction,\n Transaction,\n type ABIResult,\n type Algodv2,\n type TransactionSigner,\n type TransactionWithSigner,\n} from 'algosdk'\nimport { DEFAULT_CONFIRMATION_ROUNDS } from './constants'\nimport type { SwapMiddleware, SwapContext } from './middleware'\nimport type {\n FetchQuoteResponse,\n DeflexTransaction,\n DeflexSignature,\n DeflexQuote,\n MethodCall,\n} from './types'\n\n/**\n * A transaction signer function that supports both standard algosdk.TransactionSigner\n * and ARC-1 compliant signers that may return null for unsigned transactions.\n *\n * @param txnGroup - The complete transaction group to sign\n * @param indexesToSign - Array of indexes indicating which transactions need signing\n * @returns Array of signed transactions (may include nulls for ARC-1 compliant wallets)\n */\nexport type SignerFunction = (\n txnGroup: Transaction[],\n indexesToSign: number[],\n) => Promise<(Uint8Array | null)[]>\n\n/**\n * Status of the SwapComposer transaction group lifecycle\n */\nexport enum SwapComposerStatus {\n /** The atomic group is still under construction. */\n BUILDING,\n\n /** The atomic group has been finalized, but not yet signed. */\n BUILT,\n\n /** The atomic group has been finalized and signed, but not yet submitted to the network. */\n SIGNED,\n\n /** The atomic group has been finalized, signed, and submitted to the network. */\n SUBMITTED,\n\n /** The atomic group has been finalized, signed, submitted, and successfully committed to a block. */\n COMMITTED,\n}\n\n/**\n * Configuration for creating a SwapComposer instance\n */\nexport interface SwapComposerConfig {\n /** The quote response from fetchQuote() or newQuote() */\n readonly quote: FetchQuoteResponse | DeflexQuote\n /** The swap transactions from fetchSwapTransactions() */\n readonly deflexTxns: DeflexTransaction[]\n /** Algodv2 client instance */\n readonly algodClient: Algodv2\n /** The address of the account that will sign transactions */\n readonly address: string\n /** Transaction signer function */\n readonly signer: TransactionSigner | SignerFunction\n /** Middleware to apply during swap composition */\n readonly middleware?: SwapMiddleware[]\n}\n\n/**\n * Composer for building and executing atomic swap transaction groups\n *\n * The SwapComposer allows you to build complex transaction groups by adding custom\n * transactions before and after swap transactions. It handles pre-signed transactions,\n * automatic app opt-ins, and provides a fluent API for transaction group construction.\n *\n * @example\n * ```typescript\n * const quote = await deflex.fetchQuote({ ... })\n * const composer = await deflex.newSwap({ quote, address, slippage, signer })\n *\n * await composer\n * .addTransaction(customTxn)\n * .addSwapTransactions()\n * .execute()\n * ```\n */\nexport class SwapComposer {\n /** The ATC used to compose the group */\n private atc = new AtomicTransactionComposer()\n\n /** The maximum size of an atomic transaction group. */\n static MAX_GROUP_SIZE: number = AtomicTransactionComposer.MAX_GROUP_SIZE\n\n /** Whether the swap transactions have been added to the atomic group. */\n private swapTransactionsAdded = false\n\n private readonly quote: FetchQuoteResponse | DeflexQuote\n private readonly requiredAppOptIns: number[]\n private readonly deflexTxns: DeflexTransaction[]\n private readonly algodClient: Algodv2\n private readonly address: string\n private readonly signer: TransactionSigner | SignerFunction\n private readonly middleware: SwapMiddleware[]\n\n /**\n * Create a new SwapComposer instance\n *\n * Note: Most developers should use DeflexClient.newSwap() instead of constructing\n * this directly, as the factory method handles fetching swap transactions automatically.\n *\n * @param config - Configuration for the composer\n * @param config.quote - The quote response from fetchQuote()\n * @param config.deflexTxns - The swap transactions from fetchSwapTransactions()\n * @param config.algodClient - Algodv2 client instance\n * @param config.address - The address of the account that will sign transactions\n * @param config.signer - Transaction signer function\n * @param config.middleware - Middleware to apply during swap composition\n */\n constructor(config: SwapComposerConfig) {\n // Validate required parameters\n if (!config.quote) {\n throw new Error('Quote is required')\n }\n if (!config.deflexTxns) {\n throw new Error('Swap transactions are required')\n }\n if (config.deflexTxns.length === 0) {\n throw new Error('Swap transactions array cannot be empty')\n }\n if (!config.algodClient) {\n throw new Error('Algodv2 client instance is required')\n }\n if (!config.signer) {\n throw new Error('Signer is required')\n }\n\n this.quote = config.quote\n this.requiredAppOptIns = config.quote.requiredAppOptIns\n this.deflexTxns = config.deflexTxns\n this.algodClient = config.algodClient\n this.address = this.validateAddress(config.address)\n this.signer = config.signer\n this.middleware = config.middleware ?? []\n }\n\n /**\n * Get the status of this composer's transaction group\n *\n * @returns The current status of the transaction group\n */\n getStatus(): SwapComposerStatus {\n return this.atc.getStatus() as unknown as SwapComposerStatus\n }\n\n /**\n * Get the number of transactions currently in this atomic group\n *\n * @returns The number of transactions in the group\n */\n count(): number {\n return this.atc.count()\n }\n\n /**\n * Add a transaction to the atomic group\n *\n * Transactions are added in the order methods are called. For example:\n * ```typescript\n * composer\n * .addTransaction(txn1) // Added first\n * .addSwapTransactions() // Added second\n * .addTransaction(txn2) // Added third\n * ```\n *\n * @param transaction - The transaction to add\n * @returns This composer instance for chaining\n * @throws Error if the composer is not in the BUILDING status\n * @throws Error if the maximum group size is exceeded\n */\n addTransaction(transaction: Transaction, signer = this.defaultSigner): this {\n this.atc.addTransaction({ txn: transaction, signer })\n return this\n }\n\n /**\n * Add a method call to the atomic group\n *\n * The `signer` property in the `methodCall` parameter is optional. If not provided,\n * the signer will default to the one passed as the second parameter, or the\n * configured signer from the constructor if no second parameter is provided.\n *\n * @param methodCall - The method call to add\n * @param signer - The signer to use for the method call (defaults to constructor signer)\n * @returns This composer instance for chaining\n */\n addMethodCall(methodCall: MethodCall, signer = this.defaultSigner): this {\n this.atc.addMethodCall({\n ...methodCall,\n signer: methodCall.signer ?? signer,\n })\n return this\n }\n\n /**\n * Add swap transactions to the atomic group\n *\n * This method automatically processes required app opt-ins, executes middleware hooks,\n * and adds all swap transactions from the quote. Can only be called once per composer instance.\n *\n * Middleware hooks are executed in this order:\n * 1. beforeSwap() - Add transactions before swap transactions\n * 2. Swap transactions (from API)\n * 3. afterSwap() - Add transactions after swap transactions\n *\n * @returns This composer instance for chaining\n * @throws Error if the swap transactions have already been added\n * @throws Error if the composer is not in the BUILDING status\n * @throws Error if the maximum group size is exceeded\n */\n async addSwapTransactions(): Promise<this> {\n if (this.swapTransactionsAdded) {\n throw new Error('Swap transactions have already been added')\n }\n\n if (this.getStatus() !== SwapComposerStatus.BUILDING) {\n throw new Error(\n 'Cannot add swap transactions when composer status is not BUILDING',\n )\n }\n\n // Execute beforeSwap middleware hooks\n const beforeTxns = await this.executeMiddlewareHooks('beforeSwap')\n\n // Check total length before adding beforeSwap transactions\n if (this.atc.count() + beforeTxns.length > SwapComposer.MAX_GROUP_SIZE) {\n throw new Error(\n `Adding beforeSwap transactions exceeds the maximum atomic group size of ${SwapComposer.MAX_GROUP_SIZE}`,\n )\n }\n\n for (const txnWithSigner of beforeTxns) {\n this.atc.addTransaction(txnWithSigner)\n }\n\n // Process swap transactions and execute afterSwap hooks\n const processedTxns = await this.processSwapTransactions()\n const afterTxns = await this.executeMiddlewareHooks('afterSwap')\n\n // Check total length before adding swap and afterSwap transactions\n const totalLength =\n this.atc.count() + processedTxns.length + afterTxns.length\n\n if (totalLength > SwapComposer.MAX_GROUP_SIZE) {\n throw new Error(\n `Adding swap transactions exceeds the maximum atomic group size of ${SwapComposer.MAX_GROUP_SIZE}`,\n )\n }\n\n // Add swap transactions\n for (const txnWithSigner of processedTxns) {\n this.atc.addTransaction(txnWithSigner)\n }\n\n // Add afterSwap middleware transactions\n for (const txnWithSigner of afterTxns) {\n this.atc.addTransaction(txnWithSigner)\n }\n\n this.swapTransactionsAdded = true\n return this\n }\n\n /**\n * Finalize the transaction group by assigning group IDs\n *\n * This method builds the atomic transaction group, assigning group IDs to all transactions\n * if there is more than one transaction. After calling this method, the composer's status\n * will be at least BUILT.\n *\n * @returns Array of transactions with their associated signers\n *\n * @throws Error if the group contains 0 transactions\n *\n * @example\n * ```typescript\n * const composer = await deflex.newSwap({ quote, address, slippage, signer })\n * composer.addTransaction(customTxn)\n *\n * // Build the group to inspect transactions before signing\n * const txnsWithSigners = composer.buildGroup()\n * console.log('Group ID:', txnsWithSigners[0].txn.group)\n * console.log('Group length:', txnsWithSigners.length)\n * console.log('Status:', composer.getStatus()) // BUILT\n * ```\n */\n buildGroup(): TransactionWithSigner[] {\n return this.atc.buildGroup()\n }\n\n /**\n * Sign the transaction group\n *\n * Automatically adds swap transactions if not already added, builds the atomic group,\n * and signs all transactions using the configured signer.\n *\n * @returns A promise that resolves to an array of signed transaction blobs\n *\n * @example\n * ```typescript\n * const signedTxns = await composer.sign()\n * ```\n */\n async sign(): Promise<Uint8Array[]> {\n if (this.getStatus() >= SwapComposerStatus.SIGNED) {\n return this.atc.gatherSignatures()\n }\n\n // Auto-add swap transactions if needed\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n return await this.atc.gatherSignatures()\n }\n\n /**\n * Submit the signed transactions to the network\n *\n * This method signs the transaction group (if not already signed) and submits\n * it to the Algorand network. Does not wait for confirmation.\n *\n * @returns The transaction IDs\n * @throws Error if the transaction group has already been submitted\n *\n * @example\n * ```typescript\n * const txIds = await composer.submit()\n * console.log('Submitted transactions:', txIds)\n * ```\n */\n async submit(): Promise<string[]> {\n // Auto-add swap transactions if needed (maintains backward compatibility)\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n return this.atc.submit(this.algodClient)\n }\n\n /**\n * Execute the swap\n *\n * Signs the transaction group, submits it to the network, and waits for confirmation.\n * This is the primary method for executing swaps and combines sign(), submit(), and\n * waitForConfirmation() into a single call.\n *\n * @param waitRounds - The number of rounds to wait for confirmation (default: 4)\n * @returns Object containing the confirmed round and transaction IDs\n * @throws Error if the transaction group has already been committed\n *\n * @example\n * ```typescript\n * const result = await composer.execute()\n * console.log(`Confirmed in round ${result.confirmedRound}`)\n * console.log('Transaction IDs:', result.txIds)\n * ```\n */\n async execute(waitRounds: number = DEFAULT_CONFIRMATION_ROUNDS): Promise<{\n confirmedRound: bigint\n txIds: string[]\n methodResults: ABIResult[]\n }> {\n // Auto-add swap transactions if needed (maintains backward compatibility)\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n const { txIDs, ...result } = await this.atc.execute(\n this.algodClient,\n waitRounds,\n )\n\n return {\n ...result,\n txIds: txIDs,\n }\n }\n\n /**\n * Validates an Algorand address\n */\n private validateAddress(address: string): string {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid Algorand address: ${address}`)\n }\n return address\n }\n\n /**\n * Processes app opt-ins and decodes swap transactions from API response\n */\n private async processSwapTransactions(): Promise<TransactionWithSigner[]> {\n const appOptIns = await this.processRequiredAppOptIns()\n\n const swapTxns: TransactionWithSigner[] = []\n for (let i = 0; i < this.deflexTxns.length; i++) {\n const deflexTxn = this.deflexTxns[i]\n if (!deflexTxn) continue\n\n try {\n const txnBytes = Buffer.from(deflexTxn.data, 'base64')\n const txn = decodeUnsignedTransaction(txnBytes)\n delete txn.group\n\n if (deflexTxn.signature !== false) {\n // Pre-signed transaction - use custom Deflex signer\n swapTxns.push({\n txn,\n signer: this.createDeflexSigner(deflexTxn.signature),\n })\n } else {\n // User transaction - use configured signer\n swapTxns.push({\n txn,\n signer: this.defaultSigner,\n })\n }\n } catch (error) {\n throw new Error(\n `Failed to process swap transaction at index ${i}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n return [...appOptIns, ...swapTxns]\n }\n\n /**\n * Creates opt-in transactions for apps the user hasn't opted into yet\n */\n private async processRequiredAppOptIns(): Promise<TransactionWithSigner[]> {\n // Fetch account information\n const accountInfo = await this.algodClient\n .accountInformation(this.address)\n .do()\n\n // Check app opt-ins\n const userApps =\n accountInfo?.appsLocalState?.map((app) => Number(app.id)) || []\n const appsToOptIn = this.requiredAppOptIns.filter(\n (appId) => !userApps.includes(appId),\n )\n\n if (appsToOptIn.length === 0) return []\n\n const suggestedParams = await this.algodClient.getTransactionParams().do()\n\n return appsToOptIn.map((appId) => ({\n txn: makeApplicationOptInTxnFromObject({\n sender: this.address,\n appIndex: appId,\n suggestedParams,\n }),\n signer: this.defaultSigner,\n }))\n }\n\n /**\n * The default signer function that uses the configured signer\n */\n private defaultSigner: TransactionSigner = async (\n txnGroup: Transaction[],\n indexesToSign: number[],\n ) => {\n const result = await this.signer(txnGroup, indexesToSign)\n return result.filter((txn): txn is Uint8Array => txn !== null)\n }\n\n /**\n * Creates a TransactionSigner function for Deflex pre-signed transactions\n */\n private createDeflexSigner(signature: DeflexSignature): TransactionSigner {\n return async (\n txnGroup: Transaction[],\n indexesToSign: number[],\n ): Promise<Uint8Array[]> => {\n return indexesToSign.map((i) => {\n const txn = txnGroup[i]\n if (!txn) throw new Error(`Transaction at index ${i} not found`)\n return this.signDeflexTransaction(txn, signature)\n })\n }\n }\n\n /**\n * Re-signs a Deflex transaction using the provided logic signature or secret key\n */\n private signDeflexTransaction(\n transaction: Transaction,\n signature: DeflexSignature,\n ): Uint8Array {\n try {\n if (signature.type === 'logic_signature') {\n // Decode the signature value to extract the logic signature\n const valueArray = signature.value as Record<string, number>\n const valueBytes = new Uint8Array(Object.values(valueArray))\n const decoded = msgpackRawDecode(valueBytes) as {\n lsig?: { l: Uint8Array; arg?: Uint8Array[] }\n }\n\n if (!decoded.lsig) {\n throw new Error('Logic signature structure missing lsig field')\n }\n\n const lsig = decoded.lsig\n const logicSigAccount = new LogicSigAccount(lsig.l, lsig.arg)\n\n const signedTxn = signLogicSigTransactionObject(\n transaction,\n logicSigAccount,\n )\n return signedTxn.blob\n } else if (signature.type === 'secret_key') {\n // Convert signature.value (Record<string, number>) to Uint8Array\n const valueArray = signature.value as Record<string, number>\n const secretKey = new Uint8Array(Object.values(valueArray))\n const signedTxn = signTransaction(transaction, secretKey)\n return signedTxn.blob\n } else {\n throw new Error(`Unsupported signature type: ${signature.type}`)\n }\n } catch (error) {\n throw new Error(\n `Failed to re-sign transaction: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n /**\n * Execute middleware hooks (beforeSwap or afterSwap)\n */\n private async executeMiddlewareHooks(\n hookName: 'beforeSwap' | 'afterSwap',\n ): Promise<TransactionWithSigner[]> {\n const allTxns: TransactionWithSigner[] = []\n\n for (const mw of this.middleware) {\n const shouldApply = await mw.shouldApply({\n fromASAID: BigInt(this.quote.fromASAID),\n toASAID: BigInt(this.quote.toASAID),\n })\n\n if (!shouldApply || !mw[hookName]) {\n continue\n }\n\n const context = await this.createSwapContext()\n const txns = await mw[hookName]!(context)\n allTxns.push(...txns)\n }\n\n return allTxns\n }\n\n /**\n * Create SwapContext for middleware hooks\n */\n private async createSwapContext(): Promise<SwapContext> {\n const suggestedParams = await this.algodClient.getTransactionParams().do()\n\n // Convert to DeflexQuote if needed\n const quote: DeflexQuote =\n 'createdAt' in this.quote\n ? this.quote\n : {\n ...this.quote,\n quote: this.quote.quote === '' ? 0n : BigInt(this.quote.quote),\n amount: 0n, // Not available in FetchQuoteResponse\n createdAt: Date.now(),\n }\n\n return {\n quote,\n address: this.address,\n algodClient: this.algodClient,\n suggestedParams,\n fromASAID: BigInt(this.quote.fromASAID),\n toASAID: BigInt(this.quote.toASAID),\n signer: this.defaultSigner,\n }\n }\n}\n","/**\n * HTTP error with status code and response data\n */\nexport class HTTPError extends Error {\n constructor(\n public status: number,\n public statusText: string,\n public data: unknown,\n ) {\n super(`HTTP ${status} ${statusText}`)\n this.name = 'HTTPError'\n }\n}\n\n/**\n * Make an HTTP request and parse JSON response\n *\n * Simple wrapper around native fetch for API calls. Throws HTTPError for\n * non-2xx responses.\n *\n * @param url - The URL to request\n * @param options - Fetch options\n * @returns Parsed JSON response\n * @throws HTTPError if the response status is not ok\n */\nexport async function request<T>(\n url: string,\n options?: RequestInit,\n): Promise<T> {\n const response = await fetch(url, options)\n\n if (!response.ok) {\n let errorData: unknown\n\n try {\n errorData = await response.json()\n } catch {\n try {\n errorData = await response.text()\n } catch {\n errorData = 'Failed to parse error response'\n }\n }\n\n throw new HTTPError(\n response.status,\n response.statusText,\n JSON.stringify(errorData),\n )\n }\n\n return response.json() as Promise<T>\n}\n","import { Algodv2, isValidAddress, type TransactionSigner } from 'algosdk'\nimport { SwapComposer, type SignerFunction } from './composer'\nimport {\n DEFAULT_ALGOD_PORT,\n DEFAULT_ALGOD_TOKEN,\n DEFAULT_ALGOD_URI,\n DEFAULT_API_BASE_URL,\n DEFAULT_AUTO_OPT_IN,\n DEFAULT_FEE_BPS,\n DEFAULT_MAX_DEPTH,\n DEFAULT_MAX_GROUP_SIZE,\n DEPRECATED_PROTOCOLS,\n MAX_FEE_BPS,\n} from './constants'\nimport { request } from './utils'\nimport type { SwapMiddleware } from './middleware'\nimport type {\n FetchQuoteResponse,\n FetchSwapTxnsResponse,\n DeflexConfig,\n DeflexConfigParams,\n FetchSwapTxnsParams,\n FetchSwapTxnsBody,\n FetchQuoteParams,\n DeflexQuote,\n} from './types'\n\n/**\n * Client for interacting with the Deflex order router API\n *\n * The DeflexClient provides methods to fetch swap quotes and create transaction composers\n * for executing swaps on the Algorand blockchain. It handles API communication, transaction\n * validation, and automatic asset/app opt-in detection.\n *\n * @example\n * ```typescript\n * const deflex = new DeflexClient({\n * apiKey: 'your-api-key',\n * })\n * ```\n *\n * @example\n * ```typescript\n * const deflex = new DeflexClient({\n * apiKey: 'your-api-key',\n * apiBaseUrl: 'https://deflex.txnlab.dev',\n * algodUri: 'https://mainnet-api.4160.nodely.dev/',\n * algodToken: '',\n * algodPort: 443,\n * referrerAddress: 'REFERRER_ADDRESS...',\n * feeBps: 15,\n * autoOptIn: false,\n * })\n * ```\n */\nexport class DeflexClient {\n private readonly config: DeflexConfig\n private readonly algodClient: Algodv2\n private readonly middleware: SwapMiddleware[]\n\n /**\n * Create a new DeflexClient instance\n *\n * @param config - Configuration parameters\n * @param config.apiKey - API key for Deflex API (required)\n * @param config.apiBaseUrl - Base URL for the Deflex API (default: https://deflex.txnlab.dev)\n * @param config.algodUri - Algod node URI (default: https://mainnet-api.4160.nodely.dev/)\n * @param config.algodToken - Algod node token (default: '')\n * @param config.algodPort - Algod node port (default: 443)\n * @param config.referrerAddress - Referrer address for fee sharing (receives 25% of swap fees)\n * @param config.feeBps - Fee in basis points (default: 15 = 0.15%, max: 300 = 3.00%)\n * @param config.autoOptIn - Automatically detect and add required opt-in transactions (default: false)\n * @param config.middleware - Array of middleware to apply to swaps (default: [])\n */\n constructor(config: DeflexConfigParams & { middleware?: SwapMiddleware[] }) {\n // Validate and set config\n this.config = {\n apiKey: this.validateApiKey(config.apiKey),\n apiBaseUrl: config.apiBaseUrl ?? DEFAULT_API_BASE_URL,\n algodUri: config.algodUri ?? DEFAULT_ALGOD_URI,\n algodToken: config.algodToken ?? DEFAULT_ALGOD_TOKEN,\n algodPort: config.algodPort ?? DEFAULT_ALGOD_PORT,\n referrerAddress: config.referrerAddress\n ? this.validateAddress(config.referrerAddress)\n : undefined,\n feeBps: this.validateFeeBps(config.feeBps ?? DEFAULT_FEE_BPS),\n autoOptIn: config.autoOptIn ?? DEFAULT_AUTO_OPT_IN,\n }\n\n // Create Algodv2 client\n this.algodClient = new Algodv2(\n this.config.algodToken,\n this.config.algodUri,\n this.config.algodPort,\n )\n\n // Store middleware\n this.middleware = config.middleware ?? []\n }\n\n /**\n * Fetch a swap quote from the Deflex API\n *\n * Requests optimal swap routing from the Deflex API. The quote includes routing\n * information, price impact, required opt-ins, and an encrypted transaction payload.\n *\n * @param params - Parameters for the quote request\n * @param params.fromASAID - The ID of the asset to swap from\n * @param params.toASAID - The ID of the asset to swap to\n * @param params.amount - The amount of the asset to swap in base units\n * @param params.type - The type of the quote (default: 'fixed-input')\n * @param params.disabledProtocols - List of protocols to disable (default: [])\n * @param params.maxGroupSize - The maximum group size (default: 16)\n * @param params.maxDepth - The maximum depth (default: 4)\n * @param params.address - The address of the account that will perform the swap (recommended when using `config.autoOptIn` or `params.optIn`)\n * @param params.optIn - Whether to include asset opt-in transaction\n * - If true: API reduces maxGroupSize by 1 and includes opt-in (always included, even if not needed)\n * - If false: No opt-in transaction included\n * - If undefined: Falls back to `config.autoOptIn` behavior with account check (if `params.address` is provided)\n * @returns A FetchQuoteResponse object with routing information\n *\n * @example\n * ```typescript\n * const quote = await deflex.fetchQuote({\n * address: 'ABC...',\n * fromASAID: 0, // ALGO\n * toASAID: 31566704, // USDC\n * amount: 1_000_000, // 1 ALGO\n * })\n * ```\n */\n async fetchQuote(params: FetchQuoteParams): Promise<FetchQuoteResponse> {\n const {\n fromASAID,\n toASAID,\n amount,\n type = 'fixed-input',\n disabledProtocols = [],\n maxGroupSize = DEFAULT_MAX_GROUP_SIZE,\n maxDepth = DEFAULT_MAX_DEPTH,\n optIn,\n address,\n } = params\n\n // Always include deprecated protocols in disabled list\n const allDisabledProtocols = [\n ...new Set([...DEPRECATED_PROTOCOLS, ...disabledProtocols]),\n ]\n\n let includeOptIn = optIn\n if (includeOptIn === undefined && this.config.autoOptIn) {\n if (address) {\n includeOptIn = await this.needsAssetOptIn(\n this.validateAddress(address),\n toASAID,\n )\n } else {\n console.warn(\n 'autoOptIn is enabled but no address provided to fetchQuote(). Asset opt-in check skipped.',\n )\n }\n }\n\n const url = new URL(`${this.config.apiBaseUrl}/fetchQuote`)\n\n url.searchParams.append('apiKey', this.config.apiKey)\n url.searchParams.append('algodUri', this.config.algodUri)\n url.searchParams.append('algodToken', this.config.algodToken)\n url.searchParams.append('algodPort', String(this.config.algodPort))\n url.searchParams.append('feeBps', this.config.feeBps.toString())\n url.searchParams.append('fromASAID', BigInt(fromASAID).toString())\n url.searchParams.append('toASAID', BigInt(toASAID).toString())\n url.searchParams.append('amount', BigInt(amount).toString())\n url.searchParams.append('type', type)\n url.searchParams.append('disabledProtocols', allDisabledProtocols.join(','))\n url.searchParams.append('maxGroupSize', maxGroupSize.toString())\n url.searchParams.append('maxDepth', maxDepth.toString())\n\n if (typeof includeOptIn === 'boolean') {\n url.searchParams.append('optIn', String(includeOptIn))\n }\n\n if (this.config.referrerAddress) {\n url.searchParams.append('referrerAddress', this.config.referrerAddress)\n }\n\n return request<FetchQuoteResponse>(url.toString())\n }\n\n /**\n * Check if asset opt-in is required for the output asset\n *\n * Convenience method to determine if an address needs to opt into the output asset\n * of a swap. This is useful when you want to get a quote without requiring wallet\n * connection upfront, but need to know whether to set `optIn: true` in fetchQuote()\n * to ensure proper routing (as opt-ins reduce maxGroupSize by 1).\n *\n * Note: If you enable `config.autoOptIn`, this check is handled automatically when\n * an address is provided to fetchQuote().\n *\n * @param address - The address to check\n * @param assetId - The output asset ID to check\n * @returns True if asset opt-in is required, false otherwise (always false for ALGO)\n *\n * @example\n * ```typescript\n * // Check if opt-in needed for output asset before fetching quote\n * const needsOptIn = await deflex.needsAssetOptIn(userAddress, toAssetId)\n * const quote = await deflex.fetchQuote({\n * fromAssetId,\n * toAssetId,\n * amount,\n * optIn: needsOptIn,\n * })\n * ```\n */\n async needsAssetOptIn(\n address: string,\n assetId: number | bigint,\n ): Promise<boolean> {\n // Fetch account information\n const accountInfo = await this.algodClient.accountInformation(address).do()\n\n // Check if asset opt-in is required\n return (\n BigInt(assetId) !== 0n &&\n accountInfo?.assets?.find(\n (asset) => asset.assetId === BigInt(assetId),\n ) === undefined\n )\n }\n\n /**\n * Fetch swap transactions from the Deflex API\n *\n * Decrypts the quote payload and generates executable swap transactions for the\n * specified signer address with the given slippage tolerance.\n *\n * @param params - Parameters for the swap transaction request\n * @param params.quote - The quote response from fetchQuote()\n * @param params.address - The address of the signer\n * @param params.slippage - The slippage tolerance as a percentage (e.g., 1 for 1%)\n * @returns A FetchSwapTxnsResponse object with transaction data\n */\n async fetchSwapTransactions(\n params: FetchSwapTxnsParams,\n ): Promise<FetchSwapTxnsResponse> {\n const { quote, address, slippage } = params\n\n // Validate signer address\n this.validateAddress(address)\n\n const url = new URL(`${this.config.apiBaseUrl}/fetchExecuteSwapTxns`)\n\n const body: FetchSwapTxnsBody = {\n apiKey: this.config.apiKey,\n address,\n txnPayloadJSON: quote.txnPayload,\n slippage,\n }\n\n return request<FetchSwapTxnsResponse>(url.toString(), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n }\n\n /**\n * Fetch a quote and return an enhanced quote result\n *\n * This is the recommended way to fetch quotes. It returns an object that\n * extends the raw API response with additional metadata and type normalization.\n *\n * @param params - Parameters for the quote request\n * @param params.fromASAID - The ID of the asset to swap from\n * @param params.toASAID - The ID of the asset to swap to\n * @param params.amount - The amount of the asset to swap in base units\n * @param params.type - The type of the quote (default: 'fixed-input')\n * @param params.disabledProtocols - List of protocols to disable (default: [])\n * @param params.maxGroupSize - The maximum group size (default: 16)\n * @param params.maxDepth - The maximum depth (default: 4)\n * @param params.address - The address of the account that will perform the swap (recommended when using `config.autoOptIn` or `params.optIn`)\n * @param params.optIn - Whether to include asset opt-in transaction\n * @returns A DeflexQuote enhanced quote result\n *\n * @example\n * ```typescript\n * const quote = await deflex.newQuote({\n * address: 'ABC...',\n * fromASAID: 0,\n * toASAID: 31566704,\n * amount: 1_000_000,\n * })\n *\n * console.log(quote.quote) // bigint - quoted amount\n * console.log(quote.fromASAID) // number - input asset ID\n * console.log(quote.toASAID) // number - output asset ID\n * console.log(quote.amount) // bigint - original request amount\n * console.log(quote.createdAt) // number - timestamp\n * ```\n */\n async newQuote(params: FetchQuoteParams): Promise<DeflexQuote> {\n // Apply middleware transformations to quote params\n let adjustedParams = { ...params }\n\n for (const mw of this.middleware) {\n const shouldApply = await mw.shouldApply({\n fromASAID: BigInt(params.fromASAID),\n toASAID: BigInt(params.toASAID),\n })\n\n if (shouldApply && mw.adjustQuoteParams) {\n adjustedParams = await mw.adjustQuoteParams(adjustedParams)\n }\n }\n\n const response = await this.fetchQuote(adjustedParams)\n\n return {\n ...response,\n quote: response.quote === '' ? 0n : BigInt(response.quote),\n amount: BigInt(params.amount),\n address: params.address ?? undefined,\n createdAt: Date.now(),\n }\n }\n\n /**\n * Create a SwapComposer instance\n *\n * This factory method creates a composer that allows you to add custom transactions\n * before and after the swap transactions, with automatic handling of pre-signed transactions\n * and opt-ins.\n *\n * @param config.quote - The quote result from newQuote() or raw API response from fetchQuote()\n * @param config.address - The address of the signer\n * @param config.slippage - The slippage tolerance\n * @param config.signer - Transaction signer function\n * @returns A SwapComposer instance ready for building transaction groups\n *\n * @example\n * ```typescript\n * // Basic swap\n * const quote = await deflex.newQuote({ ... })\n * await deflex.newSwap({ quote, address, slippage, signer })\n * .execute()\n * ```\n *\n * @example\n * ```typescript\n * // Advanced swap with custom transactions\n * const quote = await deflex.newQuote({ ... })\n * const swap = await deflex.newSwap({\n * quote,\n * address,\n * slippage,\n * signer,\n * })\n *\n * console.log(swap.getStatus()) // BUILDING\n *\n * const signedTxns = await swap\n * .addTransaction(beforeTxn)\n * .addSwapTransactions() // Adds swap transactions to the group\n * .addTransaction(afterTxn)\n * .sign()\n *\n * console.log(swap.getStatus()) // SIGNED\n *\n * const result = await swap.execute(waitRounds)\n * console.log(result.confirmedRound, result.txIds)\n *\n * console.log(swap.getStatus()) // COMMITTED\n * ```\n */\n async newSwap(config: {\n quote: DeflexQuote | FetchQuoteResponse\n address: string\n slippage: number\n signer: TransactionSigner | SignerFunction\n }): Promise<SwapComposer> {\n const { quote, address, slippage, signer } = config\n\n const swapResponse = await this.fetchSwapTransactions({\n quote,\n address,\n slippage,\n })\n\n // Create the composer\n const composer = new SwapComposer({\n quote,\n deflexTxns: swapResponse.txns,\n algodClient: this.algodClient,\n address,\n signer,\n middleware: this.middleware,\n })\n\n return composer\n }\n\n /**\n * Validates the API key\n */\n private validateApiKey(apiKey: string): string {\n if (!apiKey) {\n throw new Error('API key is required')\n }\n return apiKey\n }\n\n /**\n * Validates an Algorand address\n */\n private validateAddress(address: string): string {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid Algorand address: ${address}`)\n }\n return address\n }\n\n /**\n * Validates the fee in basis points (max 300 = 3.00%)\n */\n private validateFeeBps(feeBps: number): number {\n if (feeBps < 0 || feeBps > MAX_FEE_BPS) {\n throw new Error(\n `Invalid fee: ${feeBps} basis points (must be between 0 and ${MAX_FEE_BPS})`,\n )\n }\n return feeBps\n }\n}\n"],"mappings":"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"}