ProtectedListings:createListings() doesn't create checkPoints for subsequent listing of a collection
Summary
ProtectedListings:createListings() doesn't create checkPoints for subsequent listing of a collection
Vulnerability Detail
When a tokenId of a collection is protected listed for the fist time then checkPoint is created but not for the subsequent tokenId of that collection because it doesn't call _createCheckpoint() at the end of the function
function createListings(CreateListing[] calldata _createListings) public nonReentrant lockerNotPaused {
// Loop variables
uint checkpointIndex;
bytes32 checkpointKey;
uint tokensIdsLength;
uint tokensReceived;
// Loop over the unique listing structures
for (uint i; i < _createListings.length; ++i) {
// Store our listing for cheaper access
CreateListing calldata listing = _createListings[i];
// Ensure our listing will be valid
_validateCreateListing(listing);
// Update our checkpoint for the collection if it has not been done yet for
// the listing collection.
checkpointKey = keccak256(abi.encodePacked('checkpointIndex', listing.collection));
assembly { checkpointIndex := tload(checkpointKey) }
if (checkpointIndex == 0) {
checkpointIndex = _createCheckpoint(listing.collection);
assembly { tstore(checkpointKey, checkpointIndex) }
}
// Map our listings
tokensIdsLength = listing.tokenIds.length;
tokensReceived = _mapListings(listing, tokensIdsLength, checkpointIndex) * 10 ** locker.collectionToken(listing.collection).denomination();
// Register our listing type
unchecked {
listingCount[listing.collection] += tokensIdsLength;
}
// Deposit the tokens into the locker and distribute ERC20 to user
_depositNftsAndReceiveTokens(listing, tokensReceived);
// Event fire
emit ListingsCreated(listing.collection, listing.tokenIds, listing.listing, tokensReceived, msg.sender);
}
}
This is an issue because _depositNftsAndReceiveTokens() deposits the NFTs into locker.sol which mints collectionToken. And the totalSupply of the collectionToken is used while calculating utilizationRate of the collection.
function utilizationRate(address _collection) public view virtual returns (uint listingsOfType_, uint utilizationRate_) {
//
if (listingsOfType_ != 0) {
ICollectionToken collectionToken = locker.collectionToken(_collection);
// If we have no totalSupply, then we have a zero percent utilization
uint totalSupply = collectionToken.totalSupply();
if (totalSupply != 0) {
> utilizationRate_ = (listingsOfType_ * 1e36 * 10 ** collectionToken.denomination()) / totalSupply;
}
}
}
Impact
checkPoint is not updated, as result utilizationRate of that collection will also not be updated correctly
utsav
Medium
ProtectedListings:createListings()
doesn't create checkPoints for subsequent listing of a collectionSummary
ProtectedListings:createListings()
doesn't create checkPoints for subsequent listing of a collectionVulnerability Detail
When a tokenId of a collection is protected listed for the fist time then checkPoint is created but not for the subsequent tokenId of that collection because it doesn't call
_createCheckpoint()
at the end of the functionThis is an issue because
_depositNftsAndReceiveTokens()
deposits the NFTs into locker.sol which mints collectionToken. And the totalSupply of the collectionToken is used while calculating utilizationRate of the collection.Impact
checkPoint is not updated, as result utilizationRate of that collection will also not be updated correctly
Code Snippet
https://github.com/sherlock-audit/2024-08-flayer/blob/main/flayer/src/contracts/ProtectedListings.sol#L117C4-L157C1 https://github.com/sherlock-audit/2024-08-flayer/blob/main/flayer/src/contracts/ProtectedListings.sol#L165C5-L187C1 https://github.com/sherlock-audit/2024-08-flayer/blob/main/flayer/src/contracts/ProtectedListings.sol#L261C5-L276C6
Tool used
Manual Review
Recommendation
Call
_createCheckpoint()
at the end of the function call