- add pictures to support the flow
- add some features from discussions and user comments
- Rename farms into streams
TODO: finalise the weighting coefficients
This proposal is an in-depth description of the staking approach of the AURORA token that allows for the community treasury use-case previously voted by the Aurora DAO; implements the protection from the Sybil attacks and also some additional use cases. Though the major focus of the proposal is the staking mechanism, the main functionality of the community treasury platform is also described.
AURORA is envisaged as a governance token through which the decentralized governance (voting) of the Aurora protocol should be implemented. To resist Sybil attacks (a token holder votes, transfers AURORA to another account and then votes again), a staking mechanism should be implemented. Through staking users are getting rewards and VOTE tokens.
VOTE tokens are ERC-20 in-transferrable tokens that are used to vote for the allocations of funds from community treasury through the community treasury platform (Jet). Besides this use case, aggregated historical info on the VOTE tokens accrual and usage should be available for the higher-level governance (see Further decentralisation of the governance: DAO council seats may be elected every year; the voting power of the user should be determined based on the year-long info on the earned and used VOTE tokens).
Staking is closely coupled with the logic of the Jet platform, which includes the notion of a Season. A season is a period during which projects can apply for the funding and users would vote for them, and, as a result, would distribute the allocated funding among these projects. Seasons support agile-style evolution of Jet functionality, but generally are not different from one another. The length of the season is 2 months, so there are 6 seasons per year. Each season has two major stages: application and voting, each lasting around a month (in between these stages there would be technical periods that would last days). During the application phase the developers / project teams may apply for the funding in this season; during the voting phase the AURORA token holders vote for the projects using VOTE tokens.
Besides the VOTE tokens, staking of AURORA is generating rewards to the users. Rewards are generated by streams that might be created by third parties, however, subjected to whitelisting. All the allocations of the streams are made pro-rata depending on the total weighted stake.
Locked AURORA (for example AURORA that should yet to be transferred to the private round investors) cannot be used for the staking.
Relying on the generic info about the governance tokens staking, we should anticipate that the staking contract would host around 30-50% of the circulating supply of AURORA, which would make this contract the most important contract in the Aurora ecosystem.
The staking contract should be manageable and with the highest probability it would be updated in the future. An admin for the contract should be an implicit account* of the Aurora DAO on Aurora.
*Every NEAR account has an implicit account in Aurora and is able to interact from NEAR runtime with Aurora runtime.
Multiple accounts should be able to temporarily seize the execution of staking, including paying out rewards and usage of VOTE. This is required for the fast reaction to the threats. The admin should be able to manage the list of these accounts and unfreeze the staking contract.
Users should be able to stake AURORA (deposit AURORA to the contract for some period of time). User specifies the amount of AURORA staked (minimum 5 AURORA) and the duration of the stake. The duration of the stake is determined in full seasons and can be from 0 to 24 (4 years).
Example: it’s the middle of the 3rd season, a user chooses to stake for 4 seasons. This means that his tokes would be locked from now, through the 4th, 5th, 6th and 7th season. By the end of 7th season these tokens would be able to be withdrawn.
During staking, the user gets rewards and VOTE tokens. Depending on the duration of the staking, there’s a weighting coefficient that is applied to both rewards and the amount of VOTE tokens allocated.
Coefficients should be able to be set and updated by the Admin of the contract. It is expected that the coefficients will naturally increase with the staking period for both Rewards and VOTE tokens.
If a user chooses to stake for 0 seasons, he’s able to withdraw the stake any time. This should be similar to a demand account. AURORA tokens staked for 0 seasons generate rewards, but not generate VOTE tokens. Rewards are generated every AURORA block and can be withdrawn at any time.
If a user chooses to stake for N>0 seasons, his stake cannot be withdrawn before the end of the next N seasons. For each full season during which the tokens are staked, the VOTE tokens are allocated. VOTE tokens are generated in the beginning of the respective season. By the end of the N full seasons, staked AURORA tokens should be moved to a demand account; they will be able to be withdrawn at any time, generate minimum rewards but will not generate VOTE tokens.
AURORA stakes will be stored separately from one another because of the complexity of weighting coefficients. All the staked AURORA with N=0 should be aggregated.
Example: it’s the middle of the 3rd season; a user stakes 100 AURORA for the next 5 seasons and for these tokens receives the weighting coefficient 2. During the 4th season he stakes additional 50 tokens for 1 season. The weighting coefficient for these tokens is equal to 1. The resulting amount of VOTE tokens that a user should receive during 5th season is 100*2 + 50*1 = 250 tokens.
Since it is required to treat each stake of AURORA separately, a user may face the issue of an update transaction taking too much gas. To avoid this, a method for getting rewards and claiming VOTE tokens is implemented per user per stake and can be called by a third party. There is a great deal of sense to create a script that will claim VOTE tokens for the users.
A user should be able to claim VOTE tokens and rewards. The rewards may be generated by different streams (see next), so a user should specify the stream that he claims.
An admin of the staking contract can whitelist a stream. Whitelisting of the stream provides the option for the stream creator (presumably the issuing party of a specific token) to deposit some ERC-20 tokens on the staking contract and potentially get in return some AURORA tokens. Deposited ERC-20 tokens will be distributed to the stakers over some period of time. Here are the parameters of the whitelisting method:
- Amount of the AURORA deposited by the Admin. AURORA should be transferred through transferFrom method of the AURORA ERC-20
- Stream creator address – only this account would be able to create a stream
- Rewards token address – the address of the ERC-20 tokens to be deposited in the stream
- The upper amount of the tokens, that should be deposited by the stream creator. In case the creator deposits less than the specified amount, the amount of released AURORA is decreased proportionally. All the rest of AURORA is transferred back to the admin.
- Max block height, until which the option to create the stream is active
- Rewards schedule, specified as an array of tuples (block height, amount of reward tokens that is kept on the staking contract at this block height). This array specifies the piecewise-linear dependency of the decay of the reward in the stream.
Note: the release of AURORA tokens to the stream creator is subjected to the same schedule as rewards. Thus if for a specific moment in time 30% of the rewards are distributed, then it means that 30$ of the AURORA deposit can be withdrawn by the stream creator.
Important: the allowed mechanics of the streams might be useful for two use cases.
First, the investment from either the community treasury or the Aurora DAO directly. One of the KPIs of the project that has received the investment might be the deposit of the specified amount of project tokens to the staking contract once the tokens are issued / released.
Second, staking contract implements the native way of doing an airdrop to the Aurora community. Any project that would like to do an airdrop now is able to use the staking contract.
This method is called by the stream creator (only once) and it realizes the option that was set up during the whitelisting phase.
This method can be called only by the admin and cancels the reward allocations of the stream to the staking users and the distribution of the AURORA to stream creator. This is a blacklisting functionality that is intended to be used only in emergency situations. The remainder of the rewards tokens and AURORA should be able to be transferred by the admin to any Aurora account.
50 weighting coefficients should be updatable by the admin of the contract (25 coefficients for the rewards and 25 coefficients for VOTE)
Staking contract should implement the ERC-20 interface of the VOTE token. It should be a non-transferrable token that can be consumed only by the set of the whitelisted addresses (Jet contract in the beginning). transfer method should always fail and transferFrom method should fail if it’s not called from the whitelisted contract.
Admin of the contract should be able to add or burn VOTE tokens. This is a safety method with an intention to use only in emergency situations.
For every season and every user we should record and give a public access to the two numbers: the amount of VOTE tokens that was obtained by the user (is set during the call of claim VOTE tokens); and the amount of used VOTE tokens in this season (updated every time when transferFrom is called from the whitelisted contract)
VOTE tokens should become available for claiming at the beginning of the season. However, starting with the voting phase of the season, VOTE tokens should linearly decay to zero at the end of the voting phase. Thus in the middle of the voting phase, the user should have only half of the VOTE tokens available for the voting in Jet.
In the beginning of the voting phase there should be a grace period (24-48h) before the decay start. Grace period prevent excess load on the network in the beginning of the voting phase.
Decay mechanic is used to mitigate the following problem. A voting in Jet due to the short development timeline may be implemented only in an open way. Which means that with the usage of indexers anyone would be able to figure out what is the current amount of VOTE that was used and what projects have been voted for. This gives an unfair advantage to the users that vote at the end of the season, since they can most certainly determine which projects will win and vote for them. This is important since the mechanics of the rewards, distributed to the Jet users, should depend on the results of the voting and whether the project received the grant or not, in particular: the community should be motivated to dive into projects instead of just voting for the first random application.
Staking of AURORA tokens should be possible to the other accounts: Alice should be able to create a stake to Bob’s account. Stake that is created for the other account is irrevocable.
This functionality will be useful to allow for the staked drops of AURORA: anyone would be able to create a stake of AURORA to the user, thus motivating him to take part in the governance of Aurora. Similar solution in the NEAR runtime is very popular.
- AURORA staking contract should be deployed to Aurora; but Aurora DAO is located in NEAR runtime. The functionality of the interaction with Aurora from the NEAR account is implemented, though it is not yet thoroughly tested
- Maybe we should remove the necessity of approve for VOTE tokens for the whitelisted contracts. If so, the user won’t need to send an additional transaction to the staking contract before voting.
- We have several dimensions for aggregating the staking rewards: stakes/deposits – they should be treated separately; streams. Both of these numbers (amount of deposits and streams) might be quite high. Thus claiming the rewards within a single transaction is not possible. The best solution to keep gas usage low is to specify within a claim rewards function a stream and a particular deposit. However, this would be quite inconvenient to the user since he would need to click through his wallet many times to receive all the possible rewards through all the possible deposits that he has. Fundamentally, this is the unsolvable issue without limiting the number of deposits and streams (and at least the second is non-viable). But perhaps, we can do something better than clicking through every reward. For example, allow 3rd party to withdraw the reward for the user. If so, then the backend script can withdraw the rewards periodically
- To simplify the staking contract and the management of the VOTE tokens, one can separate the token and staking functionality, turning staking contract into the factory of the VOTE token contracts that are specific to each season. These contracts would store the info on the usage and should be used for the voting purposes.
- Delegation of the VOTE tokens. Delegation mechanics has shown itself quite sustainable and result-oriented. It allows people to form cohorts, spend less time on making decisions and embraces the trust in between them.
- A good direction of the development would be to introduce a delay for the upgrade of the staking (and thus governance) mechanism. Such a delay will give more power to the token holders, since in case they are disagreeing with the upgrade, they have a time to leave the system.
- Implementation of the commit-reveal scheme for the voting in Jet might remove the necessity of VOTE decay in the future. Most probably this upgrade should come in hand with the advanced voting mechanics that protect the system from malicious behaviour, like selling votes (voting may happen multiple times with inability to prove that the vote was final).
- Some tokens might have restrictions. In the future it would be good to implement an ability to the stream creator to specify the contract that will do the check of whether the user is eligible for the rewards from the stream or not.
- There’s always a possibility to make staking liquid (give user a sAURORA token). However, this most probably requires massive overthinking of the staking mechanism, especially in the domain of staking period and weighting coefficients. There might be 3rd party projects evolving that provide the functionality of the liquid staking.
- Automatic compounding of the stakes. This might be helpful, but will substantially complicate the formulas.