Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: low
Valid

Sequential Fee Calculations Lead to Lost Platform Revenue Due to Precision Loss

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 {
// calculate fees
uint256 buyerFee = (asset.price * asset.royaltyFee) / 100;
uint256 driaFee = (buyerFee * getCurrentMarketParameters().platformFee) / 100; // Platform fee can round to 0
}

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:

  1. Combine calculations to minimize precision loss:

function transferRoyalties(AssetListing storage asset) internal {
// Calculate platform fee first to avoid rounding issues
uint256 driaFee = (asset.price * asset.royaltyFee * getCurrentMarketParameters().platformFee) / 10000;
uint256 buyerFee = (asset.price * asset.royaltyFee) / 100 - driaFee;
// Transfer fees
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:

// Constants
uint256 constant BASIS_POINTS = 10000;
// Calculations using basis points
uint256 driaFee = (asset.price * asset.royaltyFee * platformFee) / (BASIS_POINTS * BASIS_POINTS);
```
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Rounding Issue in `Swan.sol::transferRoyalties` function

Appeal created

sovaslava Auditor
12 months ago
inallhonesty Lead Judge
12 months ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Rounding Issue in `Swan.sol::transferRoyalties` function

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.