# Swaps

> Swapping on Intear DEX: swap_simple, exact input and exact output, constraints, simulating a swap, and chaining swaps through several pools or DEXs.

This page is part of the Intear DEX docs. Intear DEX is the `dex.intear.near` contract. https://docs.intear.tech/intear-dex/llms-full.txt has all of its pages in one file, and https://docs.intear.tech/llms.txt lists every page of the Intear docs.

A swap trades one asset for another on one DEX. The DEX decides the amounts, the engine moves the assets: `amount_in` from the trader to the DEX, `amount_out` from the DEX to the trader.

The [near CLI](https://docs.intear.tech/intear-dex/quickstart.md#before-you-start) examples on this page swap USDt from alice.near's inner balance, after a [storage deposit](https://docs.intear.tech/intear-dex/guides/storage.md#accounts), these registrations, and a [deposit](https://docs.intear.tech/intear-dex/guides/inner-balances.md#deposit) of 10 USDt. Together they're [one script](#the-whole-script).

```sh
near contract call-function as-transaction dex.intear.near register_assets \
  json-args '{
    "asset_ids": [
      "near",
      "nep141:usdt.tether-token.near",
      "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1"
    ]
  }' \
  prepaid-gas '30.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send
```

The whole file, tested in CI: https://docs.intear.tech/snippets/cli/swaps.sh

## Simulate

`simulate_swap_simple` is a view method that runs a swap without saving anything. It takes the same arguments as `swap_simple` plus `trader`, the account the DEX should see as the trader, and without `constraint`. It returns `[amount_in, amount_out]`.

This one asks how much USDt it takes to get exactly 0.1 NEAR, and allows 1% more for the swap:

```sh
AMOUNT_IN=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "message": "AQAAAEBCDwABAAAA3QAAAAA=",
    "trader": "alice.near",
    "asset_in": "nep141:usdt.tether-token.near",
    "asset_out": "near",
    "amount": {"ExactOut": "100000000000000000000000"}
  }' \
  network-config mainnet now | jq -r '.[0]')
# Pay up to 1% more than the simulation
MAX_AMOUNT_IN=$((AMOUNT_IN * 101 / 100))
```

The whole file, tested in CI: https://docs.intear.tech/snippets/cli/swaps.sh

The simulation doesn't check balances or registrations, so a swap that simulates fine can still fail for those reasons.

## `swap_simple`

```sh
near contract call-function as-transaction dex.intear.near swap_simple \
  json-args "$(jq -n --arg max_amount_in "$MAX_AMOUNT_IN" '{
    "dex_id": "slimedragon.near/xyk",
    "message": "AQAAAEBCDwABAAAA3QAAAAA=",
    "asset_in": "nep141:usdt.tether-token.near",
    "asset_out": "near",
    "amount": {"ExactOut": "100000000000000000000000"},
    "constraint": $max_amount_in
  }')" \
  prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send
```

The whole file, tested in CI: https://docs.intear.tech/snippets/cli/swaps.sh

| Argument | Description |
| --- | --- |
| `dex_id` | The [DEX](https://docs.intear.tech/intear-dex/guides/dexes.md) to swap on |
| `message` | Base64 bytes passed to the DEX as is. Each DEX defines its own format, usually the pool or route. For Plach, `AQAAAEBCDwABAAAA3QAAAAA=` is pool 221 (NEAR/USDt) and `AQAAAEBCDwABAAAAVQAAAAA=` is pool 85 (NEAR/USDC). See [Plach routes](https://docs.intear.tech/plach/guides/swaps.md#the-message) |
| `asset_in`, `asset_out` | The assets to swap |
| `amount` | `{"ExactIn": "<amount>"}` to pay an exact amount, or `{"ExactOut": "<amount>"}` to receive an exact amount |
| `constraint` | Optional. With `ExactIn`, the minimum `amount_out`. With `ExactOut`, the maximum `amount_in`. The swap fails if it's not met |
| `referrer` | Optional. Passed to the DEX in the swap request, and logged in the [`swap`](https://docs.intear.tech/intear-dex/reference/events.md#swap) event and with the events the DEX logs. It doesn't charge anything, and Plach ignores it. Pass the same referrer to the simulation, in case a DEX uses it |
| `referral_fees` | Optional. Fees for your app, out of the input, like `[["myapp.near", 5000]]` for 0.5%. See [Referral fees](https://docs.intear.tech/intear-dex/guides/referral-fees.md). Pass the same fees to the simulation |

It returns `[amount_in, amount_out]`. `amount_in` includes the referral fees.

Before swapping:

- Your inner balance must have at least `amount_in` of `asset_in`.
- `asset_out` must be registered for you, or the output can't be credited.

If anything fails, including the constraint, the whole call fails and no balances change.

:::tip
Always pass `constraint`. Pool prices can move between the time you simulate and the time the swap runs. The constraint is your slippage limit.
:::

## What the engine checks

The DEX returns `amount_in` and `amount_out`. The engine then checks that:

- with `ExactIn`, the DEX's `amount_in` equals the requested amount, minus the [referral fees](https://docs.intear.tech/intear-dex/guides/referral-fees.md) (`Amount in does not match` otherwise),
- with `ExactOut`, the DEX's `amount_out` equals the requested amount (`Amount out does not match` otherwise),
- the `constraint` holds, with the referral fees included in the input,
- the DEX has enough `asset_out` in its inner balance.

The DEX can't take more than `amount_in` from you or give out tokens it doesn't hold.

## Several swaps in one call

To swap through several pools or DEXs, use [`execute_operations`](https://docs.intear.tech/intear-dex/guides/operations.md) with several `SwapSimple` operations. Each one can take the output of the previous one as input with `"amount": "OutputOfLastIn"`.

This swaps 1 USDt to USDC through NEAR, with two Plach pools. To get the least USDC to accept, simulate each swap with the output of the one before:

```sh
NEAR_OUT=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "message": "AQAAAEBCDwABAAAA3QAAAAA=",
    "trader": "alice.near",
    "asset_in": "nep141:usdt.tether-token.near",
    "asset_out": "near",
    "amount": {"ExactIn": "1000000"}
  }' \
  network-config mainnet now | jq -r '.[1]')
USDC_OUT=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \
  json-args "$(jq -n --arg near_out "$NEAR_OUT" '{
    "dex_id": "slimedragon.near/xyk",
    "message": "AQAAAEBCDwABAAAAVQAAAAA=",
    "trader": "alice.near",
    "asset_in": "near",
    "asset_out": "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
    "amount": {"ExactIn": $near_out}
  }')" \
  network-config mainnet now | jq -r '.[1]')
MIN_USDC_OUT=$((USDC_OUT * 99 / 100))
```

The whole file, tested in CI: https://docs.intear.tech/snippets/cli/swaps.sh

```sh
near contract call-function as-transaction dex.intear.near execute_operations \
  json-args "$(jq -n --arg min_usdc_out "$MIN_USDC_OUT" '{
    "operations": [
      {
        "SwapSimple": {
          "dex_id": "slimedragon.near/xyk",
          "message": "AQAAAEBCDwABAAAA3QAAAAA=",
          "asset_in": "nep141:usdt.tether-token.near",
          "asset_out": "near",
          "amount": {"Amount": {"ExactIn": "1000000"}},
          "constraint": null
        }
      },
      {
        "SwapSimple": {
          "dex_id": "slimedragon.near/xyk",
          "message": "AQAAAEBCDwABAAAAVQAAAAA=",
          "asset_in": "near",
          "asset_out": "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
          "amount": "OutputOfLastIn",
          "constraint": $min_usdc_out
        }
      }
    ]
  }')" \
  prepaid-gas '200.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send
```

The whole file, tested in CI: https://docs.intear.tech/snippets/cli/swaps.sh

Put the constraint on the last swap: it limits the result of the whole chain. The intermediate assets must be registered for you, because each output is credited to your inner balance before the next swap takes it.

[Plach can also route](https://docs.intear.tech/plach/guides/swaps.md#through-several-pools) through several of its pools in one swap, with a longer route in `message`. Several `SwapSimple` operations are for routes that go through different DEXs, or when you build the route yourself.

To swap on whichever of several DEXs or routes gives the most, or to fall back to another when one fails, use a [`SwapAdvanced`](https://docs.intear.tech/intear-dex/guides/operations.md#best-of-several-dexs) operation.

## The whole script

```sh
#!/usr/bin/env bash
# Swaps USDt from the inner balance: for an exact amount of NEAR, then to USDC
# through NEAR in one call. alice.near holds USDt in the wallet and has never
# used Intear DEX.
set -euo pipefail

near contract call-function as-transaction dex.intear.near storage_deposit \
  json-args '{}' \
  prepaid-gas '30.0 Tgas' attached-deposit '0.01 NEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send

near contract call-function as-transaction dex.intear.near register_assets \
  json-args '{
    "asset_ids": [
      "near",
      "nep141:usdt.tether-token.near",
      "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1"
    ]
  }' \
  prepaid-gas '30.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send

near contract call-function as-transaction usdt.tether-token.near ft_transfer_call \
  json-args '{"receiver_id": "dex.intear.near", "amount": "10000000", "msg": ""}' \
  prepaid-gas '50.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send

AMOUNT_IN=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "message": "AQAAAEBCDwABAAAA3QAAAAA=",
    "trader": "alice.near",
    "asset_in": "nep141:usdt.tether-token.near",
    "asset_out": "near",
    "amount": {"ExactOut": "100000000000000000000000"}
  }' \
  network-config mainnet now | jq -r '.[0]')
# Pay up to 1% more than the simulation
MAX_AMOUNT_IN=$((AMOUNT_IN * 101 / 100))

near contract call-function as-transaction dex.intear.near swap_simple \
  json-args "$(jq -n --arg max_amount_in "$MAX_AMOUNT_IN" '{
    "dex_id": "slimedragon.near/xyk",
    "message": "AQAAAEBCDwABAAAA3QAAAAA=",
    "asset_in": "nep141:usdt.tether-token.near",
    "asset_out": "near",
    "amount": {"ExactOut": "100000000000000000000000"},
    "constraint": $max_amount_in
  }')" \
  prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send

NEAR_OUT=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "message": "AQAAAEBCDwABAAAA3QAAAAA=",
    "trader": "alice.near",
    "asset_in": "nep141:usdt.tether-token.near",
    "asset_out": "near",
    "amount": {"ExactIn": "1000000"}
  }' \
  network-config mainnet now | jq -r '.[1]')
USDC_OUT=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \
  json-args "$(jq -n --arg near_out "$NEAR_OUT" '{
    "dex_id": "slimedragon.near/xyk",
    "message": "AQAAAEBCDwABAAAAVQAAAAA=",
    "trader": "alice.near",
    "asset_in": "near",
    "asset_out": "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
    "amount": {"ExactIn": $near_out}
  }')" \
  network-config mainnet now | jq -r '.[1]')
MIN_USDC_OUT=$((USDC_OUT * 99 / 100))

near contract call-function as-transaction dex.intear.near execute_operations \
  json-args "$(jq -n --arg min_usdc_out "$MIN_USDC_OUT" '{
    "operations": [
      {
        "SwapSimple": {
          "dex_id": "slimedragon.near/xyk",
          "message": "AQAAAEBCDwABAAAA3QAAAAA=",
          "asset_in": "nep141:usdt.tether-token.near",
          "asset_out": "near",
          "amount": {"Amount": {"ExactIn": "1000000"}},
          "constraint": null
        }
      },
      {
        "SwapSimple": {
          "dex_id": "slimedragon.near/xyk",
          "message": "AQAAAEBCDwABAAAAVQAAAAA=",
          "asset_in": "near",
          "asset_out": "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
          "amount": "OutputOfLastIn",
          "constraint": $min_usdc_out
        }
      }
    ]
  }')" \
  prepaid-gas '200.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send
```
