Skip to content

Pools

A pool holds two different assets, NEAR, NEP-141 or NEP-245, and swaps between them. Pool IDs are counted from 0 in the order pools were created.

Anyone can add liquidity and gets shares. A public pool is created with its first liquidity, and the creator gets 1018 shares for it, so nobody else can set its starting price. Its fees can never change.

The owner, who created it, is the only one who adds and removes liquidity, and can change the fees. The owner can lock the pool, which is final: after that, its liquidity can’t be removed and its fees can’t change. Locking a pool shows traders and holders of a token that its liquidity stays.

For launching a token. The creator gives the pool all of the new token, and sets an amount of phantom liquidity of the quote asset (often NEAR): liquidity that isn’t there, but sets the starting price as if it were. As people buy, real quote asset comes in. A swap that would take the pool’s quote balance below the phantom liquidity fails, so sellers can only take out quote asset that buyers put in.

Launch pools don’t take or give back liquidity after creation, and their fees can’t change. Their fees are always collected in the quote asset. A launch pool quoted in NEAR can also have a community fee.

create_pool takes:

struct CreatePoolArgs {
assets: (AssetId, AssetId),
fees: FeeConfiguration,
pool_type: PoolType,
/// Required for public pools, optional for private pools,
/// not accepted for launch pools
initial_liquidity: Option<(u128, u128)>,
}

See Types for FeeConfiguration and PoolType, and Fees for what a fee configuration can do.

Attach:

  • NEAR for storage, always. What’s left after the storage is sent to your wallet.
  • The initial liquidity, exactly. If one of the assets is NEAR, its amount comes out of the same attached NEAR as the storage.
  • For a launch pool, the launched token (the second asset), all of it. The first asset is the quote asset, and pool_type has the phantom liquidity.

The response is the new pool’s ID, a Borsh u32. This creates a private pool of NEAR and USDT with a 0.3% fee that stays in the pool, and 1 NEAR and 5 USDT of liquidity:

00 asset 0: near
01 16 00 00 00 "usdt.tether-token.near" asset 1: nep141:usdt.tether-token.near
01 fees: V2
01 00 00 00 1 receiver
01 Pool
00 b8 0b 00 00 Fixed(3000), 0.3%
00 pool type: PrivateLatest
01 initial liquidity: Some
00 00 00 a1 ed cc ce 1b c2 d3 00 00 00 00 00 00 1000000000000000000000000 (1 NEAR)
40 4b 4c 00 00 00 00 00 00 00 00 00 00 00 00 00 5000000 (5 USDT)

It runs after a storage deposit, registering NEAR and USDT, and depositing 1.01 NEAR and 5 USDT, as in this script. near --quiet prints only the result, so the pool ID can be kept for the next calls:

Terminal window
# A private pool of NEAR and USDT with a 0.3% fee that stays in the pool, and
# 1 NEAR and 5 USDT of liquidity. The other 0.01 NEAR pays for its storage.
# --quiet prints only the result: the ID of the new pool, in Borsh and base64.
POOL_ID=$(near --quiet contract call-function as-transaction dex.intear.near dex_call \
json-args '{
"dex_id": "slimedragon.near/xyk",
"method": "create_pool",
"args": "AAEWAAAAdXNkdC50ZXRoZXItdG9rZW4ubmVhcgEBAAAAAQC4CwAAAAEAAACh7czOG8LTAAAAAAAAQEtMAAAAAAAAAAAAAAAAAA==",
"attached_assets": {
"near": "1010000000000000000000000",
"nep141:usdt.tether-token.near": "5000000"
}
}' \
prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send | jq -r .)
echo "Created pool $(echo "$POOL_ID" | base64 -d | od -An -tu4)"

get_pool takes a pool ID and returns a Borsh Option<PoolView>, None if there’s no such pool. The pool ID that create_pool returned is already the whole argument:

Terminal window
# The pool ID in Borsh is also the whole argument of get_pool
near contract call-function as-read-only dex.intear.near dex_view \
json-args "$(jq -n --arg pool_id "$POOL_ID" '{
"dex_id": "slimedragon.near/xyk",
"method": "get_pool",
"args": $pool_id
}')" \
network-config mainnet now

A PoolView has the pool’s kind, assets and balances, its fees with the protocol fee, and its fee configuration. get_pools returns several, from start_index, and get_pool_count the number of pools. See Methods.

The owner of a private pool can replace its fee configuration with edit_fees, which takes the pool ID followed by the new configuration. Attach NEAR if the new configuration adds account receivers, for their storage. This sets the fee to 0.1%:

Terminal window
# The pool ID, followed by the new fee: 0.1% that stays in the pool
ARGS=$({ echo "$POOL_ID" | base64 -d; echo "AQEAAAABAOgDAAA=" | base64 -d; } | base64)
near contract call-function as-transaction dex.intear.near dex_call \
json-args "$(jq -n --arg args "$ARGS" '{
"dex_id": "slimedragon.near/xyk",
"method": "edit_fees",
"args": $args,
"attached_assets": {}
}')" \
prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send

lock_pool takes the pool ID. Only the owner can lock a pool, and it can’t be unlocked.

Terminal window
near contract call-function as-transaction dex.intear.near dex_call \
json-args "$(jq -n --arg pool_id "$POOL_ID" '{
"dex_id": "slimedragon.near/xyk",
"method": "lock_pool",
"args": $pool_id,
"attached_assets": {}
}')" \
prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send

Pools made before Plach’s current version are V1: PrivateV1, PublicV1 and LaunchV1. They work, but V1 private pools can’t be locked or take a V2 fee configuration. pool_needs_upgrade says whether a pool is V1, and upgrade_pool upgrades it to V2. Anyone can upgrade any pool, and pays for the storage it takes, with attached NEAR. Both take the pool ID.

The Latest pool types of create_pool create pools of the current version.