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

#

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

  • Do not allow staking on accounts with Mainnet locks or FIP-6 locks, which are now only possible on new accounts.

  • Do not allow unstaking of partial amounts. The user can add staked amounts, but when they unstake, they have to unstake everything that was stake. Example:

    • Allowed:

      • Stake 100

      • Stake 200

      • Stake 300

      • Unstake 600

    • Not allowed

      • Stake 100

      • Stake 200

      • Stake 300

      • Unstake 300

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.