Yes it does indeed work on remix.
tx hash on mumbai scan : 0x358e8dccadf12e7bdd99e7365b26782dec2b91c388991554533f088b26e579ab
It’s a combinaison of 3 contracts.
One for minting Erc20s:
One for minting NFTs
One for listing and buying NFTs that inherits from the two (marketplace).
// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.1;
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
interface IERC_COLLECTION is IERC1155 {
function safeMint(string memory _tokenURI, uint256 amount) external;
}
contract NFTMarketplace is Ownable, ERC1155Holder {
uint public offerCount;
uint public tokenCount;
mapping (uint => _Offer) public offers;
IERC_COLLECTION nftCollection;
IERC20 tokenCollection;
struct _Offer {
uint offerId;
uint id;
address user;
uint price;
bool fulfilled;
}
event Offer(
uint offerId,
uint token_id,
address user,
uint price,
bool fulfilled
);
event OfferFilled(uint offerId, uint id, address newOwner);
event OfferCancelled(uint offerId, uint id, address owner);
event ClaimFunds(address user, uint amount);
constructor(address _nftCollection, address _tokenCollection) {
nftCollection = IERC_COLLECTION(_nftCollection);
tokenCollection = IERC20(_tokenCollection);
}
function SetPrice(string memory _tokenURI, uint256 amount, uint256 price) external onlyOwner {
nftCollection.safeMint(_tokenURI, amount);
tokenCount ++;
for (uint256 i = 0; i < amount; i ++) {
offers[offerCount] = _Offer(offerCount, tokenCount, address(this), price, false);
offerCount ++;
}
}
function BuyNFT(uint _offerId, uint256 price) public {
_Offer storage _offer = offers[_offerId];
uint256 token_bal = tokenCollection.balanceOf(msg.sender);
require(_offer.offerId == _offerId, "The offer must exist");
require(_offer.user != msg.sender, "The owner of the offer cannot fill it");
require(!_offer.fulfilled, "An offer cannot be fulfilled twice");
require(token_bal >= price, "An offer cannot be fulfilled twice");
require(price == _offer.price, "The TOKEN amount should match with the NFT Price");
nftCollection.safeTransferFrom(address(this), msg.sender, _offer.id, 1, "");
tokenCollection.transferFrom(msg.sender, address(this), price);
_offer.fulfilled = true;
emit OfferFilled(_offerId, _offer.id, msg.sender);
}
// Fallback: reverts if Ether is sent to this smart-contract by mistake
fallback () external {
revert();
}
}
The address of the contract is: 0xFEeD74839Ea943354e3a422702B986d410a62774
This is the ABI:
[
{
"inputs": [
{
"internalType": "uint256",
"name": "_offerId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "price",
"type": "uint256"
}
],
"name": "BuyNFT",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_nftCollection",
"type": "address"
},
{
"internalType": "address",
"name": "_tokenCollection",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "user",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "ClaimFunds",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "offerId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "token_id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "user",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "price",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bool",
"name": "fulfilled",
"type": "bool"
}
],
"name": "Offer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "offerId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OfferCancelled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "offerId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OfferFilled",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"name": "onERC1155BatchReceived",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"name": "onERC1155Received",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "_tokenURI",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "price",
"type": "uint256"
}
],
"name": "SetPrice",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "nonpayable",
"type": "fallback"
},
{
"inputs": [],
"name": "offerCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "offers",
"outputs": [
{
"internalType": "uint256",
"name": "offerId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "address",
"name": "user",
"type": "address"
},
{
"internalType": "uint256",
"name": "price",
"type": "uint256"
},
{
"internalType": "bool",
"name": "fulfilled",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tokenCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
Player (ownerAddress) should increase allowance to market( spenderAddress) to be able ton buy from it.
This would be the last step to achieve buying an erc1155 with custom erc20s in-game.
Very excited about it !
can’t thank you enough.