# Liquidity

> Providing liquidity on Plach: registering for shares, adding and removing liquidity in public pools, taking or reinvesting their fees, and liquidity of private pools.

This page is part of the Plach docs. Plach is the DEX `slimedragon.near/xyk` on the Intear DEX contract, `dex.intear.near`, and every call goes to that contract. https://docs.intear.tech/plach/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.

Liquidity is what a pool trades against. In a **public** pool anyone can add liquidity and gets shares of the pool, which earn the pool's `Pool` fees. In a **private** pool only the owner adds and removes it. Launch pools don't take liquidity after creation. See [Pools](https://docs.intear.tech/plach/guides/pools.md).

All of these are [`dex_call`](https://docs.intear.tech/intear-dex/guides/dexes.md#dex_call)s. The assets you attach come from your inner balance. What comes back, the assets of removed liquidity and what an addition didn't use, is sent to your wallet.

The examples on this page add liquidity to pool 221, NEAR/USDt, choose how to take its fees, and remove it, after this setup. Together they're [one script](#the-whole-script).

```sh
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 deposit_near \
  json-args '{}' \
  prepaid-gas '30.0 Tgas' attached-deposit '1.01 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": "10000000", "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/plach-liquidity.sh

:::caution
Assets sent to your wallet need it to be registered on their token contracts. If a transfer fails, the engine puts the assets in your inner balance, but only if they're [registered](https://docs.intear.tech/intear-dex/guides/inner-balances.md#register-assets) for you there. If they're not, they go back to Plach's inner balance, and they're no longer yours. Register the assets of a pool for yourself before you remove liquidity.
:::

## Public pools

### Register

Before your first addition to a pool, register for its shares with `register_liquidity`. Its argument is the pool ID, a Borsh `u32`. Attach NEAR for the storage: Plach uses what it needs and sends the rest to your wallet. A new provider takes its [fees](#fees) in both assets, as they're paid.

```sh
near contract call-function as-transaction dex.intear.near dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "register_liquidity",
    "args": "3QAAAA==",
    "attached_assets": {"near": "10000000000000000000000"}
  }' \
  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/plach-liquidity.sh

The creator of a public pool is registered already, with the payout it chose in `create_pool`.

### Add

`add_liquidity` takes the pool ID and the least shares you accept:

```rust
struct AddLiquidityArgs {
    pool_id: u32,
    /// Not `Some(0)`
    min_shares_received: Option<u128>,
}
```

Attach both assets of the pool. Plach mints shares for the amounts in the pool's current ratio, limited by the asset you attached less of, takes what that needs of each, and sends the rest to your wallet. So attach a bit more than the ratio needs of both. `3QAAAAA=` is pool 221 with no minimum:

```sh
near contract call-function as-transaction dex.intear.near dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "add_liquidity",
    "args": "3QAAAAA=",
    "attached_assets": {
      "near": "1000000000000000000000000",
      "nep141:usdt.tether-token.near": "10000000"
    }
  }' \
  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/plach-liquidity.sh

Set `min_shares_received` to fail if the ratio moved before your call, instead of adding liquidity at a worse price.

A public pool whose liquidity was all removed has `total_shares` `None` and both balances at 0, and many have. Adding to one works differently: all of both attached amounts go in, their ratio becomes the pool's price, you get 10<sup>18</sup> shares, and `min_shares_received` must be `None`. Attach them at the market ratio, or arbitrage takes the difference.

### Your shares

`get_pool_shares` takes a list of pool IDs and an account, and returns a Borsh `Vec<Option<u128>>`: the shares in each pool, or `None` if the account isn't registered for it.

```sh
near contract call-function as-read-only dex.intear.near dex_view \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "get_pool_shares",
    "args": "AQAAAN0AAAAKAAAAYWxpY2UubmVhcg=="
  }' \
  network-config mainnet now
```

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

Your part of the pool is `shares / total_shares` of each of its balances. [`get_pool`](https://docs.intear.tech/plach/reference/methods.md#views) returns `total_shares` and the balances. If you [reinvest](#fees) your fees, your shares grow with every swap, and `get_pool_shares` already counts what they grew into.

### Remove

```rust
struct RemoveLiquidityArgs {
    pool_id: u32,
    /// All of your shares if `None`. Not `Some(0)`
    shares_to_remove: Option<u128>,
    /// Fails if you'd get less of either asset
    min_assets_received: Option<(u128, u128)>,
}
```

Don't attach anything. Your part of both assets is sent to your wallet. `3QAAAAAA` removes all of your liquidity from pool 221, without minimums:

```sh
near contract call-function as-transaction dex.intear.near dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "remove_liquidity",
    "args": "3QAAAAAA",
    "attached_assets": {}
  }' \
  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/plach-liquidity.sh

### Fees

A public pool's `Pool` fees go to its providers, in proportion to their shares. Each provider chooses how it takes its part, with a [`FeePayoutType`](https://docs.intear.tech/plach/guides/fees.md#the-asset-a-fee-is-paid-in):

| Payout | What you get |
| --- | --- |
| `KeepBoth` | The fee in the asset each swap paid in, so some of both. New providers start with it |
| `ConvertToFirstAsset`, `ConvertToSecondAsset` | All of it in one of the pool's assets. The pool swaps the fees paid in the other asset into it, without fees |
| `Reinvest` | More shares of the pool: the fee stays in it, and your shares grow |

Fees you take out wait in the pool until you collect them. Adding liquidity, removing it, changing the payout and `collect_liquidity_fees` all collect them to your [collected fees](https://docs.intear.tech/plach/guides/fees.md#collected-fees), which `withdraw_fees` moves to your inner balance. What the pool can't split evenly between providers, after rounding, stays in it.

`set_liquidity_fee_payout` takes the pool ID and the new payout. It collects what you earned so far first. `3QAAAAI=` is pool 221 and `ConvertToSecondAsset`, USDt:

```sh
# Take this pool's fees in USDt, its second asset, from now on
near contract call-function as-transaction dex.intear.near dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "set_liquidity_fee_payout",
    "args": "3QAAAAI=",
    "attached_assets": {}
  }' \
  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/plach-liquidity.sh

`get_liquidity_position` takes the pool ID and an account, and returns a Borsh `Option<LiquidityPositionView>`, `None` if the account isn't registered for the pool:

```rust
struct LiquidityPositionView {
    payout_type: FeePayoutType,
    /// Fees in each asset of the pool that aren't collected yet
    uncollected_fees: (u128, u128),
}
```

```sh
near contract call-function as-read-only dex.intear.near dex_view \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "get_liquidity_position",
    "args": "3QAAAAoAAABhbGljZS5uZWFy"
  }' \
  network-config mainnet now
```

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

`collect_liquidity_fees` takes the pool ID and collects your fees without changing anything else. Then [withdraw them](https://docs.intear.tech/plach/guides/fees.md#withdraw-fees):

```sh
# Move the pool's fees earned so far to the fees that withdraw_fees withdraws
near contract call-function as-transaction dex.intear.near dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "collect_liquidity_fees",
    "args": "3QAAAA==",
    "attached_assets": {}
  }' \
  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/plach-liquidity.sh

## Private pools

The owner of a private pool adds liquidity with `add_liquidity` too, but there are no shares: all attached assets go into the pool, in any ratio, and `min_shares_received` must be `None`. The ratio is the price, so adding unevenly moves it.

To remove, `shares_to_remove` is the part of the pool to take out, where `1000000000000000000` (10<sup>18</sup>) is all of it, and `None` also means all of it. A [locked](https://docs.intear.tech/plach/guides/pools.md#lock-a-private-pool) pool's liquidity can't be removed.

## Events

Adding and removing liquidity log [`LiquidityAdded`](https://docs.intear.tech/plach/reference/events.md#liquidityadded) and [`LiquidityRemoved`](https://docs.intear.tech/plach/reference/events.md#liquidityremoved), with the amounts, the shares, and what the provider owns after. Collecting fees logs [`LiquidityFeesCollected`](https://docs.intear.tech/plach/reference/events.md#liquidityfeescollected), and a new payout [`LiquidityFeePayoutSet`](https://docs.intear.tech/plach/reference/events.md#liquidityfeepayoutset).

## The whole script

```sh
#!/usr/bin/env bash
# Adds liquidity to the NEAR/USDt pool on Plach, chooses how to take its fees,
# and removes it. 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 deposit_near \
  json-args '{}' \
  prepaid-gas '30.0 Tgas' attached-deposit '1.01 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": "10000000", "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-transaction dex.intear.near dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "register_liquidity",
    "args": "3QAAAA==",
    "attached_assets": {"near": "10000000000000000000000"}
  }' \
  prepaid-gas '100.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 dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "add_liquidity",
    "args": "3QAAAAA=",
    "attached_assets": {
      "near": "1000000000000000000000000",
      "nep141:usdt.tether-token.near": "10000000"
    }
  }' \
  prepaid-gas '100.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 dex_view \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "get_pool_shares",
    "args": "AQAAAN0AAAAKAAAAYWxpY2UubmVhcg=="
  }' \
  network-config mainnet now

# Take this pool's fees in USDt, its second asset, from now on
near contract call-function as-transaction dex.intear.near dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "set_liquidity_fee_payout",
    "args": "3QAAAAI=",
    "attached_assets": {}
  }' \
  prepaid-gas '100.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 dex_view \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "get_liquidity_position",
    "args": "3QAAAAoAAABhbGljZS5uZWFy"
  }' \
  network-config mainnet now

# Move the pool's fees earned so far to the fees that withdraw_fees withdraws
near contract call-function as-transaction dex.intear.near dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "collect_liquidity_fees",
    "args": "3QAAAA==",
    "attached_assets": {}
  }' \
  prepaid-gas '100.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 dex_call \
  json-args '{
    "dex_id": "slimedragon.near/xyk",
    "method": "remove_liquidity",
    "args": "3QAAAAAA",
    "attached_assets": {}
  }' \
  prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as alice.near network-config mainnet sign-with-keychain send
```
