I built an ERC1155 marketplace contract for creating and trading digital tokens.
The tokens mint correctly but they don’t appear in the marketplace and buyers can’t purchase them. I keep getting this error even though I used setApprovalForAll during minting:
Trading execution test failed:
Error: VM Exception while processing transaction: reverted with reason string 'ERC1155: caller is not owner nor approved'
at TokenMarket.balanceOf (@openzeppelin/contracts/token/ERC1155/ERC1155.sol:71)
at TokenMarket.isApprovedForAll (@openzeppelin/contracts/token/ERC1155/ERC1155.sol:110)
at TokenMarket.executePurchase (contracts/TokenMarket.sol:165)
Here’s my marketplace contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract TokenMarket is ERC1155, Ownable, ERC1155Supply {
constructor() ERC1155("") {}
mapping(uint256 => string) internal _metadataURIs;
mapping(uint256 => ListingItem) private idToListing;
Counters.Counter private _soldCounter;
struct ListingItem {
uint256 tokenId;
address payable seller;
address payable owner;
uint256 price;
bool sold;
}
event ListingCreated(
uint256 indexed tokenId,
address seller,
address owner,
uint256 price,
bool sold
);
using Counters for Counters.Counter;
Counters.Counter private _tokenCounter;
function updateURI(string memory newuri) public onlyOwner {
_setURI(newuri);
}
function createToken(
string memory metadataURI,
uint256 quantity,
uint256 askingPrice
) public returns (uint256) {
uint256 newTokenId = _tokenCounter.current();
_mint(address(this), newTokenId, quantity, "");
_setMetadataUri(newTokenId, metadataURI);
_tokenCounter.increment();
return newTokenId;
}
function listForSale(
uint256 tokenId,
uint256 askingPrice,
uint256 quantity
) private {
require(askingPrice > 0, "Price must be at least 1 wei");
idToListing[tokenId] = ListingItem(
tokenId,
payable(msg.sender),
payable(address(this)),
askingPrice,
false
);
setApprovalForAll(address(this), true);
safeTransferFrom(msg.sender, address(this), tokenId, quantity, "");
emit ListingCreated(
tokenId,
msg.sender,
address(this),
askingPrice,
false
);
}
function executePurchase(uint256 tokenId, uint256 quantity) public payable {
uint256 askingPrice = idToListing[tokenId].price;
address seller = idToListing[tokenId].seller;
idToListing[tokenId].owner = payable(msg.sender);
idToListing[tokenId].sold = true;
idToListing[tokenId].seller = payable(address(0));
_soldCounter.increment();
safeTransferFrom(address(this), msg.sender, tokenId, quantity, "");
setApprovalForAll(address(this), true);
payable(seller).transfer(msg.value);
}
function _setMetadataUri(uint256 tokenId, string memory metadataURI) private {
_metadataURIs[tokenId] = metadataURI;
}
function getAvailableListings() public view returns (ListingItem[] memory) {
uint256 totalCount = _tokenCounter.current();
uint256 availableCount = _tokenCounter.current() - _soldCounter.current();
uint256 currentIndex = 0;
ListingItem[] memory listings = new ListingItem[](availableCount);
for (uint256 i = 0; i < totalCount; i++) {
if (idToListing[i + 1].owner == address(this)) {
uint256 currentId = i + 1;
ListingItem storage currentListing = idToListing[currentId];
listings[currentIndex] = currentListing;
currentIndex += 1;
}
}
return listings;
}
}