-
Notifications
You must be signed in to change notification settings - Fork 206
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
Vesting accounts with clawback #4085
Comments
Implementation
VotingIf allowed, voting unvested tokens is not problematic, as voting power is determined by a snapshot at vote-counting time. Nothing special needs to be done for clawback. Line of CreditSince there's no way to guarantee repayment of the loan, and clawed-back tokens revert to being unbonded and have no ongoing revenue stream, I recommend that we disallow a line of credit using unvested tokens. This means that clawback will not have to contend with a lien encumbrance. (What if we encumber the loan so that it can't be transferred out of the account? Then there's little point in having the loan.) SlashingWe can have slashing preferentially affect vested tokens. But otherwise, being able to stake unvested tokens means that they might be lost to slashing and not available for clawback. However, one could consider slashing a form of early clawback - they're still confiscated from the recipient (although not returned to the issuer). The recipient is still motivated to stake wisely as long as they do not plan on a clawback. RewardsThe simplest approach is to not encumber the rewards, so I recommend that if it's allowable. We might also want to split the policy based on the type of reward, i.e. BLD vs RUN. If we do need to encumber the rewards, the simplest formula is to vest the reward when the originating token vests. |
Preferred mechanics:
|
I think I can do all the MUST (NOT) requirements, most of the SHOULDs, and perhaps the MAY. I think we can allow both vesting and locking in the same account. We can even add new awards with their own locking, vesting, or combined schedule. Slashing: It's difficult to make slashing proportional because we don't have a good way of actually knowing how much was slashed after the fact. Adding such instrumentation would require changes to the staking module, which I'd like to avoid. This is what led us to the rule for liens: slashing first affects the unliened tokens. I'd like to have the analogous behavior where slashing first affects the vested tokens. Partial clawback: We can make this work, but which sort of behavior do you want? We can cancel the soonest upcoming vesting events, cancel starting with the last vesting events, or we can proportionately reduce the amount of all upcoming vesting events. Question on signature: I envision the clawback being signed by the account that donated the original amount, even if a different account is specified as the beneficiary. If we allow multiple vesting awards to be given to the same account, are we okay with the restriction that all awards must come from the same source? If so, then we need only keep track of the combined schedule of all vesting events. Otherwise we need to store each schedule individually, plus the combined schedule - not too hard, but I don't want to commit all that storage unless we need to. |
Another option for partial clawback for @dtribble : clawback only has one setting - take all unvested tokens. If you wanted to take less than all, you can restore some by giving a fresh vesting grant with whatever amount and schedule is appropriate. At the very least, this method could delay the urgency for a partial clawback feature. |
A note on reward distribution. For slashing, we assume that staked tokens prefer to be vested tokens. For clawback, we prefer to transfer unbonded tokens first, which reflects the same policy. Therefore for reward distribution, we'll prefer to consider the bonded tokens to be the vested tokens first, then assign unvested tokens as necessary, and divide rewards between vested and unvested according to this ratio. For instance, suppose we have a vesting grant of 400 tokens vesting monthly over 4 years and we are 18 months into the schedule, so 150 have vested. There are 370 tokens total in the account: 210 in the account balance plus 160 staked. The 30 missing tokens could have been vested tokens that were transferred out, or vested tokens that got slashed. We now get a reward of 12 tokens. To distribute the reward, we see that the account has 250 unvested tokens, so 120 of the tokens are vested (= total - unvested). So for the 160 staked tokens, we'll first consider 120 of them (75%) to be vested, then 40 (25%) to be unvested. Therefore we distribute the reward as 9 (75%) tokens vested, 3 (25%) unvested. The unvested tokens will follow a vesting schedule proportional to the remaining vesting schedule for staking tokens: in even amounts over the next 30 months, i.e. 0.1 per month. |
Summary of the design. Vesting Accounts With ClawbackNote on nomenclature: in this spec we'll refer to the encumbrance implemented by other vesting accounts a "lockup". "Vesting" will refer to the new form of encumbrance here that's subject to clawback. Requirements
DesignImplement as a variation of PeriodicVestingAccount (PVE). We've previously extended PVEs to allow incremental awards. Some of the mechanisms needed for that can be reused for true vesting accounts. Distribution of Rewards, Slashing, and ClawbackWe'll prefer to consider staked tokens using the vested tokens first, followed by the unvested tokens. This is preferred for several reasons. As a practical matter, in an account with both vested and unvested tokens, some of which are staked, it is difficult to distinguish the post-slashing state from a state where some vested tokens have been transferred out. Users who feel disadvantaged by this policy are able to transfer their staked tokens to a different account that's not subject to clawback. Data structureLike a PVA, but instead of a single schedule, we store a The We'll be merging unvested rewards into these same data structures, which is okay since a Merging schedulesWe've previously implemented a "disjunctive" merge of two schedules to implement incremental grants. The combined schedule vests tokens when they are vested in either of the inputs to the merge. For true vesting plus an independent lockup dimension, we'll implement "conjunctive" merging, where coins are vested in the combined schedule when they're vested in both of the input schedules. To add a new grant or reward to a true vesting account, with vesting schedule
RewardsSee the above comment in the issue history to see a detailed description of how rewards are apportioned. Note that we have not yet taken a close look for where to insert this special method into the reward distribution flow. ClawbackThe amount of clawback is the total unvested amount in the account. But some of the account may be staked, and the staking commands do not specify which sort of tokens (vested, unlocked, etc) should be used. To retrieve the clawback amount, we'll prefer to confiscate the least encumbered tokens possible:
This means that after the clawback command succeeds, the transferred funds may still be encumbered, may still be subject to future or retroactive slashing, and may require manual action to initiate unbonding. It should be a best practice to use a new destination account for each clawback event for simpler management of the post-clawback state. If there are not enough tokens available from all sources to fulfill the amount desired for clawback, then the account must have been slashed and the amount clawed back will simply be less than desired. This is an unavoidable outcome of being able to stake unvested tokens. The vesting schedule will be truncated at the time of clawback so that there are no future vesting events. The unlocking schedule will be capped to the number of vested tokens at time of clawback, so that vested but locked tokens will still unlock in the future. Interaction with Agoric featuresWe don't want to allow a line of credit based on unvested tokens. Therefore the lien logic will need to export the number of unvested tokens in the The current state of the implementation can be seen at https://github.com/agoric-labs/cosmos-sdk/tree/4085-true-vesting |
RewardsWhen you withdraw rewards via the Fortunately, the computation simplifies greatly. Imagine that each end-of-block reward gets attached to every staked token, and the reward vests at the time its staked token vests. Therefore to compute the vested split of an integral of rewards over a time interval, you need only look at the vesting state of staked tokens at the end of the interval. If a token is vested at the end of the interval, it does not matter if it was unvested at the time of the reward. One complication with this algorithm is our preference to count slashing against vested tokens. Slashing effectively pulls previously unstaked unvested tokens into staking, thus the slashed vested tokens do not get credit for producing vested rewards. However, this effect of undercounting vested rewards is trivial compared to the effect of slashing, and can be arbitrarily minimized by frequent reward withdrawal. |
Note that there's a bug if we try to use the standard vesting account delegation bookkeeping with accounts which allow new grants to be added. (Specifically, when the unvested amount can increase.) See #4300. The bug can lead to premature unlocking of amounts which should be vested. The solution is to track delegated amounts exactly. |
@JimLarson This is in the "Up Next" pipeline, but does not have a MN-1 label. If it is needed for MN-1, please label, otherwise move from "Up Next" to "Product Backlog". I'm asking because I want "Up Next" to really reflect the things we plan to work on for MN-1. |
@Tartuffo Done. Added an "MN-1" label to github.com/agoric-labs/cosmos-sdk too, and labeled my PRs there as well. |
What is the Problem Being Solved?
It is too error-prone to perform vesting events manually for vesting token awards. There will be dozens of events on different days per month going to different accounts.
The current "vesting" accounts implement an automatic unlocking schedule which prevent tokens from being transferred out, but there is no provision for clawback. The locked-up tokens are available for staking (and subject to slashing).
We'd like to have:
Description of the Design
To allow maximum use of unvested tokens, we could simply modify current periodic vesting accounts to have a "clawback" command which transfers the unvested amount back to the funding account, subject to signature from the funding account.
For minimum use of the unvested tokens, the vesting schedule could control the incremental transfer of funds from the funding account (or an intermediate escrow account) to the target account.
In either case, it would make sense to use the same format for a vesting schedule as is used for the current periodic "vesting" accounts.
Note that the vesting dimension is orthogonal to the locking dimension. A given amount of tokens may be subject to both vesting and lockup with different schedules, and either dimension should be able to prevent transfer.
Unknowns
Security Considerations
Test Plan
The text was updated successfully, but these errors were encountered: