Decentralized Spot Exchange (Spot)
The x/spot module is responsible for creating, joining, and
exiting liquidity pools that are dictated by an AMM for swaps.
Creation of Pool
When a pool is created, a fixed amount of 100 LP shares is minted and
sent to the pool creator. The base pool share denom is in the format of
nibiru/pool/{poolId} and is displayed in the format of
NIBIRU-POOL-{poolId} to the user. One NIBIRU-POOL-{poolId} token is
equivalent to 10^18 nibiru/pool/{poolId} tokens.
Pool assets are sorted in alphabetical order by default.
You can create a pool with the nibiru-py package with:
import nibiru as nib
tx_config = nib.TxConfig(tx_type=TxType.BLOCK)
trader = nib.Sdk.authorize(MNEMONIC).with_config(tx_config)
trader.tx.execute_msgs(
nib.msg.MsgCreatePool(
creator=trader.address,
swap_fee=0.02,
exit_fee=0.1,
assets=[
nib.PoolAsset(
token=nib.Coin(
denom="unibi",
amount=1000,
),
weight=50
),
nib.PoolAsset(
token=nib.Coin(
denom="unusd",
amount=10000,
),
weight=50
),
]
)
)
You can then query the pools with the spot queries:
trader.query.spot.pools()
Joining Pool
When joining a pool, users provide the tokens they are willing to deposit. The application will try to deposit as many tokens as it can while maintaining equal weight ratios across the pool’s assets. Usually this means one asset acts as a limiting factor and all other tokens are deposited in proportion to the limited token.
For example, assume there is a 50/50 pool with 100 tokenA and 100
tokenB. A user wishes to LP 10 tokenA and 5 tokenB into the
pool. Because tokenB is the limiting factor, all of tokenB will
be deposited and only 5 of tokenA will be deposited. The user will
be left with 5 tokenA and receive LP shares for the liquidity they
provided.
trader.tx.execute_msgs(
nib.msg.JoinPool(
sender=trader.address,
pool_id=4,
tokens=[
nib.Coin(
denom="unibi",
amount=10000,
),
nib.Coin(
denom="unusd",
amount=10000,
)
]
)
)
trader.query.get_bank_balance(
trader.address,
denom="nibiru/pool/4"
)
"""
balance {
denom: "nibiru/pool/4"
amount: "200000000000000000000"
}
"""
Exiting Pool
When exiting the pool, the user also provides the number of LP shares they are returning to the pool, and will receive assets in proportion to the LP shares returned. However, unlike joining a pool, exiting a pool requires the user to pay the exit fee, which is set as the param of the pool. The share of the user gets burnt.
For example, assume there is a 50/50 pool with 50 tokenA and 150
tokenB and 200 total LP shares minted. A user wishes to return 20 LP
shares to the pool and withdraw their liquidity. Because 20/200 = 10%,
the user will receive 5 tokenA and 15 tokenB from the pool,
minus exit fees.
trader.tx.spot.exit_pool(
sender=trader.address,
pool_id=4,
pool_shares=nib.Coin(denom="nibiru/pool/4",amount=50000000000000000000)
)
trader.query.get_bank_balance(trader.address, denom="nibiru/pool/4")
"""
balance {
denom: "nibiru/pool/4"
amount: "150000000000000000000"
}
"""
Swap
During the process of swapping a specific asset, the token user is
putting into the pool is justified as tokenIn, while the token that
would be omitted after the swap is justified as tokenOut throughout
the module.
Given a tokenIn, the following calculations are done to calculate how much tokens are to be swapped and ommitted from the pool.
tokenBalanceOut * [ 1 - { tokenBalanceIn / (tokenBalanceIn+(1-swapFee) * tokenAmountIn)}^(tokenWeightIn/tokenWeightOut)]
The whole process is also able vice versa, the case where user provides tokenOut. The calculation for the amount of token that the user should be putting in is done through the following formula.
tokenBalanceIn * [{tokenBalanceOut / (tokenBalanceOut - tokenAmountOut)}^(tokenWeightOut/tokenWeightIn)-1] / tokenAmountIn
trader.tx.execute_msgs(
nib.msg.MsgSwapAssets(
sender=trader.address,
pool_id=4,
token_in=nib.Coin(denom="unusd",amount=1000000000),
token_out_denom="unibi"
)
)
The queries in the spot query module can give estimate of the output of this command with the current reserves of the pool:
trader.query.spot.estimate_swap_exact_amount_in(
pool_id=4,
token_in=nib.Coin(denom="unibi", amount=10000),
token_out_denom="unusd"
)
Spot Price
Meanwhile, calculation of the spot price with a swap fee is done using the following formula
spotPrice / (1-swapFee)
where spotPrice is
(tokenBalanceIn / tokenWeightIn) / (tokenBalanceOut / tokenWeightOut)
You can query the spot price with:
trader.query.spot.spot_price(
pool_id=4,
token_in_denom="unibi",
token_out_denom="unusd"
)