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 Incentives] Allow early withdrawals for frozen positions #4525

Merged
merged 199 commits into from
Mar 15, 2023

Conversation

AlpinYukseloglu
Copy link
Contributor

Closes: #4456, #4514

What is the purpose of the change

This PR implements early position exits for frozen positions. It allows users to exit even before their freezeDuration is over if they are willing to forfeit the incentives they have accrued.

Brief Changelog

  • Abstract common logic between fee and incentive claiming as described in [CL Incentives] Abstract common incentive/fee claiming logic #4514
  • Implement new helper, claimAllIncentivesForPosition, that claims and returns all the accrued incentives for a given position. This helper takes in a forfeitIncentives parameter which, when true, redeposits the claimed incentives into the appropriate accumulators right after claiming. If it is false, the rewards are claimed but no balance transfers are processed (this is to keep the helper useful in standard claiming logic while avoiding duplicate code)

Testing and Verifying

  • All new functionality is tested in incentives_test.go and lp_test.go
  • Note that since much of the logic for the helpers are already thoroughly tested by collectIncentives and collectFees, the cases included are mainly sanity checks and cases for new functionality e.g. forfeiting rewards.

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)

czarcas7ic and others added 30 commits January 25, 2023 21:01
* single fee accum

* lint

if tc.expectError != nil {
s.Require().Error(err)
s.Require().ErrorIs(err, tc.expectError)
Copy link
Member

Choose a reason for hiding this comment

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

I don't believe we have any error cases we are testing here, can we:

  1. Verify that there aren't any error cases we need to check here and
  2. If we add error cases, change this to ErrorContains. Otherwise, remove.

I believe there are likely error cases we want to test on ClaimAllIncentivesForPosition though

Copy link
Contributor Author

@AlpinYukseloglu AlpinYukseloglu Mar 12, 2023

Choose a reason for hiding this comment

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

Since this function was extracted from CollectIncentives, there are thorough tests there for all the relevant cases on ClaimAllIncentivesForPosition, but I agree that at least having sanity error checks is good even if duplicates.

Adding rn

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines 3126 to 3143
if tc.forfeitIncentives {
newUptimeAccumValues, err := clKeeper.GetUptimeAccumulatorValues(s.Ctx, validPoolId)
s.Require().NoError(err)

// Subtract the initial accum values to get the delta
uptimeAccumDeltaValues, err := osmoutils.SubDecCoinArrays(newUptimeAccumValues, initUptimeAccumValues)
s.Require().NoError(err)

// Convert DecCoins to Coins by truncation for comparison
normalizedUptimeAccumDelta := sdk.NewCoins()
for _, uptimeAccumDelta := range uptimeAccumDeltaValues {
normalizedUptimeAccumDelta = normalizedUptimeAccumDelta.Add(sdk.NormalizeCoins(uptimeAccumDelta)...)
}

s.Require().Equal(normalizedUptimeAccumDelta, amountClaimed)
}
})
}
Copy link
Member

Choose a reason for hiding this comment

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

Something that would make me feel extra comfortable with this is that we check bank balances before and after claim, to ensure that the rewards in fact did not make it to the account.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AlpinYukseloglu and others added 8 commits March 10, 2023 10:38
Co-authored-by: Roman <[email protected]>
* draft implementation

* begin testing

* add more test cases

* add error catching test cases

* implement createIncentive message

* cli and codec

* add check and related tests

* add further tests and lint

* add test case for existing incentive records
Base automatically changed from alpo-create-incentive to alpo-uptime-claim March 10, 2023 23:06
@AlpinYukseloglu AlpinYukseloglu changed the base branch from alpo-uptime-claim to alpo-create-incentive March 10, 2023 23:12
Copy link
Contributor

@stackman27 stackman27 left a comment

Choose a reason for hiding this comment

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

LGTM, just found some nits

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.

Well done! I would like to hear your response to the withdrawAll comment, but other than that it looks good to me!

Comment on lines +450 to +452
// claimAllIncentivesForPosition claims and returns all the incentives for a given position.
// It takes in a `forfeitIncentives` boolean to indicate whether the accrued incentives should be forfeited, in which case it
// redeposits the accrued rewards back into the accumulator as additional rewards for other participants.
Copy link
Member

Choose a reason for hiding this comment

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

One minor test case I think would be good to see is that, if we have three positions (one 20%, one 50%, and one 30%) that get created at the same time, if the 20% forfeits rewards that is is properly distributed between the 50% and 30% proportionally. Not at all blocking, just something I thought would be good to verify.

Comment on lines 130 to 140
// If the position is still frozen, claim and forfeit any accrued incentives for the position.
isPositionFrozen := joinTime.Add(position.FreezeDuration).After(ctx.BlockTime())
if isPositionFrozen {
if !requestedLiquidityAmountToWithdraw.Equal(position.Liquidity) {
return sdk.Int{}, sdk.Int{}, fmt.Errorf("If withdrawing from frozen position, must withdraw all liquidity.")
}

_, err := k.claimAllIncentivesForPosition(ctx, poolId, owner, position, lowerTick, upperTick, true)
if err != nil {
return sdk.Int{}, sdk.Int{}, err
}
Copy link
Member

Choose a reason for hiding this comment

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

Unsure how I feel about this implicit (if I withdraw everything then I give away all my incentives). Feels like it should be an explicit param.

Base automatically changed from alpo-create-incentive to main March 15, 2023 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CL Incentives] Allow early withdrawals for frozen positions
3 participants