I'm creating a statistics app for tracking my positions on uniswap.
As you can see below I have 0.019 unclaimed ETH rewards. However, when I try to reproduce this in my statistics app, I get 0.016 unclaimed ETH rewards. When running the numbers for the USDT token it is also off by about 10USDT. I will walk you trough how I've done this:
I get my active positions using a graphql query from the Uniswap API, you can run the query at https://thegraph.com/explorer/subgraph/uniswap/uniswap-v3:
{
positions(where: { owner: "0x44A2432332ca9166EC606501DA8067fC3C3c9058", liquidity_gt: 0}) {
liquidity
feeGrowthInside0LastX128
feeGrowthInside1LastX128
token0 {
decimals
derivedETH
}
token1
{
decimals
derivedETH
}
tickUpper {
tickIdx
feeGrowthOutside0X128
feeGrowthOutside1X128
}
tickLower {
tickIdx
feeGrowthOutside0X128
feeGrowthOutside1X128
}
pool {
tick
feeGrowthGlobal0X128
feeGrowthGlobal1X128,
totalValueLockedUSD
}
}
}
Using the information I found at https://blog.uniswap.org/uniswap-v3-math-primer-2#calculating-uncollected-fees-in-a-position I created the following functions (C#) to calculate the rewards.
var value0 = CalculateReward(
BigRational.Parse(position.Liquidity),
BigRational.Parse(position.Pool.FeeGrowthGlobal0X128),
BigRational.Parse(position.TickUpper.FeeGrowthOutside0X128),
BigRational.Parse(position.TickLower.FeeGrowthOutside0X128),
BigRational.Parse(position.FeeGrowthInside0LastX128),
position.TickUpper.TickIdx,
position.TickLower.TickIdx,
position.Pool.Tick);
value0 = value0 / BigRational.Pow(10, position.Token0.Decimals);
private BigRational CalculateReward(
BigRational liquidity,
BigRational feeGrowthGlobal,
BigRational feeGrowthOutsideUpperTick,
BigRational feeGrowthOutsideLowerTick,
BigRational feeGrowthInside,
int tickUpper,
int tickLower,
int tick)
{
var feeGrowthInsideCurrent = CalculateCurrentFeeGrowthInside(
feeGrowthGlobal,
feeGrowthOutsideUpperTick,
feeGrowthOutsideLowerTick,
tickUpper,
tickLower,
tick);
return liquidity * (feeGrowthInsideCurrent - feeGrowthInside) / BigRational.Pow(2, 128);
}
private BigRational CalculateCurrentFeeGrowthInside(
BigRational feeGrowthGlobal,
BigRational feeGrowthOutsideUpperTick,
BigRational feeGrowthOutsideLowerTick,
int tickUpper,
int tickLower,
int tick)
{
var feesBelowLowerTick = CalculateFeesBelowLowerTick(feeGrowthGlobal, feeGrowthOutsideLowerTick, tickLower, tick);
var feesBelowUpperTick = CalculateFeesBelowUpperTick(feeGrowthGlobal, feeGrowthOutsideUpperTick, tickUpper, tick);
return feeGrowthGlobal - feesBelowLowerTick - feesBelowUpperTick;
}
private BigRational CalculateFeesBelowLowerTick(
BigRational feeGrowthGlobal,
BigRational feeGrowthOutsideLowerTick,
int tickLower,
int tick)
{
if (tick >= tickLower)
{
return feeGrowthOutsideLowerTick;
}
else
{
return feeGrowthGlobal - feeGrowthOutsideLowerTick;
}
}
private BigRational CalculateFeesBelowUpperTick(
BigRational feeGrowthGlobal,
BigRational feeGrowthOutsideUpperTick,
int tickUpper,
int tick)
{
if (tick >= tickUpper)
{
return feeGrowthGlobal - feeGrowthOutsideUpperTick;
}
else
{
return feeGrowthOutsideUpperTick;
}
}
For example, if I run the following numbers (which I got from running the above graphql query) through the calculations, I get 0.016 instead of 0.019. What am I doing wrong?
var value0 = CalculateReward(
BigRational.Parse("1367429764868973"),
BigRational.Parse("356531773596110297175139730895619992793974"),
BigRational.Parse("0"),
BigRational.Parse("349599952281522978521834276098134191845749"),
BigRational.Parse("2736330194804551556695334267654167873990"),
-196915,
-199341,
-198304);
value0 = value0 / BigRational.Pow(10, 18);
I also tried communicating with the smart contracts directly, with the same result.