3

I want to create an NFT Game in which users can buy NFT with my custom token.

for example, Decentraland has a token called Mana. as you can see they listed the NFT with Mana!

Decentraland NFT example on OpenSea

enter image description here

In OpenSea there is an option to list NFT with a custom token but it's deprecated

enter image description here

as you can see there is a custom token like GALA

enter image description here

but it's deprecated and I can't add the new token

enter image description here

What is my problem

I know how to create a token and NFT but I don't know how to list it on my custom token

What I tried

I could create a token and NFT

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Shiaf is ERC20 {
    constructor() ERC20("Shiaf", "MTK") {
        _mint(msg.sender, 10000000 * 10 ** decimals());
    }
}

Update

I asked someone and he told me:

Well, this depends in what you prefer to do, but you could do your own marketplace to sell the nfts and only accept as a payment method your own token or you could write some mint function for your nft that in order for mint take some amount of tokens from the user

this is exactly what I want but I don't know how to accept as a payment method my own token

2
  • what do you mean about list your nft ? you want an function that with a getter to list the "_tokenId" ? if is that you will need to create an nftFactory.sol with an function setNft and une function getNft from an mapping. hope that can help you.
    – karl block
    Jan 16, 2022 at 15:53
  • I mean I want to set the price for my Item with this token: 0xa25d542f35bb2ce4cfa913d763b1cffba6139d45 Jan 17, 2022 at 11:36

3 Answers 3

2

Well, this depends in what you prefer to do, but you could do your own marketplace to sell the nfts and only accept as a payment method your own token or you could write some mint function for your nft that in order for mint take some amount of tokens from the user

If this is what you actually want, then you can do it easily.
You can run your own marketplace and accept your tokens from the user to sell them. You can see this example here.
[https://shop.foxfinance.io/homepage] [https://bscscan.com/address/0x435Cd5A3d0be367Da997a547Fdf0e482587008DA#code]

2
3
+50

Here is a mock marketplace contract (please excuse errors):

pragma solidity ^0.8.0;

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {Vault} from "./Vault.sol";

contract Sale {

    // -------- ADDRESS --------

    address public vault;

    // -------- UINT --------

    uint public saleNonce;

    // -------- MAPPINGS --------

    mapping(uint => bool) public saleStatus;
    mapping(uint => SaleInfo) public nftSale;
    mapping(address => SaleInfo[]) public userSale;
    mapping(address => SaleInfo[]) public userPurchase;
    mapping(address => mapping(uint => bool)) public nftStatus;
    mapping(address => mapping(uint => uint)) public nftNonce;

    // -------- STRUCTS --------

    struct SaleInfo {

        address buyer;
        address seller;
        address nft;
        uint id;
        uint price;
        uint endTime;
        bool completed;

    }

    // -------- EVENTS --------

    event NewListing(address _nft, uint _id, uint _price, uint _endTime);
    event SaleChanged(address _nft, uint _id, uint _price, uint _endTime);
    event SaleCanceled(address _nft, uint _id);
    event Purchase(address _nft, uint _id, uint _price);

    // -------- SINGLE NFT TX --------

    function createSingleSale(IERC721 _nft, uint _id, uint _price, uint _saleTime) external {
        nftSale[saleNonce] = SaleInfo({
            seller : address(0),
            buyer : msg.sender,
            nft : address(_nft),
            id : _id,
            price : _price,
            endTime : block.timestamp + _saleTime,
            completed : false
        });
        saleStatus[saleNonce] = true;
        userSale[msg.sender].push(nftSale[saleNonce]);
        nftStatus[address(_nft)][_id] = true;
        nftNonce[address(_nft)][_id] = saleNonce;
        _nft.transferFrom(msg.sender, vault, _id);
        emit NewListing(address(_nft), _id, _price, block.timestamp + _saleTime);
        saleNonce++;
    }

    function adjustSingleSale(address _nft, uint _id, uint _price, uint _saleTime) external {
        require(nftSale[nftNonce[address(_nft)][_id]].seller == msg.sender && !nftSale[nftNonce[address(_nft)][_id]].completed);
        nftSale[nftNonce[_nft][_id]] = SaleInfo({
            seller : msg.sender,
            buyer : address(0),
            nft : _nft,
            id : _id,
            price : _price,
            endTime : block.timestamp + _saleTime,
            completed : false
        });
        emit SaleChanged(_nft, _id, _price, block.timestamp + _saleTime);
    }

    function cancelSingleSale(IERC721 _nft, uint _id) external {
        require(nftSale[nftNonce[address(_nft)][_id]].seller == msg.sender && !nftSale[nftNonce[address(_nft)][_id]].completed);
        saleStatus[nftNonce[address(_nft)][_id]] = false;
        Vault(vault).sendToken(_nft, _id, msg.sender, vault);
        emit SaleCanceled(address(_nft), _id);
    }

    // -------- MULTI NFT TX --------

    function createBatchSale(IERC721[] memory _nft, uint[] memory _id, uint[] memory _price, uint[] memory _saleTime) external {
        uint amount = _nft.length;
        for(uint i = 0; i < amount; i++) {
            nftSale[saleNonce] = SaleInfo({
                seller : msg.sender,
                buyer : address(0),
                nft : address(_nft[i]),
                id : _id[i],
                price : _price[i],
                endTime : block.timestamp + _saleTime[i],
                completed : false
            });
            saleStatus[saleNonce] = true;
            userSale[msg.sender].push(nftSale[saleNonce]);
            nftStatus[address(_nft[i])][_id[i]] = true;
            nftNonce[address(_nft[i])][_id[i]] = saleNonce;
            _nft[i].transferFrom(msg.sender, vault, _id[i]);
            emit NewListing(address(_nft[i]), _id[i], _price[i], nftSale[nftNonce[address(_nft[i])][_id[i]]].endTime);
            saleNonce++;
        }
    }

    function adjustBatchSale(address[] memory _nft, uint[] memory _id, uint[] memory _price, uint[] memory _saleTime) external {
        uint amount = _nft.length;
        for(uint i = 0; i < amount; i++) {
            require(nftSale[nftNonce[address(_nft[i])][_id[i]]].seller == msg.sender && !nftSale[nftNonce[_nft[i]][_id[i]]].completed);
            nftSale[nftNonce[_nft[i]][_id[i]]] = SaleInfo({
                seller : msg.sender,
                buyer : address(0),
                nft : _nft[i],
                id : _id[i],
                price : _price[i],
                endTime : block.timestamp + _saleTime[i],
                completed : false
            });
            emit SaleChanged(_nft[i], _id[i], _price[i], block.timestamp + _saleTime[i]);
        }
    }

    function cancelBatchSale(IERC721[] memory _nft, uint[] memory _id) external {
        uint amount = _nft.length;
        for(uint i = 0; i < amount; i++) {
            require(nftSale[nftNonce[address(_nft[i])][_id[i]]].seller == msg.sender && !nftSale[nftNonce[address(_nft[i])][_id[i]]].completed);
            saleStatus[nftNonce[address(_nft[i])][_id[i]]] = false;
            Vault(vault).sendToken(_nft[i], _id[i], vault, msg.sender);
            emit SaleCanceled(address(_nft[i]), _id[i]);
        }
    }

    // -------- PURCHASE AND CHECKOUT --------

    function checkOutSingle(IERC721 _nft, uint _id) payable external {
        require(
            msg.value == nftSale[nftNonce[address(_nft)][_id]].price 
            && nftStatus[address(_nft)][_id]
            && !nftSale[nftNonce[address(_nft)][_id]].completed
        );
        
        address seller = nftSale[nftNonce[address(_nft)][_id]].seller;
        uint nonce = nftNonce[address(_nft)][_id];
        nftSale[nonce].buyer = msg.sender;
        nftSale[nonce].completed = true;

        userPurchase[msg.sender].push(nftSale[nonce]);

        nftNonce[address(_nft)][_id]++;

        (bool sent, ) = seller.call{value: nftSale[nonce].price}("");
        require(sent, "Failed to send Ether");
        Vault(vault).sendToken(_nft, _id, vault, msg.sender);

        emit Purchase(address(_nft), _id, nftSale[nonce].price);
    }

    function checkOutBatch(IERC721[] memory _nft, uint[] memory _id) payable external {
        uint amount = _nft.length;
        uint totalBatchPrice = getBatchCost(_nft, _id);
        require(msg.value == totalBatchPrice);
        for(uint j = 0; j < amount; j++) {
            require(
                nftStatus[address(_nft[j])][_id[j]]
                && !nftSale[nftNonce[address(_nft[j])][_id[j]]].completed
            );

            uint nonce = nftNonce[address(_nft[j])][_id[j]];
            address seller = nftSale[nonce].seller;
            nftSale[nonce].buyer = msg.sender;
            nftSale[nonce].completed = true;

            userPurchase[msg.sender].push(nftSale[nonce]);

            nftNonce[address(_nft[j])][_id[j]]++;

            (bool sent, ) = seller.call{value: nftSale[nonce].price}("");
            require(sent, "Failed to send Ether");
            Vault(vault).sendToken(_nft[j], _id[j], vault, msg.sender);
            
            emit Purchase(address(_nft[j]), _id[j], nftSale[nonce].price);
        }
    }

    // -------- VIEW --------

    function getBatchCost(IERC721[] memory _nft, uint[] memory _id) view public returns(uint totalBatchPrice){
        uint amount = _nft.length;
        for(uint i = 0; i < amount; i++) {
            totalBatchPrice += nftSale[nftNonce[address(_nft[i])][_id[i]]].price;
        }
    }

    function getSingleCost(address _nft, uint _id) view external returns(uint price){
        price = nftSale[nftNonce[_nft][_id]].price;
    }

}

If you want to require users to pay with your token, in the function checkoutSingle instead of making it payable, you can add a require statement that the price paid must be some amount of your tokens. Then, in the tx you send the NFT to the buyer and the custom tokens to the seller.

Keep in mind, to send the tokens to the seller, you may have to enable special permissions in the transferFrom function to allow your contract to send tokens from one address to another within a function. Otherwise you can have the trader approve the contract before a swap.

1

What you are going to want to do is implement the ERC-20 token as an ERC-777 token which is a backward-compatible version of the ERC-20 standard with a few extra features. One of these new features is the ability to notify recipients of their balance change events. With this trigger, inside the NFT contract, which is also of type ERC-777 Recipient, the tokensReceived method of in your NFT will be called and before you return the selector you can adjust a mapping of addresses to their sent amount. In the mint function, require said mapping to contain msg.sender's sent amount >= to the mint cost, subtract the mint cost from the balance, and, finally, mint the NFT to the recipient.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.