sherlock-audit / 2024-08-flayer-judging

0 stars 0 forks source link

Shiny Glass Hare - Unintended Tax Refund for Liquidation Listings in Relist Function #793

Open sherlock-admin4 opened 4 days ago

sherlock-admin4 commented 4 days ago

Shiny Glass Hare

Medium

Unintended Tax Refund for Liquidation Listings in Relist Function

Summary

The relist function in the Listings contract does not differentiate between regular listings and liquidation listings when processing tax refunds. This oversight could lead to unintended tax refunds being issued for liquidation listings, which should not receive any refunds.

Vulnerability Detail

In the relist function, tax refunds are processed for all listings without checking if they are liquidation listings:


function relist(CreateListing calldata _listing, bool _payTaxWithEscrow) public nonReentrant lockerNotPaused {
    // ...
    (uint _fees,) = _resolveListingTax(oldListing, _collection, true);
    if (_fees != 0) {
        emit ListingFeeCaptured(_collection, _tokenId, _fees);
    }
    // ...
}

Test:

    function test_refuntToLiqLists() public {
        // Set our keeper address
        address payable _owner = users[1];
        address keeperAddress = address(10);

        uint _tokenId = 0;

        erc721a.mint(_owner, _tokenId);
        vm.startPrank(_owner);

        // Provide the user with sufficient ERC20 to fulfill the partial adjustment
        deal(
            address(locker.collectionToken(address(erc721a))),
            address(this),
            1 ether
        );

        locker.collectionToken(address(erc721a)).approve(
            address(protectedListings),
            1 ether
        );

        // Create our listing
        erc721a.approve(address(protectedListings), _tokenId);
        _createProtectedListing({
            _listing: IProtectedListings.CreateListing({
                collection: address(erc721a),
                tokenIds: _tokenIdToArray(_tokenId),
                listing: IProtectedListings.ProtectedListing({
                    owner: _owner,
                    tokenTaken: 0.5 ether,
                    checkpoint: 0
                })
            })
        });

        // Warp forward to a point at which the collateral available is negative
        vm.warp(block.timestamp + LIQUIDATION_TIME);
        vm.stopPrank();
        // Trigger our liquidation
        vm.prank(keeperAddress);
        protectedListings.liquidateProtectedListing(address(erc721a), _tokenId);

        locker.collectionToken(address(erc721a)).approve(
            address(listings),
            type(uint).max
        );
        address token = address(locker.collectionToken(address(erc721a)));
        deal(token, address(this), type(uint).max);
        emit log_uint(listings.balances(_owner, address(token)));
        listings.relist(
            IListings.CreateListing({
                collection: address(erc721a),
                tokenIds: _tokenIdToArray(_tokenId),
                listing: IListings.Listing({
                    owner: payable(address(this)),
                    created: uint40(block.timestamp),
                    duration: listings.MIN_LIQUID_DURATION(),
                    floorMultiple: 500
                })
            }),
            false
        );
        emit log_uint(listings.balances(_owner, address(token)));
    }

Impact

This vulnerability could lead to financial losses for the protocol. Liquidation listings, which are created when a protected listing is liquidated, should not receive tax refunds.

Code Snippet

https://github.com/sherlock-audit/2024-08-flayer/blob/0ec252cf9ef0f3470191dcf8318f6835f5ef688c/flayer/src/contracts/Listings.sol#L644

Tool used

Manual Review

Recommendation

Implement a check to differentiate between regular listings and liquidation listings before processing tax refunds.