[SOLVED] 1155 marketplace can't buyItem

Hi, I would like to add a marketplace to my DApp so my users can purchase their NFTs directly from us. I have successfully built the rariable clone a few times so I decided to expand on the tutorial to allow for the listing and purchasing 1155 NFTs. I have no issues adding items,or removing items for sale. But I cannot get the buyItem function to execute although the seller has been marked as a payable address I can also see the correct value is being sent. The error in remix is stating its not marked as payable. What am I missing any ideas?

smart contract

pragma solidity ^0.8.7;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.3.2/contracts/token/ERC1155/IERC1155.sol";

contract WalletMonstersMarketplace {
        struct AuctionItem {
            uint256 id;
            address tokenAddress;
            uint256 tokenId;
            address payable seller;
            uint256 askingPrice;
            uint256 units;
            bool isSold;
        }
        
        AuctionItem[] public itemsForSale;
        mapping(address => mapping(uint256 => bool))activeItems; //know if item on sale
        
        event itemAdded(uint256 id, uint256 tokenId, address tokenAddress,uint amount ,uint256 askingPrice);
        event enjimonAdded(uint256 id, uint256 tokenId, address tokenAddress, uint256 askingPrice);
        event itemSold(uint256 id, address buyer,uint256 amount, uint256 askingPrice);
        event itemRemoved(uint256 id, address seller, uint256 amount, uint256 askingPrice, uint256 date); 
        modifier OnlyItemOwner(address tokenAddress, uint256 tokenId)
        {
            IERC1155 tokenContract = IERC1155(tokenAddress);
            require(tokenContract.balanceOf(msg.sender, tokenId) > 0); //check if caller is owner of this token
            _;
        }
        
         modifier HasTransferApproval(address tokenAddress, uint256 tokenId)
        {
            IERC1155 tokenContract = IERC1155(tokenAddress);
            require(tokenContract.isApprovedForAll(msg.sender, address(this)) == true); //check if callers given contract approvals
            _;
        }
        
        modifier ItemExist(uint256 id) 
        {
            require(id < itemsForSale.length && itemsForSale[id].id == id,"could not find id");
            _;
        }
        
         modifier IsForSale(uint256 id) 
        {
            require(itemsForSale[id].isSold == false,"id already sold");
            _;
        }
        
        
        function additemToMarket(uint256 tokenId, address tokenAddress,uint256 units, uint256 askingPrice) OnlyItemOwner(tokenAddress,tokenId) HasTransferApproval(tokenAddress,tokenId) external returns(uint256){
            require(activeItems[tokenAddress][tokenId] == false,"Item up for sale already");
            uint256 newItemId = itemsForSale.length;
            
            itemsForSale.push(AuctionItem(newItemId, tokenAddress, tokenId, payable(msg.sender), askingPrice, units, false));
            
            activeItems[tokenAddress][tokenId] = true; //items now up for sale
            
            assert(itemsForSale[newItemId].id == newItemId);
            emit itemAdded(newItemId, tokenId, tokenAddress, units ,askingPrice);
            
            return newItemId;
            
        }
        
        function addEnjimonToMarket(uint256 tokenId, address tokenAddress, uint256 askingPrice) OnlyItemOwner(tokenAddress,tokenId) HasTransferApproval(tokenAddress,tokenId) external returns(uint256){
            require(activeItems[tokenAddress][tokenId] == false,"Item up for sale already");
            uint256 newItemId = itemsForSale.length;
            
            itemsForSale.push(AuctionItem(newItemId, tokenAddress, tokenId,payable(msg.sender), askingPrice, 1, false));
            
            activeItems[tokenAddress][tokenId] = true; //items now up for sale
            
            assert(itemsForSale[newItemId].id == newItemId);
            emit enjimonAdded(newItemId, tokenId, tokenAddress, askingPrice);
            
            return newItemId;
            
        }
        
        function buyItem(uint256 id) payable external ItemExist(id) IsForSale(id) HasTransferApproval(itemsForSale[id].tokenAddress, itemsForSale[id].tokenId){
            require(msg.value >= itemsForSale[id].askingPrice, "Not enough funds sent");
            require(msg.sender != itemsForSale[id].seller); 
            
            address payable sellerAddress = payable(itemsForSale[id].seller);
            
            itemsForSale[id].isSold = true; //items been marked as sold
            activeItems[itemsForSale[id].tokenAddress][itemsForSale[id].tokenId] = false; //
            
            
            IERC1155(sellerAddress).safeTransferFrom(sellerAddress, payable(msg.sender), itemsForSale[id].tokenId, itemsForSale[id].units, '');
            sellerAddress.transfer(msg.value); //send funds to seller
            
            emit itemSold(id, msg.sender, itemsForSale[id].units ,itemsForSale[id].askingPrice);
            
        }
        
        function removeItem(uint256 id) public ItemExist(id) IsForSale(id) returns(bool success){
            require(msg.sender == itemsForSale[id].seller);
            
             activeItems[itemsForSale[id].tokenAddress][itemsForSale[id].tokenId] = false;
             delete itemsForSale[id];
              
             emit itemRemoved(id, msg.sender, itemsForSale[id].units , itemsForSale[id].askingPrice, block.timestamp); 
            
        }
}

example of revert

you can try to debug it to see on what line it reverts,
you can also try to change from function buyItem(uint256 id) payable external to function buyItem(uint256 id) payable public

1 Like

it’s reverting on

IERC1155(sellerAddress).safeTransferFrom(sellerAddress, payable(msg.sender), itemsForSale[id].tokenId, itemsForSale[id].units, ‘’);

but I cant find an alternative way to implement the function.

what is seller address there? it should be a smart contract address if you convert it to IERC1155

1 Like

Originally I had the users address that listed the item as the sellerAddress, since I have tried both the marketplace and the NFT collection contract addresses still producing the same results.

you can also try to remove that payable from payable(msg.sender), not sure if it will help

it looks like this was the original line:

IERC721(itemsForSale[id].tokenAddress).safeTransferFrom(itemsForSale[id].seller, msg.sender, itemsForSale[id].tokenId);

1 Like

I have taken your advice still no luck, do you think its a bad idea to place marketplace functionality within the same contract as the NFT collection? I figure ill be able to bypass transferring tokens with the IERC1155 implementation since I currently have no problems transferring tokens there. The concept seem straight forward. Although I worry about the contract size becoming an issue

In theory it should work what you are trying to do there.
I noticed now that you also have this line: address payable sellerAddress = payable(itemsForSale[id].seller);

yeah, I removed that one as well, oddly enough I’m still getting the same error, I’m going through line by to see where the revert is triggering but I’ve removed nearly all functionality that matters, I’m thinking something in my modifiers.

Ok got things to function properly, the issue was indeed within the modifier, specifically how I was calling setApprovalForAll… i.e. I wasn’t lol . …Jesus thank you so much for your patience and assistance [solved]

Hi, im still new to 1155 and im building a nft marketplace,

i would like to know is the approval is for all amount of token created ? once transferred has been done for 1 item, do the seller need to set approval again ?

it may be an option to approve all or only a specific amount, so it can depend

doesnt have that option. only can set marketplace address. i will test my code first, any problem ill ask again. thanks

yes by default it will approve the fund from msg.sender so whoever call the approve function will give access to the operator a portion of their funds :raised_hands: