Click here to Skip to main content
15,886,069 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
Problem/Clarification:


I have a NFT minting DApp that mints with multiple ERC20 tokens.

I'm having an issue with the react code which calls the smart contract minting function multiple times.

When a user mints with their preferred ERC20 token, the react code is structured in a way that a user would see 3 meta-mask popups.

1. The first metamask popup asks the user to approve the NFT smart contract to access their ERC20 token.

2. The second metamask popup asks the user to approve the transfer of the ERC20 tokens into the smart contract.

3. The third and final popup allows the user to go ahead and mint by calling the `mintWithERCToken(mintAmount, tokenID)` function in the smart contract. This part is problematic because once the ERC20 has been transferred, and then the user decides to cancel/reject the mint, the token would have already been transferred into the smart contract.

*All three metamask calls requires the spending of gas.*

What is the correct sequence of events? What is the correct way to write the react code?

Could someone help restructure the react code?

React Code

TypeScript
async function mintWithCrypto(tokenId) {
    
        Web3EthContract.setProvider(ethereum);
        let web3 = new Web3(ethereum);
    	
    	//get erc20 contract address
        var erc20address = await blockchain.smartContract.methods.getCryptotoken(tokenId).call();
    	
    	//get token contract information
        var currency = new web3.eth.Contract(TOKENABI, erc20address);
    	
    	//get NFT cost
        var mintRate = await blockchain.smartContract.methods.getNFTCost(tokenId).call();
    	
    	//get mint amount and convert to int
        var _mintAmount = Number(mintAmount);
    	
    	//get total cost of NFTs minted
        var totalAmount = mintRate * _mintAmount;
    
        let gasLimit = 285000;
    	
    	//get total gas
        let totalGasLimit = String(gasLimit * _mintAmount);
    
        setFeedback(`Minting your NFT, please hold on...`);
    	
    	//approve contract address for ERC20 token
        currency.methods.approve(CONFIG.CONTRACT_ADDRESS, String(totalAmount)).send({from: blockchain.account, gasLimit: String(totalGasLimit)})
    	
    	//transfer ERC20 token to smart contract. **Problematic code**
        .then(await currency.methods.transfer(CONFIG.CONTRACT_ADDRESS, String(totalAmount)).send({from: blockchain.account},
          async function (error, transactionHash) {
            // console.log("Transfer Submitted, Hash: ", transactionHash)
            let transactionReceipt = null
            while (transactionReceipt == null) {
              transactionReceipt = await web3.eth.getTransactionReceipt(transactionHash);
              await sleep(10000)
            }
        }))
    	
    	//mint NFT **Problematic code**
        .then(blockchain.smartContract.methods.mintWithERCToken(_mintAmount, tokenId).send({from: blockchain.account, gasLimit: String(totalGasLimit)})
        .once("error", (err) => {
          if (err.message == "MetaMask Tx Signature: User denied transaction signature.") {
            setFeedback("Transaction cancelled.");
          } else {
            setFeedback("Sorry, something went wrong please try again later.");
          }
        })
        .then((receipt) => {
          console.log(receipt);
          setFeedback(`Congratulations! You've minted a ${CONFIG.NFT_NAME}.`);
          dispatch(fetchData(blockchain.account));
        })
        )
        }



Smart Contract code

function mintWithERCToken(uint256 mintAmount, uint256 tokenID) public payable {
            CryptoTokenInfo storage tokens = permittedCrypto[tokenID];
            IERC20 paytoken;
            paytoken = tokens.paytoken;
            uint256 costval;
            costval = tokens.costvalue;
            uint256 supply = totalSupply();
    
            require(mintAmount > 0, "You need to mint at least 1 NFT");
            require(mintAmount <= maxMintAmount, "Max mint amount per session exceeded");
            require(supply + mintAmount <= maxSupply, "Max NFT exceeded");
                
            if (msg.sender != owner()) {
             //check if the user is whitelisted
             if(onlyWhitelisted == true) {
                    require(isWhitelisted(msg.sender), "Sorry, address is not whitelisted");
                } 
                require(msg.value == costval * mintAmount, "Insufficient funds. Please add more funds to address");
            }
    
                for (uint256 i = 1; i <= mintAmount; i++) {
                    require(paytoken.transferFrom(msg.sender, address(this), costval));
                    _safeMint(msg.sender, supply + i);
                }
            }


What I have tried:

I've exhausted all avenues with the react code. I'm not sure how to transfer the actual ERC20 token. Mint + ERC20 transfer.
Posted
Updated 15-Nov-22 19:08pm

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900