0

I was recently made aware of a hack involving a contract where you have a 10% chance to mint a rare NFT.

The hacker was able to see the decision on whether it was a rare or regular and cancel the mint before it happened. This is the code:

uint256 tokenId = totalSupply();

        // Getting random number
        uint256 rand = getRandom(tokenId);

        // Store transaction datas
        TransactionData memory transaction = TransactionData(
            _minter,
            block.timestamp,
            _amount
        );
        transactions.push(transaction);
        transactionsForAddress[_minter].push(transaction);

        uint256 typeId = getRandomType(rand);
        uint256 level = gen1
            ? typeId == 0 ? _regular : _rare
            : 1;

        // Store NFT Metadata
        nfts.push(NFT(tokenId, typeId, level));

        _safeMint(_minter, tokenId);

        emit TokenMinted(_minter, tokenId);
    }

How is this possible? Is it because the mint is done after the decision in another function?

If so does that mean each function is executed in separate blocks?

I am currently working on one and do not wish to make the same mistake

Edit: Asked for the random functions:

function getRandom(uint256 _seed) internal view returns (uint256) {
        return
            uint256(
                keccak256(
                    abi.encodePacked(
                        blockhash(block.number + 4),
                        tx.origin,
                        blockhash(block.number + 2),
                        blockhash(block.number + 3),
                        blockhash(block.number + 1),
                        _seed,
                        block.timestamp
                    )
                )
            );
    }

function getRandomType(uint256 _seed) internal pure returns (uint256) {
        // Generate number between 0 and 9

        if (uint256(uint256(keccak256(abi.encode(_seed, 5))) % 10) == 0) {
            // 10% luck, 1 = RARE
            return 1;
        } else {
            // 90% luck, 0 = NORMAL
            return 0;
        }
    }

Thank you

Pearl
  • 392
  • 2
  • 12
  • you shouldn't generate random numbers on-chain, instead, use an oracle to generate your random number to prevent cheating :) – elguapo Mar 03 '22 at 00:10
  • I know(not my code) but how is someone able to watch the transaction and stop it when they realize they are not getting a rare???? – Pearl Mar 03 '22 at 00:18

0 Answers0