How to prevent duplicate ERC1155 token IDs

I found that I could mint a new token with the same token ID as a previously minted token under the same ERC1155 contract.

There was no error about duplicate ID. This would defeat the notion of uniqueness / scarcity / non-fungibility of NFTs.

Are we meant to add custom code ourselves into our ERC1155 contract in order to prevent this?

I notice that OpenZeppelin provides ERC1155Supply that we could use to check for duplicates. But isn't it weird that duplication checks aren't included in the ERC1155 standard?

So would adding this require fix it for single token miniting?

    function mint(
        address account,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public onlyOwner {
        require(!ERC1155Supply.exists(id), "Token with that id has already been minted");

        _mint(account, id, amount, data);
    }

I've also done a test with mintBatch by adding a duplicate token ID in the ids array and found that 11 tokens got minted for that token ID, even though only 1 was passed in amounts for each token to be minted. Please fix this bug.

In the meantime, what's the most efficient way to deduplicate the arrays that are passed into mintBatch?

Is this caused by string concatenation instead of mathematical addition in
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a5445b0afb8b350417b6e6ab3160554967bc151f/contracts/token/ERC1155/ERC1155.sol#L301 ?

I had passed the array of integers [1, 1, 1] for amounts from a hardhat scrript.

That code works for single token minting, I've just tested.

For batch minting this code works:


function mintBatch(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data

    ) public onlyOwner {
        for (uint256 i = 0; i < ids.length - 1; i++) {
            require(
                !ERC1155Supply.exists(ids[i]),
                "ids contains tokens that have already been minted"
            );
        }

        require(!hasDuplicate(ids), "ids has duplicates");

        _mintBatch(to, ids, amounts, data);
    }

hasDuplicate is in:

Are these the most elegant workarounds?

This is more is efficient, but are 2 loops really needed?:

function mintBatch(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public onlyOwner {
        for (uint256 i = 0; i < ids.length - 1; i++) {
            require(!ERC1155Supply.exists(ids[i]), "ids array contains IDs of tokens that have already been minted");

            for (uint256 j = i + 1; j < ids.length; j++)
                require(ids[i] != ids[j], "ids has duplicates");
        }
        require(!ERC1155Supply.exists(ids[ids.length - 1]), "ids array contains IDs of tokens that have already been minted");

        _mintBatch(to, ids, amounts, data);
    }