ERC721: How to receive a fixed amount of ETH per mint transaction?

So the idea is to make an ERC721 NFT series where buyers mint the NFT themselves and thus pay the minting fee with a minimum price (say 0.01 ETH) which goes to the contract address.

When testing the awardItem function in testnet, the 0.01 ETH minimum price doesn't get added to the transaction, only gas fee appears and thus the error message.

Please help!

contract Tokenv3 is ERC721URIStorage, Ownable {
    
    using SafeMath for uint256;
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
   
    address payable private _owner;
    uint256 public _maxSupply = 2000;
    uint256 public totalSupply;

    constructor() ERC721("Token", "TKN") {}
    
    function _baseURI() internal pure override returns (string memory) {
        return "ipfs://xxx/";
    }

    function awardItem(address player)
        payable
        public
        returns (uint256)
    {
        require(totalSupply < _maxSupply);
        require(msg.value == 0.01 ether, "Minting fee of 0.01 ether");
        
        _tokenIds.increment();
        
        string memory tokenURI;
        uint256 newItemId = _tokenIds.current();
        
        _setTokenURI(newItemId, tokenURI);
        _safeMint(player, newItemId);
        
        return newItemId;
    }
    
1 Like

Interesting question, can you post the entire contract or deployed link?

1 Like
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract Tokenv3 is ERC721URIStorage, Ownable {
    
    using SafeMath for uint256;
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    
    uint256 private price = 25000000000000000; // 0.025 Ether
    bool public isSaleActive = true;
    
    address payable private _owner;
    uint256 public _maxSupply = 2000;
    uint256 memory public totalSupply;

    constructor() ERC721("Token", "TKN") {
    }
    
    function _baseURI() internal pure override returns (string memory) {
        return "ipfs://xxx/";
    }
    
    // original award item
    function awardItem(address player)
        payable
        public
        returns (uint256)
    {
        require(isSaleActive, "Sale is not active" );
        require(totalSupply < _maxSupply);
        require(msg.value == 0.02 ether, "Need to send 0.2 ether");
        
        _tokenIds.increment();
        totalSupply = totalSupply + 1
        
        string memory tokenURI;
        uint256 newItemId = _tokenIds.current();
        
        _safeMint(player, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;
    }
    
    // smartcontract selling status
    function flipSaleStatus() public onlyOwner {
        isSaleActive = !isSaleActive;
    }

    function maxSupply() public view returns (uint256){
        return _maxSupply;
    }
    
    function withdraw(address payable recipient) public onlyOwner {
        uint256 balance = address(this).balance;
        recipient.transfer(balance);
    }
    
}

@Annabelle75 thank you! here is the updated code. I did get some advice that i have to define msg.value itself, and the 'require' statement is not sufficient.

I'm doing something similar in the coming weeks so will paste the finished code when done.

But, yes, at just a cursory look -- the require statement is a check that'll throw with the error "Need to send 0.2 ether", which must be the unspecified error message you mentioned? Meaning: You need to define a value for msg.value -- you're checking for a value that hasn't been set.

Can you flatten and paste it all?

Safemath is extraneous in solc ^0.8, compiler handles overflows now (and you're not using it anyway).

i realised i might have gotten something conceptually wrong, which is buyers cannot pay the smart contract right? the smart contract has to transfer the eth from address to address.

Hey there, I am facing a similar problem so I was wondering if you found your solution.

Hi there, i'm still working on this so can't verify if it really works yet.

first you set the minting function as a 'payable'

using example code from the openzeppelin wizard, but adding the 'payable' to safemint (the require line is to check the eth value sent)

function safeMint(address to, string memory uri) payable public {
    uint256 tokenId = _tokenIdCounter.current();
    require(msg.value >= mintRate, "Not enough eth sent.");
    _tokenIdCounter.increment();
    _safeMint(to, tokenId);
    _setTokenURI(tokenId, uri);
}

its at the frontend (website for minting) that you have to set the eth to be sent

so that will be a js issue (i.e. when user clicks the 'mint' button on the website, they will send a fixed amount of eth to the nft contract)