duality-labs / duality-web-app

2 stars 2 forks source link

Optimize user state queries using new API endpoints #414

Closed dib542 closed 9 months ago

dib542 commented 1 year ago

This work should follow on from the changes made to use the user state endpoints in:

Discussion

With the introduction of the endpoint /dualitylabs/duality/dex/pool/{pairID}/{tickIndex}/{fee} in https://github.com/duality-labs/duality/pull/446 (which is included in Duality v0.4.0)

User queries from the front end can now look up their own data from

and use these known center tick indexes and fees to find the reserves of both lower_tick0 and upper_tick1 of a center tick at the same time (and avoid having a 404 not found error on empty upper or lower tick requests).

This should help the front end:

Unexpected developments

When requesting this feature I was asking for (importantly this data is from the same block height) an endpoint to return a pool's

This I wanted to combine with the user data of /dualitylabs/duality/dex/user/deposits/{address} which returns the user's shares in sharesOwned, to calculate a user's holding in terms of reserves, ie.

However the new endpoint returns only

message QueryPoolResponse {
    Pool pool = 1 [(gogoproto.nullable) = true];
}
message Pool {
    PoolReserves lower_tick0 = 1;
    PoolReserves upper_tick1 = 2;
}

Which does not have enough information to piece together the amount of reserves that a user holds at a certain block in time. Because the requests for this information must still be made in at least two separate requests we cannot guarantee that the data is from the same height, so the calculated user reserves remain an estimation.

Conclusion

So while this endpoint does serve to reduce the number of network requests from 3 to 2 per user deposit, It is not particularly helpful.

requests used previously per user deposit:

requests used after new endpoint per user deposit:

The endpoint as is may be used to reduce network calls, but I don't think this is a priority compared to other issues such as the guarantee that this calculation is accurate by guaranteeing that the data is from the same block height.

dib542 commented 9 months ago

Suggestions for improvements to the API:

New logic

On the app I would like to make a distinction between "accurateUserReserves" and "estimatedUserReserves" with an implementation of maybe both using React hooks.

Accurate user reserves

"accurateUserReserves" is for pages that require accurate detail such as the Pool Management pages with show the user deposits in real-time.

"accurateUserReserves" would require knowing the users reserves calculated correctly at each block, as we currently lack this same-block guarantee, accurate reserves cannot be calculated.

Estimated user reserves

"estimatedUserReserves" can be for pages that do not show individual user deposits but aggregated user deposit values such as the Portfolio page which sums a user's reserve value in each pair.

"estimatedUserReserves" requires knowing the number of user's reserves (exact or approximate) at a recent point in time, and then assuming what the reserves are at the current point in time assuming that the token pair pools are perfectly arbitraged at the current point in time (which is likely not true but the calculated result should be approximately correct for pools with enough liquidity)

Indicative user reserves

both "accurateUserReserves" and "estimatedUserReserves" can be calculated from a new concept "indicativeUserReserves" which contains for each pool:

where the indicativeReserves here is the pre-calculated (userReserves = (sharesOwned / totalShares) * tickReserves) value of the users shares if they were wholly as reserves0 or reserves1.

Estimated user reserves calculations

Using indicativeReserves values and the real-world (ie. third party CoinGecko API) current price of the tokens, the front end can make an estimation of the user's reserves and their monetary value by using the assumption that the the pair price reflects the real world price, and that there are no "behind enemy lines" deposits (ie. that the token pair is perfectly arbitraged). By knowing the token prices and determining the tickIndex that assumedly separates reserves from the token0 side and token1 side, the reserves of each side can be estimated.

Accurate user reserves calculations

Using accurate indicativeReserves values and real-time liquidity value provided by the indexer on /liquidity/pair/{tokenA}/{tokenB} the proportion of reserves for each pool of a pair is known for each block and therefore the accurate number of user's reserves can be known at each block.

Indicative user reserves calculations

"indicativeReserves" can be calculated from userReserves = (sharesOwned / totalShares) * tickReserves at any point in time (but will only be "accurate" when totalShares and tickReserves are fetched from the same block height as they may change every/any block height, sharesOwned only changes with user actions).

These values can be currently collected from:

but if would be better if they could be collected from one place, allowing the app to have an "accurate" (numbers from the same height) version of the user's indicative reserves:

Conclusion

Therefore I think my recommendation is to add:

This allows the app to

Additionally for other applications: the ability to continually fetch /duality/dex/user/deposits/{address} whenever to get an accurate total of the user's reserves at the current point in time could be very helpful in building simple applications.

dib542 commented 9 months ago

The previous comment has been expanded out into separate issues: