## Summary
A malicious user can fill up the `Swan.ssetsPerBuyerRound[_buyer][round]` array to reach the `maxAssetCount` by listing the buyer with assets of **zero price**, which will prevent further assets from being listed for that agent for an entire round.
## Vulnerability Details
- Any seller can list an asset/assets to any buyer agent via `Swan.list()`, where the seller determines to which agent this asset to be listed and for which price.
- Befor the asset is added to the `Swan.ssetsPerBuyerRound[_buyer][round]` of the buyer, a check is made to ensure that the currently listed assets number for this buyer at his current round doesn't exceed the maximum assets allowed to be listed for buyers:
```javascript
function list(
string calldata _name,
string calldata _symbol,
bytes calldata _desc,
uint256 _price,
address _buyer
) external {
//...
if (getCurrentMarketParameters().maxAssetCount == assetsPerBuyerRound[_buyer][round].length) {
revert AssetLimitExceeded(getCurrentMarketParameters().maxAssetCount);
}
//...
}
```
- And after the asset is added to the buyer listed assets; the royalities are transferred from the seller (the one who listed to the buyer agent) to the platform and the buyer agent via `transferRoyalties()`
```javascript
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);
}
```
- But as can be noticed; there's no check on the listed asset price if it's > 0; which will open the door for any malicious seller to fill up the `Swan.ssetsPerBuyerRound[_buyer][round]` with the maximumAssetCount determined by the platform with assets of zero price.
## Impact
By knowing that listing assets for a buyer agent can be done only when the buyer is in the sell phase; then filling up the `Swan.ssetsPerBuyerRound[_buyer][round]` with the maximumAssetCount with assets of zero price will result in freezing further listing of assets for that buyer for the current round (DoSing any further listing for the current round), resulting in a loss of value for the buyer agent as he might be missing any assets that entitled to be listed to him and DoSed from being listed as the maxAssetCount for him is reached maliciously, while the malicious seller (the attacker) will be losing only the gas fees to execute the attack if he listed assets with zero price.
## Proof of Concept
[Swan.list() function/ L168-L170](https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/Swan.sol#L168C9-L170C10)
```javascript
function list(
string calldata _name,
string calldata _symbol,
bytes calldata _desc,
uint256 _price,
address _buyer
) external {
//...
if (getCurrentMarketParameters().maxAssetCount == assetsPerBuyerRound[_buyer][round].length) {
revert AssetLimitExceeded(getCurrentMarketParameters().maxAssetCount);
}
//...
}
```
## Tools Used
Manual Review.
## Recommendations
Introduce a `minAssetPrice` variable to be enforced on each asset when listed, and update `Swan.list()` to check for this price:
```diff
function list(
string calldata _name,
string calldata _symbol,
bytes calldata _desc,
uint256 _price,
address _buyer
) external {
+ require(_price > minAssetPrice);
//...
}
```