Liquidity
This page is also Markdown, for agents: /plach/guides/liquidity.md, and /llms.txt lists every page.
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.
All of these are dex_calls. 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.
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 sendPublic pools
Section titled “Public pools”Register
Section titled “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 in both assets, as they’re paid.
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 sendThe creator of a public pool is registered already, with the payout it chose in create_pool.
add_liquidity takes the pool ID and the least shares you accept:
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:
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 sendSet 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 1018 shares, and min_shares_received must be None. Attach them at the market ratio, or arbitrage takes the difference.
Your shares
Section titled “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.
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 nowYour part of the pool is shares / total_shares of each of its balances. get_pool returns total_shares and the balances. If you reinvest your fees, your shares grow with every swap, and get_pool_shares already counts what they grew into.
Remove
Section titled “Remove”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:
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 sendA 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:
| 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, 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:
# Take this pool's fees in USDt, its second asset, from now onnear 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 sendget_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:
struct LiquidityPositionView { payout_type: FeePayoutType, /// Fees in each asset of the pool that aren't collected yet uncollected_fees: (u128, u128),}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 nowcollect_liquidity_fees takes the pool ID and collects your fees without changing anything else. Then withdraw them:
# Move the pool's fees earned so far to the fees that withdraw_fees withdrawsnear 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 sendPrivate pools
Section titled “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 (1018) is all of it, and None also means all of it. A locked pool’s liquidity can’t be removed.
Events
Section titled “Events”Adding and removing liquidity log LiquidityAdded and LiquidityRemoved, with the amounts, the shares, and what the provider owns after. Collecting fees logs LiquidityFeesCollected, and a new payout LiquidityFeePayoutSet.
The whole script
Section titled “The whole script”#!/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 onnear 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 withdrawsnear 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