Summary
BuyerAgents have a max asset count per round for buying assets, an attacker can fill this limit with unwanted assets. Under normal conditions this would not cause an issue as sellers have to pay a fee to buyers to list assets for them but an attacker can set the price of an asset to zero, this also sets the buyer fee to zero making this attack possible.
Vulnerability Details
In Swan.sol using list function a seller can list an asset for a buyer, you can observe that if asset count hits the maxAssetCount the function reverts:
function list(string calldata _name, string calldata _symbol, bytes calldata _desc, uint256 _price, address _buyer)
external
{
BuyerAgent buyer = BuyerAgent(_buyer);
(uint256 round, BuyerAgent.Phase phase,) = buyer.getRoundPhase();
if (phase != BuyerAgent.Phase.Sell) {
revert BuyerAgent.InvalidPhase(phase, BuyerAgent.Phase.Sell);
}
if (getCurrentMarketParameters().maxAssetCount == assetsPerBuyerRound[_buyer][round].length) {
revert AssetLimitExceeded(getCurrentMarketParameters().maxAssetCount);
}
address asset = address(swanAssetFactory.deploy(_name, _symbol, _desc, msg.sender));
listings[asset] = AssetListing({
createdAt: block.timestamp,
royaltyFee: buyer.royaltyFee(),
price: _price,
seller: msg.sender,
status: AssetStatus.Listed,
buyer: _buyer,
round: round
});
assetsPerBuyerRound[_buyer][round].push(asset);
transferRoyalties(listings[asset]);
emit AssetListed(msg.sender, asset, _price);
}
For transferRoyalties function responsible for sending fees to the buyer, you can observe that if the asset price is specified as zero, fees will come out as zero:
function transferRoyalties(AssetListing storage asset) internal {
uint256 buyerFee = (asset.price * asset.royaltyFee) / 100;
uint256 driaFee = (buyerFee * getCurrentMarketParameters().platformFee) / 100;
token.transferFrom(asset.seller, address(this), buyerFee);
token.transfer(asset.buyer, buyerFee - driaFee);
token.transfer(owner(), driaFee);
}
This makes it possible for an attacker to list as many trash assets as needed to block the intended use of the protocol.
Impact
Buyer's ability to buy assets is denied for a round. Next round the attack can be repeated.
Recommendations
A minimum check for asset price should be introduced.