Too Discrete to Handle: How Low CAT Precision Can Become an Issue
A few days ago, an NFT Reward Distributor test was released as part of the DIG alpha deployment. The NFT distributor allows anyone to stake DataLayer Minion NFTs to continuously receive a share from a DIG token stream. This deployment is intended to test the capabilities of the reward distributor before it gets used as a means to allocate DIG mirror rewards. Fortunately (and unfortunately), the alpha test has uncovered a design flaw that leads to an uneven token distribution rate over time. This article will describe the issue, as well as what it means for minion stakers, how new puzzles will address it, and how to catch similar issues earlier in the future.
CAT Precision
On Ethereum, ERC-20 tokens usually have 18 decimals, likely taking inspiration from Ether (1 ether = 10^18 wei). Chia’s designers have chosen 12 decimals for XCH, but were met with a small issue when developing the Chia Asset Token (CAT) standard: for CATs to work in the coinset model, they would have to lock up small amounts of XCH (usually measured in mojos, 1 XCH = 10^12 mojos). The precision tradeoff they faced can be put as follows: giving CATs too many decimals means significant XCH needs to be locked up to mint the said CATs. If you give your CAT a precision of 12, you need to lock up a whole XCH to mint one CAT token. Giving your CAT too few decimals, on the other hand, might make it harder to use as the CAT can be broken down into fewer pieces. Ultimately, CATs now have 3 decimals, meaning the smallest non-zero CAT unit you can hold is 0.001.
Note that this is more of a social convention for UIs: in reality, every CAT you hold is a coin with a special puzzle and a value of cat_amount * 1000 mojos.
Reward Distributors and Precision
As I previously mentioned, reward distributors were heavily inspired by the math behind liquidity farms. In short, the distributor syncs when someone interacts with it and calculates how many tokens should be distributed for the last period based on state data. Given the title and introduction of the article, it’s natural to ask what happens with the ‘remainder’ that can’t be distributed for a period. For example, if 10,000 NFTs are staked and the distributor needs to allocate 10.001 DIG, what happens with the 0.001 DIG?
The worst fate the 0.001 DIG could have is to be discarded, as that means no one will ever get it. This has, of course, been the main concern around the formulas during puzzle development and review - and can’t happen for reward distributors. In the current puzzle, the distributor, like liquidity farms, allocates the 0.001 DIG to the remainder of the epoch. Essentially, the reward rate is slightly boosted so the 0.001 DIG is allocated to someone eventually.
This approach works fine for ERC-20 tokens because they have so many decimals that the remainder is an extremely small error that’s irrelevant in practice. On Chia, however, this becomes a relevant issue because the smallest unit is 0.001 DIG. In practice, 87,500 DIG per year means that roughly 0.001 DIG will be given to every staked NFT every hour. If someone syncs the distributor every few minutes - like everyone did during the first days, when users rushed to stake their NFTs - the 0.001 DIG per NFT will be pushed later and later into the epoch. Staked NFTs then had a reward rate of around 0 DIG per day during high-activity days, a relatively normal reward rate for low-activity periods that spanned hours, and will have a much higher reward rate towards the end of the epoch, when all the accumulated ‘postponed’ rewards will get distributed.
More generally, the smallest unit of distribution takes a while to be assigned to every NFT, and syncing smaller intervals leads to rewards being ‘postponed.’ Done often enough, someone can make the reward allocation rate slower over some periods. In turn, other periods will have a higher rate to compensate.
What This Means for Minion Holders
Extreme care was put into ensuring that rewards are not lost. Stakers will still get the 8.750 DIG per minion per year they’re owed (assuming all NFTs are staked - otherwise, the number will be higher). However, the rate at which DIG is assigned will vary based on how often people interact with the distributor.
Next Steps
The current reward distributor puzzles will be updated to fix this issue. At a high level, the new version of the distributor will have a higher internal precision for CATs. This precision will be ‘stripped’ just before payouts. The update will allow the correct distribution of small fractions of 0.001 DIG if sync operations are done for short time intervals, effectively leading to the same behavior observed on Ethereum, where the postponed reward amounts are so small they are not practically relevant.
Lessons Learned
This design flaw was still caught during testing, but I believe there are ways to catch these kinds of limitations earlier. A few suggestions include:
When designing puzzles, continuously ask yourself how the differences between Chia and the other systems where the mechanism was implemented may lead to unexpected behavior. Note that ‘behavior’ extends past security issues such as the loss of funds.
Test under real conditions. As part of early development, the distributor puzzles were tested on a simulator. The tests included scenarios with one or a few NFTs staked over short periods of time. The problematic precision behavior would’ve been detected if the tests included more realistic or extreme scenarios (e.g., test distribution when 10,000 NFTs are staked and 50,000 test CATs are distributed over 10 years, with someone interacting with a distributor every few minutes).
Broader reviews/audits: Instead of strictly looking for ways funds could be lost, the main question in a review or audit should be “What can someone do to make the behavior of the system deviate from what’s expected?”. This requires the purpose of the system to be well-defined in advance, and for the specification to be very verbose.
Documenting common issues: By posting about this issue, the hope is that other developers will have it on top of their mind when designing similar systems in the future.
Conclusion
Lastly, let me extend a big thank you to everyone that has helped with testing so far. As you can see, these tests provide vital feedback that will improve the final version of the DIG Network.
You can find more about the DIG Network at dig.net.