Lock period precision issue
Overview
This issue has been discovered during development of FIP-21 Staking and requires a consideration and decision on best path forward.
The Issue
Requirements
Staking requirements state that:
When user unstakes tokens, those tokens are locked for a period of 7 days.
User can unstake any amount less than what they originally staked.
User can stake/unstake from an account which has Mainnet or FIP-6 locks.
7 day lock technical approach
The technical approach to deliver the 7 day unstake lock is to rely on FIP-6 functionality which is defined by:
Total locked amount
Percentage unlocked at any given period with 3 decimal precision.
Example
Locked amount: 100
Periods
Period 1
Duration: 10 days
Percent: 50.000%
Period 2
Duration: 20 days
Percent: 50.000%
Result
50 tokens will unlock after 10 days
50 tokens will unlock after 20 days
When user unstakes an amount the FIP-6 locks are supposed to be adjusted to insert a new unlock period. To continue the above example, if the user of the above account staked 100 tokens and now unstakes 10, their FIP-6 locks would be adapted as follows:
Locked amount: 110
Periods
Period 0
Duration: 7 days
Percent: 9.09090909090909…
Period 1
Duration: 10 days
Percent: 45.45454545454545…
Period 2
Duration: 20 days
Percent: 45.45454545454545…
However FIP-6 percent precision is decimals, so each period will have to be rounded as follows:
9.09090909090909 becomes 9.091
45.45454545454545 becomes 45.455
Which when added equal to 100.001%
We initially thought this could be solved by adjusting the “slack” of Period 0 in the above example like this:
Period 0
Duration: 7 days
Percent: 9.090
Period 1
Duration: 10 days
Percent: 45.455
Period 2
Duration: 20 days
Percent: 45.455
Result
9.999 tokens will unlock after 7 days
50.0005 tokens will unlock after 10 days
50.0005 tokens will unlock after 20 days
However, after additional consideration this approach appears undesirable because:
It causes undesired differences in token amounts, which may be hard to explain to users.
In extreme cases it can lead to undesired behavior, when the user may be rounded down. For example:
User got 50,000,000 FIO tokens locked via FIP-6 locks for 1 year
They now stake 10,000 FIO
They now want to unstake 250 FIO
Since 250 is 0.0004999% it will get rounded to 0%, and even if the “slack” logic above was in place the user would unstake 500 FIO
Solutions
# | Solution | Description | Tech difficulty | Hack vs. right way |
---|---|---|---|---|
1 | Leave as is | User will get behavior described above, but an argument could be made that most users will not be affected in a meaningful way. Future uses of locks for other purposes may run into the same issue. | None | HACK |
2 | The right thing to do | Re-architect the FIP-6 locks to operate on SUFs and not percentages. This removes the precision issue from the chain altogether and makes locks more flexible for potential future uses. | HIGH | RIGH WAY |
3 | Implement staking limits |
| LOW | Medium |
4 | Remove unstake 7-day lock | When unstaking, the user will immediately receive 100% of what they wanted to unstake. | LOW | Medium |
2021-06-01 Discussion
During a discussion with @Luke Stokes @Eric Butz @Ed Rotthoff @Pawel Mastalerz a decision was made to proceed with Option #2:
Dev/testing incremental time estimates:
Option 1: 0
Option 2: +3 weeks
Option 3: +1 week
Option 4: 0 (or reduction)
Option 1 was disqualified due to usability issues it creates.
Option 4 was disqualified as it removes a major reason for the project: ability to not include staked tokens in circulating supply and further creates a potential for unpredictable gaming of staking.
Option 2 is 2 weeks longer than Option 1, but:
It modifies locks to be more robust for locking, staking and any other application in the future.
Removal of percentages simplifies testing.
Staking is dependent on Bahamas release, which is currently planned for 6/25 (may be pulled in earlier). It is therefore estimated that Staking will deploy to Testnet on July 9th and that date is unlikely to be impacted by selecting Option 2, because the additional development will occur before that time. Although, there is risk that additional locks testing will uncover unforeseen bugs which will push the date out.
Even if the date is pushed out by a week or two, it seems like a reasonable price to pay for more robust chain functionality.
In order to limit migration risk a new FIP will be created to temporarily disable FIP-6 staking, until this FIP is launched.