Closed dib542 closed 11 months ago
Suggestions for improvements to the API:
On the app I would like to make a distinction between "accurateUserReserves" and "estimatedUserReserves" with an implementation of maybe both using React hooks.
"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.
"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)
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
.
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.
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.
"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:
sharesOwned
from /cosmos/bank/v1beta1/balances/{address}
/dualitylabs/duality/dex/user/deposits/{address}
if poolID
was returned on DepositRecord
, but it is not so this is not recommend after the update of https://github.com/duality-labs/duality/commit/9ede0f2bedb85bd1d479824174b00c94e8053b94totalShares
from /cosmos/bank/v1beta1/supply/{denom}
lowerReserves
from /dualitylabs/duality/dex/pool_reserves/{pairID}/{tokenIn}/{tickIndex}/{fee}
upperReserves
from /dualitylabs/duality/dex/pool_reserves/{pairID}/{tokenIn}/{tickIndex}/{fee}
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:
/duality/dex/user/deposits/{address}
:
indicativeReservesAsToken0
and indicativeReservesAsToken1
directly/duality/dex/pool/{poolID}
and/or /duality/dex/pool/{pairID}/{tickIndex}/{fee}
:
totalShares
on QueryPoolResponse
or the Pool
type/duality/dex/user/deposits/{address}
/duality/dex/user/deposits/{address}
should return poolID
if only the /duality/dex/pool/{poolID}
endpoint will contain the totalShares
information./cosmos/bank/v1beta1/balances/{address}
but this endpoint will no longer give an indication of which pools belong to which token pair (without fetching metadata for each pool)/duality/dex/user/deposits/{address}
would be more beneficial./duality/dex/user/deposits/{address}/{poolID}
indicativeReserves
for a single pool. which would be a typical request after the users makes a Dex action that causes a bank transfer
action to occur against their wallet address.indicativeReserves
to the /duality/dex/user/deposits/{address}
endpoint. If we add totalShares
there instead the required data to update the app state for a single pool will be available on the /duality/dex/pool/{poolID}
and/or /duality/dex/pool/{pairID}/{tickIndex}/{fee}
endpoints if the totalShares
information is added there. Therefore I think my recommendation is to add:
Pool
type (https://github.com/neutron-org/neutron/blob/main/proto/neutron/dex/pool.proto):
totalShares
lowerReserves0
and upperReserves1
Pool
type suitable for calculating accurate indicative reserves for the app/duality/dex/user/deposits/{address}
:
pool
(with new totalShares
info)This allows the app to
/duality/dex/user/deposits/{address}
on app start / address change
accurateUserReserves
and estimatedUserReserves
) in one network request./duality/dex/pool/{poolID}
upon any bank.transfer
updates to the user's bank
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.
The previous comment has been expanded out into separate issues:
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
/dualitylabs/duality/dex/user/positions/{address}
/dualitylabs/duality/dex/user/deposits/{address}
/dualitylabs/duality/dex/user/limit_orders/{address}
and use these known center tick indexes and fees to find the reserves of both
lower_tick0
andupper_tick1
of a center tick at the same time (and avoid having a404 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 insharesOwned
, to calculate a user's holding in terms of reserves, ie.userReserves0 = (sharesOwned / totalShares) * lowerTickReserves
userReserves1 = (sharesOwned / totalShares) * upperTickReserves
However the new endpoint returns only
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:
totalShares
from/cosmos/bank/v1beta1/supply/{denom}
lowerReserves
from/dualitylabs/duality/dex/pool_reserves/{pairID}/{tokenIn}/{tickIndex}/{fee}
upperReserves
from/dualitylabs/duality/dex/pool_reserves/{pairID}/{tokenIn}/{tickIndex}/{fee}
requests used after new endpoint per user deposit:
totalShares
from/cosmos/bank/v1beta1/supply/{denom}
lowerReserves
andupperReserves
from/dualitylabs/duality/dex/pool/{pairID}/{tickIndex}/{fee}
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.