Adding a Price & Multiple Mints to your ERC721 Token Contract đź’°

Ryan Foo
5 min readSep 8, 2021

--

Hi web3 creators!

Adding a Price and Multiple Mints.

Back with another quick tutorial on how to add prices to your ERC-721 token mint.

As an artist or creator, you might want to charge for your work. This is how you do that.

You might want to allow for multiple mints in one transaction. Also, you probably want to put a supply limit so a person isn’t able to mint ALL of your project’s tokens.

We do all that in this tutorial.

Pre-reqs:

You should be comfortable with Solidity. If you are unsure what we’re building, check out the first tutorial on making a Cypherpunk Loot Derivative here.

We implement:

(1) The basic claim function.

(2) How to add a price to that & transform it to a mint function.

(3) How to allow multiple mints in one transaction.

(3) How to restrict to a maximum amount for your mint. (I.E: A max of 10).

The final snippet is at the end of this post. If you know what you’re doing, then go ahead, but we’re going to build up to it, so we don’t get overwhelmed. No rush!

—

(1) The Claim Function

function claim(uint256 tokenId) public {require(tokenId > 0 && tokenId < 7778, "Exceeds token supply");
_safeMint(_msgSender(), tokenId);
}

Recall that this is our basic claim function from the previous tutorial. We say: hey, call me with a tokenId between 1 and 7777, and you’ll get the token.

—

(2) Adding a Price to the Mint Function

Let’s transform this into a mint function by adding a requirement for price, and changing the name of the function.

function mint(uint256 tokenId) public payable {require(tokenId > 0 && tokenId < 7778, "Exceeds token supply");
require(msg.value >= 0.05 ether, "Not enough ETH sent: check price.");
_safeMint(_msgSender(), tokenId);
}

To do this, we add the modifier payable behind public. This tells any client interacting with the contract to request for $ in the transaction. I.E: when you call this function, ask the user to pay the contract.

When a function is declared as payable, the variable msg.value becomes available for use by that function. This contains the amount of wei a user has put into that function.

The second thing we did above was require an amount in msg.value. You can think of require as a “requirement”, or something that needs to happen in order for the contract to execute the rest of its actions. Otherwise, it shows the message listed. (“Exceeds token supply”, for example.)

So to recap, the third line says: we require the payload, or the amount sent to the contract, to be more than, or equal to 0.05 ether. Otherwise, throw an error, with the message “Not enough ETH sent: check price.”

This is the end of the basic tutorial! If you just wanted to learn how to put a price on your contract, you’re done here. :)

If you wanted to go more advanced, and you have a bit more energy, you can continue. We’ll show how to allow multiple mints, and then restrict the maximum amount any one person can mint, with reference to the Animetas contract. (linked below).

—

(3) Allowing Multiple Mints

Perhaps you want to allow a person to mint between 1–10 at once. This is how you do it.

This gets a bit more complex, but still doable. This also removes the ability for a person to specify which number they want to claim / mint.

function mint(uint256 num) public payable {
uint256 supply = totalSupply();
require( supply + num < 7778, “Exceeds maximum supply” );
require( msg.value >= 0.05 ether * num, "Not enough ETH sent, check price” );
for(uint256 i; i < num; i++){
_safeMint( msg.sender, supply + i );
}
}

A few new things here.

Now, our input has changed. We don’t ask for a tokenId. Instead, we ask for the number of tokens they’d like to mint. (uint256 num).

We declare a new variable supply, which is a uint256, using the function totalSupply().

We know totalSupply() is a function because it has two brackets after, which shows that it’s a function call. totalSupply is a built in function on ERC-721 contracts, which… gives you back a number, showing the total supply in the market.

We know the total supply already minted — we’ve saved that in supply, so we check that the new tokens being minted doesn’t exceed the max amount allowed.

If that’s okay, we do the final check: that the amount they send to the contract, aka msg.value, is greater than the price 0.05 ether, multiplied by the number they asked for. If not, tell them “Not enough ETH sent!”

Now if they’ve passed all those requirements, we can do a for loop, that starts at number i, and goes up to num, and mint the amount that they’ve said for.

Recall now that _safeMint is our function that creates a new token. It takes two inputs, the sender of the message, who will be the new owner of this token, and the tokenId. In this case, we create num tokens.

—

(4) Maximum Amount for Mint

Next, let’s add a maximum amount for the mint. Let’s say we want a maximum of 10 per transaction for the mint. There are reasons why you might want to do this: prevent a whale from (too easily) buying up a majority market share in your token, for example.

function mint(uint256 num) public payable {
uint256 supply = totalSupply();
require( num < 11, “You can mint a maximum of 10” );
require( supply + num < 7778, “Exceeds maximum supply” );
require( msg.value >= 0.05 ether * num, "Not enough ETH sent, check price” );
for(uint256 i; i < num; i++){
_safeMint( msg.sender, supply + i );
}
}

It’s a one liner:

require(num < 11, "You can mint a maximum of 10" );

Recall that the active parts of the function don’t execute if any of the requirements fail. That’s why they’re called requirements ;)

We’re done!

—

P.S.

In interest of open source & credit, I’m going to share my process for how I began writing this tutorial. I went to another contract which I knew had these features: the Animetas contract.

It’s located here:
https://etherscan.io/address/0x18df6c571f6fe9283b87f910e41dc5c8b77b7da5#code

First, we search for “mint”, or “claim” on that contract.

And then, I took the features required to write this story. There are some additional features that are out of scope for this article, including pausing of a smart contract, and reserved amounts.

There are many ways to handle a reserve amount: in this case, they used a reserved variable. But one can just as well use ownerClaim like in our previous article.

—

Again, I claim no responsibility for your contracts. This is purely for your education and development. Please do further research if you are putting real money into deploying a smart contract.

Thank you!

—

If you liked this story, please give it a few claps đź‘Ź

Would love for you to share this knowledge with others as well :)

I also write on play-and-earn, NFTs and crypto games @ Metaversus, and tweet @0xRyze.

--

--