-
Notifications
You must be signed in to change notification settings - Fork 2
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
Immediately transfer tokens when the vesting period has ended #37
Comments
It will have implications to indexers and app logic too. This makes campaign actions into a mixture of Instant and Airstreams actions, since the |
Right. Would it help if we emitted different events? |
Event will be required for sure! But we could simply emit a |
Yeah, that should work well. I wonder if a boolean flag would be helpful, though? That would be slightly clearer |
@razgraf since you suggested setting
Do you think it would be better for UI integration if we just have a common
|
It would have simplified things, yes. But since we already support two types of claim events, it doesn't really make a difference right now. So it's a question of simplicity at a contract level. I do wish to stress on thing with this feature: users (like Polynomial) for Merkle Lockups relied on these contracts issuing a valid stream upon claim. So they may expect streams from Lockup-based campaigns and will (probably) not pay attention to the changelog since it's a bit of an internal logic change (e.g. will be hard to catch for subgraph integrators). Are we 100% sure we want to still implement this feature, or is it something we can skip? |
@PaulRBerg, since you advocated for this idea. Wdyt? Another approach to implement it is to trigger a withdrawal from the stream inside the claim if A natural behaviour of a claimer could be to withdraw from the stream right after claim if it has been fully vested. So I see no problem in combining these two into a single transaction without causing any issues for integrators, as @razgraf mentioned above. |
Yes, creating the stream and claiming, as a bundle, would be great! AFAIK, the consideration around doing this single transfer instead of the atomic bundle was regarding gas. But that would come at the expense of backwards-compatibility and DX (both internal and external), which is why I'm asking again, before moving forward with this. |
This ultimately boils down to how we signal the vesting/no vesting dichotomy. There appear to be three options:
I'm against Option 2 because it's an ad hoc solution. 'Sentinel' values are not self-explanatory; an integrator needs to carefully read the docs to understand what Option 3 is OK, but I have a slight preference for Option 1 because:
We can tell them about it on Telegram. I'll ask them what they think about Option 1. |
How about introducing an enum and emitting an enum value as the first parameter of the enum ClaimType {
VESTING,
INSTANT
} Note: naming is not final |
Yes
|
How does introducing an enum solve the problem? It does not standardise the Claim event because there will still be a Also, the argument that "an integrator needs to carefully read the docs to understand" also applies to enums as they are integers only. I am inclined towards Option 2 but since the problem is relevant to integrators, I will let you and @razgraf make a decision on it. |
I'm in favor of Option 3 to be honest since that offers the least resistance (but good point re. accounting, will influence revenues calculation as well, although that still seems easier to handle than the new non-stream system). |
Any follow up comment on this @PaulRBerg? |
@smol-ninja an enum with two possible values is much more intuitive than using
I wasn't suggesting that. I was suggesting differentiation through enums. I continue to be in favor of Option 1 because what's happening under the hood is different when the vesting period has ended VS when it has not. Two Yes, this requires a little bit of extra logic in the subgraphs/integrators' code, but it's not a lot. Also, on Mainnet, we will be saving a lot of precious gas costs. I've asked Polynomial for feedback on having multiple |
My 2c is it's not little extra logic either. They'd have users receiving two different entities from the same source: a stream vs. pure tokens, instead of a clear single entity like Instant, AVCA and the current version of Merkle Lockup. Therefore, I still think mixing the two systems under the same campaign type would cause misconceptions. |
Is it reasonable to assume that in 90% of lockup campaigns, the vesting period extends beyond the campaign's expiration? if so, in most cases, users will still need to pay the full gas cost (200k) for both creating a stream and withdrawing from it later. Having said that, by implementing option (1) (different events), this feature would apply to only about 10% of cases (or potentially even fewer?). As a result, the expected savings would be significantly lower ( Now if we compare this 6% expected saving with the development effort and potential misconceptions (as @razgraf pointed out), is it justifiable? With option (3), the expected savings would be zero, but there would also be no additional development effort for integrators. With option (2), the expected saving is 6% with minimal development efforts. What do you think looks better option from this perspective? |
That may be a reasonable assumption for duration-based vested airdrops, where the vesting period starts when the user claims. However, that doesn't sound reasonable for ranged airdrops (which have become the default option). What's the point of setting the expiration after the vesting end? Users who haven't claimed yet would be rug-pulled. Speaking of this — I have created an issue in the Interfaces repo to add a disclaimer in case the expiration is earlier than the vesting period end.
Absolutely! I suggest we adopt this heuristic: whenever we have to choose between minimal extra development and better UX (especially economic UX!), let's choose the latter.
The extra effort is minimal and as I've explained above, my proposed design is clearer from an architectural POV since there are no sentinel values nor any faux-streams that are not-actually-streams.
Au contraire — fewer misconceptions with Option 1. See my previous comment. |
Yet another benefit of Option 1 — having fewer faux streams means:
|
Additional thoughts on this to try to persuade you @razgraf and @smol-ninja that Option 1 is the better approach:
Also: this disagreement reminds me of the VCA discussion, where we ultimately decided to go with implementing the vesting logic within the VCA contract. Here the analogy is that the tokens are immediately disbursed to the user because that's what the contract should do. |
Let's then go with the different events approach. I can see why it might not be the right choice to implement superfluous logic, when analyzed in an independent context. My own cost analysis still yields a larger effort of integration (separate events, extra state machine end states) so I cannot fully agree that it'd be an easier job / minimal extra effort, but I'm willing to give it a shot and implement it, for enhanced UX long term. It may prove beneficial long term, thus invalidating my cost analysis. Note: Would be nice to have some diagrams here comparing (1) the different types of merkle airdrops and (2) the end states / lifecycles for each. |
When
end time <= block timestamp
, transfer the airdrop amount directly to the user, without creating a stream.cc @sablier-labs/frontend, this may have implications for the informatinal tooltips in the UI
Discussed in #33
Originally posted by PaulRBerg December 23, 2024
The text was updated successfully, but these errors were encountered: