The following paragraphs are highly logically technical. Feel free to skip to the "Proposed Solution" section.
Creating a governance DAO that meets all of these requirements is conceptually simple. However, there are some technical design challenges due to how solidity works. Implicit in the above requirements is the following requirement: Any time someone wants to withdraw locked tokens, the protocol needs to look back at every single time tokens were allocated to a user account and calculate what portion of those tokens are now available due the passage of time, and add all of those up. Then when the user withdraws tokens, it is not clear which "allocation event" those withdrawn tokens come from. Once a corresponding allocation event is decided due to some optimization, the additional data of how many tokens were claimed needs to be stored for each allocation event. The protocol could create a virtually infinite number of allocation events if the user is actively claiming rewards whenever they are available. Depending on the allocation events chosen for a withdrawal event, the system may need to look back through years of allocation events every time a user claims some of their tokens.
Implementing this system to these implicit requirements is complex, bug-prone, and would take a vast amount of on-chain computation and storage, making the protocol more expensive to use. A couple of quick shortcuts to alleviate, but not solve, the drawbacks come to mind:
By this time, we can see a clear zero-sum tradeoff: larger batches mean realistic computational (and monetary cost) complexity but larger cliffs. Another solution comes to mind:
None of these options or tradeoffs seem great. Either you have big cliffs, or you have more expensive and computationally intensive transactions, and regardless you have high complexity code with a high risk of bugs. What if we try something completely different? This is a solution with its own set of tradeoffs but also has its own potentially desirable characteristics.
Store three values per user account:
When the protocol allocates tokens to a user:
If this is the first time the account has received an allocation, the protocol sets the "last time tokens claimed" variable to the current time. If the user has received an allocation before, the count is increased only.
The user can then claim instantly available tokens at any time but is no longer able to vote with them and earn voting rewards with them. The user can claim long-term locked tokens at any time. The locked token count available uses a simple algorithm. All locked tokens are available after two years since the last time tokens were claimed. If the time since the last time tokens were claimed is less than two years, a proportional number of tokens are available. For example, if the count of tokens locked is 100 and it's been one year since the user last claimed tokens, then 50 tokens are available to claim. When the user claims those tokens, they can no longer vote/earn voting rewards with them, AND the last time tokens were claimed number is updated.
This is far easier to implement without making any mistakes and is less gas, storage, and computation expensive. However, this also has some interesting characteristics, which can be illustrated by example:
A user was allocated 125 tokens one year ago. Twenty-five tokens are instantly available and can be withdrawn at any time. The user is eligible to withdraw 50 of the remaining tokens since one year has passed. If they wait another year, they can withdraw 100 tokens AND all additional tokens earned during that time through voting or protocol participation. If they withdraw 50 tokens now, they will have 50 remaining tokens locked with a start date of NOW, so they will have to wait another two years to claim those 50 tokens and any additional tokens they earn during that time. If in another year they withdraw 25 tokens, they will have to wait another two years to withdraw the remaining 25 tokens, for a total of four years for 100 tokens. If they had waited two years, they would have received all 100 tokens in two years, along with voting inflation rewards on all 100 tokens.
This proposed DAO structure incentivizes people to hold tokens for the longer term and to vote with them, aligning the user's incentives with the protocol. In addition, this solution is simple to implement and cheap to execute on-chain. If the user wants more tokens earlier, they can have them, which means that the remaining tokens will be locked up for longer. They will therefore be disincentivized to abandon the project or make poor governance decisions due to the remaining value locked. Aligning incentives is what the block-chain is built for.
What are your thoughts? Do you have an alternative solution? Share them in Discord and help shape the Trustless DAO!