@txnlab/deflex 1.0.0 → 1.2.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 +41 -21
- package/dist/index.d.ts +109 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +108 -94
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
# Deflex SDK
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@txnlab/deflex)
|
|
4
|
+
[](https://bundlejs.com/?q=%40txnlab%2Fdeflex%40latest&treeshake=%5B*%5D)
|
|
5
|
+
[](https://github.com/TxnLab/deflex-js/actions/workflows/ci.yml)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
3
9
|
TypeScript/JavaScript SDK for [Deflex Order Router](https://txnlab.gitbook.io/deflex-api) - smart order routing and DEX aggregation on Algorand.
|
|
4
10
|
|
|
5
11
|
## Prerequisites
|
|
6
12
|
|
|
7
13
|
- **Deflex API Key** - Request an API key by emailing [support@txnlab.dev](mailto:support@txnlab.dev)
|
|
14
|
+
- algosdk 3.0.0 or later
|
|
8
15
|
|
|
9
16
|
## Installation
|
|
10
17
|
|
|
11
18
|
```bash
|
|
12
|
-
npm install @txnlab/deflex
|
|
19
|
+
npm install @txnlab/deflex algosdk
|
|
13
20
|
```
|
|
14
21
|
|
|
22
|
+
> **Note**: `algosdk` is a peer dependency and must be installed alongside `@txnlab/deflex`.
|
|
23
|
+
|
|
15
24
|
## Quick Start
|
|
16
25
|
|
|
17
26
|
```typescript
|
|
@@ -171,6 +180,7 @@ await swap.execute()
|
|
|
171
180
|
```
|
|
172
181
|
|
|
173
182
|
The signer function supports two return patterns:
|
|
183
|
+
|
|
174
184
|
- **Pattern 1** (Pera, Defly, algosdk): Returns only the signed transactions as `Uint8Array[]`
|
|
175
185
|
- **Pattern 2** (Lute, ARC-1 compliant): Returns an array matching the transaction group length with `null` for unsigned transactions as `(Uint8Array | null)[]`
|
|
176
186
|
|
|
@@ -178,17 +188,25 @@ Both patterns are automatically handled by the SDK.
|
|
|
178
188
|
|
|
179
189
|
### Advanced Transaction Composition
|
|
180
190
|
|
|
181
|
-
Build the transaction group by adding custom transactions before or after the swap using the [`SwapComposer`](#swapcomposer) instance:
|
|
191
|
+
Build the transaction group by adding custom transactions and ABI method calls before or after the swap using the [`SwapComposer`](#swapcomposer) instance:
|
|
182
192
|
|
|
183
193
|
```typescript
|
|
184
|
-
import { Transaction } from 'algosdk'
|
|
194
|
+
import { ABIMethod, Transaction } from 'algosdk'
|
|
185
195
|
import { useWallet } from '@txnlab/use-wallet-*' // react, vue, solid, or svelte
|
|
186
196
|
|
|
187
197
|
const { activeAddress, transactionSigner } = useWallet()
|
|
188
198
|
|
|
189
199
|
// Create your custom transactions
|
|
190
|
-
const
|
|
191
|
-
|
|
200
|
+
const customTxn = new Transaction({...})
|
|
201
|
+
|
|
202
|
+
// Define an ABI method call
|
|
203
|
+
const methodCall = {
|
|
204
|
+
appID: 123456,
|
|
205
|
+
method: new ABIMethod({...}),
|
|
206
|
+
methodArgs: [...],
|
|
207
|
+
sender: activeAddress,
|
|
208
|
+
suggestedParams: await algodClient.getTransactionParams().do(),
|
|
209
|
+
}
|
|
192
210
|
|
|
193
211
|
// Build and execute the transaction group
|
|
194
212
|
const swap = await deflex.newSwap({
|
|
@@ -199,9 +217,9 @@ const swap = await deflex.newSwap({
|
|
|
199
217
|
})
|
|
200
218
|
|
|
201
219
|
const result = await swap
|
|
202
|
-
.addTransaction(
|
|
220
|
+
.addTransaction(customTxn) // Add transaction before swap
|
|
203
221
|
.addSwapTransactions() // Add swap transactions
|
|
204
|
-
.
|
|
222
|
+
.addMethodCall(methodCall) // Add ABI method call after swap
|
|
205
223
|
.execute() // Sign and execute entire group
|
|
206
224
|
```
|
|
207
225
|
|
|
@@ -307,11 +325,11 @@ Returns a [`SwapComposer`](#swapcomposer) instance for building and executing sw
|
|
|
307
325
|
async newSwap(config: SwapComposerConfig): Promise<SwapComposer>
|
|
308
326
|
```
|
|
309
327
|
|
|
310
|
-
| Parameter | Description | Type
|
|
311
|
-
| ---------- | ------------------------------------------------- |
|
|
312
|
-
| `quote` | Quote result or raw API response | `DeflexQuote \| FetchQuoteResponse`
|
|
313
|
-
| `address` | Signer address | `string`
|
|
314
|
-
| `slippage` | Slippage tolerance as percentage (e.g., 1 for 1%) | `number`
|
|
328
|
+
| Parameter | Description | Type |
|
|
329
|
+
| ---------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
330
|
+
| `quote` | Quote result or raw API response | `DeflexQuote \| FetchQuoteResponse` |
|
|
331
|
+
| `address` | Signer address | `string` |
|
|
332
|
+
| `slippage` | Slippage tolerance as percentage (e.g., 1 for 1%) | `number` |
|
|
315
333
|
| `signer` | Transaction signer function | `algosdk.TransactionSigner \| ((txnGroup: Transaction[], indexesToSign: number[]) => Promise<(Uint8Array \| null)[]>)` |
|
|
316
334
|
|
|
317
335
|
#### DeflexClient.needsAssetOptIn()
|
|
@@ -365,15 +383,17 @@ Plain object returned by [`newQuote()`](#deflexclientnewquote). Extends the raw
|
|
|
365
383
|
|
|
366
384
|
Builder for constructing and executing atomic swap transaction groups, returned by [`newSwap()`](#deflexclientnewswap).
|
|
367
385
|
|
|
368
|
-
| Method
|
|
369
|
-
|
|
|
370
|
-
| `addTransaction(transaction)` | Add a transaction to the atomic group | `transaction: algosdk.Transaction` | `SwapComposer`
|
|
371
|
-
| `
|
|
372
|
-
| `
|
|
373
|
-
| `
|
|
374
|
-
| `
|
|
375
|
-
| `
|
|
376
|
-
| `
|
|
386
|
+
| Method | Description | Parameters | Returns |
|
|
387
|
+
| -------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
388
|
+
| `addTransaction(transaction, signer?)` | Add a transaction to the atomic group | `transaction: algosdk.Transaction, signer?: TransactionSigner` | `SwapComposer` |
|
|
389
|
+
| `addMethodCall(methodCall, signer?)` | Add an ABI method call to the atomic group | `methodCall: MethodCall, signer?: TransactionSigner` | `SwapComposer` |
|
|
390
|
+
| `addSwapTransactions()` | Add swap transactions to the group (includes required app opt-ins) | None | `Promise<SwapComposer>` |
|
|
391
|
+
| `buildGroup()` | Build the transaction group and assign group IDs | None | `TransactionWithSigner[]` |
|
|
392
|
+
| `sign()` | Sign the transaction group | None | `Promise<Uint8Array[]>` |
|
|
393
|
+
| `submit()` | Sign and submit the transaction group | None | `Promise<string[]>` (transaction IDs) |
|
|
394
|
+
| `execute(waitRounds?)` | Sign, submit, and wait for confirmation | `waitRounds?: number` (default: 4) | `Promise<{ confirmedRound: bigint, txIds: string[], methodResults: ABIResult[] }>` |
|
|
395
|
+
| `getStatus()` | Get current status: `BUILDING`, `BUILT`, `SIGNED`, `SUBMITTED`, or `COMMITTED` | None | `SwapComposerStatus` |
|
|
396
|
+
| `count()` | Get the number of transactions in the group | None | `number` |
|
|
377
397
|
|
|
378
398
|
## Documentation
|
|
379
399
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import algosdk, { Transaction, TransactionSigner } from "algosdk";
|
|
1
|
+
import { ABIArgument, ABIMethod, ABIResult, Address, Algodv2, BoxReference, OnApplicationComplete, ResourceReference, SuggestedParams, Transaction, TransactionSigner, TransactionWithSigner } from "algosdk";
|
|
3
2
|
|
|
4
3
|
//#region src/constants.d.ts
|
|
5
4
|
/**
|
|
@@ -282,14 +281,66 @@ interface FetchSwapTxnsResponse {
|
|
|
282
281
|
/**
|
|
283
282
|
* Processed transaction with optional pre-signature
|
|
284
283
|
*
|
|
284
|
+
* @deprecated This type is no longer used internally. Use algosdk.TransactionWithSigner instead.
|
|
285
285
|
* @internal
|
|
286
286
|
*/
|
|
287
287
|
interface SwapTransaction {
|
|
288
288
|
/** The Algorand transaction */
|
|
289
|
-
readonly txn:
|
|
289
|
+
readonly txn: Transaction;
|
|
290
290
|
/** Pre-signature from Deflex (if applicable) */
|
|
291
291
|
readonly deflexSignature?: DeflexSignature;
|
|
292
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* Method call to be executed as part of the swap
|
|
295
|
+
*/
|
|
296
|
+
interface MethodCall {
|
|
297
|
+
/** The ID of the smart contract to call. Set this to 0 to indicate an application creation call. */
|
|
298
|
+
appID: number | bigint;
|
|
299
|
+
/** The method to call on the smart contract */
|
|
300
|
+
method: ABIMethod;
|
|
301
|
+
/** The arguments to include in the method call. If omitted, no arguments will be passed to the method. */
|
|
302
|
+
methodArgs?: ABIArgument[];
|
|
303
|
+
/** The address of the sender of this application call */
|
|
304
|
+
sender: string | Address;
|
|
305
|
+
/** Transactions params to use for this application call */
|
|
306
|
+
suggestedParams: SuggestedParams;
|
|
307
|
+
/** The OnComplete action to take for this application call. If omitted, OnApplicationComplete.NoOpOC will be used. */
|
|
308
|
+
onComplete?: OnApplicationComplete;
|
|
309
|
+
/** The approval program for this application call. Only set this if this is an application creation call, or if onComplete is OnApplicationComplete.UpdateApplicationOC */
|
|
310
|
+
approvalProgram?: Uint8Array;
|
|
311
|
+
/** The clear program for this application call. Only set this if this is an application creation call, or if onComplete is OnApplicationComplete.UpdateApplicationOC */
|
|
312
|
+
clearProgram?: Uint8Array;
|
|
313
|
+
/** The global integer schema size. Only set this if this is an application creation call. */
|
|
314
|
+
numGlobalInts?: number;
|
|
315
|
+
/** The global byte slice schema size. Only set this if this is an application creation call. */
|
|
316
|
+
numGlobalByteSlices?: number;
|
|
317
|
+
/** The local integer schema size. Only set this if this is an application creation call. */
|
|
318
|
+
numLocalInts?: number;
|
|
319
|
+
/** The local byte slice schema size. Only set this if this is an application creation call. */
|
|
320
|
+
numLocalByteSlices?: number;
|
|
321
|
+
/** The number of extra pages to allocate for the application's programs. Only set this if this is an application creation call. If omitted, defaults to 0. */
|
|
322
|
+
extraPages?: number;
|
|
323
|
+
/** Array of Address strings that represent external accounts supplied to this application. If accounts are provided here, the accounts specified in the method args will appear after these. */
|
|
324
|
+
appAccounts?: Array<string | Address>;
|
|
325
|
+
/** Array of App ID numbers that represent external apps supplied to this application. If apps are provided here, the apps specified in the method args will appear after these. */
|
|
326
|
+
appForeignApps?: Array<number | bigint>;
|
|
327
|
+
/** Array of Asset ID numbers that represent external assets supplied to this application. If assets are provided here, the assets specified in the method args will appear after these. */
|
|
328
|
+
appForeignAssets?: Array<number | bigint>;
|
|
329
|
+
/** The box references for this application call */
|
|
330
|
+
boxes?: BoxReference[];
|
|
331
|
+
/** The resource references for this application call */
|
|
332
|
+
access?: ResourceReference[];
|
|
333
|
+
/** The note value for this application call */
|
|
334
|
+
note?: Uint8Array;
|
|
335
|
+
/** The lease value for this application call */
|
|
336
|
+
lease?: Uint8Array;
|
|
337
|
+
/** If provided, the address that the sender will be rekeyed to at the conclusion of this application call */
|
|
338
|
+
rekeyTo?: string | Address;
|
|
339
|
+
/** The lowest application version for which this transaction should immediately fail. 0 indicates that no version check should be performed. */
|
|
340
|
+
rejectVersion?: number | bigint;
|
|
341
|
+
/** A transaction signer that can authorize this application call from sender */
|
|
342
|
+
signer?: TransactionSigner;
|
|
343
|
+
}
|
|
293
344
|
//#endregion
|
|
294
345
|
//#region src/composer.d.ts
|
|
295
346
|
/**
|
|
@@ -324,8 +375,8 @@ interface SwapComposerConfig {
|
|
|
324
375
|
readonly quote: FetchQuoteResponse | DeflexQuote;
|
|
325
376
|
/** The swap transactions from fetchSwapTransactions() */
|
|
326
377
|
readonly deflexTxns: DeflexTransaction[];
|
|
327
|
-
/**
|
|
328
|
-
readonly
|
|
378
|
+
/** Algodv2 client instance */
|
|
379
|
+
readonly algodClient: Algodv2;
|
|
329
380
|
/** The address of the account that will sign transactions */
|
|
330
381
|
readonly address: string;
|
|
331
382
|
/** Transaction signer function */
|
|
@@ -341,25 +392,24 @@ interface SwapComposerConfig {
|
|
|
341
392
|
* @example
|
|
342
393
|
* ```typescript
|
|
343
394
|
* const quote = await deflex.fetchQuote({ ... })
|
|
344
|
-
* const composer = await deflex.newSwap({ quote, address, slippage })
|
|
395
|
+
* const composer = await deflex.newSwap({ quote, address, slippage, signer })
|
|
345
396
|
*
|
|
346
397
|
* await composer
|
|
347
398
|
* .addTransaction(customTxn)
|
|
348
399
|
* .addSwapTransactions()
|
|
349
|
-
* .execute(
|
|
400
|
+
* .execute()
|
|
350
401
|
* ```
|
|
351
402
|
*/
|
|
352
403
|
declare class SwapComposer {
|
|
404
|
+
/** The ATC used to compose the group */
|
|
405
|
+
private atc;
|
|
353
406
|
/** The maximum size of an atomic transaction group. */
|
|
354
407
|
static MAX_GROUP_SIZE: number;
|
|
355
|
-
|
|
356
|
-
private transactions;
|
|
408
|
+
/** Whether the swap transactions have been added to the atomic group. */
|
|
357
409
|
private swapTransactionsAdded;
|
|
358
|
-
private signedTxns;
|
|
359
|
-
private txIds;
|
|
360
410
|
private readonly requiredAppOptIns;
|
|
361
411
|
private readonly deflexTxns;
|
|
362
|
-
private readonly
|
|
412
|
+
private readonly algodClient;
|
|
363
413
|
private readonly address;
|
|
364
414
|
private readonly signer;
|
|
365
415
|
/**
|
|
@@ -371,7 +421,7 @@ declare class SwapComposer {
|
|
|
371
421
|
* @param config - Configuration for the composer
|
|
372
422
|
* @param config.requiredAppOptIns - The quote response from fetchQuote()
|
|
373
423
|
* @param config.deflexTxns - The swap transactions from fetchSwapTransactions()
|
|
374
|
-
* @param config.
|
|
424
|
+
* @param config.algodClient - Algodv2 client instance
|
|
375
425
|
* @param config.address - The address of the account that will sign transactions
|
|
376
426
|
* @param config.signer - Transaction signer function
|
|
377
427
|
*/
|
|
@@ -404,7 +454,19 @@ declare class SwapComposer {
|
|
|
404
454
|
* @throws Error if the composer is not in the BUILDING status
|
|
405
455
|
* @throws Error if the maximum group size is exceeded
|
|
406
456
|
*/
|
|
407
|
-
addTransaction(transaction: Transaction): this;
|
|
457
|
+
addTransaction(transaction: Transaction, signer?: TransactionSigner): this;
|
|
458
|
+
/**
|
|
459
|
+
* Add a method call to the atomic group
|
|
460
|
+
*
|
|
461
|
+
* The `signer` property in the `methodCall` parameter is optional. If not provided,
|
|
462
|
+
* the signer will default to the one passed as the second parameter, or the
|
|
463
|
+
* configured signer from the constructor if no second parameter is provided.
|
|
464
|
+
*
|
|
465
|
+
* @param methodCall - The method call to add
|
|
466
|
+
* @param signer - The signer to use for the method call (defaults to constructor signer)
|
|
467
|
+
* @returns This composer instance for chaining
|
|
468
|
+
*/
|
|
469
|
+
addMethodCall(methodCall: MethodCall, signer?: TransactionSigner): this;
|
|
408
470
|
/**
|
|
409
471
|
* Add swap transactions to the atomic group
|
|
410
472
|
*
|
|
@@ -417,6 +479,30 @@ declare class SwapComposer {
|
|
|
417
479
|
* @throws Error if the maximum group size is exceeded
|
|
418
480
|
*/
|
|
419
481
|
addSwapTransactions(): Promise<this>;
|
|
482
|
+
/**
|
|
483
|
+
* Finalize the transaction group by assigning group IDs
|
|
484
|
+
*
|
|
485
|
+
* This method builds the atomic transaction group, assigning group IDs to all transactions
|
|
486
|
+
* if there is more than one transaction. After calling this method, the composer's status
|
|
487
|
+
* will be at least BUILT.
|
|
488
|
+
*
|
|
489
|
+
* @returns Array of transactions with their associated signers
|
|
490
|
+
*
|
|
491
|
+
* @throws Error if the group contains 0 transactions
|
|
492
|
+
*
|
|
493
|
+
* @example
|
|
494
|
+
* ```typescript
|
|
495
|
+
* const composer = await deflex.newSwap({ quote, address, slippage, signer })
|
|
496
|
+
* composer.addTransaction(customTxn)
|
|
497
|
+
*
|
|
498
|
+
* // Build the group to inspect transactions before signing
|
|
499
|
+
* const txnsWithSigners = composer.buildGroup()
|
|
500
|
+
* console.log('Group ID:', txnsWithSigners[0].txn.group)
|
|
501
|
+
* console.log('Group length:', txnsWithSigners.length)
|
|
502
|
+
* console.log('Status:', composer.getStatus()) // BUILT
|
|
503
|
+
* ```
|
|
504
|
+
*/
|
|
505
|
+
buildGroup(): TransactionWithSigner[];
|
|
420
506
|
/**
|
|
421
507
|
* Sign the transaction group
|
|
422
508
|
*
|
|
@@ -468,6 +554,7 @@ declare class SwapComposer {
|
|
|
468
554
|
execute(waitRounds?: number): Promise<{
|
|
469
555
|
confirmedRound: bigint;
|
|
470
556
|
txIds: string[];
|
|
557
|
+
methodResults: ABIResult[];
|
|
471
558
|
}>;
|
|
472
559
|
/**
|
|
473
560
|
* Validates an Algorand address
|
|
@@ -482,11 +569,13 @@ declare class SwapComposer {
|
|
|
482
569
|
*/
|
|
483
570
|
private processRequiredAppOptIns;
|
|
484
571
|
/**
|
|
485
|
-
*
|
|
486
|
-
|
|
487
|
-
|
|
572
|
+
* The default signer function that uses the configured signer
|
|
573
|
+
*/
|
|
574
|
+
private defaultSigner;
|
|
575
|
+
/**
|
|
576
|
+
* Creates a TransactionSigner function for Deflex pre-signed transactions
|
|
488
577
|
*/
|
|
489
|
-
private
|
|
578
|
+
private createDeflexSigner;
|
|
490
579
|
/**
|
|
491
580
|
* Re-signs a Deflex transaction using the provided logic signature or secret key
|
|
492
581
|
*/
|
|
@@ -524,7 +613,7 @@ declare class SwapComposer {
|
|
|
524
613
|
*/
|
|
525
614
|
declare class DeflexClient {
|
|
526
615
|
private readonly config;
|
|
527
|
-
private readonly
|
|
616
|
+
private readonly algodClient;
|
|
528
617
|
/**
|
|
529
618
|
* Create a new DeflexClient instance
|
|
530
619
|
*
|
|
@@ -738,5 +827,5 @@ declare class HTTPError extends Error {
|
|
|
738
827
|
*/
|
|
739
828
|
declare function request<T>(url: string, options?: RequestInit): Promise<T>;
|
|
740
829
|
//#endregion
|
|
741
|
-
export { Asset, DEFAULT_ALGOD_PORT, DEFAULT_ALGOD_TOKEN, DEFAULT_ALGOD_URI, DEFAULT_API_BASE_URL, DEFAULT_AUTO_OPT_IN, DEFAULT_CONFIRMATION_ROUNDS, DEFAULT_FEE_BPS, DEFAULT_MAX_DEPTH, DEFAULT_MAX_GROUP_SIZE, DEPRECATED_PROTOCOLS, DeflexClient, DeflexConfig, DeflexConfigParams, DeflexQuote, DeflexSignature, DeflexTransaction, DexQuote, FetchQuoteParams, FetchQuoteResponse, FetchSwapTxnsBody, FetchSwapTxnsParams, FetchSwapTxnsResponse, HTTPError, MAX_FEE_BPS, PathElement, Profit, Protocol, QuoteType, Route, SignerFunction, SwapComposer, SwapComposerConfig, SwapComposerStatus, SwapTransaction, TxnPayload, request };
|
|
830
|
+
export { Asset, DEFAULT_ALGOD_PORT, DEFAULT_ALGOD_TOKEN, DEFAULT_ALGOD_URI, DEFAULT_API_BASE_URL, DEFAULT_AUTO_OPT_IN, DEFAULT_CONFIRMATION_ROUNDS, DEFAULT_FEE_BPS, DEFAULT_MAX_DEPTH, DEFAULT_MAX_GROUP_SIZE, DEPRECATED_PROTOCOLS, DeflexClient, DeflexConfig, DeflexConfigParams, DeflexQuote, DeflexSignature, DeflexTransaction, DexQuote, FetchQuoteParams, FetchQuoteResponse, FetchSwapTxnsBody, FetchSwapTxnsParams, FetchSwapTxnsResponse, HTTPError, MAX_FEE_BPS, MethodCall, PathElement, Profit, Protocol, QuoteType, Route, SignerFunction, SwapComposer, SwapComposerConfig, SwapComposerStatus, SwapTransaction, TxnPayload, request };
|
|
742
831
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/constants.ts","../src/types.ts","../src/composer.ts","../src/client.ts","../src/utils.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/constants.ts","../src/types.ts","../src/composer.ts","../src/client.ts","../src/utils.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LogicSigAccount, Transaction, assignGroupID, decodeUnsignedTransaction, isValidAddress, makeApplicationOptInTxnFromObject, msgpackRawDecode, signLogicSigTransactionObject, signTransaction, waitForConfirmation } from "algosdk";
|
|
1
|
+
import { Algodv2, AtomicTransactionComposer, LogicSigAccount, Transaction, decodeUnsignedTransaction, isValidAddress, makeApplicationOptInTxnFromObject, msgpackRawDecode, signLogicSigTransactionObject, signTransaction } from "algosdk";
|
|
3
2
|
|
|
4
3
|
//#region src/constants.ts
|
|
5
4
|
/**
|
|
@@ -69,25 +68,24 @@ let SwapComposerStatus = /* @__PURE__ */ function(SwapComposerStatus$1) {
|
|
|
69
68
|
* @example
|
|
70
69
|
* ```typescript
|
|
71
70
|
* const quote = await deflex.fetchQuote({ ... })
|
|
72
|
-
* const composer = await deflex.newSwap({ quote, address, slippage })
|
|
71
|
+
* const composer = await deflex.newSwap({ quote, address, slippage, signer })
|
|
73
72
|
*
|
|
74
73
|
* await composer
|
|
75
74
|
* .addTransaction(customTxn)
|
|
76
75
|
* .addSwapTransactions()
|
|
77
|
-
* .execute(
|
|
76
|
+
* .execute()
|
|
78
77
|
* ```
|
|
79
78
|
*/
|
|
80
79
|
var SwapComposer = class SwapComposer {
|
|
80
|
+
/** The ATC used to compose the group */
|
|
81
|
+
atc = new AtomicTransactionComposer();
|
|
81
82
|
/** The maximum size of an atomic transaction group. */
|
|
82
|
-
static MAX_GROUP_SIZE =
|
|
83
|
-
|
|
84
|
-
transactions = [];
|
|
83
|
+
static MAX_GROUP_SIZE = AtomicTransactionComposer.MAX_GROUP_SIZE;
|
|
84
|
+
/** Whether the swap transactions have been added to the atomic group. */
|
|
85
85
|
swapTransactionsAdded = false;
|
|
86
|
-
signedTxns = [];
|
|
87
|
-
txIds = [];
|
|
88
86
|
requiredAppOptIns;
|
|
89
87
|
deflexTxns;
|
|
90
|
-
|
|
88
|
+
algodClient;
|
|
91
89
|
address;
|
|
92
90
|
signer;
|
|
93
91
|
/**
|
|
@@ -99,7 +97,7 @@ var SwapComposer = class SwapComposer {
|
|
|
99
97
|
* @param config - Configuration for the composer
|
|
100
98
|
* @param config.requiredAppOptIns - The quote response from fetchQuote()
|
|
101
99
|
* @param config.deflexTxns - The swap transactions from fetchSwapTransactions()
|
|
102
|
-
* @param config.
|
|
100
|
+
* @param config.algodClient - Algodv2 client instance
|
|
103
101
|
* @param config.address - The address of the account that will sign transactions
|
|
104
102
|
* @param config.signer - Transaction signer function
|
|
105
103
|
*/
|
|
@@ -107,11 +105,11 @@ var SwapComposer = class SwapComposer {
|
|
|
107
105
|
if (!config.quote) throw new Error("Quote is required");
|
|
108
106
|
if (!config.deflexTxns) throw new Error("Swap transactions are required");
|
|
109
107
|
if (config.deflexTxns.length === 0) throw new Error("Swap transactions array cannot be empty");
|
|
110
|
-
if (!config.
|
|
108
|
+
if (!config.algodClient) throw new Error("Algodv2 client instance is required");
|
|
111
109
|
if (!config.signer) throw new Error("Signer is required");
|
|
112
110
|
this.requiredAppOptIns = config.quote.requiredAppOptIns;
|
|
113
111
|
this.deflexTxns = config.deflexTxns;
|
|
114
|
-
this.
|
|
112
|
+
this.algodClient = config.algodClient;
|
|
115
113
|
this.address = this.validateAddress(config.address);
|
|
116
114
|
this.signer = config.signer;
|
|
117
115
|
}
|
|
@@ -121,7 +119,7 @@ var SwapComposer = class SwapComposer {
|
|
|
121
119
|
* @returns The current status of the transaction group
|
|
122
120
|
*/
|
|
123
121
|
getStatus() {
|
|
124
|
-
return this.
|
|
122
|
+
return this.atc.getStatus();
|
|
125
123
|
}
|
|
126
124
|
/**
|
|
127
125
|
* Get the number of transactions currently in this atomic group
|
|
@@ -129,7 +127,7 @@ var SwapComposer = class SwapComposer {
|
|
|
129
127
|
* @returns The number of transactions in the group
|
|
130
128
|
*/
|
|
131
129
|
count() {
|
|
132
|
-
return this.
|
|
130
|
+
return this.atc.count();
|
|
133
131
|
}
|
|
134
132
|
/**
|
|
135
133
|
* Add a transaction to the atomic group
|
|
@@ -147,10 +145,29 @@ var SwapComposer = class SwapComposer {
|
|
|
147
145
|
* @throws Error if the composer is not in the BUILDING status
|
|
148
146
|
* @throws Error if the maximum group size is exceeded
|
|
149
147
|
*/
|
|
150
|
-
addTransaction(transaction) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
addTransaction(transaction, signer = this.defaultSigner) {
|
|
149
|
+
this.atc.addTransaction({
|
|
150
|
+
txn: transaction,
|
|
151
|
+
signer
|
|
152
|
+
});
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Add a method call to the atomic group
|
|
157
|
+
*
|
|
158
|
+
* The `signer` property in the `methodCall` parameter is optional. If not provided,
|
|
159
|
+
* the signer will default to the one passed as the second parameter, or the
|
|
160
|
+
* configured signer from the constructor if no second parameter is provided.
|
|
161
|
+
*
|
|
162
|
+
* @param methodCall - The method call to add
|
|
163
|
+
* @param signer - The signer to use for the method call (defaults to constructor signer)
|
|
164
|
+
* @returns This composer instance for chaining
|
|
165
|
+
*/
|
|
166
|
+
addMethodCall(methodCall, signer = this.defaultSigner) {
|
|
167
|
+
this.atc.addMethodCall({
|
|
168
|
+
...methodCall,
|
|
169
|
+
signer: methodCall.signer ?? signer
|
|
170
|
+
});
|
|
154
171
|
return this;
|
|
155
172
|
}
|
|
156
173
|
/**
|
|
@@ -166,14 +183,40 @@ var SwapComposer = class SwapComposer {
|
|
|
166
183
|
*/
|
|
167
184
|
async addSwapTransactions() {
|
|
168
185
|
if (this.swapTransactionsAdded) throw new Error("Swap transactions have already been added");
|
|
169
|
-
if (this.
|
|
186
|
+
if (this.getStatus() !== SwapComposerStatus.BUILDING) throw new Error("Cannot add swap transactions when composer status is not BUILDING");
|
|
170
187
|
const processedTxns = await this.processSwapTransactions();
|
|
171
|
-
if (this.
|
|
172
|
-
this.
|
|
188
|
+
if (this.atc.count() + processedTxns.length > SwapComposer.MAX_GROUP_SIZE) throw new Error(`Adding swap transactions exceeds the maximum atomic group size of ${SwapComposer.MAX_GROUP_SIZE}`);
|
|
189
|
+
for (const txnWithSigner of processedTxns) this.atc.addTransaction(txnWithSigner);
|
|
173
190
|
this.swapTransactionsAdded = true;
|
|
174
191
|
return this;
|
|
175
192
|
}
|
|
176
193
|
/**
|
|
194
|
+
* Finalize the transaction group by assigning group IDs
|
|
195
|
+
*
|
|
196
|
+
* This method builds the atomic transaction group, assigning group IDs to all transactions
|
|
197
|
+
* if there is more than one transaction. After calling this method, the composer's status
|
|
198
|
+
* will be at least BUILT.
|
|
199
|
+
*
|
|
200
|
+
* @returns Array of transactions with their associated signers
|
|
201
|
+
*
|
|
202
|
+
* @throws Error if the group contains 0 transactions
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* const composer = await deflex.newSwap({ quote, address, slippage, signer })
|
|
207
|
+
* composer.addTransaction(customTxn)
|
|
208
|
+
*
|
|
209
|
+
* // Build the group to inspect transactions before signing
|
|
210
|
+
* const txnsWithSigners = composer.buildGroup()
|
|
211
|
+
* console.log('Group ID:', txnsWithSigners[0].txn.group)
|
|
212
|
+
* console.log('Group length:', txnsWithSigners.length)
|
|
213
|
+
* console.log('Status:', composer.getStatus()) // BUILT
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
buildGroup() {
|
|
217
|
+
return this.atc.buildGroup();
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
177
220
|
* Sign the transaction group
|
|
178
221
|
*
|
|
179
222
|
* Automatically adds swap transactions if not already added, builds the atomic group,
|
|
@@ -187,34 +230,9 @@ var SwapComposer = class SwapComposer {
|
|
|
187
230
|
* ```
|
|
188
231
|
*/
|
|
189
232
|
async sign() {
|
|
190
|
-
if (this.
|
|
233
|
+
if (this.getStatus() >= SwapComposerStatus.SIGNED) return this.atc.gatherSignatures();
|
|
191
234
|
if (!this.swapTransactionsAdded) await this.addSwapTransactions();
|
|
192
|
-
|
|
193
|
-
const txnGroup = [];
|
|
194
|
-
const indexesToSign = [];
|
|
195
|
-
for (let i = 0; i < transactions.length; i++) {
|
|
196
|
-
const item = transactions[i];
|
|
197
|
-
if (!item) continue;
|
|
198
|
-
txnGroup.push(item.txn);
|
|
199
|
-
if (!item.deflexSignature) indexesToSign.push(i);
|
|
200
|
-
}
|
|
201
|
-
const userSignedTxns = (await this.signer(txnGroup, indexesToSign)).filter((txn) => txn !== null);
|
|
202
|
-
const finalSignedTxns = [];
|
|
203
|
-
let userSignedIndex = 0;
|
|
204
|
-
for (const item of transactions) if (item.deflexSignature) {
|
|
205
|
-
const signedTxnBlob = this.signDeflexTransaction(item.txn, item.deflexSignature);
|
|
206
|
-
finalSignedTxns.push(signedTxnBlob);
|
|
207
|
-
} else {
|
|
208
|
-
const userSignedTxn = userSignedTxns[userSignedIndex];
|
|
209
|
-
if (!userSignedTxn) throw new Error(`Missing signature for user transaction at index ${userSignedIndex}`);
|
|
210
|
-
finalSignedTxns.push(userSignedTxn);
|
|
211
|
-
userSignedIndex++;
|
|
212
|
-
}
|
|
213
|
-
const txIds = this.transactions.map((t) => t.txn.txID());
|
|
214
|
-
this.signedTxns = finalSignedTxns;
|
|
215
|
-
this.txIds = txIds;
|
|
216
|
-
this.status = SwapComposerStatus.SIGNED;
|
|
217
|
-
return finalSignedTxns;
|
|
235
|
+
return await this.atc.gatherSignatures();
|
|
218
236
|
}
|
|
219
237
|
/**
|
|
220
238
|
* Submit the signed transactions to the network
|
|
@@ -232,11 +250,8 @@ var SwapComposer = class SwapComposer {
|
|
|
232
250
|
* ```
|
|
233
251
|
*/
|
|
234
252
|
async submit() {
|
|
235
|
-
if (this.
|
|
236
|
-
|
|
237
|
-
await this.algorand.client.algod.sendRawTransaction(stxns).do();
|
|
238
|
-
this.status = SwapComposerStatus.SUBMITTED;
|
|
239
|
-
return this.txIds;
|
|
253
|
+
if (!this.swapTransactionsAdded) await this.addSwapTransactions();
|
|
254
|
+
return this.atc.submit(this.algodClient);
|
|
240
255
|
}
|
|
241
256
|
/**
|
|
242
257
|
* Execute the swap
|
|
@@ -257,13 +272,11 @@ var SwapComposer = class SwapComposer {
|
|
|
257
272
|
* ```
|
|
258
273
|
*/
|
|
259
274
|
async execute(waitRounds = DEFAULT_CONFIRMATION_ROUNDS) {
|
|
260
|
-
if (this.
|
|
261
|
-
const
|
|
262
|
-
const confirmedTxnInfo = await waitForConfirmation(this.algorand.client.algod, txIds[0], waitRounds);
|
|
263
|
-
this.status = SwapComposerStatus.COMMITTED;
|
|
275
|
+
if (!this.swapTransactionsAdded) await this.addSwapTransactions();
|
|
276
|
+
const { txIDs,...result } = await this.atc.execute(this.algodClient, waitRounds);
|
|
264
277
|
return {
|
|
265
|
-
|
|
266
|
-
txIds
|
|
278
|
+
...result,
|
|
279
|
+
txIds: txIDs
|
|
267
280
|
};
|
|
268
281
|
}
|
|
269
282
|
/**
|
|
@@ -287,9 +300,12 @@ var SwapComposer = class SwapComposer {
|
|
|
287
300
|
delete txn.group;
|
|
288
301
|
if (deflexTxn.signature !== false) swapTxns.push({
|
|
289
302
|
txn,
|
|
290
|
-
|
|
303
|
+
signer: this.createDeflexSigner(deflexTxn.signature)
|
|
304
|
+
});
|
|
305
|
+
else swapTxns.push({
|
|
306
|
+
txn,
|
|
307
|
+
signer: this.defaultSigner
|
|
291
308
|
});
|
|
292
|
-
else swapTxns.push({ txn });
|
|
293
309
|
} catch (error) {
|
|
294
310
|
throw new Error(`Failed to process swap transaction at index ${i}: ${error instanceof Error ? error.message : String(error)}`);
|
|
295
311
|
}
|
|
@@ -300,34 +316,36 @@ var SwapComposer = class SwapComposer {
|
|
|
300
316
|
* Creates opt-in transactions for apps the user hasn't opted into yet
|
|
301
317
|
*/
|
|
302
318
|
async processRequiredAppOptIns() {
|
|
303
|
-
const userApps = (await this.
|
|
319
|
+
const userApps = (await this.algodClient.accountInformation(this.address).do())?.appsLocalState?.map((app) => Number(app.id)) || [];
|
|
304
320
|
const appsToOptIn = this.requiredAppOptIns.filter((appId) => !userApps.includes(appId));
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
return appOptInTxns.map((txn) => ({ txn }));
|
|
321
|
+
if (appsToOptIn.length === 0) return [];
|
|
322
|
+
const suggestedParams = await this.algodClient.getTransactionParams().do();
|
|
323
|
+
return appsToOptIn.map((appId) => ({
|
|
324
|
+
txn: makeApplicationOptInTxnFromObject({
|
|
325
|
+
sender: this.address,
|
|
326
|
+
appIndex: appId,
|
|
327
|
+
suggestedParams
|
|
328
|
+
}),
|
|
329
|
+
signer: this.defaultSigner
|
|
330
|
+
}));
|
|
318
331
|
}
|
|
319
332
|
/**
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
* The composer's status will be at least BUILT after executing this method.
|
|
333
|
+
* The default signer function that uses the configured signer
|
|
323
334
|
*/
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
335
|
+
defaultSigner = async (txnGroup, indexesToSign) => {
|
|
336
|
+
return (await this.signer(txnGroup, indexesToSign)).filter((txn) => txn !== null);
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Creates a TransactionSigner function for Deflex pre-signed transactions
|
|
340
|
+
*/
|
|
341
|
+
createDeflexSigner(signature) {
|
|
342
|
+
return async (txnGroup, indexesToSign) => {
|
|
343
|
+
return indexesToSign.map((i) => {
|
|
344
|
+
const txn = txnGroup[i];
|
|
345
|
+
if (!txn) throw new Error(`Transaction at index ${i} not found`);
|
|
346
|
+
return this.signDeflexTransaction(txn, signature);
|
|
347
|
+
});
|
|
348
|
+
};
|
|
331
349
|
}
|
|
332
350
|
/**
|
|
333
351
|
* Re-signs a Deflex transaction using the provided logic signature or secret key
|
|
@@ -425,7 +443,7 @@ async function request(url, options) {
|
|
|
425
443
|
*/
|
|
426
444
|
var DeflexClient = class {
|
|
427
445
|
config;
|
|
428
|
-
|
|
446
|
+
algodClient;
|
|
429
447
|
/**
|
|
430
448
|
* Create a new DeflexClient instance
|
|
431
449
|
*
|
|
@@ -450,11 +468,7 @@ var DeflexClient = class {
|
|
|
450
468
|
feeBps: this.validateFeeBps(config.feeBps ?? DEFAULT_FEE_BPS),
|
|
451
469
|
autoOptIn: config.autoOptIn ?? DEFAULT_AUTO_OPT_IN
|
|
452
470
|
};
|
|
453
|
-
this.
|
|
454
|
-
server: this.config.algodUri,
|
|
455
|
-
port: this.config.algodPort,
|
|
456
|
-
token: this.config.algodToken
|
|
457
|
-
} });
|
|
471
|
+
this.algodClient = new Algodv2(this.config.algodToken, this.config.algodUri, this.config.algodPort);
|
|
458
472
|
}
|
|
459
473
|
/**
|
|
460
474
|
* Fetch a swap quote from the Deflex API
|
|
@@ -538,7 +552,7 @@ var DeflexClient = class {
|
|
|
538
552
|
* ```
|
|
539
553
|
*/
|
|
540
554
|
async needsAssetOptIn(address, assetId) {
|
|
541
|
-
const accountInfo = await this.
|
|
555
|
+
const accountInfo = await this.algodClient.accountInformation(address).do();
|
|
542
556
|
return BigInt(assetId) !== 0n && accountInfo?.assets?.find((asset) => asset.assetId === BigInt(assetId)) === void 0;
|
|
543
557
|
}
|
|
544
558
|
/**
|
|
@@ -670,7 +684,7 @@ var DeflexClient = class {
|
|
|
670
684
|
address,
|
|
671
685
|
slippage
|
|
672
686
|
})).txns,
|
|
673
|
-
|
|
687
|
+
algodClient: this.algodClient,
|
|
674
688
|
address,
|
|
675
689
|
signer
|
|
676
690
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["txnGroup: Transaction[]","indexesToSign: number[]","finalSignedTxns: Uint8Array[]","appOptIns: SwapTransaction[]","swapTxns: SwapTransaction[]","appOptInTxns: Transaction[]","status: number","statusText: string","data: unknown","errorData: unknown","body: FetchSwapTxnsBody"],"sources":["../src/constants.ts","../src/composer.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["/**\n * Supported DEX protocols for swap routing\n */\nexport enum Protocol {\n TinymanV2 = 'TinymanV2',\n Algofi = 'Algofi',\n Algomint = 'Algomint',\n Pact = 'Pact',\n Folks = 'Folks',\n TAlgo = 'TAlgo',\n}\n\n/**\n * Deprecated protocols that are automatically excluded from routing\n *\n * @internal\n */\nexport const DEPRECATED_PROTOCOLS = ['Humble', 'Tinyman'] as const\n\n/** Default Algod node URI for mainnet */\nexport const DEFAULT_ALGOD_URI = 'https://mainnet-api.4160.nodely.dev/'\n\n/** Default Algod node token (empty for public nodes) */\nexport const DEFAULT_ALGOD_TOKEN = ''\n\n/** Default Algod node port */\nexport const DEFAULT_ALGOD_PORT = 443\n\n/** Default Deflex API base URL */\nexport const DEFAULT_API_BASE_URL = 'https://deflex.txnlab.dev/api'\n\n/** Default fee in basis points (0.15%) */\nexport const DEFAULT_FEE_BPS = 15\n\n/** Maximum allowed fee in basis points (3.00%) */\nexport const MAX_FEE_BPS = 300\n\n/** Default maximum transaction group size */\nexport const DEFAULT_MAX_GROUP_SIZE = 16\n\n/** Default maximum routing depth (number of hops) */\nexport const DEFAULT_MAX_DEPTH = 4\n\n/** Default auto opt-in setting (automatic asset/app opt-in detection) */\nexport const DEFAULT_AUTO_OPT_IN = false\n\n/** Default number of rounds to wait for transaction confirmation */\nexport const DEFAULT_CONFIRMATION_ROUNDS = 4\n","import {\n assignGroupID,\n decodeUnsignedTransaction,\n isValidAddress,\n signLogicSigTransactionObject,\n signTransaction,\n LogicSigAccount,\n makeApplicationOptInTxnFromObject,\n msgpackRawDecode,\n Transaction,\n waitForConfirmation,\n} from 'algosdk'\nimport { DEFAULT_CONFIRMATION_ROUNDS } from './constants'\nimport type {\n FetchQuoteResponse,\n DeflexTransaction,\n SwapTransaction,\n DeflexSignature,\n DeflexQuote,\n} from './types'\nimport type { AlgorandClient } from '@algorandfoundation/algokit-utils'\nimport type { TransactionSigner } from 'algosdk'\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 /** AlgorandClient instance for blockchain operations */\n readonly algorand: AlgorandClient\n /** The address of the account that will sign transactions */\n readonly address: string\n /** Transaction signer function */\n readonly signer: TransactionSigner | SignerFunction\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 })\n *\n * await composer\n * .addTransaction(customTxn)\n * .addSwapTransactions()\n * .execute(signer)\n * ```\n */\nexport class SwapComposer {\n /** The maximum size of an atomic transaction group. */\n static MAX_GROUP_SIZE: number = 16\n\n private status: SwapComposerStatus = SwapComposerStatus.BUILDING\n private transactions: SwapTransaction[] = []\n private swapTransactionsAdded = false\n private signedTxns: Uint8Array[] = []\n private txIds: string[] = []\n\n private readonly requiredAppOptIns: number[]\n private readonly deflexTxns: DeflexTransaction[]\n private readonly algorand: AlgorandClient\n private readonly address: string\n private readonly signer: TransactionSigner | SignerFunction\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.requiredAppOptIns - The quote response from fetchQuote()\n * @param config.deflexTxns - The swap transactions from fetchSwapTransactions()\n * @param config.algorand - AlgorandClient instance for blockchain operations\n * @param config.address - The address of the account that will sign transactions\n * @param config.signer - Transaction signer function\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.algorand) {\n throw new Error('AlgorandClient instance is required')\n }\n if (!config.signer) {\n throw new Error('Signer is required')\n }\n\n this.requiredAppOptIns = config.quote.requiredAppOptIns\n this.deflexTxns = config.deflexTxns\n this.algorand = config.algorand\n this.address = this.validateAddress(config.address)\n this.signer = config.signer\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.status\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.transactions.length\n }\n\n /**\n * Add a transaction to the atomic group\n *\n * Transactions are added in the order methods are called. For example:\n * ```typescript\n * composer\n * .addTransaction(txn1) // Added first\n * .addSwapTransactions() // Added second\n * .addTransaction(txn2) // Added third\n * ```\n *\n * @param transaction - The transaction to add\n * @returns This composer instance for chaining\n * @throws Error if the composer is not in the BUILDING status\n * @throws Error if the maximum group size is exceeded\n */\n addTransaction(transaction: Transaction): this {\n if (this.status !== SwapComposerStatus.BUILDING) {\n throw new Error(\n 'Cannot add transactions when composer status is not BUILDING',\n )\n }\n\n if (this.transactions.length === SwapComposer.MAX_GROUP_SIZE) {\n throw new Error(\n `Adding an additional transaction exceeds the maximum atomic group size of ${SwapComposer.MAX_GROUP_SIZE}`,\n )\n }\n\n this.transactions.push({ txn: transaction })\n return this\n }\n\n /**\n * Add swap transactions to the atomic group\n *\n * This method automatically processes required app opt-ins and adds all swap\n * transactions from the quote. Can only be called once per composer instance.\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.status !== SwapComposerStatus.BUILDING) {\n throw new Error(\n 'Cannot add swap transactions when composer status is not BUILDING',\n )\n }\n\n const processedTxns = await this.processSwapTransactions()\n const newLength = this.transactions.length + processedTxns.length\n\n if (newLength > 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 this.transactions.push(...processedTxns)\n\n this.swapTransactionsAdded = true\n return this\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.status >= SwapComposerStatus.SIGNED) {\n return this.signedTxns\n }\n\n // Auto-add swap transactions if needed\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n // Build the transaction group, ensure status is BUILT\n const transactions = this.buildGroup()\n\n // Collect all transactions and identify which ones need user signature\n const txnGroup: Transaction[] = []\n const indexesToSign: number[] = []\n\n for (let i = 0; i < transactions.length; i++) {\n const item = transactions[i]\n if (!item) continue\n\n txnGroup.push(item.txn)\n\n if (!item.deflexSignature) {\n // User transaction - needs user signature\n indexesToSign.push(i)\n }\n }\n\n // Sign all transactions with the complete group\n const signedTxns = await this.signer(txnGroup, indexesToSign)\n\n // Normalize signedTxns - handle both wallet patterns:\n // Pattern 1: Returns only signed txns (length < txnGroup.length)\n // Pattern 2: Returns array matching group length with nulls for non-signed (ARC-1)\n const userSignedTxns = signedTxns.filter(\n (txn): txn is Uint8Array => txn !== null,\n )\n\n // Rebuild complete group in correct order\n const finalSignedTxns: Uint8Array[] = []\n let userSignedIndex = 0\n\n for (const item of transactions) {\n if (item.deflexSignature) {\n // Pre-signed transaction - re-sign with Deflex signature\n const signedTxnBlob = this.signDeflexTransaction(\n item.txn,\n item.deflexSignature,\n )\n finalSignedTxns.push(signedTxnBlob)\n } else {\n // User transaction - use signature from signer\n const userSignedTxn = userSignedTxns[userSignedIndex]\n if (!userSignedTxn) {\n throw new Error(\n `Missing signature for user transaction at index ${userSignedIndex}`,\n )\n }\n finalSignedTxns.push(userSignedTxn)\n userSignedIndex++\n }\n }\n\n const txIds = this.transactions.map((t) => t.txn.txID())\n\n this.signedTxns = finalSignedTxns\n this.txIds = txIds\n this.status = SwapComposerStatus.SIGNED\n\n return finalSignedTxns\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 if (this.status > SwapComposerStatus.SUBMITTED) {\n throw new Error('Transaction group cannot be resubmitted')\n }\n\n const stxns = await this.sign()\n await this.algorand.client.algod.sendRawTransaction(stxns).do()\n\n this.status = SwapComposerStatus.SUBMITTED\n return this.txIds\n }\n\n /**\n * Execute the swap\n *\n * Signs the transaction group, submits it to the network, and waits for confirmation.\n * This is the primary method for executing swaps and combines sign(), submit(), and\n * waitForConfirmation() into a single call.\n *\n * @param waitRounds - The number of rounds to wait for confirmation (default: 4)\n * @returns Object containing the confirmed round and transaction IDs\n * @throws Error if the transaction group has already been committed\n *\n * @example\n * ```typescript\n * const result = await composer.execute()\n * console.log(`Confirmed in round ${result.confirmedRound}`)\n * console.log('Transaction IDs:', result.txIds)\n * ```\n */\n async execute(waitRounds: number = DEFAULT_CONFIRMATION_ROUNDS): Promise<{\n confirmedRound: bigint\n txIds: string[]\n }> {\n if (this.status === SwapComposerStatus.COMMITTED) {\n throw new Error(\n 'Transaction group has already been executed successfully',\n )\n }\n\n const txIds = await this.submit()\n\n const confirmedTxnInfo = await waitForConfirmation(\n this.algorand.client.algod,\n txIds[0]!,\n waitRounds,\n )\n\n this.status = SwapComposerStatus.COMMITTED\n\n const confirmedRound = confirmedTxnInfo.confirmedRound!\n\n return {\n confirmedRound,\n 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<SwapTransaction[]> {\n // Process required app opt-ins\n const appOptIns: SwapTransaction[] = await this.processRequiredAppOptIns()\n\n // Decode and process swap transactions from API\n const swapTxns: SwapTransaction[] = []\n for (let i = 0; i < this.deflexTxns.length; i++) {\n const deflexTxn = this.deflexTxns[i]\n if (!deflexTxn) continue\n\n try {\n // Decode transaction from base64 data\n const txnBytes = Buffer.from(deflexTxn.data, 'base64')\n const txn = decodeUnsignedTransaction(txnBytes)\n\n // Remove group ID (will be reassigned later)\n delete txn.group\n\n if (deflexTxn.signature !== false) {\n // Pre-signed transaction - needs re-signing with provided signature\n swapTxns.push({\n txn,\n deflexSignature: deflexTxn.signature,\n })\n } else {\n // User transaction - needs user signature\n swapTxns.push({\n txn,\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<SwapTransaction[]> {\n // Fetch account information\n const accountInfo = await this.algorand.account.getInformation(this.address)\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 // Create opt-in transactions if needed\n const appOptInTxns: Transaction[] = []\n if (appsToOptIn.length > 0) {\n const suggestedParams = await this.algorand.client.algod\n .getTransactionParams()\n .do()\n\n for (const appId of appsToOptIn) {\n const optInTxn = makeApplicationOptInTxnFromObject({\n sender: this.address,\n appIndex: appId,\n suggestedParams,\n })\n appOptInTxns.push(optInTxn)\n }\n }\n\n return appOptInTxns.map((txn) => ({ txn }))\n }\n\n /**\n * Finalizes the transaction group by assigning group IDs\n *\n * The composer's status will be at least BUILT after executing this method.\n */\n private buildGroup(): SwapTransaction[] {\n if (this.status === SwapComposerStatus.BUILDING) {\n if (this.transactions.length === 0) {\n throw new Error('Cannot build a group with 0 transactions')\n }\n if (this.transactions.length > 1) {\n assignGroupID(this.transactions.map((t) => t.txn))\n }\n this.status = SwapComposerStatus.BUILT\n }\n return this.transactions\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 * 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 { AlgorandClient } from '@algorandfoundation/algokit-utils'\nimport { 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 {\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 algorand: AlgorandClient\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 */\n constructor(config: DeflexConfigParams) {\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 AlgorandClient\n this.algorand = AlgorandClient.fromConfig({\n algodConfig: {\n server: this.config.algodUri,\n port: this.config.algodPort,\n token: this.config.algodToken,\n },\n })\n }\n\n /**\n * Fetch a swap quote from the Deflex API\n *\n * Requests optimal swap routing from the Deflex API. The quote includes routing\n * information, price impact, required opt-ins, and an encrypted transaction payload.\n *\n * @param params - Parameters for the quote request\n * @param params.fromASAID - The ID of the asset to swap from\n * @param params.toASAID - The ID of the asset to swap to\n * @param params.amount - The amount of the asset to swap in base units\n * @param params.type - The type of the quote (default: 'fixed-input')\n * @param params.disabledProtocols - List of protocols to disable (default: [])\n * @param params.maxGroupSize - The maximum group size (default: 16)\n * @param params.maxDepth - The maximum depth (default: 4)\n * @param params.address - The address of the account that will perform the swap (recommended when using `config.autoOptIn` or `params.optIn`)\n * @param params.optIn - Whether to include asset opt-in transaction\n * - If true: API reduces maxGroupSize by 1 and includes opt-in (always included, even if not needed)\n * - If false: No opt-in transaction included\n * - If undefined: Falls back to `config.autoOptIn` behavior with account check (if `params.address` is provided)\n * @returns A FetchQuoteResponse object with routing information\n *\n * @example\n * ```typescript\n * const quote = await deflex.fetchQuote({\n * address: 'ABC...',\n * fromASAID: 0, // ALGO\n * toASAID: 31566704, // USDC\n * amount: 1_000_000, // 1 ALGO\n * })\n * ```\n */\n async fetchQuote(params: FetchQuoteParams): Promise<FetchQuoteResponse> {\n const {\n fromASAID,\n toASAID,\n amount,\n type = 'fixed-input',\n disabledProtocols = [],\n maxGroupSize = DEFAULT_MAX_GROUP_SIZE,\n maxDepth = DEFAULT_MAX_DEPTH,\n optIn,\n address,\n } = params\n\n // Always include deprecated protocols in disabled list\n const allDisabledProtocols = [\n ...new Set([...DEPRECATED_PROTOCOLS, ...disabledProtocols]),\n ]\n\n let includeOptIn = optIn\n if (includeOptIn === undefined && this.config.autoOptIn) {\n if (address) {\n includeOptIn = await this.needsAssetOptIn(\n this.validateAddress(address),\n toASAID,\n )\n } else {\n console.warn(\n 'autoOptIn is enabled but no address provided to fetchQuote(). Asset opt-in check skipped.',\n )\n }\n }\n\n const url = new URL(`${this.config.apiBaseUrl}/fetchQuote`)\n\n url.searchParams.append('apiKey', this.config.apiKey)\n url.searchParams.append('algodUri', this.config.algodUri)\n url.searchParams.append('algodToken', this.config.algodToken)\n url.searchParams.append('algodPort', String(this.config.algodPort))\n url.searchParams.append('feeBps', this.config.feeBps.toString())\n url.searchParams.append('fromASAID', BigInt(fromASAID).toString())\n url.searchParams.append('toASAID', BigInt(toASAID).toString())\n url.searchParams.append('amount', BigInt(amount).toString())\n url.searchParams.append('type', type)\n url.searchParams.append('disabledProtocols', allDisabledProtocols.join(','))\n url.searchParams.append('maxGroupSize', maxGroupSize.toString())\n url.searchParams.append('maxDepth', maxDepth.toString())\n\n if (typeof includeOptIn === 'boolean') {\n url.searchParams.append('optIn', String(includeOptIn))\n }\n\n if (this.config.referrerAddress) {\n url.searchParams.append('referrerAddress', this.config.referrerAddress)\n }\n\n return request<FetchQuoteResponse>(url.toString())\n }\n\n /**\n * Check if asset opt-in is required for the output asset\n *\n * Convenience method to determine if an address needs to opt into the output asset\n * of a swap. This is useful when you want to get a quote without requiring wallet\n * connection upfront, but need to know whether to set `optIn: true` in fetchQuote()\n * to ensure proper routing (as opt-ins reduce maxGroupSize by 1).\n *\n * Note: If you enable `config.autoOptIn`, this check is handled automatically when\n * an address is provided to fetchQuote().\n *\n * @param address - The address to check\n * @param assetId - The output asset ID to check\n * @returns True if asset opt-in is required, false otherwise (always false for ALGO)\n *\n * @example\n * ```typescript\n * // Check if opt-in needed for output asset before fetching quote\n * const needsOptIn = await deflex.needsAssetOptIn(userAddress, toAssetId)\n * const quote = await deflex.fetchQuote({\n * fromAssetId,\n * toAssetId,\n * amount,\n * optIn: needsOptIn,\n * })\n * ```\n */\n async needsAssetOptIn(\n address: string,\n assetId: number | bigint,\n ): Promise<boolean> {\n // Fetch account information\n const accountInfo = await this.algorand.account.getInformation(address)\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 const response = await this.fetchQuote(params)\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 algorand: this.algorand,\n address,\n signer,\n })\n\n return composer\n }\n\n /**\n * Validates the API key\n */\n private validateApiKey(apiKey: string): string {\n if (!apiKey) {\n throw new Error('API key is required')\n }\n return apiKey\n }\n\n /**\n * Validates an Algorand address\n */\n private validateAddress(address: string): string {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid Algorand address: ${address}`)\n }\n return address\n }\n\n /**\n * Validates the fee in basis points (max 300 = 3.00%)\n */\n private validateFeeBps(feeBps: number): number {\n if (feeBps < 0 || feeBps > MAX_FEE_BPS) {\n throw new Error(\n `Invalid fee: ${feeBps} basis points (must be between 0 and ${MAX_FEE_BPS})`,\n )\n }\n return feeBps\n }\n}\n"],"mappings":";;;;;;;AAGA,IAAY,gDAAL;AACL;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAQF,MAAa,uBAAuB,CAAC,UAAU,UAAU;;AAGzD,MAAa,oBAAoB;;AAGjC,MAAa,sBAAsB;;AAGnC,MAAa,qBAAqB;;AAGlC,MAAa,uBAAuB;;AAGpC,MAAa,kBAAkB;;AAG/B,MAAa,cAAc;;AAG3B,MAAa,yBAAyB;;AAGtC,MAAa,oBAAoB;;AAGjC,MAAa,sBAAsB;;AAGnC,MAAa,8BAA8B;;;;;;;ACR3C,IAAY,oEAAL;;AAEL;;AAGA;;AAGA;;AAGA;;AAGA;;;;;;;;;;;;;;;;;;;;;AAqCF,IAAa,eAAb,MAAa,aAAa;;CAExB,OAAO,iBAAyB;CAEhC,AAAQ,SAA6B,mBAAmB;CACxD,AAAQ,eAAkC,EAAE;CAC5C,AAAQ,wBAAwB;CAChC,AAAQ,aAA2B,EAAE;CACrC,AAAQ,QAAkB,EAAE;CAE5B,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;;;;;;;;;;;;;CAejB,YAAY,QAA4B;AAEtC,MAAI,CAAC,OAAO,MACV,OAAM,IAAI,MAAM,oBAAoB;AAEtC,MAAI,CAAC,OAAO,WACV,OAAM,IAAI,MAAM,iCAAiC;AAEnD,MAAI,OAAO,WAAW,WAAW,EAC/B,OAAM,IAAI,MAAM,0CAA0C;AAE5D,MAAI,CAAC,OAAO,SACV,OAAM,IAAI,MAAM,sCAAsC;AAExD,MAAI,CAAC,OAAO,OACV,OAAM,IAAI,MAAM,qBAAqB;AAGvC,OAAK,oBAAoB,OAAO,MAAM;AACtC,OAAK,aAAa,OAAO;AACzB,OAAK,WAAW,OAAO;AACvB,OAAK,UAAU,KAAK,gBAAgB,OAAO,QAAQ;AACnD,OAAK,SAAS,OAAO;;;;;;;CAQvB,YAAgC;AAC9B,SAAO,KAAK;;;;;;;CAQd,QAAgB;AACd,SAAO,KAAK,aAAa;;;;;;;;;;;;;;;;;;CAmB3B,eAAe,aAAgC;AAC7C,MAAI,KAAK,WAAW,mBAAmB,SACrC,OAAM,IAAI,MACR,+DACD;AAGH,MAAI,KAAK,aAAa,WAAW,aAAa,eAC5C,OAAM,IAAI,MACR,6EAA6E,aAAa,iBAC3F;AAGH,OAAK,aAAa,KAAK,EAAE,KAAK,aAAa,CAAC;AAC5C,SAAO;;;;;;;;;;;;;CAcT,MAAM,sBAAqC;AACzC,MAAI,KAAK,sBACP,OAAM,IAAI,MAAM,4CAA4C;AAG9D,MAAI,KAAK,WAAW,mBAAmB,SACrC,OAAM,IAAI,MACR,oEACD;EAGH,MAAM,gBAAgB,MAAM,KAAK,yBAAyB;AAG1D,MAFkB,KAAK,aAAa,SAAS,cAAc,SAE3C,aAAa,eAC3B,OAAM,IAAI,MACR,qEAAqE,aAAa,iBACnF;AAGH,OAAK,aAAa,KAAK,GAAG,cAAc;AAExC,OAAK,wBAAwB;AAC7B,SAAO;;;;;;;;;;;;;;;CAgBT,MAAM,OAA8B;AAClC,MAAI,KAAK,UAAU,mBAAmB,OACpC,QAAO,KAAK;AAId,MAAI,CAAC,KAAK,sBACR,OAAM,KAAK,qBAAqB;EAIlC,MAAM,eAAe,KAAK,YAAY;EAGtC,MAAMA,WAA0B,EAAE;EAClC,MAAMC,gBAA0B,EAAE;AAElC,OAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;GAC5C,MAAM,OAAO,aAAa;AAC1B,OAAI,CAAC,KAAM;AAEX,YAAS,KAAK,KAAK,IAAI;AAEvB,OAAI,CAAC,KAAK,gBAER,eAAc,KAAK,EAAE;;EAUzB,MAAM,kBALa,MAAM,KAAK,OAAO,UAAU,cAAc,EAK3B,QAC/B,QAA2B,QAAQ,KACrC;EAGD,MAAMC,kBAAgC,EAAE;EACxC,IAAI,kBAAkB;AAEtB,OAAK,MAAM,QAAQ,aACjB,KAAI,KAAK,iBAAiB;GAExB,MAAM,gBAAgB,KAAK,sBACzB,KAAK,KACL,KAAK,gBACN;AACD,mBAAgB,KAAK,cAAc;SAC9B;GAEL,MAAM,gBAAgB,eAAe;AACrC,OAAI,CAAC,cACH,OAAM,IAAI,MACR,mDAAmD,kBACpD;AAEH,mBAAgB,KAAK,cAAc;AACnC;;EAIJ,MAAM,QAAQ,KAAK,aAAa,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC;AAExD,OAAK,aAAa;AAClB,OAAK,QAAQ;AACb,OAAK,SAAS,mBAAmB;AAEjC,SAAO;;;;;;;;;;;;;;;;;CAkBT,MAAM,SAA4B;AAChC,MAAI,KAAK,SAAS,mBAAmB,UACnC,OAAM,IAAI,MAAM,0CAA0C;EAG5D,MAAM,QAAQ,MAAM,KAAK,MAAM;AAC/B,QAAM,KAAK,SAAS,OAAO,MAAM,mBAAmB,MAAM,CAAC,IAAI;AAE/D,OAAK,SAAS,mBAAmB;AACjC,SAAO,KAAK;;;;;;;;;;;;;;;;;;;;CAqBd,MAAM,QAAQ,aAAqB,6BAGhC;AACD,MAAI,KAAK,WAAW,mBAAmB,UACrC,OAAM,IAAI,MACR,2DACD;EAGH,MAAM,QAAQ,MAAM,KAAK,QAAQ;EAEjC,MAAM,mBAAmB,MAAM,oBAC7B,KAAK,SAAS,OAAO,OACrB,MAAM,IACN,WACD;AAED,OAAK,SAAS,mBAAmB;AAIjC,SAAO;GACL,gBAHqB,iBAAiB;GAItC;GACD;;;;;CAMH,AAAQ,gBAAgB,SAAyB;AAC/C,MAAI,CAAC,eAAe,QAAQ,CAC1B,OAAM,IAAI,MAAM,6BAA6B,UAAU;AAEzD,SAAO;;;;;CAMT,MAAc,0BAAsD;EAElE,MAAMC,YAA+B,MAAM,KAAK,0BAA0B;EAG1E,MAAMC,WAA8B,EAAE;AACtC,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;GAC/C,MAAM,YAAY,KAAK,WAAW;AAClC,OAAI,CAAC,UAAW;AAEhB,OAAI;IAGF,MAAM,MAAM,0BADK,OAAO,KAAK,UAAU,MAAM,SAAS,CACP;AAG/C,WAAO,IAAI;AAEX,QAAI,UAAU,cAAc,MAE1B,UAAS,KAAK;KACZ;KACA,iBAAiB,UAAU;KAC5B,CAAC;QAGF,UAAS,KAAK,EACZ,KACD,CAAC;YAEG,OAAO;AACd,UAAM,IAAI,MACR,+CAA+C,EAAE,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GAC5G;;;AAIL,SAAO,CAAC,GAAG,WAAW,GAAG,SAAS;;;;;CAMpC,MAAc,2BAAuD;EAKnE,MAAM,YAHc,MAAM,KAAK,SAAS,QAAQ,eAAe,KAAK,QAAQ,GAI7D,gBAAgB,KAAK,QAAQ,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE;EACjE,MAAM,cAAc,KAAK,kBAAkB,QACxC,UAAU,CAAC,SAAS,SAAS,MAAM,CACrC;EAGD,MAAMC,eAA8B,EAAE;AACtC,MAAI,YAAY,SAAS,GAAG;GAC1B,MAAM,kBAAkB,MAAM,KAAK,SAAS,OAAO,MAChD,sBAAsB,CACtB,IAAI;AAEP,QAAK,MAAM,SAAS,aAAa;IAC/B,MAAM,WAAW,kCAAkC;KACjD,QAAQ,KAAK;KACb,UAAU;KACV;KACD,CAAC;AACF,iBAAa,KAAK,SAAS;;;AAI/B,SAAO,aAAa,KAAK,SAAS,EAAE,KAAK,EAAE;;;;;;;CAQ7C,AAAQ,aAAgC;AACtC,MAAI,KAAK,WAAW,mBAAmB,UAAU;AAC/C,OAAI,KAAK,aAAa,WAAW,EAC/B,OAAM,IAAI,MAAM,2CAA2C;AAE7D,OAAI,KAAK,aAAa,SAAS,EAC7B,eAAc,KAAK,aAAa,KAAK,MAAM,EAAE,IAAI,CAAC;AAEpD,QAAK,SAAS,mBAAmB;;AAEnC,SAAO,KAAK;;;;;CAMd,AAAQ,sBACN,aACA,WACY;AACZ,MAAI;AACF,OAAI,UAAU,SAAS,mBAAmB;IAExC,MAAM,aAAa,UAAU;IAE7B,MAAM,UAAU,iBADG,IAAI,WAAW,OAAO,OAAO,WAAW,CAAC,CAChB;AAI5C,QAAI,CAAC,QAAQ,KACX,OAAM,IAAI,MAAM,+CAA+C;IAGjE,MAAM,OAAO,QAAQ;AAOrB,WAJkB,8BAChB,aAHsB,IAAI,gBAAgB,KAAK,GAAG,KAAK,IAAI,CAK5D,CACgB;cACR,UAAU,SAAS,cAAc;IAE1C,MAAM,aAAa,UAAU;AAG7B,WADkB,gBAAgB,aADhB,IAAI,WAAW,OAAO,OAAO,WAAW,CAAC,CACF,CACxC;SAEjB,OAAM,IAAI,MAAM,+BAA+B,UAAU,OAAO;WAE3D,OAAO;AACd,SAAM,IAAI,MACR,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACzF;;;;;;;;;;ACrhBP,IAAa,YAAb,cAA+B,MAAM;CACnC,YACE,AAAOC,QACP,AAAOC,YACP,AAAOC,MACP;AACA,QAAM,QAAQ,OAAO,GAAG,aAAa;EAJ9B;EACA;EACA;AAGP,OAAK,OAAO;;;;;;;;;;;;;;AAehB,eAAsB,QACpB,KACA,SACY;CACZ,MAAM,WAAW,MAAM,MAAM,KAAK,QAAQ;AAE1C,KAAI,CAAC,SAAS,IAAI;EAChB,IAAIC;AAEJ,MAAI;AACF,eAAY,MAAM,SAAS,MAAM;UAC3B;AACN,OAAI;AACF,gBAAY,MAAM,SAAS,MAAM;WAC3B;AACN,gBAAY;;;AAIhB,QAAM,IAAI,UACR,SAAS,QACT,SAAS,YACT,KAAK,UAAU,UAAU,CAC1B;;AAGH,QAAO,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACIxB,IAAa,eAAb,MAA0B;CACxB,AAAiB;CACjB,AAAiB;;;;;;;;;;;;;;CAejB,YAAY,QAA4B;AAEtC,OAAK,SAAS;GACZ,QAAQ,KAAK,eAAe,OAAO,OAAO;GAC1C,YAAY,OAAO,cAAc;GACjC,UAAU,OAAO,YAAY;GAC7B,YAAY,OAAO,cAAc;GACjC,WAAW,OAAO,aAAa;GAC/B,iBAAiB,OAAO,kBACpB,KAAK,gBAAgB,OAAO,gBAAgB,GAC5C;GACJ,QAAQ,KAAK,eAAe,OAAO,UAAU,gBAAgB;GAC7D,WAAW,OAAO,aAAa;GAChC;AAGD,OAAK,WAAW,eAAe,WAAW,EACxC,aAAa;GACX,QAAQ,KAAK,OAAO;GACpB,MAAM,KAAK,OAAO;GAClB,OAAO,KAAK,OAAO;GACpB,EACF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCJ,MAAM,WAAW,QAAuD;EACtE,MAAM,EACJ,WACA,SACA,QACA,OAAO,eACP,oBAAoB,EAAE,EACtB,eAAe,wBACf,WAAW,mBACX,OACA,YACE;EAGJ,MAAM,uBAAuB,CAC3B,GAAG,IAAI,IAAI,CAAC,GAAG,sBAAsB,GAAG,kBAAkB,CAAC,CAC5D;EAED,IAAI,eAAe;AACnB,MAAI,iBAAiB,UAAa,KAAK,OAAO,UAC5C,KAAI,QACF,gBAAe,MAAM,KAAK,gBACxB,KAAK,gBAAgB,QAAQ,EAC7B,QACD;MAED,SAAQ,KACN,4FACD;EAIL,MAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,WAAW,aAAa;AAE3D,MAAI,aAAa,OAAO,UAAU,KAAK,OAAO,OAAO;AACrD,MAAI,aAAa,OAAO,YAAY,KAAK,OAAO,SAAS;AACzD,MAAI,aAAa,OAAO,cAAc,KAAK,OAAO,WAAW;AAC7D,MAAI,aAAa,OAAO,aAAa,OAAO,KAAK,OAAO,UAAU,CAAC;AACnE,MAAI,aAAa,OAAO,UAAU,KAAK,OAAO,OAAO,UAAU,CAAC;AAChE,MAAI,aAAa,OAAO,aAAa,OAAO,UAAU,CAAC,UAAU,CAAC;AAClE,MAAI,aAAa,OAAO,WAAW,OAAO,QAAQ,CAAC,UAAU,CAAC;AAC9D,MAAI,aAAa,OAAO,UAAU,OAAO,OAAO,CAAC,UAAU,CAAC;AAC5D,MAAI,aAAa,OAAO,QAAQ,KAAK;AACrC,MAAI,aAAa,OAAO,qBAAqB,qBAAqB,KAAK,IAAI,CAAC;AAC5E,MAAI,aAAa,OAAO,gBAAgB,aAAa,UAAU,CAAC;AAChE,MAAI,aAAa,OAAO,YAAY,SAAS,UAAU,CAAC;AAExD,MAAI,OAAO,iBAAiB,UAC1B,KAAI,aAAa,OAAO,SAAS,OAAO,aAAa,CAAC;AAGxD,MAAI,KAAK,OAAO,gBACd,KAAI,aAAa,OAAO,mBAAmB,KAAK,OAAO,gBAAgB;AAGzE,SAAO,QAA4B,IAAI,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BpD,MAAM,gBACJ,SACA,SACkB;EAElB,MAAM,cAAc,MAAM,KAAK,SAAS,QAAQ,eAAe,QAAQ;AAGvE,SACE,OAAO,QAAQ,KAAK,MACpB,aAAa,QAAQ,MAClB,UAAU,MAAM,YAAY,OAAO,QAAQ,CAC7C,KAAK;;;;;;;;;;;;;;CAgBV,MAAM,sBACJ,QACgC;EAChC,MAAM,EAAE,OAAO,SAAS,aAAa;AAGrC,OAAK,gBAAgB,QAAQ;EAE7B,MAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,WAAW,uBAAuB;EAErE,MAAMC,OAA0B;GAC9B,QAAQ,KAAK,OAAO;GACpB;GACA,gBAAgB,MAAM;GACtB;GACD;AAED,SAAO,QAA+B,IAAI,UAAU,EAAE;GACpD,QAAQ;GACR,SAAS,EACP,gBAAgB,oBACjB;GACD,MAAM,KAAK,UAAU,KAAK;GAC3B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCJ,MAAM,SAAS,QAAgD;EAC7D,MAAM,WAAW,MAAM,KAAK,WAAW,OAAO;AAE9C,SAAO;GACL,GAAG;GACH,OAAO,SAAS,UAAU,KAAK,KAAK,OAAO,SAAS,MAAM;GAC1D,QAAQ,OAAO,OAAO,OAAO;GAC7B,SAAS,OAAO,WAAW;GAC3B,WAAW,KAAK,KAAK;GACtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmDH,MAAM,QAAQ,QAKY;EACxB,MAAM,EAAE,OAAO,SAAS,UAAU,WAAW;AAiB7C,SARiB,IAAI,aAAa;GAChC;GACA,aATmB,MAAM,KAAK,sBAAsB;IACpD;IACA;IACA;IACD,CAAC,EAKyB;GACzB,UAAU,KAAK;GACf;GACA;GACD,CAAC;;;;;CAQJ,AAAQ,eAAe,QAAwB;AAC7C,MAAI,CAAC,OACH,OAAM,IAAI,MAAM,sBAAsB;AAExC,SAAO;;;;;CAMT,AAAQ,gBAAgB,SAAyB;AAC/C,MAAI,CAAC,eAAe,QAAQ,CAC1B,OAAM,IAAI,MAAM,6BAA6B,UAAU;AAEzD,SAAO;;;;;CAMT,AAAQ,eAAe,QAAwB;AAC7C,MAAI,SAAS,KAAK,SAAS,YACzB,OAAM,IAAI,MACR,gBAAgB,OAAO,uCAAuC,YAAY,GAC3E;AAEH,SAAO"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["swapTxns: TransactionWithSigner[]","status: number","statusText: string","data: unknown","errorData: unknown","body: FetchSwapTxnsBody"],"sources":["../src/constants.ts","../src/composer.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["/**\n * Supported DEX protocols for swap routing\n */\nexport enum Protocol {\n TinymanV2 = 'TinymanV2',\n Algofi = 'Algofi',\n Algomint = 'Algomint',\n Pact = 'Pact',\n Folks = 'Folks',\n TAlgo = 'TAlgo',\n}\n\n/**\n * Deprecated protocols that are automatically excluded from routing\n *\n * @internal\n */\nexport const DEPRECATED_PROTOCOLS = ['Humble', 'Tinyman'] as const\n\n/** Default Algod node URI for mainnet */\nexport const DEFAULT_ALGOD_URI = 'https://mainnet-api.4160.nodely.dev/'\n\n/** Default Algod node token (empty for public nodes) */\nexport const DEFAULT_ALGOD_TOKEN = ''\n\n/** Default Algod node port */\nexport const DEFAULT_ALGOD_PORT = 443\n\n/** Default Deflex API base URL */\nexport const DEFAULT_API_BASE_URL = 'https://deflex.txnlab.dev/api'\n\n/** Default fee in basis points (0.15%) */\nexport const DEFAULT_FEE_BPS = 15\n\n/** Maximum allowed fee in basis points (3.00%) */\nexport const MAX_FEE_BPS = 300\n\n/** Default maximum transaction group size */\nexport const DEFAULT_MAX_GROUP_SIZE = 16\n\n/** Default maximum routing depth (number of hops) */\nexport const DEFAULT_MAX_DEPTH = 4\n\n/** Default auto opt-in setting (automatic asset/app opt-in detection) */\nexport const DEFAULT_AUTO_OPT_IN = false\n\n/** Default number of rounds to wait for transaction confirmation */\nexport const DEFAULT_CONFIRMATION_ROUNDS = 4\n","import {\n AtomicTransactionComposer,\n decodeUnsignedTransaction,\n isValidAddress,\n LogicSigAccount,\n makeApplicationOptInTxnFromObject,\n msgpackRawDecode,\n signLogicSigTransactionObject,\n signTransaction,\n Transaction,\n type ABIResult,\n type Algodv2,\n type TransactionSigner,\n type TransactionWithSigner,\n} from 'algosdk'\nimport { DEFAULT_CONFIRMATION_ROUNDS } from './constants'\nimport type {\n FetchQuoteResponse,\n DeflexTransaction,\n DeflexSignature,\n DeflexQuote,\n MethodCall,\n} from './types'\n\n/**\n * A transaction signer function that supports both standard algosdk.TransactionSigner\n * and ARC-1 compliant signers that may return null for unsigned transactions.\n *\n * @param txnGroup - The complete transaction group to sign\n * @param indexesToSign - Array of indexes indicating which transactions need signing\n * @returns Array of signed transactions (may include nulls for ARC-1 compliant wallets)\n */\nexport type SignerFunction = (\n txnGroup: Transaction[],\n indexesToSign: number[],\n) => Promise<(Uint8Array | null)[]>\n\n/**\n * Status of the SwapComposer transaction group lifecycle\n */\nexport enum SwapComposerStatus {\n /** The atomic group is still under construction. */\n BUILDING,\n\n /** The atomic group has been finalized, but not yet signed. */\n BUILT,\n\n /** The atomic group has been finalized and signed, but not yet submitted to the network. */\n SIGNED,\n\n /** The atomic group has been finalized, signed, and submitted to the network. */\n SUBMITTED,\n\n /** The atomic group has been finalized, signed, submitted, and successfully committed to a block. */\n COMMITTED,\n}\n\n/**\n * Configuration for creating a SwapComposer instance\n */\nexport interface SwapComposerConfig {\n /** The quote response from fetchQuote() or newQuote() */\n readonly quote: FetchQuoteResponse | DeflexQuote\n /** The swap transactions from fetchSwapTransactions() */\n readonly deflexTxns: DeflexTransaction[]\n /** Algodv2 client instance */\n readonly algodClient: Algodv2\n /** The address of the account that will sign transactions */\n readonly address: string\n /** Transaction signer function */\n readonly signer: TransactionSigner | SignerFunction\n}\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 requiredAppOptIns: number[]\n private readonly deflexTxns: DeflexTransaction[]\n private readonly algodClient: Algodv2\n private readonly address: string\n private readonly signer: TransactionSigner | SignerFunction\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.requiredAppOptIns - 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 */\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.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 }\n\n /**\n * Get the status of this composer's transaction group\n *\n * @returns The current status of the transaction group\n */\n getStatus(): SwapComposerStatus {\n return this.atc.getStatus() as unknown as SwapComposerStatus\n }\n\n /**\n * Get the number of transactions currently in this atomic group\n *\n * @returns The number of transactions in the group\n */\n count(): number {\n return this.atc.count()\n }\n\n /**\n * Add a transaction to the atomic group\n *\n * Transactions are added in the order methods are called. For example:\n * ```typescript\n * composer\n * .addTransaction(txn1) // Added first\n * .addSwapTransactions() // Added second\n * .addTransaction(txn2) // Added third\n * ```\n *\n * @param transaction - The transaction to add\n * @returns This composer instance for chaining\n * @throws Error if the composer is not in the BUILDING status\n * @throws Error if the maximum group size is exceeded\n */\n addTransaction(transaction: Transaction, signer = this.defaultSigner): this {\n this.atc.addTransaction({ txn: transaction, signer })\n return this\n }\n\n /**\n * Add a method call to the atomic group\n *\n * The `signer` property in the `methodCall` parameter is optional. If not provided,\n * the signer will default to the one passed as the second parameter, or the\n * configured signer from the constructor if no second parameter is provided.\n *\n * @param methodCall - The method call to add\n * @param signer - The signer to use for the method call (defaults to constructor signer)\n * @returns This composer instance for chaining\n */\n addMethodCall(methodCall: MethodCall, signer = this.defaultSigner): this {\n this.atc.addMethodCall({\n ...methodCall,\n signer: methodCall.signer ?? signer,\n })\n return this\n }\n\n /**\n * Add swap transactions to the atomic group\n *\n * This method automatically processes required app opt-ins and adds all swap\n * transactions from the quote. Can only be called once per composer instance.\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 const processedTxns = await this.processSwapTransactions()\n const newLength = this.atc.count() + processedTxns.length\n\n if (newLength > 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 for (const txnWithSigner of processedTxns) {\n this.atc.addTransaction(txnWithSigner)\n }\n\n this.swapTransactionsAdded = true\n return this\n }\n\n /**\n * Finalize the transaction group by assigning group IDs\n *\n * This method builds the atomic transaction group, assigning group IDs to all transactions\n * if there is more than one transaction. After calling this method, the composer's status\n * will be at least BUILT.\n *\n * @returns Array of transactions with their associated signers\n *\n * @throws Error if the group contains 0 transactions\n *\n * @example\n * ```typescript\n * const composer = await deflex.newSwap({ quote, address, slippage, signer })\n * composer.addTransaction(customTxn)\n *\n * // Build the group to inspect transactions before signing\n * const txnsWithSigners = composer.buildGroup()\n * console.log('Group ID:', txnsWithSigners[0].txn.group)\n * console.log('Group length:', txnsWithSigners.length)\n * console.log('Status:', composer.getStatus()) // BUILT\n * ```\n */\n buildGroup(): TransactionWithSigner[] {\n return this.atc.buildGroup()\n }\n\n /**\n * Sign the transaction group\n *\n * Automatically adds swap transactions if not already added, builds the atomic group,\n * and signs all transactions using the configured signer.\n *\n * @returns A promise that resolves to an array of signed transaction blobs\n *\n * @example\n * ```typescript\n * const signedTxns = await composer.sign()\n * ```\n */\n async sign(): Promise<Uint8Array[]> {\n if (this.getStatus() >= SwapComposerStatus.SIGNED) {\n return this.atc.gatherSignatures()\n }\n\n // Auto-add swap transactions if needed\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n return await this.atc.gatherSignatures()\n }\n\n /**\n * Submit the signed transactions to the network\n *\n * This method signs the transaction group (if not already signed) and submits\n * it to the Algorand network. Does not wait for confirmation.\n *\n * @returns The transaction IDs\n * @throws Error if the transaction group has already been submitted\n *\n * @example\n * ```typescript\n * const txIds = await composer.submit()\n * console.log('Submitted transactions:', txIds)\n * ```\n */\n async submit(): Promise<string[]> {\n // Auto-add swap transactions if needed (maintains backward compatibility)\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n return this.atc.submit(this.algodClient)\n }\n\n /**\n * Execute the swap\n *\n * Signs the transaction group, submits it to the network, and waits for confirmation.\n * This is the primary method for executing swaps and combines sign(), submit(), and\n * waitForConfirmation() into a single call.\n *\n * @param waitRounds - The number of rounds to wait for confirmation (default: 4)\n * @returns Object containing the confirmed round and transaction IDs\n * @throws Error if the transaction group has already been committed\n *\n * @example\n * ```typescript\n * const result = await composer.execute()\n * console.log(`Confirmed in round ${result.confirmedRound}`)\n * console.log('Transaction IDs:', result.txIds)\n * ```\n */\n async execute(waitRounds: number = DEFAULT_CONFIRMATION_ROUNDS): Promise<{\n confirmedRound: bigint\n txIds: string[]\n methodResults: ABIResult[]\n }> {\n // Auto-add swap transactions if needed (maintains backward compatibility)\n if (!this.swapTransactionsAdded) {\n await this.addSwapTransactions()\n }\n\n const { txIDs, ...result } = await this.atc.execute(\n this.algodClient,\n waitRounds,\n )\n\n return {\n ...result,\n txIds: txIDs,\n }\n }\n\n /**\n * Validates an Algorand address\n */\n private validateAddress(address: string): string {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid Algorand address: ${address}`)\n }\n return address\n }\n\n /**\n * Processes app opt-ins and decodes swap transactions from API response\n */\n private async processSwapTransactions(): Promise<TransactionWithSigner[]> {\n const appOptIns = await this.processRequiredAppOptIns()\n\n const swapTxns: TransactionWithSigner[] = []\n for (let i = 0; i < this.deflexTxns.length; i++) {\n const deflexTxn = this.deflexTxns[i]\n if (!deflexTxn) continue\n\n try {\n const txnBytes = Buffer.from(deflexTxn.data, 'base64')\n const txn = decodeUnsignedTransaction(txnBytes)\n delete txn.group\n\n if (deflexTxn.signature !== false) {\n // Pre-signed transaction - use custom Deflex signer\n swapTxns.push({\n txn,\n signer: this.createDeflexSigner(deflexTxn.signature),\n })\n } else {\n // User transaction - use configured signer\n swapTxns.push({\n txn,\n signer: this.defaultSigner,\n })\n }\n } catch (error) {\n throw new Error(\n `Failed to process swap transaction at index ${i}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n return [...appOptIns, ...swapTxns]\n }\n\n /**\n * Creates opt-in transactions for apps the user hasn't opted into yet\n */\n private async processRequiredAppOptIns(): Promise<TransactionWithSigner[]> {\n // Fetch account information\n const accountInfo = await this.algodClient\n .accountInformation(this.address)\n .do()\n\n // Check app opt-ins\n const userApps =\n accountInfo?.appsLocalState?.map((app) => Number(app.id)) || []\n const appsToOptIn = this.requiredAppOptIns.filter(\n (appId) => !userApps.includes(appId),\n )\n\n if (appsToOptIn.length === 0) return []\n\n const suggestedParams = await this.algodClient.getTransactionParams().do()\n\n return appsToOptIn.map((appId) => ({\n txn: makeApplicationOptInTxnFromObject({\n sender: this.address,\n appIndex: appId,\n suggestedParams,\n }),\n signer: this.defaultSigner,\n }))\n }\n\n /**\n * The default signer function that uses the configured signer\n */\n private defaultSigner: TransactionSigner = async (\n txnGroup: Transaction[],\n indexesToSign: number[],\n ) => {\n const result = await this.signer(txnGroup, indexesToSign)\n return result.filter((txn): txn is Uint8Array => txn !== null)\n }\n\n /**\n * Creates a TransactionSigner function for Deflex pre-signed transactions\n */\n private createDeflexSigner(signature: DeflexSignature): TransactionSigner {\n return async (\n txnGroup: Transaction[],\n indexesToSign: number[],\n ): Promise<Uint8Array[]> => {\n return indexesToSign.map((i) => {\n const txn = txnGroup[i]\n if (!txn) throw new Error(`Transaction at index ${i} not found`)\n return this.signDeflexTransaction(txn, signature)\n })\n }\n }\n\n /**\n * Re-signs a Deflex transaction using the provided logic signature or secret key\n */\n private signDeflexTransaction(\n transaction: Transaction,\n signature: DeflexSignature,\n ): Uint8Array {\n try {\n if (signature.type === 'logic_signature') {\n // Decode the signature value to extract the logic signature\n const valueArray = signature.value as Record<string, number>\n const valueBytes = new Uint8Array(Object.values(valueArray))\n const decoded = msgpackRawDecode(valueBytes) as {\n lsig?: { l: Uint8Array; arg?: Uint8Array[] }\n }\n\n if (!decoded.lsig) {\n throw new Error('Logic signature structure missing lsig field')\n }\n\n const lsig = decoded.lsig\n const logicSigAccount = new LogicSigAccount(lsig.l, lsig.arg)\n\n const signedTxn = signLogicSigTransactionObject(\n transaction,\n logicSigAccount,\n )\n return signedTxn.blob\n } else if (signature.type === 'secret_key') {\n // Convert signature.value (Record<string, number>) to Uint8Array\n const valueArray = signature.value as Record<string, number>\n const secretKey = new Uint8Array(Object.values(valueArray))\n const signedTxn = signTransaction(transaction, secretKey)\n return signedTxn.blob\n } else {\n throw new Error(`Unsupported signature type: ${signature.type}`)\n }\n } catch (error) {\n throw new Error(\n `Failed to re-sign transaction: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n}\n","/**\n * 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 {\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\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 */\n constructor(config: DeflexConfigParams) {\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\n /**\n * Fetch a swap quote from the Deflex API\n *\n * Requests optimal swap routing from the Deflex API. The quote includes routing\n * information, price impact, required opt-ins, and an encrypted transaction payload.\n *\n * @param params - Parameters for the quote request\n * @param params.fromASAID - The ID of the asset to swap from\n * @param params.toASAID - The ID of the asset to swap to\n * @param params.amount - The amount of the asset to swap in base units\n * @param params.type - The type of the quote (default: 'fixed-input')\n * @param params.disabledProtocols - List of protocols to disable (default: [])\n * @param params.maxGroupSize - The maximum group size (default: 16)\n * @param params.maxDepth - The maximum depth (default: 4)\n * @param params.address - The address of the account that will perform the swap (recommended when using `config.autoOptIn` or `params.optIn`)\n * @param params.optIn - Whether to include asset opt-in transaction\n * - If true: API reduces maxGroupSize by 1 and includes opt-in (always included, even if not needed)\n * - If false: No opt-in transaction included\n * - If undefined: Falls back to `config.autoOptIn` behavior with account check (if `params.address` is provided)\n * @returns A FetchQuoteResponse object with routing information\n *\n * @example\n * ```typescript\n * const quote = await deflex.fetchQuote({\n * address: 'ABC...',\n * fromASAID: 0, // ALGO\n * toASAID: 31566704, // USDC\n * amount: 1_000_000, // 1 ALGO\n * })\n * ```\n */\n async fetchQuote(params: FetchQuoteParams): Promise<FetchQuoteResponse> {\n const {\n fromASAID,\n toASAID,\n amount,\n type = 'fixed-input',\n disabledProtocols = [],\n maxGroupSize = DEFAULT_MAX_GROUP_SIZE,\n maxDepth = DEFAULT_MAX_DEPTH,\n optIn,\n address,\n } = params\n\n // Always include deprecated protocols in disabled list\n const allDisabledProtocols = [\n ...new Set([...DEPRECATED_PROTOCOLS, ...disabledProtocols]),\n ]\n\n let includeOptIn = optIn\n if (includeOptIn === undefined && this.config.autoOptIn) {\n if (address) {\n includeOptIn = await this.needsAssetOptIn(\n this.validateAddress(address),\n toASAID,\n )\n } else {\n console.warn(\n 'autoOptIn is enabled but no address provided to fetchQuote(). Asset opt-in check skipped.',\n )\n }\n }\n\n const url = new URL(`${this.config.apiBaseUrl}/fetchQuote`)\n\n url.searchParams.append('apiKey', this.config.apiKey)\n url.searchParams.append('algodUri', this.config.algodUri)\n url.searchParams.append('algodToken', this.config.algodToken)\n url.searchParams.append('algodPort', String(this.config.algodPort))\n url.searchParams.append('feeBps', this.config.feeBps.toString())\n url.searchParams.append('fromASAID', BigInt(fromASAID).toString())\n url.searchParams.append('toASAID', BigInt(toASAID).toString())\n url.searchParams.append('amount', BigInt(amount).toString())\n url.searchParams.append('type', type)\n url.searchParams.append('disabledProtocols', allDisabledProtocols.join(','))\n url.searchParams.append('maxGroupSize', maxGroupSize.toString())\n url.searchParams.append('maxDepth', maxDepth.toString())\n\n if (typeof includeOptIn === 'boolean') {\n url.searchParams.append('optIn', String(includeOptIn))\n }\n\n if (this.config.referrerAddress) {\n url.searchParams.append('referrerAddress', this.config.referrerAddress)\n }\n\n return request<FetchQuoteResponse>(url.toString())\n }\n\n /**\n * Check if asset opt-in is required for the output asset\n *\n * Convenience method to determine if an address needs to opt into the output asset\n * of a swap. This is useful when you want to get a quote without requiring wallet\n * connection upfront, but need to know whether to set `optIn: true` in fetchQuote()\n * to ensure proper routing (as opt-ins reduce maxGroupSize by 1).\n *\n * Note: If you enable `config.autoOptIn`, this check is handled automatically when\n * an address is provided to fetchQuote().\n *\n * @param address - The address to check\n * @param assetId - The output asset ID to check\n * @returns True if asset opt-in is required, false otherwise (always false for ALGO)\n *\n * @example\n * ```typescript\n * // Check if opt-in needed for output asset before fetching quote\n * const needsOptIn = await deflex.needsAssetOptIn(userAddress, toAssetId)\n * const quote = await deflex.fetchQuote({\n * fromAssetId,\n * toAssetId,\n * amount,\n * optIn: needsOptIn,\n * })\n * ```\n */\n async needsAssetOptIn(\n address: string,\n assetId: number | bigint,\n ): Promise<boolean> {\n // Fetch account information\n const accountInfo = await this.algodClient.accountInformation(address).do()\n\n // Check if asset opt-in is required\n return (\n BigInt(assetId) !== 0n &&\n accountInfo?.assets?.find(\n (asset) => asset.assetId === BigInt(assetId),\n ) === undefined\n )\n }\n\n /**\n * Fetch swap transactions from the Deflex API\n *\n * Decrypts the quote payload and generates executable swap transactions for the\n * specified signer address with the given slippage tolerance.\n *\n * @param params - Parameters for the swap transaction request\n * @param params.quote - The quote response from fetchQuote()\n * @param params.address - The address of the signer\n * @param params.slippage - The slippage tolerance as a percentage (e.g., 1 for 1%)\n * @returns A FetchSwapTxnsResponse object with transaction data\n */\n async fetchSwapTransactions(\n params: FetchSwapTxnsParams,\n ): Promise<FetchSwapTxnsResponse> {\n const { quote, address, slippage } = params\n\n // Validate signer address\n this.validateAddress(address)\n\n const url = new URL(`${this.config.apiBaseUrl}/fetchExecuteSwapTxns`)\n\n const body: FetchSwapTxnsBody = {\n apiKey: this.config.apiKey,\n address,\n txnPayloadJSON: quote.txnPayload,\n slippage,\n }\n\n return request<FetchSwapTxnsResponse>(url.toString(), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n }\n\n /**\n * Fetch a quote and return an enhanced quote result\n *\n * This is the recommended way to fetch quotes. It returns an object that\n * extends the raw API response with additional metadata and type normalization.\n *\n * @param params - Parameters for the quote request\n * @param params.fromASAID - The ID of the asset to swap from\n * @param params.toASAID - The ID of the asset to swap to\n * @param params.amount - The amount of the asset to swap in base units\n * @param params.type - The type of the quote (default: 'fixed-input')\n * @param params.disabledProtocols - List of protocols to disable (default: [])\n * @param params.maxGroupSize - The maximum group size (default: 16)\n * @param params.maxDepth - The maximum depth (default: 4)\n * @param params.address - The address of the account that will perform the swap (recommended when using `config.autoOptIn` or `params.optIn`)\n * @param params.optIn - Whether to include asset opt-in transaction\n * @returns A DeflexQuote enhanced quote result\n *\n * @example\n * ```typescript\n * const quote = await deflex.newQuote({\n * address: 'ABC...',\n * fromASAID: 0,\n * toASAID: 31566704,\n * amount: 1_000_000,\n * })\n *\n * console.log(quote.quote) // bigint - quoted amount\n * console.log(quote.fromASAID) // number - input asset ID\n * console.log(quote.toASAID) // number - output asset ID\n * console.log(quote.amount) // bigint - original request amount\n * console.log(quote.createdAt) // number - timestamp\n * ```\n */\n async newQuote(params: FetchQuoteParams): Promise<DeflexQuote> {\n const response = await this.fetchQuote(params)\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 })\n\n return composer\n }\n\n /**\n * Validates the API key\n */\n private validateApiKey(apiKey: string): string {\n if (!apiKey) {\n throw new Error('API key is required')\n }\n return apiKey\n }\n\n /**\n * Validates an Algorand address\n */\n private validateAddress(address: string): string {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid Algorand address: ${address}`)\n }\n return address\n }\n\n /**\n * Validates the fee in basis points (max 300 = 3.00%)\n */\n private validateFeeBps(feeBps: number): number {\n if (feeBps < 0 || feeBps > MAX_FEE_BPS) {\n throw new Error(\n `Invalid fee: ${feeBps} basis points (must be between 0 and ${MAX_FEE_BPS})`,\n )\n }\n return feeBps\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@txnlab/deflex",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.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.20.0",
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "tsdown && publint --strict",
|
|
50
50
|
"test": "vitest run",
|
|
@@ -53,15 +53,15 @@
|
|
|
53
53
|
"typecheck": "tsc --noEmit"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@types/node": "
|
|
57
|
-
"@vitest/coverage-v8": "
|
|
56
|
+
"@types/node": "22.19.0",
|
|
57
|
+
"@vitest/coverage-v8": "4.0.6",
|
|
58
|
+
"algosdk": "3.5.2",
|
|
58
59
|
"publint": "0.3.15",
|
|
59
|
-
"tsdown": "0.15.
|
|
60
|
+
"tsdown": "0.15.12",
|
|
60
61
|
"typescript": "5.9.3",
|
|
61
|
-
"vitest": "
|
|
62
|
+
"vitest": "4.0.6"
|
|
62
63
|
},
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"algosdk": "3.5.2"
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"algosdk": "^3.0.0"
|
|
66
66
|
}
|
|
67
67
|
}
|