function getUserMemorabiliaDetailed(address user)
external
view
returns (uint256[] memory tokenIds, uint256[] memory collectionIds, uint256[] memory itemIds)
{
uint256 count = 0;
@> for (uint256 cId = 1; cId < nextCollectionId; cId++) {
@> for (uint256 iId = 1; iId < collections[cId].currentItemId; iId++) {
uint256 tokenId = encodeTokenId(cId, iId);
if (balanceOf(user, tokenId) > 0) {
count++;
}
}
}
tokenIds = new uint256[](count);
collectionIds = new uint256[](count);
itemIds = new uint256[](count);
uint256 index = 0;
@> for (uint256 cId = 1; cId < nextCollectionId; cId++) {
@> for (uint256 iId = 1; iId < collections[cId].currentItemId; iId++) {
uint256 tokenId = encodeTokenId(cId, iId);
if (balanceOf(user, tokenId) > 0) {
tokenIds[index] = tokenId;
collectionIds[index] = cId;
itemIds[index] = iId;
index++;
}
}
}
return (tokenIds, collectionIds, itemIds);
}
function test_poc_gas_intensive_loop() public {
for (uint256 i = 0; i < 20; i++) {
vm.prank(organizer);
festivalPass.createMemorabiliaCollection("Collection", "ipfs://...", 1, 100, true);
for (uint256 j = 0; j < 50; j++) {
address randomUser = address(uint160(uint256(keccak256(abi.encodePacked(i, j)))));
vm.prank(address(festivalPass));
beatToken.mint(randomUser, 1e18);
vm.startPrank(randomUser);
beatToken.approve(address(festivalPass), 1e18);
festivalPass.redeemMemorabilia(100 + i);
vm.stopPrank();
}
}
uint256 startGas = gasleft();
(uint256[] memory tokenIds,,) = festivalPass.getUserMemorabiliaDetailed(user1);
uint256 gasUsed = startGas - gasleft();
assertTrue(gasUsed < 1_000_000, "Gas usage is too high!");
}
// In FestivalPass.sol
+ // Mapping from user address to an array of their owned memorabilia token IDs
+ mapping(address => uint256[]) private userOwnedMemorabilia;
// Redeem a memorabilia NFT from a collection
function redeemMemorabilia(uint256 collectionId) external {
MemorabiliaCollection storage collection = collections[collectionId];
require(collection.priceInBeat > 0, "Collection does not exist");
require(collection.isActive, "Collection not active");
require(collection.currentItemId < collection.maxSupply, "Collection sold out");
// Burn BEAT tokens
BeatToken(beatToken).burnFrom(msg.sender, collection.priceInBeat);
// Generate unique token ID
uint256 itemId = collection.currentItemId++;
uint256 tokenId = encodeTokenId(collectionId, itemId);
// Store edition number
tokenIdToEdition[tokenId] = itemId;
// Mint the unique NFT
_mint(msg.sender, tokenId, 1, "");
+ // Add the token to the user's list
+ userOwnedMemorabilia[msg.sender].push(tokenId);
emit MemorabiliaRedeemed(msg.sender, tokenId, collectionId, itemId);
}
- // Get all memorabilia owned by a user with details
- function getUserMemorabiliaDetailed(address user)
- external
- view
- returns (uint256[] memory tokenIds, uint256[] memory collectionIds, uint256[] memory itemIds)
- {
- // First, count how many memorabilia they own
- uint256 count = 0;
- for (uint256 cId = 1; cId < nextCollectionId; cId++) {
- for (uint256 iId = 1; iId < collections[cId].currentItemId; iId++) {
- uint256 tokenId = encodeTokenId(cId, iId);
- if (balanceOf(user, tokenId) > 0) {
- count++;
- }
- }
- }
-
- // Then populate arrays
- tokenIds = new uint256[](count);
- collectionIds = new uint256[](count);
- itemIds = new uint256[](count);
-
- uint256 index = 0;
- for (uint256 cId = 1; cId < nextCollectionId; cId++) {
- for (uint256 iId = 1; iId < collections[cId].currentItemId; iId++) {
- uint256 tokenId = encodeTokenId(cId, iId);
- if (balanceOf(user, tokenId) > 0) {
- tokenIds[index] = tokenId;
- collectionIds[index] = cId;
- itemIds[index] = iId;
- index++;
- }
- }
- }
-
- return (tokenIds, collectionIds, itemIds);
- }
+ // Get all memorabilia owned by a user with details
+ function getUserMemorabiliaDetailed(address user)
+ external
+ view
+ returns (uint256[] memory tokenIds, uint256[] memory collectionIds, uint256[] memory itemIds)
+ {
+ tokenIds = userOwnedMemorabilia[user];
+ uint256 count = tokenIds.length;
+ collectionIds = new uint256[](count);
+ itemIds = new uint256[](count);
+
+ for (uint256 i = 0; i < count; i++) {
+ (collectionIds[i], itemIds[i]) = decodeTokenId(tokenIds[i]);
+ }
+
+ return (tokenIds, collectionIds, itemIds);
+ }