v2-periphery
v2-periphery copied to clipboard
math error in computeProfitMaximizingTrade
I was working out the math behind computeProfitMaximizingTrade and I discovered an issue there
assuming a, b are reserve0 and reserve1, the math in that function: sqrt(a*b*price/0.997) - a/0.997
differs from what I got by working it back from the spot price: (sqrt(a*b*price) - a)/0.997
Here's how I worked it out:
Starting with price = a / b
, then applying the post-trade reserve amounts or price = (a+0.997x)/((a*b) / (a+0.997x))
, assuming x is the input amount, we get (a+0.997x)**2 / (a*b)
After expanding that we get (sqrt(a*b*price) - a)/0.997
It's likely that this wasn't noticed so far due to the relatively small impact of this error
Update: the correct formula for spot is actually (a+x)/(a*b / (a+0.997x))
, but even with that I can't work it out to sqrt(a*b*price/0.997) - a/0.997
as it's in the contact
There's some other issues hinting that there may be a math bug: https://github.com/Uniswap/uniswap-v2-periphery/issues/100 https://github.com/Uniswap/uniswap-v2-periphery/issues/91 - none of them seem to explain the reasoning but price = (a+x)/(a*b / (a+0.997x))
is definitely not solved to x = sqrt(a*b*price/0.997) - a/0.997
. When we disregard the fee, my method is consistent with the contract (getting x = sqrt(a*b*price) - a
starting from price = (a+x)^2 / (a*b)
)
Hello @Ivshti
It seems that you are right. In my case I do not make the function work in full detail. You don't end up calculating the best swap amount entry in Uniswap v2.
Do you know any other way to calculate the best entry amount for the pair?
Hi @Ivshti
I checked the math here and it looks correct:
Let k = (1 - fee rate), i.e. 997/1000 in the implementation. The profit f(x) = - p1 / p0 * x + (k * r1 * x) / (r0 + k * x), where x is the input amount of tokenA (we assume tokenA is the input token), r0 and r1 are the amounts of tokenA and tokenB respectively, p0 and p1 are true prices for tokenA and tokenB respectively. The first term is the amount of tokenB we can purchase from the market using true prices, while the second term is the amount of tokenB we can swap for using Uniswap.
To maximize f(x), we will consider its derivative f'(x) = 0, which will result in x = sqrt(p0 / p1 * r0 * r1 / k) - r0 / k. This is the same as the one in the implementation.
Please let me know if I made any mistakes in the calculation.
@dshe-certik why is k
applied to the second term but not to the first? Also I'm not sure whether it has to apply to both the nominator and the denominator on the second term.
But please check my way of deriving the formula cause it starts from scratch and it uses the formulas on the Uniswap contracts themselves. Sorry for the confusing way I've written it, what matter is after "Update: the correct formula for spot is actually". Notice how in that case the k
(fee multiplier) is not applied to one of the nominators ((a+x)/(a*b / (a+0.997x))
) - the reason for this is that the WHOLE amount is actually added to the pool (we're talking v2 here only), so then the spot calculation DOES include the fee amount (0.003*input
). This is how it works in practice - with computeProfitMaximizingTrade
we want to calculate the amount such that we achieve a certain spot price (r0 / r1
).
Just to make sure we're on the same page, the function takes p1
and p0
but they represent the target ratio between r0
and r1
- I call this spot price
@Ivshti I think this function is designed to calculate the profit a transaction can make from the price difference between some market and Uniswap. For example, if I can purchase 1 tokenA with the price of 100 tokenB on some market, while I can swap 1 tokenA for 110 tokenB with Uniswap, then I would purchase tokenA on the market and sell it with Uniswap.
truePriceTokenA
and truePriceTokenB
are the prices of tokenA and tokenB on the market, rather than the spot prices on Uniswap. That's why k
is not applied to the first term. Hope it answers your question.
hi guys, I'm kind of new here. Sorry for the basic question. What is exactly truePriceTokenA? Because true prices can be from spot market or from another dex. What should I consider? Furthermore, how do I calculate it? Thank you in advnace.
@djmoura True Price could be loosely read as the 'desired' price. The price the market should be moved to.
For example, let's say tokenA is worth 3 tokenB (1tokenA:3tokenB) to you, but is trading on Uniswap at 2 tokenB (1tokenA:2tokenB) market price. You would say the truePriceTokenA is 3, even though the price on Uniswap is 2. This formula calculates the amountIn on tokenB required to move the Uniswap market price to 3 (1tokenA:3tokenB).
dshe-certik A very simple argument for why the current formula is wrong is evaluating it when b = a/price Trade amount should obviously be 0, but current formula gives:
sqrt(a*(a/price)*price/0.997)-a/0.997 = a(1/sqrt(0.997)-1/0.997)
putting k (=0.997) outside the sqrt yields the right evaluation