Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dex): add single asset join #1038

Merged
merged 10 commits into from
Nov 1, 2022
Merged

feat(dex): add single asset join #1038

merged 10 commits into from
Nov 1, 2022

Conversation

matthiasmatt
Copy link
Contributor

@matthiasmatt matthiasmatt commented Oct 27, 2022

xyk math to optimize join

Introduction

Let say I have 20 ATOM and 10 USDC and I want to join a ATOM-USDC xyk pool with these funds. Considering an even weighted pool, and the current price of $14.31 USDC per ATOM, I would need to first swap some ATOM to get more USDC in order to get the maximum amount of tokens.

Most of the protocols are currently defining the amount of token you can get using a binary search method, but math can give us an algaebric solution to this, and save some iterations for our precious nodes.

Math notation

We will write $x$ and $y$ the respective amount of ATOM and USDC tokens we want to use to join a price. We will also note $l_{x}$ and $l_{y}$ the liquidity of the pool in both denomination.

We will also consider $f$ the swapping fee of the protocol, and $k$ our invariant such as $k=l_{x}\times l_{y}$

Swap

In our case, we will first swap a quantity $x'$ of ATOM tokens to get $y'$ USDC and then join our pool.

Using our invariant $xy=k$ to our problem and applying fees, we get:

$$\left\{ \begin{array}{ll} & l_x \times l_y = k \\\ & \left[l_x+(x'\times(1-f)\right] \times (l_y+y') = k \\\ \end{array} \right. \\\\\ \mbox {Which means:}\\\ \begin{align} y' & = l_y \times (1-\frac{l_x}{l_x + x' \times (1-f)}) \\ y' & = l_y - \frac{k}{l_x + x' \times (1-f)} \end{align}$$

Which means that we know how much tokens we get our of our swap based on the tokens given in.

Using this, we then need to define the value of $y + y'$ in relation to our $x - x'$ of ATOM that we will have after the swap.

Join the pool

The logic to join a pool for a n token $x_1x_2...x_n=k$ pool with no weight is to find minimum amount of share of the pool we can get from $x$ token and $y$ token.

Meaning:

$$s_{out} = \min_{\forall i \in [1,n]} \left(s_i =\frac{x_i}{l_i}\right)$$

Which means that in order to have the highest possible share of the pool, we need to have all $s_i$ equals. Otherwise,

$$\exists i \in [1,n] \text{ such as } \left\{ \begin{array}{ll} & s_i = s_{out} + \frac{x_i'}{l_i} \\\ & x_i' > 0 \\\ \end{array} \right.$$

This means that we have $x'i$ amount of crypto that can be swapped for other denom to have a bigger $s{out}$.

Back to our problem, if we have our wallet with $y+y'$ USDC and $x-x'$ ATOM, we can maximise our share by satisfying the equality:

$$\frac {y + y'}{l_y'} = \frac {x - x'}{l_x'}$$

The liquidity of the pool was changed by the initial swap, which are represented by $l_y'$ and $l_x'$ .

We can compute their values as:

$$l_y'=l_y-y' \\\ l_x'=l_x + (1+f) \times x'$$

By combining $\mbox{(1), (2) and (3)}$, we get:

$$\frac {y + y'}{l_y-y'} = \frac {x - x'}{l_x + (1+f) \times x'} \\\ \frac {y + l_y - \frac{k}{l_x + x' \times (1-f)}}{\frac{k}{l_x + x' \times (1-f)}} = \frac {x - x'}{l_x + (1+f) \times x'}\\\ [{l_x + x' \times (1-f)}]\frac {(y + l_y) }{k} - 1 = \frac {x - x'}{l_x + (1+f) \times x'}$$

Because of the term in $f$, solving this means solving the root of a heavy quadratic formula:

$$\left(y-yf^2+l_y-f^2l_y\right)x'^2+\left(-fk+2yl_x+2l_yl_x\right)x'+y\left(l_x\right)^2+\left(l_x\right)^2l_y-kl_x-xk=0$$

For the sanity of the reader, we will compute the solution for a pool where the swap fee $f=0$.

At Nibiru, we assume that by entering a pool for LP your fees are paid by the join/exit fees of the pool. For this reason joining with a single asset or with an imbalance will inccur no swapping fee.

$(4)$ becomes:

$$\frac{\left(y+l_y\right)\left(l_x+x'\right)^2}{k}-\left(l_x+x'\right)=x-x'\\\ \frac{\left(y+l_y\right)\left(l_x+x'\right)^2}{k}-l_x=x\\\ \frac{\left(y+l_y\right)\left(l_x+x'\right)^2k}{k}=xk+l_xk;\quad \:k\ne \:0\\\ \left(l_x+x'\right)^2=\frac{xk+kl_x}{y+l_y};\quad \:k\ne \:0,\:y+x'_y\ne \:0\\$$

Our solutions are then:

$$x'=\sqrt{\frac{xk+kl_x}{y+l_y}}-l_x;\:x'=-\sqrt{\frac{xk+kl_x}{y+l_y}}-l_x$$

Of course, since we want a positive $x'$, our final solution will be the first term.

Practical example

Let's say Alice want to join the ATOM-NUSD pool in Nibiru with:

  • Liquidity in the pool: 35,000 ATOM - 500,000 NUSD (instant price 14.28)
  • Alice want to open a position with x=700 ATOM and y=3,000 NUSD

The individual shares without swapping would be $s_{atom}=2%;s_{nusd}=0.6%$. Which means we would join the pool with 3,000 NUSD and 210 ATOM ($0.6% \times 35000$).

This means that we will need to swap some ATOM to get more NUSD.

We have:

$$\begin{align} x' & =\sqrt{\frac{xk+kl_x}{y+l_y}}-l_x \\\ & =\sqrt{\frac{700\times 17.5 billion + 17.5 billion \times 35,000}{3,000+500,000}}-35,000\\\ & = 242.7 \end{align}$$

Let's simulate this transaction to showcase the result:

  • Alice swaps 242.7 ATOM
  • She receives (see eq 1) $y' = l_y - \frac{k}{l_x + x'}=3,443.27$ NUSD
  • Pool liquidity is now: 35,242.7 ATOM - 496,556.73 NUSD
  • Her wallet is now 457.3 ATOM - 6,443.27 NUSD
  • Individual shares are now:
    • $s_{atom} = 457.3 / 35,242.7 * 10000 = 129.76bp$
    • $s_{nusd} = 6443.27 / 496556.73 * 10000 = 129.76bp$
  • She can now safely join the pool and receive shares worth $1.2976%$ of the pool

@matthiasmatt matthiasmatt marked this pull request as ready for review October 31, 2022 18:51
@matthiasmatt matthiasmatt requested a review from a team as a code owner October 31, 2022 18:51
x/dex/types/shares.go Outdated Show resolved Hide resolved
x/dex/types/shares.go Outdated Show resolved Hide resolved
@matthiasmatt matthiasmatt merged commit 9585eba into master Nov 1, 2022
@matthiasmatt matthiasmatt deleted the mat/single-asset-join branch November 1, 2022 10:09
@matthiasmatt matthiasmatt linked an issue Nov 1, 2022 that may be closed by this pull request
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat(dex): single asset join
3 participants