Dria

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

Buyers can buy items from previus rounds

Summary

Buyers can buy items from previous rounds, without these items being re-listed.

Vulnerability Details

The documentation taken note in a few places that assets are meant to last only 1 round and for the buyer to be able to buy them the next, each seller should re-list his item.

We can also see a note for it in the natspec of relist "Relist the asset for another round"

@> /// @notice Relist the asset for another round and/or another buyer and/or another price.
/// @param _asset address of the asset.
/// @param _buyer new buyerAgent for the asset.
/// @param _price new price of the token.
function relist(address _asset, address _buyer, uint256 _price) external {

However that is not implemented in the code as purchase does not care which round the asset has been listed.

function purchase(address _asset) external {
AssetListing storage listing = listings[_asset];
// asset must be listed to be purchased
if (listing.status != AssetStatus.Listed) {
revert InvalidStatus(listing.status, AssetStatus.Listed);
}
// only the buyer can purchase the asset
if (listing.buyer != msg.sender) {
revert Unauthorized(msg.sender);
}
// update asset status to be sold
listing.status = AssetStatus.Sold;
// transfer asset from seller to Swan, and then from Swan to buyer
// this ensure that only approval to Swan is enough for the sellers
SwanAsset(_asset).transferFrom(listing.seller, address(this), 1);
SwanAsset(_asset).transferFrom(address(this), listing.buyer, 1);
// transfer money
token.transferFrom(listing.buyer, address(this), listing.price);
token.transfer(listing.seller, listing.price);
emit AssetSold(listing.seller, msg.sender, _asset, listing.price);
}

This enables generators to suggest assets that were listed many rounds ago and then for buyers to buy them.

Impact

Sellers would not need to relist any item, unless they want to change the buyer. This saves them the money if the assets is not the best for the current round. This would also reduce the profits each buyer makes as sellers would wait for their asset to be brought instead of relisting it for the new round.

  • Worse experience for all parties

  • Sellers are not incentivized to relist their items

  • Sellers are incentivized to wait until their item gets purchased

Tools Used

Manual review

Recommendations

Make it so only assets from this rounds can be selected for the oracle output. This can be done inside purchase

function purchase(address _asset) external {
AssetListing storage listing = listings[_asset];
+ (uint256 round, ,) = buyer.getRoundPhase();
+ // asset must be listed this round
+ if (listing.round != round) {
+ revert AssetExpired(listing.round, round);
+ }
// asset must be listed to be purchased
if (listing.status != AssetStatus.Listed) {
revert InvalidStatus(listing.status, AssetStatus.Listed);
}
// only the buyer can purchase the asset
if (listing.buyer != msg.sender) {
revert Unauthorized(msg.sender);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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