> For the complete documentation index, see [llms.txt](https://txnlab.gitbook.io/haystack-router/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://txnlab.gitbook.io/haystack-router/order-router-protocol/architecture/order-router-app.md).

# Order Router App V3 (legacy)

{% hint style="info" %}
This page describes the V3 app ([3172554435](https://lora.algokit.io/mainnet/application/3172554435)), which executes swaps for API keys not yet on V4. V4 is rolling out across API keys, first to select keys, then to all: see [Order Router App V4](/haystack-router/order-router-protocol/architecture/order-router-app-v4.md).
{% endhint %}

## Overview

The order-router smart contract (app) is used to **atomically** perform multiple swaps through Algorand DEXs. The swaps are performed using contract-to-contract calls. Assets are sent to the app address before a group of swaps. After a swap, the assets are retained by the order router app account for future swaps in the transaction group (allowing users to perform multi-hop swaps through different trading pairs). After all swaps are completed, the app finalizes and confirms that its balance of the output asset meets or exceeds minimum required amount of the output asset, and closes out all assets to a beneficiary.

The three main operations of the order-router app are (called in this order):

1. **Opt Into Assets:** Opts the order-router app into all assets that are involved in the given swap route.
2. **Swap:** Perform an on-chain swap, by the order-router app, using a supported DEX.
3. **Finalize:** Confirm that the order-router app's balance of the output asset meets or exceeds minimum required amount of the output asset, and closes out all assets to a beneficiary.

## ABI

The app is [ARC-4](https://arc.algorand.foundation/ARCs/arc-0004) compliant and exposes an ABI ([download here](https://github.com/deflex-fi/deflex-abis/blob/main/order-router-app.json)).

We prefix operation names with the entity that is supposed / allowed to call that operation. In the order-router app we have one entity: the user that is performing the swap.

### `User_opt_into_assets`

Opts the app account into the assets that are provided in the application call's foreign assets array.

Foreign accounts passed to this operation are ignored. Up to V3.1, two foreign accounts rekeyed the app to the second one, for AlgoFi nanoswap swaps made on the app's behalf; since V3.1 those run as ordinary swaps, and V3.2 removed the rekey.

The transaction must be succeeded by a `User_swap_finalize` transaction (see below) to ensure that the assets are eventually opted out of in the same transaction group.

#### Parameters

1. `expected_amount_out`: The expected output amount of for the whole swap group
2. `finalize_index_offset`: The offset of the `User_swap_finalize` call with respect to the position of this txn. For example, if this transaction is at position 2 and `User_swap_finalize` is at position 8 then the offset is 6.
3. `foreign_assets`: This is a list of asset IDs that must be specified as the app call's foreign asset array.
4. `foreign_account`: Ignored since V3.2 (optional).

#### Required Network Fees

* 1000 microALGO for the call itself
* 1000 \* `len(foreign_assets)` microALGO for inner calls to opt the assets in

### `User_swap`

Perform a sequence of swaps through the app. The swaps are performed using assets belonging to the order-router app account.

`User_swap` batches up to three swaps into one call (determined by paramter `nr_swaps`). How many swaps can actually be batched into one call depends on the number of foreign assets, applications, and accounts that need to be referenced.

The swaps in one call do not have to trade the same asset pair. They run in order, each on a percentage of the app's live balance of its input asset, so consecutive hops of a route can share a call. The API packs them into as few calls as fit within 8 foreign references per call.

Most of the parameters of `User_swap` are fixed-sized arrays of length three. If, say, only two swaps are contained a batch, the third element of the respective parameter is the zero-value for the respective data type (e.g., the zero address for address parameters).

#### Parameters

1. `nr_swaps`: the number of swaps that are executed in this batch
2. `protocol_list`: the internal protocol IDs for each swap in the sequence: 0=algofi, 1=pact, 2=humble, 3=tinyman-v2, 6=folks deposit, 7=folks withdraw, 8=tALGO mint, 9=tALGO unmint, 10=xALGO mint, 11=xALGO unmint, 12=pact-v2 (ID 4=algomint is no longer routed)
3. `assets_list`: a 3x2 array, where `assets_list[i][0]` and `assets_list[i][1]` denote the i-th swap's input and output assets, respectively
4. `applications_list`: a 3x2 array containing the applications involved for each swap (e.g., algofi requires the pool's app ID as well as the ID of the manager contract)
5. `accounts_list`: an array of length three that contains the pool addresses
6. `percent_bps_balance_amount_in_list`: an array of length three with the percent of current balance of input asset for each swap in the sequence
7. `amount_in_offset_list`: an array of length three with the amount to deduct from percent bps of input asset to swap (for fixed-output) for each swap in the sequence
8. `unstructured_metadata_bytes_list`: an array of length three with unstructured metadata for each swap in the sequence
9. `swap_note`: note for each swap in the sequence

#### Required Network Fees

* 1000 microALGO for the call itself
* `X` microALGO for performing the swap (different DEXes have different fees)

#### **Prerequisites**

This operation can only be called after the input assets required for the swap are sent to the app account address. This can be done directly from the swapper, or can be the result of a preceding swap.

### `User_swap_finalize`

Assert the final amount exceeds the minimum amount out, and close out assets to the beneficiary.

#### Parameters

1. `input_asset`: the input asset ID
2. `output_asset`: the output asset ID
3. `opt_out_list`: up to 10 asset IDs (typically the intermediate assets of the route) that the app closes out to the beneficiary
4. `min_amount_out`: the minimum amount out (for fixed-output, the exact output)
5. `type`: the type of the swap (0 for fixed-input, 1 for fixed-output)
6. `beneficiary`: the beneficiary that receives the output
7. `treasury_account`: order-router app treasury account
8. `referrer_account`: referrer treasury account (the protocol treasury account when there is no referrer)
9. `fee_bps`: output fee bps charged on output (split 75% / 25% between treasury and referrer). Must be at least 10. Total fees, including captured positive slippage, are capped at 3% of the expected output.

#### Required Network Fees

* 1000 microALGO for the call itself
* 1000 microALGO for an inner call that raises the opcode budget
* 1000 microALGO for paying fee to the treasury account
* 1000 microALGO paying fee to the referrer treasury account
* 1000 \* \`len(foreign\_assets)\` microALGO for closing out non-ALGO assets to beneficiary
* 1000 microALGO if the output asset is ALGO for sending the output to the beneficiary

## Transaction Group

The group returned by [`fetchExecuteSwapTxns`](/haystack-router/developers/api-order-router.md) is laid out as follows. The order-router app calls can be sent by any account: the API sends them from a single-use account and returns them pre-signed, so the swapper only signs their own transactions. Network fees for the whole group are pooled on the swapper's input transfer, and the app calls carry a fee of 0.

1. (optional) Asset opt-in *(only if the quote was requested with `optIn=true` and the output asset is not ALGO)*
   * Sender: Swapper Account
   * Receiver: Swapper Account
   * Amount: 0
   * Asset: Output Asset
2. (optional) Treasury escrow opt-in *(only if a fee escrow is not yet opted into the output asset; repeated per escrow)*
   * Payment of 0.1 ALGO from the Swapper Account to the escrow
   * Application call to the Referrer Treasury App, method `opt_escrow_into_assets`, sent by the Swapper Account
3. Application *(Opt the order router app into all assets involved in the given route)*
   * ID: Order-Router App ID
   * Method: `User_opt_into_assets`
   * Sender: Any account (pre-signed by the API)
   * Args: \[Expected Amount Out, Finalize Index Offset, Asset IDs]
   * On Complete: NoOp
4. Send the input amount from user to order-router app
   * Payment, only if input asset is ALGO
     * Sender: Swapper Account
     * Receiver: Order-Router App Account
     * Amount: Input Amount
   * Asset Transfer, only if input asset is non-ALGO
     * Sender: Swapper Account
     * Receiver: Order-Router App Account
     * Amount: Input Amount
     * Asset: Input Asset
5. (optional) For routes through AlgoFi nanoswap, a payment from the Swapper Account to the Order-Router App Account that funds the nanoswap pools' own app-call fees, which the order router app pays when it calls them
6. Application *(to perform up to three swaps, can be repeated)*
   * ID: Order-Router App ID
   * Method: `User_swap`
   * Sender: Any account (pre-signed by the API)
   * Args: \[Number of Swaps, Protocol IDs, Assets, Applications, Accounts, Percent Bps of Balance, Amount In Offsets, Unstructured Metadata, Swap Note]
   * On Complete: NoOp
7. Application *(to finalize)*
   * ID: Order-Router App ID
   * Method: `User_swap_finalize`
   * Sender: Any account (pre-signed by the API)
   * Args: \[Input Asset ID, Output Asset ID, Opt-Out Asset IDs, Minimum Amount Out, Type, Beneficiary Address, Treasury Address, Referrer Address, Fee Bps]
   * On Complete: NoOp
