@txnlab/deflex 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/index.d.mts +102 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +154 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -120,6 +120,28 @@ console.log(`Confirmed in round ${result.confirmedRound}`)
|
|
|
120
120
|
console.log('Transaction IDs:', result.txIds)
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
+
### Transaction Tracking
|
|
124
|
+
|
|
125
|
+
Add a custom note to the input transaction for tracking purposes, and retrieve its transaction ID after execution:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const swap = await deflex.newSwap({
|
|
129
|
+
quote,
|
|
130
|
+
address: activeAddress,
|
|
131
|
+
signer: transactionSigner,
|
|
132
|
+
slippage: 1,
|
|
133
|
+
note: new TextEncoder().encode('tracking-id-123'), // Custom note for tracking
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const result = await swap.execute()
|
|
137
|
+
|
|
138
|
+
// Get the transaction ID of the user-signed input transaction
|
|
139
|
+
const inputTxId = swap.getInputTransactionId()
|
|
140
|
+
console.log('Input transaction ID:', inputTxId)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The `note` is applied only to the user-signed payment or asset transfer transaction (not pre-signed or middleware transactions). The transaction ID is available after calling `buildGroup()`, `sign()`, or `execute()`.
|
|
144
|
+
|
|
123
145
|
### Transaction Signing
|
|
124
146
|
|
|
125
147
|
The SDK supports both standard `algosdk.TransactionSigner` and ARC-1 compliant signer functions.
|
|
@@ -395,6 +417,7 @@ async newSwap(config: SwapComposerConfig): Promise<SwapComposer>
|
|
|
395
417
|
| `address` | Signer address | `string` |
|
|
396
418
|
| `slippage` | Slippage tolerance as percentage (e.g., 1 for 1%) | `number` |
|
|
397
419
|
| `signer` | Transaction signer function | `algosdk.TransactionSigner \| ((txnGroup: Transaction[], indexesToSign: number[]) => Promise<(Uint8Array \| null)[]>)` |
|
|
420
|
+
| `note` | Optional note for the user-signed input transaction (for tracking purposes) | `Uint8Array` |
|
|
398
421
|
|
|
399
422
|
#### DeflexClient.needsAssetOptIn()
|
|
400
423
|
|
|
@@ -458,6 +481,7 @@ Builder for constructing and executing atomic swap transaction groups, returned
|
|
|
458
481
|
| `execute(waitRounds?)` | Sign, submit, and wait for confirmation | `waitRounds?: number` (default: 4) | `Promise<{ confirmedRound: bigint, txIds: string[], methodResults: ABIResult[] }>` |
|
|
459
482
|
| `getStatus()` | Get current status: `BUILDING`, `BUILT`, `SIGNED`, `SUBMITTED`, or `COMMITTED` | None | `SwapComposerStatus` |
|
|
460
483
|
| `count()` | Get the number of transactions in the group | None | `number` |
|
|
484
|
+
| `getInputTransactionId()` | Get the transaction ID of the user-signed input transaction (available after `buildGroup()`, `sign()`, or `execute()`) | None | `string \| undefined` |
|
|
461
485
|
|
|
462
486
|
## Documentation
|
|
463
487
|
|
package/dist/index.d.mts
CHANGED
|
@@ -317,6 +317,36 @@ interface SwapTransaction {
|
|
|
317
317
|
/** Pre-signature from Deflex (if applicable) */
|
|
318
318
|
readonly deflexSignature?: DeflexSignature;
|
|
319
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Summary of a swap transaction group after execution
|
|
322
|
+
*
|
|
323
|
+
* Contains the exact input/output amounts and total transaction fees.
|
|
324
|
+
* Only available after calling execute() on a SwapComposer instance.
|
|
325
|
+
*/
|
|
326
|
+
interface SwapSummary {
|
|
327
|
+
/** Input asset ID (0 for ALGO) */
|
|
328
|
+
inputAssetId: bigint;
|
|
329
|
+
/** Output asset ID (0 for ALGO) */
|
|
330
|
+
outputAssetId: bigint;
|
|
331
|
+
/** Exact input amount in base units, from the user-signed transaction */
|
|
332
|
+
inputAmount: bigint;
|
|
333
|
+
/** Exact output amount received in base units, from the inner transaction */
|
|
334
|
+
outputAmount: bigint;
|
|
335
|
+
/** Quote type */
|
|
336
|
+
type: QuoteType;
|
|
337
|
+
/** Total ALGO transaction fees in microAlgos */
|
|
338
|
+
totalFees: bigint;
|
|
339
|
+
/** Number of transactions in the group */
|
|
340
|
+
transactionCount: number;
|
|
341
|
+
/** Transaction ID of the user-signed input transaction (payment/asset transfer) */
|
|
342
|
+
inputTxnId: string;
|
|
343
|
+
/** Transaction ID of the app call containing the output transfer as an inner transaction */
|
|
344
|
+
outputTxnId: string;
|
|
345
|
+
/** Address that sent the input asset (the user) */
|
|
346
|
+
inputSender: string;
|
|
347
|
+
/** Address that sent the output asset to the user */
|
|
348
|
+
outputSender: string;
|
|
349
|
+
}
|
|
320
350
|
/**
|
|
321
351
|
* Method call to be executed as part of the swap
|
|
322
352
|
*/
|
|
@@ -674,6 +704,8 @@ interface SwapComposerConfig {
|
|
|
674
704
|
readonly signer: TransactionSigner | SignerFunction;
|
|
675
705
|
/** Middleware to apply during swap composition */
|
|
676
706
|
readonly middleware?: SwapMiddleware[];
|
|
707
|
+
/** Optional note field for the user-signed input transaction (payment or asset transfer) */
|
|
708
|
+
readonly note?: Uint8Array;
|
|
677
709
|
}
|
|
678
710
|
/**
|
|
679
711
|
* Composer for building and executing atomic swap transaction groups
|
|
@@ -707,6 +739,11 @@ declare class SwapComposer {
|
|
|
707
739
|
private readonly address;
|
|
708
740
|
private readonly signer;
|
|
709
741
|
private readonly middleware;
|
|
742
|
+
private readonly note?;
|
|
743
|
+
private inputTransactionIndex?;
|
|
744
|
+
private outputTransactionIndex?;
|
|
745
|
+
/** Summary data built incrementally during swap composition */
|
|
746
|
+
private summaryData?;
|
|
710
747
|
/**
|
|
711
748
|
* Create a new SwapComposer instance
|
|
712
749
|
*
|
|
@@ -859,12 +896,67 @@ declare class SwapComposer {
|
|
|
859
896
|
txIds: string[];
|
|
860
897
|
methodResults: ABIResult[];
|
|
861
898
|
}>;
|
|
899
|
+
/**
|
|
900
|
+
* Get the transaction ID of the user-signed input transaction
|
|
901
|
+
*
|
|
902
|
+
* Returns the transaction ID of the payment or asset transfer transaction
|
|
903
|
+
* that sends the input asset. This is the transaction whose note field can
|
|
904
|
+
* be customized via the `note` config option.
|
|
905
|
+
*
|
|
906
|
+
* The transaction ID is only available after the group has been built
|
|
907
|
+
* (after calling buildGroup(), sign(), submit(), or execute()).
|
|
908
|
+
*
|
|
909
|
+
* @returns The transaction ID, or undefined if the group hasn't been built yet
|
|
910
|
+
* or if the input transaction index couldn't be determined
|
|
911
|
+
*
|
|
912
|
+
* @example
|
|
913
|
+
* ```typescript
|
|
914
|
+
* const swap = await deflex.newSwap({
|
|
915
|
+
* quote,
|
|
916
|
+
* address,
|
|
917
|
+
* slippage,
|
|
918
|
+
* signer,
|
|
919
|
+
* note: new TextEncoder().encode('tracking-123')
|
|
920
|
+
* })
|
|
921
|
+
*
|
|
922
|
+
* await swap.execute()
|
|
923
|
+
* const inputTxId = swap.getInputTransactionId()
|
|
924
|
+
* console.log('Input transaction ID:', inputTxId)
|
|
925
|
+
* ```
|
|
926
|
+
*/
|
|
927
|
+
getInputTransactionId(): string | undefined;
|
|
928
|
+
/**
|
|
929
|
+
* Get a summary of the swap amounts and fees
|
|
930
|
+
*
|
|
931
|
+
* Returns the exact input and output amounts, total transaction fees,
|
|
932
|
+
* and transaction IDs. This is useful for displaying a complete summary
|
|
933
|
+
* after a swap has been executed.
|
|
934
|
+
*
|
|
935
|
+
* Only available after calling execute() - returns undefined before execution.
|
|
936
|
+
*
|
|
937
|
+
* @returns SwapSummary containing exact amounts and fees, or undefined if not yet executed
|
|
938
|
+
*
|
|
939
|
+
* @example
|
|
940
|
+
* ```typescript
|
|
941
|
+
* const swap = await deflex.newSwap({ quote, address, slippage, signer })
|
|
942
|
+
* const result = await swap.execute()
|
|
943
|
+
*
|
|
944
|
+
* const summary = swap.getSummary()
|
|
945
|
+
* if (summary) {
|
|
946
|
+
* console.log('Sent:', summary.inputAmount, 'Received:', summary.outputAmount)
|
|
947
|
+
* console.log('Total fees:', summary.totalFees, 'microAlgos')
|
|
948
|
+
* }
|
|
949
|
+
* ```
|
|
950
|
+
*/
|
|
951
|
+
getSummary(): SwapSummary | undefined;
|
|
862
952
|
/**
|
|
863
953
|
* Validates an Algorand address
|
|
864
954
|
*/
|
|
865
955
|
private validateAddress;
|
|
866
956
|
/**
|
|
867
957
|
* Processes app opt-ins and decodes swap transactions from API response
|
|
958
|
+
*
|
|
959
|
+
* Also initializes summaryData with input transaction details and output transaction ID
|
|
868
960
|
*/
|
|
869
961
|
private processSwapTransactions;
|
|
870
962
|
/**
|
|
@@ -887,6 +979,13 @@ declare class SwapComposer {
|
|
|
887
979
|
* Execute middleware hooks (beforeSwap or afterSwap)
|
|
888
980
|
*/
|
|
889
981
|
private executeMiddlewareHooks;
|
|
982
|
+
/**
|
|
983
|
+
* Extract the actual output amount from the confirmed output transaction's inner transactions
|
|
984
|
+
*
|
|
985
|
+
* Analyzes only the output transaction (last app call in the swap) to find the
|
|
986
|
+
* inner transaction that transfers the output asset to the user.
|
|
987
|
+
*/
|
|
988
|
+
private extractActualOutputAmount;
|
|
890
989
|
}
|
|
891
990
|
//#endregion
|
|
892
991
|
//#region src/client.d.ts
|
|
@@ -1100,6 +1199,8 @@ declare class DeflexClient {
|
|
|
1100
1199
|
address: string;
|
|
1101
1200
|
slippage: number;
|
|
1102
1201
|
signer: TransactionSigner | SignerFunction;
|
|
1202
|
+
/** Optional note field for the user-signed input transaction (payment or asset transfer) */
|
|
1203
|
+
note?: Uint8Array;
|
|
1103
1204
|
}): Promise<SwapComposer>;
|
|
1104
1205
|
/**
|
|
1105
1206
|
* Validates the API key
|
|
@@ -1138,5 +1239,5 @@ declare class HTTPError extends Error {
|
|
|
1138
1239
|
*/
|
|
1139
1240
|
declare function request<T>(url: string, options?: RequestInit): Promise<T>;
|
|
1140
1241
|
//#endregion
|
|
1141
|
-
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 };
|
|
1242
|
+
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, SwapSummary, SwapTransaction, TxnPayload, request };
|
|
1142
1243
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +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":";;;;;;AAGY,aAAA,QAAA;EAcC,SAAA,GAAA,WAAqD;EAGrD,MAAA,GAAA,QAAA;EAGA,QAAA,GAAA,UAAA;EAGA,IAAA,GAAA,MAAA;EAGA,KAAA,GAAA,OAAA;EAGA,KAAA,GAAA,OAAA;AAGb;AAGA;AAGA;AAGA;AAGA;;cA9Ba;;ACDI,cDIJ,iBAAA,GCJsB,sCAAA;AA+BnC;AACW,cDzBE,mBAAA,GCyBF,EAAA;;AADgB,cDrBd,kBAAA,GCqBc,GAAA;;AAUf,cD5BC,oBAAA,GC4BQ,+BAAA;AAKrB;AA4DiB,cD1FJ,eAAA,GC0FS,EAAA;AAkBtB;AAUiB,cDnHJ,WAAA,GCyHE,GAEC;AAMhB;AAUiB,cDxIJ,sBAAA,GCwIY,EAAA;AAYzB;AAUiB,cD3JJ,iBAAA,GC2JsB,CAAA;;AAgBjB,cDxKL,mBAAA,GCwKK,KAAA;;AAIC,cDzKN,2BAAA,GCyKM,EAAA;;;;ADrNnB;AAcA;AAGa,UCJI,kBAAA,CDIa;EAGjB;EAGA,SAAA,MAAA,EAAA,MAAkB;EAGlB;EAGA,SAAA,UAAe,CAAA,EAAA,MAAA;EAGf;EAGA,SAAA,QAAA,CAAA,EAAA,MAAsB;EAGtB;EAGA,SAAA,UAAA,CAAA,EAAmB,MAAA;EAGnB;;;;EC/BI;EA+BL,SAAA,MAAY,CAAA,EAAA,MAAA;EACb;EAAT,SAAA,SAAA,CAAA,EAAA,OAAA;;;AASF;AAKA;AA4DA;AAkBA;AAUiB,KAvGL,YAAA,GAAe,IA6GZ,CA5Gb,QA8Gc,CA9GL,kBA8GU,CAAA,EAAA,iBAAA,CAAA,GAAA;EAMJ,SAAK,eAIL,EAAA,MAAW,GAAA,SAAA;AAM5B,CAAA;AAYA;AAUA;;AAgBkB,KA3JN,SAAA,GA2JM,aAAA,GAAA,cAAA;;;;AAUO,UAhKR,gBAAA,CAgKQ;EAAM;EAgBnB,SAAA,SAAW,EAAA,MAAQ,GAAA,MAAA;EAsBd;EAUA,SAAA,OAAA,EAAA,MAAiB,GAAA,MAQZ;EAML;EAgBA,SAAA,MAAA,EAAA,MAAiB,GAAA,MAMP;EAQV;EAWA,SAAA,IAAA,CAAA,EA5PC,SA4Pc;
|
|
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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"}
|
package/dist/index.mjs
CHANGED
|
@@ -90,6 +90,11 @@ var SwapComposer = class SwapComposer {
|
|
|
90
90
|
address;
|
|
91
91
|
signer;
|
|
92
92
|
middleware;
|
|
93
|
+
note;
|
|
94
|
+
inputTransactionIndex;
|
|
95
|
+
outputTransactionIndex;
|
|
96
|
+
/** Summary data built incrementally during swap composition */
|
|
97
|
+
summaryData;
|
|
93
98
|
/**
|
|
94
99
|
* Create a new SwapComposer instance
|
|
95
100
|
*
|
|
@@ -117,6 +122,7 @@ var SwapComposer = class SwapComposer {
|
|
|
117
122
|
this.address = this.validateAddress(config.address);
|
|
118
123
|
this.signer = config.signer;
|
|
119
124
|
this.middleware = config.middleware ?? [];
|
|
125
|
+
this.note = config.note;
|
|
120
126
|
}
|
|
121
127
|
/**
|
|
122
128
|
* Get the status of this composer's transaction group
|
|
@@ -201,9 +207,11 @@ var SwapComposer = class SwapComposer {
|
|
|
201
207
|
const beforeTxns = await this.executeMiddlewareHooks("beforeSwap");
|
|
202
208
|
if (this.atc.count() + beforeTxns.length > SwapComposer.MAX_GROUP_SIZE) throw new Error(`Adding beforeSwap transactions exceeds the maximum atomic group size of ${SwapComposer.MAX_GROUP_SIZE}`);
|
|
203
209
|
for (const txnWithSigner of beforeTxns) this.atc.addTransaction(txnWithSigner);
|
|
204
|
-
const processedTxns = await this.processSwapTransactions();
|
|
210
|
+
const { txns: processedTxns, inputTxnRelativeIndex, outputTxnRelativeIndex } = await this.processSwapTransactions();
|
|
205
211
|
const afterTxns = await this.executeMiddlewareHooks("afterSwap");
|
|
206
212
|
if (this.atc.count() + processedTxns.length + afterTxns.length > SwapComposer.MAX_GROUP_SIZE) throw new Error(`Adding swap transactions exceeds the maximum atomic group size of ${SwapComposer.MAX_GROUP_SIZE}`);
|
|
213
|
+
if (inputTxnRelativeIndex !== void 0) this.inputTransactionIndex = this.atc.count() + inputTxnRelativeIndex;
|
|
214
|
+
if (outputTxnRelativeIndex !== void 0) this.outputTransactionIndex = this.atc.count() + outputTxnRelativeIndex;
|
|
207
215
|
for (const txnWithSigner of processedTxns) this.atc.addTransaction(txnWithSigner);
|
|
208
216
|
for (const txnWithSigner of afterTxns) this.atc.addTransaction(txnWithSigner);
|
|
209
217
|
this.swapTransactionsAdded = true;
|
|
@@ -293,12 +301,91 @@ var SwapComposer = class SwapComposer {
|
|
|
293
301
|
async execute(waitRounds = DEFAULT_CONFIRMATION_ROUNDS) {
|
|
294
302
|
if (!this.swapTransactionsAdded) await this.addSwapTransactions();
|
|
295
303
|
const { txIDs, ...result } = await this.atc.execute(this.algodClient, waitRounds);
|
|
304
|
+
if (this.summaryData) {
|
|
305
|
+
if (this.inputTransactionIndex !== void 0) this.summaryData.inputTxnId = txIDs[this.inputTransactionIndex];
|
|
306
|
+
if (this.outputTransactionIndex !== void 0) this.summaryData.outputTxnId = txIDs[this.outputTransactionIndex];
|
|
307
|
+
}
|
|
308
|
+
await this.extractActualOutputAmount();
|
|
296
309
|
return {
|
|
297
310
|
...result,
|
|
298
311
|
txIds: txIDs
|
|
299
312
|
};
|
|
300
313
|
}
|
|
301
314
|
/**
|
|
315
|
+
* Get the transaction ID of the user-signed input transaction
|
|
316
|
+
*
|
|
317
|
+
* Returns the transaction ID of the payment or asset transfer transaction
|
|
318
|
+
* that sends the input asset. This is the transaction whose note field can
|
|
319
|
+
* be customized via the `note` config option.
|
|
320
|
+
*
|
|
321
|
+
* The transaction ID is only available after the group has been built
|
|
322
|
+
* (after calling buildGroup(), sign(), submit(), or execute()).
|
|
323
|
+
*
|
|
324
|
+
* @returns The transaction ID, or undefined if the group hasn't been built yet
|
|
325
|
+
* or if the input transaction index couldn't be determined
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* const swap = await deflex.newSwap({
|
|
330
|
+
* quote,
|
|
331
|
+
* address,
|
|
332
|
+
* slippage,
|
|
333
|
+
* signer,
|
|
334
|
+
* note: new TextEncoder().encode('tracking-123')
|
|
335
|
+
* })
|
|
336
|
+
*
|
|
337
|
+
* await swap.execute()
|
|
338
|
+
* const inputTxId = swap.getInputTransactionId()
|
|
339
|
+
* console.log('Input transaction ID:', inputTxId)
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
getInputTransactionId() {
|
|
343
|
+
if (this.getStatus() < SwapComposerStatus.BUILT) return;
|
|
344
|
+
if (this.inputTransactionIndex === void 0) return;
|
|
345
|
+
return (this.atc.buildGroup()[this.inputTransactionIndex]?.txn)?.txID();
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Get a summary of the swap amounts and fees
|
|
349
|
+
*
|
|
350
|
+
* Returns the exact input and output amounts, total transaction fees,
|
|
351
|
+
* and transaction IDs. This is useful for displaying a complete summary
|
|
352
|
+
* after a swap has been executed.
|
|
353
|
+
*
|
|
354
|
+
* Only available after calling execute() - returns undefined before execution.
|
|
355
|
+
*
|
|
356
|
+
* @returns SwapSummary containing exact amounts and fees, or undefined if not yet executed
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* ```typescript
|
|
360
|
+
* const swap = await deflex.newSwap({ quote, address, slippage, signer })
|
|
361
|
+
* const result = await swap.execute()
|
|
362
|
+
*
|
|
363
|
+
* const summary = swap.getSummary()
|
|
364
|
+
* if (summary) {
|
|
365
|
+
* console.log('Sent:', summary.inputAmount, 'Received:', summary.outputAmount)
|
|
366
|
+
* console.log('Total fees:', summary.totalFees, 'microAlgos')
|
|
367
|
+
* }
|
|
368
|
+
* ```
|
|
369
|
+
*/
|
|
370
|
+
getSummary() {
|
|
371
|
+
if (!this.summaryData || this.summaryData.outputAmount === void 0 || this.summaryData.inputTxnId === void 0 || this.summaryData.outputTxnId === void 0 || this.summaryData.outputSender === void 0) return;
|
|
372
|
+
const txns = this.atc.buildGroup();
|
|
373
|
+
const totalFees = txns.reduce((sum, tws) => sum + tws.txn.fee, 0n);
|
|
374
|
+
return {
|
|
375
|
+
inputAssetId: this.summaryData.inputAssetId,
|
|
376
|
+
outputAssetId: this.summaryData.outputAssetId,
|
|
377
|
+
inputAmount: this.summaryData.inputAmount,
|
|
378
|
+
outputAmount: this.summaryData.outputAmount,
|
|
379
|
+
type: this.quote.type,
|
|
380
|
+
totalFees,
|
|
381
|
+
transactionCount: txns.length,
|
|
382
|
+
inputTxnId: this.summaryData.inputTxnId,
|
|
383
|
+
outputTxnId: this.summaryData.outputTxnId,
|
|
384
|
+
inputSender: this.summaryData.inputSender,
|
|
385
|
+
outputSender: this.summaryData.outputSender
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
302
389
|
* Validates an Algorand address
|
|
303
390
|
*/
|
|
304
391
|
validateAddress(address) {
|
|
@@ -307,10 +394,14 @@ var SwapComposer = class SwapComposer {
|
|
|
307
394
|
}
|
|
308
395
|
/**
|
|
309
396
|
* Processes app opt-ins and decodes swap transactions from API response
|
|
397
|
+
*
|
|
398
|
+
* Also initializes summaryData with input transaction details and output transaction ID
|
|
310
399
|
*/
|
|
311
400
|
async processSwapTransactions() {
|
|
312
401
|
const appOptIns = await this.processRequiredAppOptIns();
|
|
313
402
|
const swapTxns = [];
|
|
403
|
+
let inputTxnRelativeIndex;
|
|
404
|
+
let inputTxn;
|
|
314
405
|
for (let i = 0; i < this.deflexTxns.length; i++) {
|
|
315
406
|
const deflexTxn = this.deflexTxns[i];
|
|
316
407
|
if (!deflexTxn) continue;
|
|
@@ -321,15 +412,36 @@ var SwapComposer = class SwapComposer {
|
|
|
321
412
|
txn,
|
|
322
413
|
signer: this.createDeflexSigner(deflexTxn.signature)
|
|
323
414
|
});
|
|
324
|
-
else
|
|
325
|
-
txn
|
|
326
|
-
|
|
327
|
-
|
|
415
|
+
else {
|
|
416
|
+
if (this.note !== void 0) txn.note = this.note;
|
|
417
|
+
inputTxnRelativeIndex = appOptIns.length + swapTxns.length;
|
|
418
|
+
inputTxn = txn;
|
|
419
|
+
swapTxns.push({
|
|
420
|
+
txn,
|
|
421
|
+
signer: this.defaultSigner
|
|
422
|
+
});
|
|
423
|
+
}
|
|
328
424
|
} catch (error) {
|
|
329
425
|
throw new Error(`Failed to process swap transaction at index ${i}: ${error instanceof Error ? error.message : String(error)}`);
|
|
330
426
|
}
|
|
331
427
|
}
|
|
332
|
-
|
|
428
|
+
if (inputTxn) {
|
|
429
|
+
const paymentAmount = inputTxn.payment?.amount;
|
|
430
|
+
const assetTransferAmount = inputTxn.assetTransfer?.amount;
|
|
431
|
+
const inputAmount = paymentAmount ?? assetTransferAmount ?? 0n;
|
|
432
|
+
this.summaryData = {
|
|
433
|
+
inputAssetId: BigInt(this.quote.fromASAID),
|
|
434
|
+
outputAssetId: BigInt(this.quote.toASAID),
|
|
435
|
+
inputAmount,
|
|
436
|
+
inputSender: this.address
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
const outputTxnRelativeIndex = swapTxns.length > 0 ? appOptIns.length + swapTxns.length - 1 : void 0;
|
|
440
|
+
return {
|
|
441
|
+
txns: [...appOptIns, ...swapTxns],
|
|
442
|
+
inputTxnRelativeIndex,
|
|
443
|
+
outputTxnRelativeIndex
|
|
444
|
+
};
|
|
333
445
|
}
|
|
334
446
|
/**
|
|
335
447
|
* Creates opt-in transactions for apps the user hasn't opted into yet
|
|
@@ -421,6 +533,39 @@ var SwapComposer = class SwapComposer {
|
|
|
421
533
|
}
|
|
422
534
|
return allTxns;
|
|
423
535
|
}
|
|
536
|
+
/**
|
|
537
|
+
* Extract the actual output amount from the confirmed output transaction's inner transactions
|
|
538
|
+
*
|
|
539
|
+
* Analyzes only the output transaction (last app call in the swap) to find the
|
|
540
|
+
* inner transaction that transfers the output asset to the user.
|
|
541
|
+
*/
|
|
542
|
+
async extractActualOutputAmount() {
|
|
543
|
+
if (!this.summaryData?.outputTxnId) return;
|
|
544
|
+
const outputAssetId = this.summaryData.outputAssetId;
|
|
545
|
+
const userAddress = this.address;
|
|
546
|
+
try {
|
|
547
|
+
const innerTxns = (await this.algodClient.pendingTransactionInformation(this.summaryData.outputTxnId).do()).innerTxns;
|
|
548
|
+
if (!innerTxns) return;
|
|
549
|
+
for (const innerTxn of innerTxns) {
|
|
550
|
+
const txn = innerTxn.txn.txn;
|
|
551
|
+
const payment = txn.payment;
|
|
552
|
+
const assetTransfer = txn.assetTransfer;
|
|
553
|
+
const receiver = payment?.receiver ?? assetTransfer?.receiver;
|
|
554
|
+
if (!receiver) continue;
|
|
555
|
+
if (receiver.toString() !== userAddress) continue;
|
|
556
|
+
const senderAddress = txn.sender.toString();
|
|
557
|
+
if (outputAssetId === 0n && payment?.amount != null) {
|
|
558
|
+
this.summaryData.outputAmount = payment.amount;
|
|
559
|
+
this.summaryData.outputSender = senderAddress;
|
|
560
|
+
} else if (outputAssetId !== 0n && assetTransfer) {
|
|
561
|
+
if (assetTransfer.assetIndex === outputAssetId && assetTransfer.amount != null) {
|
|
562
|
+
this.summaryData.outputAmount = assetTransfer.amount;
|
|
563
|
+
this.summaryData.outputSender = senderAddress;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
} catch {}
|
|
568
|
+
}
|
|
424
569
|
};
|
|
425
570
|
|
|
426
571
|
//#endregion
|
|
@@ -746,7 +891,7 @@ var DeflexClient = class {
|
|
|
746
891
|
* ```
|
|
747
892
|
*/
|
|
748
893
|
async newSwap(config) {
|
|
749
|
-
const { quote, address, slippage, signer } = config;
|
|
894
|
+
const { quote, address, slippage, signer, note } = config;
|
|
750
895
|
return new SwapComposer({
|
|
751
896
|
quote,
|
|
752
897
|
deflexTxns: (await this.fetchSwapTransactions({
|
|
@@ -757,7 +902,8 @@ var DeflexClient = class {
|
|
|
757
902
|
algodClient: this.algodClient,
|
|
758
903
|
address,
|
|
759
904
|
signer,
|
|
760
|
-
middleware: this.middleware
|
|
905
|
+
middleware: this.middleware,
|
|
906
|
+
note
|
|
761
907
|
});
|
|
762
908
|
}
|
|
763
909
|
/**
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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 * @throws Error if attempting to compose with a non-composable swap (Tinyman v1)\n */\n addTransaction(transaction: Transaction, signer = this.defaultSigner): this {\n // Check if the quote uses Tinyman v1 (non-composable protocol)\n const usesTinymanV1 =\n this.quote.flattenedRoute?.['Tinyman'] !== undefined &&\n this.quote.flattenedRoute['Tinyman'] > 0\n\n if (usesTinymanV1) {\n throw new Error(\n 'Cannot add transactions to a swap group that uses Tinyman v1. ' +\n 'Tinyman v1 produces non-composable transaction groups. ' +\n 'Asset opt-ins, opt-outs, and other transactions must be sent in separate groups. ' +\n 'If you need to support Tinyman v1 swaps, you must handle multi-group coordination manually.',\n )\n }\n\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 * @throws Error if attempting to compose with a non-composable swap (Tinyman v1)\n */\n addMethodCall(methodCall: MethodCall, signer = this.defaultSigner): this {\n // Check if the quote uses Tinyman v1 (non-composable protocol)\n const usesTinymanV1 =\n this.quote.flattenedRoute?.['Tinyman'] !== undefined &&\n this.quote.flattenedRoute['Tinyman'] > 0\n\n if (usesTinymanV1) {\n throw new Error(\n 'Cannot add method calls to a swap group that uses Tinyman v1. ' +\n 'Tinyman v1 produces non-composable transaction groups. ' +\n 'Asset opt-ins, opt-outs, and other transactions must be sent in separate groups. ' +\n 'If you need to support Tinyman v1 swaps, you must handle multi-group coordination manually.',\n )\n }\n\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 _allowNonComposableSwaps = false,\n } = params\n\n // Validate incompatible parameter combinations\n if (_allowNonComposableSwaps && (optIn === true || this.config.autoOptIn)) {\n throw new Error(\n 'Cannot use _allowNonComposableSwaps with optIn or autoOptIn. ' +\n 'When allowing non-composable swaps (Tinyman v1), you must handle ' +\n 'asset opt-ins and opt-outs in separate transaction groups.',\n )\n }\n\n // Conditionally include deprecated protocols in disabled list\n // If _allowNonComposableSwaps is true, only exclude Tinyman v1 from auto-disabled list\n // Otherwise, always include all deprecated protocols (Tinyman v1, Humble)\n const allDisabledProtocols = _allowNonComposableSwaps\n ? [...new Set(['Humble', ...disabledProtocols])]\n : [...new Set([...DEPRECATED_PROTOCOLS, ...disabledProtocols])]\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 // Block usage of _allowNonComposableSwaps with newQuote (middleware path)\n if (params._allowNonComposableSwaps) {\n throw new Error(\n 'The _allowNonComposableSwaps parameter is not supported with newQuote(). ' +\n 'This parameter is only available with fetchQuote() for advanced use cases. ' +\n 'The newQuote() method is designed for composable swaps with middleware support.',\n )\n }\n\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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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["swapTxns: TransactionWithSigner[]","inputTxnRelativeIndex: number | undefined","inputTxn: Transaction | undefined","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 SwapSummary,\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 /** Optional note field for the user-signed input transaction (payment or asset transfer) */\n readonly note?: Uint8Array\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 private readonly note?: Uint8Array\n private inputTransactionIndex?: number\n private outputTransactionIndex?: number\n\n /** Summary data built incrementally during swap composition */\n private summaryData?: {\n inputAssetId: bigint\n outputAssetId: bigint\n inputAmount: bigint\n inputTxnId?: string\n outputTxnId?: string\n inputSender: string\n outputSender?: string\n outputAmount?: bigint\n }\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 this.note = config.note\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 * @throws Error if attempting to compose with a non-composable swap (Tinyman v1)\n */\n addTransaction(transaction: Transaction, signer = this.defaultSigner): this {\n // Check if the quote uses Tinyman v1 (non-composable protocol)\n const usesTinymanV1 =\n this.quote.flattenedRoute?.['Tinyman'] !== undefined &&\n this.quote.flattenedRoute['Tinyman'] > 0\n\n if (usesTinymanV1) {\n throw new Error(\n 'Cannot add transactions to a swap group that uses Tinyman v1. ' +\n 'Tinyman v1 produces non-composable transaction groups. ' +\n 'Asset opt-ins, opt-outs, and other transactions must be sent in separate groups. ' +\n 'If you need to support Tinyman v1 swaps, you must handle multi-group coordination manually.',\n )\n }\n\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 * @throws Error if attempting to compose with a non-composable swap (Tinyman v1)\n */\n addMethodCall(methodCall: MethodCall, signer = this.defaultSigner): this {\n // Check if the quote uses Tinyman v1 (non-composable protocol)\n const usesTinymanV1 =\n this.quote.flattenedRoute?.['Tinyman'] !== undefined &&\n this.quote.flattenedRoute['Tinyman'] > 0\n\n if (usesTinymanV1) {\n throw new Error(\n 'Cannot add method calls to a swap group that uses Tinyman v1. ' +\n 'Tinyman v1 produces non-composable transaction groups. ' +\n 'Asset opt-ins, opt-outs, and other transactions must be sent in separate groups. ' +\n 'If you need to support Tinyman v1 swaps, you must handle multi-group coordination manually.',\n )\n }\n\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 {\n txns: processedTxns,\n inputTxnRelativeIndex,\n outputTxnRelativeIndex,\n } = 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 // Calculate the absolute index of the user-signed input transaction\n // This is: current ATC count (user txns + beforeSwap) + relative index within processed txns\n if (inputTxnRelativeIndex !== undefined) {\n this.inputTransactionIndex = this.atc.count() + inputTxnRelativeIndex\n }\n\n // Calculate the absolute index of the output transaction (last app call in swap)\n if (outputTxnRelativeIndex !== undefined) {\n this.outputTransactionIndex = this.atc.count() + outputTxnRelativeIndex\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 // Store transaction IDs in summaryData\n if (this.summaryData) {\n if (this.inputTransactionIndex !== undefined) {\n this.summaryData.inputTxnId = txIDs[this.inputTransactionIndex]\n }\n if (this.outputTransactionIndex !== undefined) {\n this.summaryData.outputTxnId = txIDs[this.outputTransactionIndex]\n }\n }\n\n // Extract actual output amount from confirmed transaction\n await this.extractActualOutputAmount()\n\n return {\n ...result,\n txIds: txIDs,\n }\n }\n\n /**\n * Get the transaction ID of the user-signed input transaction\n *\n * Returns the transaction ID of the payment or asset transfer transaction\n * that sends the input asset. This is the transaction whose note field can\n * be customized via the `note` config option.\n *\n * The transaction ID is only available after the group has been built\n * (after calling buildGroup(), sign(), submit(), or execute()).\n *\n * @returns The transaction ID, or undefined if the group hasn't been built yet\n * or if the input transaction index couldn't be determined\n *\n * @example\n * ```typescript\n * const swap = await deflex.newSwap({\n * quote,\n * address,\n * slippage,\n * signer,\n * note: new TextEncoder().encode('tracking-123')\n * })\n *\n * await swap.execute()\n * const inputTxId = swap.getInputTransactionId()\n * console.log('Input transaction ID:', inputTxId)\n * ```\n */\n getInputTransactionId(): string | undefined {\n if (this.getStatus() < SwapComposerStatus.BUILT) {\n return undefined\n }\n if (this.inputTransactionIndex === undefined) {\n return undefined\n }\n const txns = this.atc.buildGroup()\n const txn = txns[this.inputTransactionIndex]?.txn\n return txn?.txID()\n }\n\n /**\n * Get a summary of the swap amounts and fees\n *\n * Returns the exact input and output amounts, total transaction fees,\n * and transaction IDs. This is useful for displaying a complete summary\n * after a swap has been executed.\n *\n * Only available after calling execute() - returns undefined before execution.\n *\n * @returns SwapSummary containing exact amounts and fees, or undefined if not yet executed\n *\n * @example\n * ```typescript\n * const swap = await deflex.newSwap({ quote, address, slippage, signer })\n * const result = await swap.execute()\n *\n * const summary = swap.getSummary()\n * if (summary) {\n * console.log('Sent:', summary.inputAmount, 'Received:', summary.outputAmount)\n * console.log('Total fees:', summary.totalFees, 'microAlgos')\n * }\n * ```\n */\n getSummary(): SwapSummary | undefined {\n // Only return summary after execution when we have all the data\n if (\n !this.summaryData ||\n this.summaryData.outputAmount === undefined ||\n this.summaryData.inputTxnId === undefined ||\n this.summaryData.outputTxnId === undefined ||\n this.summaryData.outputSender === undefined\n ) {\n return undefined\n }\n\n const txns = this.atc.buildGroup()\n const totalFees = txns.reduce((sum, tws) => sum + tws.txn.fee, 0n)\n\n return {\n inputAssetId: this.summaryData.inputAssetId,\n outputAssetId: this.summaryData.outputAssetId,\n inputAmount: this.summaryData.inputAmount,\n outputAmount: this.summaryData.outputAmount,\n type: this.quote.type as QuoteType,\n totalFees,\n transactionCount: txns.length,\n inputTxnId: this.summaryData.inputTxnId,\n outputTxnId: this.summaryData.outputTxnId,\n inputSender: this.summaryData.inputSender,\n outputSender: this.summaryData.outputSender,\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 * Also initializes summaryData with input transaction details and output transaction ID\n */\n private async processSwapTransactions(): Promise<{\n txns: TransactionWithSigner[]\n inputTxnRelativeIndex?: number\n outputTxnRelativeIndex?: number\n }> {\n const appOptIns = await this.processRequiredAppOptIns()\n\n const swapTxns: TransactionWithSigner[] = []\n let inputTxnRelativeIndex: number | undefined\n let inputTxn: Transaction | undefined\n\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 // Input payment or asset transfer transaction - use configured signer\n // Set the note if provided (using type assertion since note is readonly but safe to modify before signing)\n if (this.note !== undefined) {\n ;(txn as { note: Uint8Array }).note = this.note\n }\n // Track the relative index within processed transactions (after app opt-ins)\n inputTxnRelativeIndex = appOptIns.length + swapTxns.length\n inputTxn = txn\n\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 // Initialize summary data with input transaction details\n if (inputTxn) {\n // Extract input amount from payment or asset transfer\n const paymentAmount = inputTxn.payment?.amount\n const assetTransferAmount = inputTxn.assetTransfer?.amount\n const inputAmount = paymentAmount ?? assetTransferAmount ?? 0n\n\n this.summaryData = {\n inputAssetId: BigInt(this.quote.fromASAID),\n outputAssetId: BigInt(this.quote.toASAID),\n inputAmount,\n inputSender: this.address,\n }\n }\n\n // The last transaction in swapTxns is the app call that will contain\n // the inner transaction sending the output asset to the user\n // We'll get its ID after buildGroup() is called\n // Store the relative index so we can get the ID later\n const outputTxnRelativeIndex =\n swapTxns.length > 0 ? appOptIns.length + swapTxns.length - 1 : undefined\n\n return {\n txns: [...appOptIns, ...swapTxns],\n inputTxnRelativeIndex,\n outputTxnRelativeIndex,\n }\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 * Extract the actual output amount from the confirmed output transaction's inner transactions\n *\n * Analyzes only the output transaction (last app call in the swap) to find the\n * inner transaction that transfers the output asset to the user.\n */\n private async extractActualOutputAmount(): Promise<void> {\n if (!this.summaryData?.outputTxnId) {\n return\n }\n\n const outputAssetId = this.summaryData.outputAssetId\n const userAddress = this.address\n\n try {\n const pendingInfo = await this.algodClient\n .pendingTransactionInformation(this.summaryData.outputTxnId)\n .do()\n\n const innerTxns = pendingInfo.innerTxns\n if (!innerTxns) return\n\n for (const innerTxn of innerTxns) {\n const txn = innerTxn.txn.txn\n const payment = txn.payment\n const assetTransfer = txn.assetTransfer\n\n // Get receiver address based on transaction type\n const receiver = payment?.receiver ?? assetTransfer?.receiver\n if (!receiver) continue\n\n // Check if this transfer is to the user\n if (receiver.toString() !== userAddress) continue\n\n // Get sender address for outputSender\n const senderAddress = txn.sender.toString()\n\n if (outputAssetId === 0n && payment?.amount != null) {\n // ALGO output to user\n this.summaryData.outputAmount = payment.amount\n this.summaryData.outputSender = senderAddress\n } else if (outputAssetId !== 0n && assetTransfer) {\n // ASA output - verify it's the right asset\n const assetId = assetTransfer.assetIndex\n if (assetId === outputAssetId && assetTransfer.amount != null) {\n this.summaryData.outputAmount = assetTransfer.amount\n this.summaryData.outputSender = senderAddress\n }\n }\n }\n } catch {\n // Silently fail - outputAmount will remain undefined\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 _allowNonComposableSwaps = false,\n } = params\n\n // Validate incompatible parameter combinations\n if (_allowNonComposableSwaps && (optIn === true || this.config.autoOptIn)) {\n throw new Error(\n 'Cannot use _allowNonComposableSwaps with optIn or autoOptIn. ' +\n 'When allowing non-composable swaps (Tinyman v1), you must handle ' +\n 'asset opt-ins and opt-outs in separate transaction groups.',\n )\n }\n\n // Conditionally include deprecated protocols in disabled list\n // If _allowNonComposableSwaps is true, only exclude Tinyman v1 from auto-disabled list\n // Otherwise, always include all deprecated protocols (Tinyman v1, Humble)\n const allDisabledProtocols = _allowNonComposableSwaps\n ? [...new Set(['Humble', ...disabledProtocols])]\n : [...new Set([...DEPRECATED_PROTOCOLS, ...disabledProtocols])]\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 // Block usage of _allowNonComposableSwaps with newQuote (middleware path)\n if (params._allowNonComposableSwaps) {\n throw new Error(\n 'The _allowNonComposableSwaps parameter is not supported with newQuote(). ' +\n 'This parameter is only available with fetchQuote() for advanced use cases. ' +\n 'The newQuote() method is designed for composable swaps with middleware support.',\n )\n }\n\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 /** Optional note field for the user-signed input transaction (payment or asset transfer) */\n note?: Uint8Array\n }): Promise<SwapComposer> {\n const { quote, address, slippage, signer, note } = 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 note,\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
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "TypeScript/JavaScript SDK for Deflex Order Router - smart order routing and DEX aggregation on Algorand",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"algorand",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=20"
|
|
46
46
|
},
|
|
47
|
-
"packageManager": "pnpm@10.
|
|
47
|
+
"packageManager": "pnpm@10.27.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.
|
|
57
|
-
"@vitest/coverage-v8": "4.0.
|
|
56
|
+
"@types/node": "22.19.3",
|
|
57
|
+
"@vitest/coverage-v8": "4.0.16",
|
|
58
58
|
"algosdk": "3.5.2",
|
|
59
|
-
"publint": "0.3.
|
|
60
|
-
"tsdown": "0.
|
|
59
|
+
"publint": "0.3.16",
|
|
60
|
+
"tsdown": "0.18.4",
|
|
61
61
|
"typescript": "5.9.3",
|
|
62
|
-
"vitest": "4.0.
|
|
62
|
+
"vitest": "4.0.16"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"algosdk": "^3.0.0"
|