Best way to prevent onERC721Received reentrancy during mint?

I have a mint function which accepts quantity up to 20 and calls _safeMint in a loop up to 20 times.
I have a check that makes sure the total supply is less than 1000.

Since onERC721Received is called after each individual _safeMint, how can I stop a malicious contract calling my mint function again and triggering 20 more _safeMints before the total supply has finished updating from the initial call?

function mint(uint256 _quantity) external {
	require(_tokenIds.current() < 1000, "maximum supply reached");
	require(_tokenIds.current() + _quantity <= 1000, "mint quantity exceeds max supply");
	require(_quantity > 0 && _quantity <= 20, "mint quantity must be between 1-20");

	for (uint256 i = 0; i < _quantity; i++) {
		_tokenIds.increment();
        _safeMint(msg.sender, _tokenIds.current());
	}
}
1 Like

Would Inheriting from ReentrancyGuard and simply applying nonReentrant to my mint function solve my issue?

1 Like

Hi @Joel welcome to Open Zeppelin

To my understanding reentrancy guard is for functions re-calling one that has already been entered. It’s not intended to stop 2 users from calling a function in the same block (near the same time). Each user would call it separately and they would function properly.

Your function right now works “fine” as intended.

_safeMint would finish before calling itself again in your loop in a synchronous manner.

how can I stop a malicious contract calling my mint function again and triggering 20 more _safeMints before the total supply has finished updating from the initial call?

First create a new boolean variable bool public inMinting that should be global in scope.

Then create a modifier function

modifier lockTheMinting {
        inMinting = true;
        _;
        inMinting = false;
    }

Add this modifier to your mint function, or perhaps in a separate function.

You will need to add a
require(!inMinting, "Contract is minting, This function cannot be called while Minting.")
Somewhere in your contract to make sure they can’t call the function while the minting is going on.

This way when someone mints, they are the only person that can mint at that time.

HOWEVER this introduces another problem.

What if a Malicious contract calls your Mint function before someone else can? Malicious contracts with bots could lock up the minting function and make sure no one else could mint.

My solution to that would be to create a whitelist.

Or you could create a blacklist only allowing one contract to mint one time.

It’s really up to you and what you are requiring for your project.

I hope this helps, please let me know if you have more questions.

1 Like