Submitted by ABAIKUNANBAEV
At the moment, the function AllocateTokens() uses the Quo() operation when calculating the pool fraction for a particular validator pool. The problem is that it does not round down to 0, allowing to receive a bigger fraction than it actually is.
Lets take a look at how the operation is implemented:
https://github.com/initia-labs/initia/blob/main/x/distribution/keeper/allocation.go#L83
Here, the rewardWeight is divided by the WeightsSum using the Quo() arithmetic and not QuoTruncate() that rounds the number down. The number is not truncated here as the Quo() function is used. The problem lies in the fact of how the Quo() method rounds the number:
Quo() calls chopPrecisionAndRound():
https://github.com/piplabs/cosmos-sdk/blob/7ce4a34e92b12fc3aed8eec6e080b6493554072d/math/dec.go#L356
QuoTruncate() (which should be used instead) calls chopPrecisionAndTruncate() under the hood:
https://github.com/piplabs/cosmos-sdk/blob/7ce4a34e92b12fc3aed8eec6e080b6493554072d/math/dec.go#L376
The method always rounds down and has to be used instead; otherwise, the users will get the bigger poolFraction and therefore, bigger rewards. Take a look at the vanilla CosmosSDK implementation and how it rounds down the fractions:
https://github.com/cosmos/cosmos-sdk/blob/main/x/distribution/keeper/allocation.go#L71
Use QuoTruncate() instead of Quo().
beer-1 (Initia) confirmed and commented:
Initia mitigated:
Status: Mitigation confirmed. Full details in reports from 0xAlix2, berndartmueller and Franfran.
