Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: medium
Invalid

A buyer can set the royaltyFee very high, effectively using it as a discount, allowing them to acquire the asset at a significantly lower price

Summary

Any buyer can set the royaltyfee upto 100%, if they do so the price of asset will be reduced by that factor making it cheap for buyer.

Vulnerability Details

If a buyer wants to reduce the price of an asset listed by the seller, they can simply increase the royaltyFee, which will then be transferred to the buyer. The effective amount the buyer will pay will be calculated as the:- price - royaltyFee.

Since the buyerFee is calculated as a % of price of asset.

the seller transfer the royaltyfee to buyer, hence the price of asset is dropped if the royaltyfee is set very high.

function transferRoyalties(AssetListing storage asset) internal {
// calculate fees
@> uint256 buyerFee = (asset.price * asset.royaltyFee) / 100;
uint256 driaFee = (buyerFee * getCurrentMarketParameters().platformFee) / 100;
// first, Swan receives the entire fee from seller
// this allows only one approval from the seller's side
token.transferFrom(asset.seller, address(this), buyerFee);
// send the buyer's portion to them
@> token.transfer(asset.buyer, buyerFee - driaFee);
// then it sends the remaining to Swan owner
token.transfer(owner(), driaFee);
}

Impact

Since the buyer set the royaltyfee, and the buyerfee is calculated as % of asset price the buyer will indirectly determine the price of asset by adjusting the royaltyfee.

This will work as discount to buyer and the seller will not get the fair price of asset.

Tools Used

Manual review

Recommendations

Make following changes in the below given functions (one constructor and other setFeeRoyalty function).

reduce the range of _royaltyFee variable form 100 -> to a reasonable range, which will not be exploit by the buyer.

lets say 1% to 50% { it is just an example the owner of protocol should change it to some reasonable range}

constructor(
string memory _name,
string memory _description,
uint96 _royaltyFee,
uint256 _amountPerRound,
address _operator,
address _owner
) Ownable(_owner) {
- if (_royaltyFee < 1 || _royaltyFee > 100) {
- revert InvalidFee(_royaltyFee);
- }
+ if (_royaltyFee < 1 || _royaltyFee > 50) {
+ revert InvalidFee(_royaltyFee);
+ }
royaltyFee = _royaltyFee;
swan = Swan(_operator);
amountPerRound = _amountPerRound;
name = _name;
description = _description;
createdAt = block.timestamp;
marketParameterIdx = swan.getMarketParameters().length - 1;
// approve the coordinator to take fees
swan.token().approve(address(swan.coordinator()), type(uint256).max);
swan.token().approve(address(swan), type(uint256).max);
}
function setFeeRoyalty(uint96 _fee) public onlyOwner {
_checkRoundPhase(Phase.Withdraw);
- if (_fee < 1 || _fee > 100) {
- revert InvalidFee(_fee);
- }
+ if (_fee < 1 || _fee > 50) {
+ revert InvalidFee(_fee);
+ }
royaltyFee = _fee;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Appeal created

saurabh_singh Submitter
12 months ago
inallhonesty Lead Judge
12 months ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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