# Inner balances

> How Intear DEX holds assets for users and DEXs: registering assets, depositing NEAR, tokens, NFTs and multi tokens, transferring and withdrawing.

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.

The engine holds assets for two kinds of owners: **accounts** (users) and **DEXs**. Each owner has an inner balance per asset. Swaps, transfers and DEX calls only move amounts between inner balances. Tokens leave the engine only when they're withdrawn.

An owner is written as `{ "Account": "alice.near" }` or `{ "Dex": "slimedragon.near/xyk" }` in method arguments.

The [near CLI](https://docs.intear.tech/intear-dex/quickstart.md#before-you-start) examples on this page run in order, as alice.near after a [storage deposit](https://docs.intear.tech/intear-dex/guides/storage.md#accounts). Together they're [one script](#the-whole-script).

## Register assets

An owner can only receive an asset that is registered for it. Anything that would credit an unregistered asset fails with `Asset <asset> is not registered for Account(<account>)`. This includes deposits, the output of swaps, and transfers.

```sh
near contract call-function as-transaction dex.intear.near register_assets \
  json-args '{"asset_ids": ["near", "nep141:usdt.tether-token.near"]}' \
  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/inner-balances.sh

And for another account:

```sh
near contract call-function as-transaction dex.intear.near register_assets \
  json-args '{
    "asset_ids": ["nep141:usdt.tether-token.near"],
    "for": {"Account": "bob.near"}
  }' \
  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/inner-balances.sh

- `for` is optional and defaults to you. You can register assets for another account or for a DEX.
- The storage is always paid from **your** [storage balance](https://docs.intear.tech/intear-dex/guides/storage.md), even when registering for someone else.
- Assets that are already registered are skipped. Registration can't be undone.

Use `are_assets_registered` to check, for example before building a transaction:

```sh
near contract call-function as-read-only dex.intear.near are_assets_registered \
  json-args '{
    "asset_ids": ["near", "nep141:usdt.tether-token.near"],
    "for": {"Account": "alice.near"}
  }' \
  network-config mainnet now
```

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

## Deposit

Deposits credit your inner balance. Each kind of asset arrives in its own way:

| Asset | How to deposit | Credited to |
| --- | --- | --- |
| `near` | `deposit_near` on the engine, with the NEAR attached | The caller |
| `nep141:<contract>` | `ft_transfer_call` on the token, to `dex.intear.near` | `sender_id` |
| `nep171:<contract>:<token id>` | `nft_transfer_call` on the NFT contract, to `dex.intear.near` | `previous_owner_id` |
| `nep245:<contract>:<token id>` | `mt_transfer_call` or `mt_batch_transfer_call` on the contract, to `dex.intear.near` | Each `previous_owner_id` |

Leave `msg` empty (`""`) for a plain deposit, and don't pass `operations` to `deposit_near`. Each plain deposit logs a [`user_deposit`](https://docs.intear.tech/intear-dex/reference/events.md#user_deposit) event.

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

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

```sh
near contract call-function as-transaction usdt.tether-token.near ft_transfer_call \
  json-args '{"receiver_id": "dex.intear.near", "amount": "5000000", "msg": ""}' \
  prepaid-gas '50.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/inner-balances.sh

With a non-empty `msg`, the deposit doesn't go to your inner balance: the tokens are used by the [operations](https://docs.intear.tech/intear-dex/guides/operations.md#operations-in-a-deposit) in `msg`.

If the deposit fails, for example because the asset isn't registered for you, the token contract gets the tokens back to you, as NEP-141, NEP-171 and NEP-245 transfers do when the receiver fails.

:::note
For NEP-141 tokens, the engine itself must be registered on the token contract (have a storage deposit there). The engine is registered on most tokens already. If it's not, call `storage_deposit` on the token with `"account_id": "dex.intear.near"`.
:::

You can also deposit NEAR with [`execute_operations`](https://docs.intear.tech/intear-dex/guides/operations.md#execute_operations): if you attach more than 1 yoctoNEAR, the whole deposit is added to your inner balance before the operations run.

## Check balances

```sh
near contract call-function as-read-only dex.intear.near asset_balance_of \
  json-args '{"of": {"Account": "alice.near"}, "asset_id": "nep141:usdt.tether-token.near"}' \
  network-config mainnet now

near contract call-function as-read-only dex.intear.near registered_assets_of \
  json-args '{"account_id": "alice.near", "from_index": 0, "limit": 100}' \
  network-config mainnet now
```

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

`asset_balance_of` returns the balance, or `null` if the asset isn't registered for the owner.

`registered_assets_of` takes `account_id`, or `dex_id` for a DEX (exactly one of them), and the required `from_index` and `limit`. It returns `[[asset_id, balance], ...]` for at most `limit` registered assets, starting at index `from_index`, in the order they were registered.

## Transfer

`transfer_asset` moves an amount from your inner balance to another account or DEX inside the engine. The receiver must have the asset registered.

```sh
near contract call-function as-transaction dex.intear.near transfer_asset \
  json-args '{
    "to": {"Account": "bob.near"},
    "asset_id": "nep141:usdt.tether-token.near",
    "amount": "1000000"
  }' \
  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/inner-balances.sh

## Withdraw

`withdraw` sends assets from your inner balance out of the engine: NEAR with a transfer, tokens with `ft_transfer`, `nft_transfer` or `mt_transfer`.

A NEP-141 token can only be sent to a wallet that is registered on the token contract. Register bob.near there first, unless they already hold the token:

```sh
near contract call-function as-transaction usdt.tether-token.near storage_deposit \
  json-args '{"account_id": "bob.near", "registration_only": true}' \
  prepaid-gas '30.0 Tgas' attached-deposit '0.00125 NEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send
```

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

Then withdraw to them:

```sh
near contract call-function as-transaction dex.intear.near withdraw \
  json-args '{
    "asset_id": "nep141:usdt.tether-token.near",
    "amount": {"Exact": "2000000"},
    "withdraw_to": "bob.near"
  }' \
  prepaid-gas '50.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/inner-balances.sh

| Argument | Description |
| --- | --- |
| `asset_id` | The asset to withdraw |
| `amount` | `{ "Exact": "<amount>" }`, or `{ "Full": { "at_least": "<amount>" } }` for the whole balance. `Full` fails if the balance is lower than `at_least`. `at_least` can be `null` |
| `withdraw_to` | The wallet to send to. Optional, defaults to you |

The amount leaves your inner balance right away, and the transfer happens in the next receipt. The method returns `true` if the transfer succeeded, and logs a [`withdraw`](https://docs.intear.tech/intear-dex/reference/events.md#withdraw) event.

If the transfer fails, it returns `false` and the assets are refunded to an inner balance:

1. to the receiver (`withdraw_to`), if the asset is registered for them in the engine,
2. otherwise back to you.

Withdrawing an amount of 0 does nothing and returns `true`.

## The whole script

```sh
#!/usr/bin/env bash
# Deposits USDt and NEAR, transfers USDt to bob.near inside the engine, and
# withdraws USDt to bob.near's wallet. 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"]}' \
  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 dex.intear.near register_assets \
  json-args '{
    "asset_ids": ["nep141:usdt.tether-token.near"],
    "for": {"Account": "bob.near"}
  }' \
  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-read-only dex.intear.near are_assets_registered \
  json-args '{
    "asset_ids": ["near", "nep141:usdt.tether-token.near"],
    "for": {"Account": "alice.near"}
  }' \
  network-config mainnet now

near contract call-function as-transaction dex.intear.near deposit_near \
  json-args '{}' \
  prepaid-gas '30.0 Tgas' attached-deposit '1 NEAR' \
  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": "5000000", "msg": ""}' \
  prepaid-gas '50.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send

near contract call-function as-read-only dex.intear.near asset_balance_of \
  json-args '{"of": {"Account": "alice.near"}, "asset_id": "nep141:usdt.tether-token.near"}' \
  network-config mainnet now

near contract call-function as-read-only dex.intear.near registered_assets_of \
  json-args '{"account_id": "alice.near", "from_index": 0, "limit": 100}' \
  network-config mainnet now

near contract call-function as-transaction dex.intear.near transfer_asset \
  json-args '{
    "to": {"Account": "bob.near"},
    "asset_id": "nep141:usdt.tether-token.near",
    "amount": "1000000"
  }' \
  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 storage_deposit \
  json-args '{"account_id": "bob.near", "registration_only": true}' \
  prepaid-gas '30.0 Tgas' attached-deposit '0.00125 NEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send

near contract call-function as-transaction dex.intear.near withdraw \
  json-args '{
    "asset_id": "nep141:usdt.tether-token.near",
    "amount": {"Exact": "2000000"},
    "withdraw_to": "bob.near"
  }' \
  prepaid-gas '50.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send
```
