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

[CL]: Join-time tracker sumtree #3898

Closed
wants to merge 24 commits into from
Closed

[CL]: Join-time tracker sumtree #3898

wants to merge 24 commits into from

Conversation

AlpinYukseloglu
Copy link
Contributor

@AlpinYukseloglu AlpinYukseloglu commented Dec 31, 2022

Pulled from #3886

What is the purpose of the change

Note to reviewer: the majority of the file diff is updating wiring for sumtree usage (switching Int to Dec)

This PR implements a join-time tracker sumtree that dynamically updates as positions are changed in a given pool. This allows us to get the amount of liquidity that joined a pool before, at, or after a given join time, allowing us to incentivize uptime.

Once we finalize our process for reward calculation post-#3894 & decide on whether we want to support multiple uptime tiers per incentive token, we can add a second sum to our sumtree to track accumulated rewards.

Brief Changelog

  • Change sumtree to accumulate sdk.Dec instead of sdk.Int
  • Populate a sumtree tracking position join times for each pool every time a position is updated
  • Thoroughly fuzz test new sumtree logic

Testing and Verifying

All of the new logic is heavily tested in position_test.go (both by expanding existing tests & adding new robust fuzz tests)

Documentation and Release Note

  • Does this pull request introduce a new feature or user-facing behavior changes? (no)
  • Is a relevant changelog entry added to the Unreleased section in CHANGELOG.md? (no)
  • How is the feature or change documented? (not documented)

Copy link
Member

@czarcas7ic czarcas7ic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, have a few questions and then will happily review a second time (didn't feel I should approve on first look since this is my first time reviewing sumtree stuff)

Comment on lines +23 to +26
// Since we want to reset a position's JoinTime every time they update their liquidity, any
// liquidity update is equivalent to removing the old JoinTime node from the liquidity tree
// and replacing it with a new one. Thus, this function simply takes in the old and new liquidity
// amounts and leaves liquidity delta calculations to the caller.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: this will require the user to claim any outstanding rewards prior to replacing the node from the liquidity tree right?

Comment on lines +192 to +196
// Update expectedPos time to current context's blocktime
if test.expectedPosition != nil {
test.expectedPosition.JoinTime = s.Ctx.BlockTime()
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This got added but it appears nothing tests this logic

Comment on lines +237 to +238
// We generate a new test account per position for robustness
testAccounts := osmoutils.CreateRandomAccounts(numPositions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like, for robustness, we should have accounts with multiple positions (this feels like the more complex logic imo)

Comment on lines +267 to +269
// Generate random lower and upper ticks
lowerTick := (-1) * (rand.Int63() % tickLowerBound)
upperTick := rand.Int63() % tickUpperBound
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like what you did with this fuzz testing, but I think we might need to expand this to prevent every lower tick from being negative and every upper tick from being positive. Seems like we might be leaving some edge cases untested.

@@ -0,0 +1,83 @@
package concentrated_liquidity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you planning to add tests for these?

Copy link
Member

@p0mvn p0mvn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall logic LGTM, nice work!

I'm wondering whether migration is justified. Is there a workaround to avoid changing Int -> Dec in the accumulator proto?

I still need to review position test updates. Also, would love to see tests added for logic in incentives.go

@@ -3,6 +3,7 @@ module github.com/osmosis-labs/osmosis/v13
go 1.18

require (
cosmossdk.io/errors v1.0.0-beta.7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? We can import errors from our sdk fork? Might be an erroneous import

@@ -11,7 +11,7 @@ message Node { repeated Child children = 1; }
message Child {
bytes index = 1;
string accumulation = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is likely to require migrations for pre-existing lockup and incentives logic. Do we have a plan for this?

"github.com/osmosis-labs/osmosis/v13/x/concentrated-liquidity/types"
)

// Gets the current join-time sumtree for the passed in pool ID.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: for style consistency

ditto for other specs in this file

Suggested change
// Gets the current join-time sumtree for the passed in pool ID.
// getSumtree gets the current join-time sumtree for the passed in pool ID.


// Gets the current join-time sumtree for the passed in pool ID.
func (k Keeper) getSumtree(ctx sdk.Context, poolID uint64) sumtree.Tree {
return sumtree.NewTree(prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyAccumulationStore(poolID)), 10)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing the choice of 10 for the branching factor was taken from other modules. I'm not sure how much it matters here but we might want to analyze it

func KeyJoinTime(joinTime time.Time) (res []byte) {
timeBz := sdk.FormatTimeBytes(joinTime)
timeBzL := len(timeBz)
prefixL := len(TimePrefix)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can be stored as const

// copy the prefix
copy(bz[:prefixL], TimePrefix)

// copy the encoded time bytes length
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we also need length?


// Remove liquidity from `position`s join time without resetting position.JoinTime.
// This is to allow for LPs to remove a portion of their liquidity without forfeiting their uptime
// on their remaining liquidity.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// on their remaining liquidity.
// on their remaining liquidity.
// The given liquidity must be positive. Fails with an error otherwise.

@@ -57,6 +57,18 @@ func (k Keeper) initOrUpdatePosition(
// TODO: consider deleting position if liquidity becomes zero

k.setPosition(ctx, poolId, owner, lowerTick, upperTick, position)

// Update pool's liquidity tree to reflect new position
if liquidityDelta.GT(sdk.ZeroDec()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we can store sdk.ZeroDec as a global variable to avoid underlying reallocations every time

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an IsPositive helper? It might be helpful here

@AlpinYukseloglu AlpinYukseloglu marked this pull request as draft January 1, 2023 09:50
@AlpinYukseloglu
Copy link
Contributor Author

AlpinYukseloglu commented Jan 1, 2023

Thanks for the comments all – I recently realized that this sumtree logic needs another layer to track tick range for joins for it to be useful for incentives, so I'm converting this to a draft while I flesh out what the final version should look like

@p0mvn p0mvn mentioned this pull request Jan 12, 2023
32 tasks
@github-actions
Copy link
Contributor

This pull request has been automatically marked as stale because it has not had any recent activity. It will be closed if no further activity occurs. Thank you!

@github-actions github-actions bot added the Stale label Jan 16, 2023
@github-actions github-actions bot closed this Jan 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants