Description:
Here
The transferRoyalties function calculates fees using sequential percentage calculations with integer division. This approach leads to precision loss as each division operation rounds down, particularly affecting small transactions or those with low percentage fees.
function transferRoyalties(AssetListing storage asset) internal {
uint256 buyerFee = (asset.price * asset.royaltyFee) / 100;
uint256 driaFee = (buyerFee * getCurrentMarketParameters().platformFee) / 100;
}
Impact:
-
Platform loses revenue when driaFee calculations round to zero
-
Affects all transactions where (buyerFee * platformFee) < 100
-
Cumulative loss of revenue over many small transactions
-
Inconsistent fee application based on transaction size
Proof of Concept:
// Test Case 1: Small Transaction - Platform Gets Nothing// Test Case 1: Small Transaction - Platform Gets Nothing
asset.price = 100
asset.royaltyFee = 3 // 3%
platformFee = 5 // 5%
buyerFee = (100 * 3) / 100 = 3
driaFee = (3 * 5) / 100 = 0 // Rounds to 0, platform gets nothing
// Test Case 2: Larger Transaction - Platform Gets Fee
asset.price = 1000
asset.royaltyFee = 3 // 3%
platformFee = 5 // 5%
buyerFee = (1000 * 3) / 100 = 30
driaFee = (30 * 5) / 100 = 1 // Platform receives fee
Recommended Mitigation:
Combine calculations to minimize precision loss:
function transferRoyalties(AssetListing storage asset) internal {
uint256 driaFee = (asset.price * asset.royaltyFee * getCurrentMarketParameters().platformFee) / 10000;
uint256 buyerFee = (asset.price * asset.royaltyFee) / 100 - driaFee;
token.transferFrom(asset.seller, address(this), buyerFee + driaFee);
token.transfer(asset.buyer, buyerFee);
token.transfer(owner(), driaFee);
}
2.Consider using basis points (10000) instead of percentages for more precise calculations:
uint256 constant BASIS_POINTS = 10000;
uint256 driaFee = (asset.price * asset.royaltyFee * platformFee) / (BASIS_POINTS * BASIS_POINTS);
```