Precision loss in getDistribution
resulting in revert
Description
When a user invokes the yeet
function with their funds, the function distributes the funds to multiple pots and taxes.
function _yeet(uint256[] memory tokenIds) internal {
// (...)
(
uint valueToPot,
uint valueToYeetback,
uint valueToStakers,
uint publicGoods,
uint teamRevenue
) = getDistribution(msg.value);
// (...)
}
function getDistribution(uint256 yeetAmount) public view returns (uint256, uint256, uint256, uint256, uint256) {
uint256 scale = gameSettings.SCALE();
uint valueAfterTax = (yeetAmount / scale) * (scale - TAX_PER_YEET);
uint valueToYeetBack = (yeetAmount / scale) * (YEETBACK_PERCENTAGE);
uint valueToPot = (yeetAmount / scale) * (scale - YEETBACK_PERCENTAGE - TAX_PER_YEET);
uint tax = yeetAmount - valueAfterTax;
uint256 valueToStakers = (tax / scale) * TAX_TO_STAKERS;
uint256 publicGoods = (tax / scale) * TAX_TO_PUBLIC_GOODS;
uint256 teamRevenue = (tax / scale) * TAX_TO_TREASURY;
require(valueToPot + valueToYeetBack + valueToStakers + publicGoods + teamRevenue == yeetAmount, "Yeet: Distribution error");
return (valueToPot, valueToYeetBack, valueToStakers, publicGoods, teamRevenue);
}
The getDistribution
function tries to ensure that the sum of the distributed amounts is equal to the input amount. However, it should be noted that parts of the tax are calculated with rounding down. Because the dust amount caused by this rounding down is not handled, unless the tax
is divisible by the scale
, getDistribution
reverts.
Impact
The getDistribution
function reverts if the tax
is not divisible by the scale
. This prevents the yeet
function from being invoked with specific amounts.
Recommendations
Consider removing the check mentioned above. We believe that the dust lost with this precision loss is negligible, and the potential configuration misses are checked when the configuration is changed.
Remediation
This issue has been acknowledged by Sanguine Labs LTD, and a fix was implemented in commit a29e6dbf↗.