sherlock-audit / 2024-08-flayer-judging

0 stars 0 forks source link

Round Silver Cuckoo - User's listing can expire unexpectedly due to pause #716

Open sherlock-admin3 opened 4 days ago

sherlock-admin3 commented 4 days ago

Round Silver Cuckoo

Medium

User's listing can expire unexpectedly due to pause

Summary

The listing::getListingType function is time-dependent and is used to determine the type of a specific listing within the protocol. Liquid listings expire after a specified period and transition into dutch listings. However, pause time can affect this process, as it is not considered in the calculation

Vulnerability Detail

Medusa creates a liquid listing and expects it to expire in 150 days Medusa's listing has not been filled even on day 149 since her listing The protocol became paused some hours to the end of day 150 and still remain paused after day 150 medusa's listing has now expired is now a Dutch listing Medusa can no longer modify her listing, or cancel her listing 😭 Recon can now buy her listing as Dutch 💀

Impact

User's listing gets expired not considering pause time

Code Snippet

https://github.com/sherlock-audit/2024-08-flayer/blob/0ec252cf9ef0f3470191dcf8318f6835f5ef688c/flayer/src/contracts/Listings.sol#L962 There is an if statement below which prevents you from calling the modifyListings function if your listing has expired

    function modifyListings(address _collection, ModifyListing[] calldata _modifyListings, bool _payTaxWithEscrow) public nonReentrant lockerNotPaused returns (uint taxRequired_, uint refund_) {
        uint fees;

        for (uint i; i < _modifyListings.length; ++i) {
            // Store the listing
            ModifyListing memory params = _modifyListings[i];
            Listing storage listing = _listings[_collection][params.tokenId];

            // We can only modify liquid listings
@>            if (getListingType(listing) != Enums.ListingType.LIQUID) revert InvalidListingType();

There is an if statement below which prevents you from calling the cancelListings function if your listing has expired

    function cancelListings(address _collection, uint[] memory _tokenIds, bool _payTaxWithEscrow) public lockerNotPaused {
        uint fees;
        uint refund; 

        for (uint i; i < _tokenIds.length; ++i) {
            uint _tokenId = _tokenIds[i];

            // Read the listing in a single read
            Listing memory listing = _listings[_collection][_tokenId];

            // Ensure the caller is the owner of the listing
            if (listing.owner != msg.sender) revert CallerIsNotOwner(listing.owner);

            // We cannot allow a dutch listing to be cancelled. This will also check that a liquid listing has not
            // expired, as it will instantly change to a dutch listing type.
            Enums.ListingType listingType = getListingType(listing);
  @>          if (listingType != Enums.ListingType.LIQUID) revert CannotCancelListingType();

The code block here shows how listing types are determined

    function getListingType(Listing memory _listing) public view returns (Enums.ListingType) {
        // If we cannot find a valid listing and get a null parameter value, then we know
        // that the listing does not exist and it is therefore just a base token.
        if (_listing.owner == address(0)) {
            return Enums.ListingType.NONE;
        }

        // If the listing was created as a dutch listing, or if the liquid listing has
        // expired, then this is a dutch listing.
        if (
            (_listing.duration >= MIN_DUTCH_DURATION && _listing.duration <= MAX_DUTCH_DURATION) ||
@>            _listing.created + _listing.duration < block.timestamp 
        ) {
            return Enums.ListingType.DUTCH;
        }

        // For all other eventualities, we have a default liquid listing
        return Enums.ListingType.LIQUID; 

Tool used

Manual Review

Recommendation

Consider taking pause time into consideration to avoid