reactjs – Transaction has been reverted by the EVM without reason

I am trying to implement lazy mint in NFT Marketplace using solidity. So for test and deploy smart contract, I used hardhat. But my code is passed test, and the result was good. So I integrated smart contract to front-end using web3.js But then revert transaction error occurred.

{
  "blockHash": "0x5b225f40446888ce55711856eb55a6fcee9c15e2c627bec3e6cdd489ef74f447",
  "blockNumber": 11077400,
  "contractAddress": null,
  "cumulativeGasUsed": 505099,
  "effectiveGasPrice": 2500000008,
  "from": "0xcbd382ac994de5633a348347cec4aaaf02a2954d",
  "gasUsed": 299562,
  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "status": false,
  "to": "0x192b786dd546c00c56849fedbb5b1f66fd501a47",
  "transactionHash": "0x8c21c1606c2f7e71ba7654f3cf3b5066b9b6f7191b0ef7310ee99a2e42832101",
  "transactionIndex": 1,
  "type": "0x2",
  "events": {}
}
    at Object.TransactionError (errors.js:87:1)
    at Object.TransactionRevertedWithoutReasonError (errors.js:98:1)
    at index.js:396:1

NFT smart contract is:

// SPDX-License-Identifier: MIT
// Author: topstardev.703@gmail.com
pragma solidity >=0.8.0 <0.9.0;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";

interface ICrea2Crypto {
  function symbol() external view returns (string memory);
  function transfer(address to, uint tokens) external;
  function balanceOf(address addr) external returns (uint256);
  function transferFrom(address from , address to, uint tokens) external returns(bool);
  function allowance(address owner, address spender) external returns(uint256);
}

contract Crea2orsNFT is ERC1155, Ownable, EIP712 {
    uint256 public _currentTokenID = 0;
    string private _contractURI;
    uint256 private tokenLimit;
    string public name;
    string public symbol;
    ICrea2Crypto cr2Contract;

    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    mapping(uint256 => address) public royaltyAddresses; //NFT creator not owner
    mapping(uint256 => uint256) public initialSupplies;
    mapping(uint256 => uint256) public curMintedSupplies;
    mapping(uint256 => uint256) public royaltyFees;
    mapping(uint256 => string) private metaDataUris;
    
    bool private constructed = false;
    string private constant SIGNING_DOMAIN = "LazyNFT-Voucher";
    string private constant SIGNATURE_VERSION = "1";

    struct Sig {
        bytes32 r;
        bytes32 s;
        uint8 v;
    }

    struct NFTVoucher {
        uint256 tokenId;
        string metaUri;
        uint256 mintCount;
        uint256 mintPrice;
        uint256 initialSupply;
        uint256 royaltyFee;
        address royaltyAddress;
    }

    constructor(
        string memory name_,
        string memory symbol_,
        string memory contractURI_,
        uint256 totalLimit_,
        address cr2ContractAddress_
    ) ERC1155("") EIP712(SIGNING_DOMAIN, SIGNATURE_VERSION) {
        constructed = true;
        tokenLimit = totalLimit_;
        name = name_;
        symbol = symbol_;
        cr2Contract = ICrea2Crypto(cr2ContractAddress_);
        emit ContractDeployed(msg.sender, contractURI_);

        setContractURI(contractURI_);
    }

    function getCurMintedSupply(uint256 tokenID) public view returns(uint256) {
        return curMintedSupplies[tokenID];
    }

    function init(string memory _name, string memory _symbol) public {
        require(!constructed, "ERC155 Tradeable must not be constructed yet");

        name = _name;
        symbol = _symbol;
    }

    function setContractURI(string memory contractURI_) public onlyOwner payable {
        _contractURI = contractURI_;

        emit ContractURIChanged(contractURI_);
    }

    function redeemtest() public view returns(string memory) {
        return cr2Contract.symbol();
    }

    function redeem(address redeemer, uint256 tokenId, string memory metaUri, uint256 initialSupply, uint256 mintPrice, uint256 mintCount, uint256 royaltyFee, address royaltyAddress) public payable returns (uint256) {
        require(mintPrice < cr2Contract.balanceOf(msg.sender), "insufficient funds");
        require(initialSupply <= 1000, "Initial supply cannot be more than 1000");
        require(_currentTokenID < tokenLimit, "Flushed nft total limit");
        require(mintCount != 0, "Can not mint Zero count");

        if (curMintedSupplies[tokenId] == 0) {
            require(mintCount < initialSupply, "You can not mint over than initial Supply: first");
            initialSupplies[_currentTokenID] = initialSupply;
            royaltyAddresses[_currentTokenID] = royaltyAddress;
            royaltyFees[_currentTokenID] = royaltyFee;
            setURI(_currentTokenID, metaUri);
            _mint(redeemer, _currentTokenID, mintCount, "");
            curMintedSupplies[_currentTokenID] += mintCount;
            _currentTokenID++;
            emit LazyMinted(_currentTokenID);
        } else {
            require(curMintedSupplies[tokenId] + mintCount < initialSupplies[tokenId], "You can not mint over than initial supply: not first");
            _mint(redeemer, tokenId, mintCount, "");
            curMintedSupplies[tokenId] += mintCount;
            emit LazyMinted(tokenId);
        }

        // when mint, transfer CREA2 token to NFT creator
        require(cr2Contract.allowance(msg.sender, address(this))>= mintPrice, "allowance is less");
        cr2Contract.transferFrom(msg.sender, royaltyAddress, mintPrice);
        return tokenId;
    }

    //This is transfer function
    function transferNFT(uint256 _id, uint256 _amount, address from, address to) public {
        require(_amount > 0, "Can not transfer zero NFT");
        
        // Send NFT to buyer
        safeTransferFrom(from, to, _id, _amount, "");
        emit NFTTransfered(_id, _amount, from, to);
    }

    function setURI(uint256 _id, string memory _uri) public payable {
        require(_exists(_id), "ERC1155#uri: NONEXISTENT_TOKEN");
        metaDataUris[_id] = _uri;
        emit TokenURIChanged(_id, _uri);
    }

    function uri(uint256 _id) public view override returns (string memory) {
        require(_exists(_id), "ERC1155#uri: NONEXISTENT_TOKEN");

        string memory _tokenURI = metaDataUris[_id];
        return _tokenURI;
    }

    function getRoyaltyFee(uint256 _id) public view returns(uint256) {
        return royaltyFees[_id];
    }

    function getRoyaltyAddress(uint256 _id) public view returns(address) {
        return royaltyAddresses[_id];
    }

    function batchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public payable {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: transfer caller is not owner nor approved"
        );
        safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    function burn(uint256 _id, uint256 _amount) public onlyOwner payable {
        require(_exists(_id), "ERC1155 #burn: NONEXISTENT_TOKEN");
        _burn(msg.sender, _id, _amount);
    }

    function contractURI() public view returns (string memory) {
        return _contractURI;
    }

    function totalSupply(uint256 _id) public view returns (uint256) {
        return initialSupplies[_id];
    }

    function _exists(uint256 _id) internal view returns (bool) {
        return royaltyAddresses[_id] != address(0);
    }

    function _getNextTokenID() private view returns (uint256) {
        return _currentTokenID + 1;
    }

    function _incrementTokenTypeId() private {
        _currentTokenID++;
    }

    event ContractDeployed(address, string);
    event ContractURIChanged(string);
    event TokenURIChanged(uint256, string);
    event LazyMinted(uint256);
    event NFTTransfered(uint256, uint256, address, address);
}

ERC20 token contract:

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
//
// ----------------------------------------------------------------------------
/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// ----------------------------------------------------------------------------
// Safe Math Library
// ----------------------------------------------------------------------------
contract SafeMath {
    function safeAdd(uint a, uint b) public pure returns (uint c) {
        c = a + b;
        require(c >= a);
    }
    function safeSub(uint a, uint b) public pure returns (uint c) {
        require(b <= a); c = a - b; } function safeMul(uint a, uint b) public pure returns (uint c) { c = a * b; require(a == 0 || c / a == b); } function safeDiv(uint a, uint b) public pure returns (uint c) { require(b > 0);
        c = a / b;
    }
}

// Context Library
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// Ownable Library
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _setOwner(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}


contract Crea2ors is IERC20, Ownable, SafeMath {
    string public name;
    string public symbol;
    uint8 public decimals; // 18 decimals is the strongly suggested default, avoid changing it

    uint256 public _totalSupply;

    struct holder {
      uint lockupAmount;
      uint unlockTime;
      bool bCreated;
    }

    mapping(address => uint) balances;
    mapping(address => mapping(address => uint)) allowed;
    mapping(address => holder) holders;

    address private _rewardPoolAddress = 0x26810913499451a31a9E17C0b021b326C0a73c94;
    address private _developmentAddress = 0x5aAd91b0c9d866aCeC2768dcf500b38537F856Fb;
    address private _MKTAddress = 0x4b1D5A0E5C2940A43B8881fD7c739C4F47b784C6;
    address private _burnAddress = 0xcdD6D090efd7f5cbF52E40Cc49b09a5D368B9923;
    /**
     * Constrctor function
     *
     * Initializes contract with initial supply tokens to the creator of the contract
     */
    constructor() {
        name = "Crea2ors";
        symbol = "CR2";
        decimals = 9;
        _totalSupply = 10000000000 * 10 ** 9;
        //8 000 000 000 tokens to owner
        //2 000 000 000 tokens to liquidity pool
        uint256 amount2Owner = 8000000000 * 10 ** 9;
        balances[msg.sender] = amount2Owner;
        balances[_rewardPoolAddress] = 2000000000 * 10 ** 9;
        emit Transfer(address(0), msg.sender, amount2Owner);
    }

    function totalSupply() public override view returns (uint) {
        return _totalSupply  - balances[address(0)];
    }

    function balanceOf(address tokenOwner) public override view returns (uint balance) {
        return balances[tokenOwner];
    }

    function allowance(address tokenOwner, address spender) public override view returns (uint remaining) {
        return allowed[tokenOwner][spender];
    }

    function approve(address spender, uint tokens) public override returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        return true;
    }

    function transfer(address to, uint tokens) public override returns (bool success) {
        //25% of tokens is locked only first time.
        address from = msg.sender;

        require(tokens <= balances[from], 'Amount Exceed!');

        if (balances[from] - holders[from].lockupAmount < tokens) {
            require(block.timestamp >= holders[from].unlockTime, "You can unlock tokens after 2 years from initial mintTime");
            holders[from].lockupAmount = 0;
        }

        if (!holders[to].bCreated) {
          holders[to].lockupAmount = tokens * 25 / 100;
          holders[to].unlockTime = block.timestamp + 2 * 365 * 24 * 3600;
          holders[to].bCreated = true;
        }

        balances[msg.sender] = safeSub(balances[msg.sender], tokens);
        //2.5% of transaction goes to burn address
        //2.5% goes to development address
        //2.5% goes to MKT address
        uint amount2to = tokens * 925 / 1000;
        uint amountPiece = tokens * 25 / 1000;

        balances[to] = safeAdd(balances[to], amount2to);
        balances[_MKTAddress] = safeAdd(balances[_MKTAddress], amountPiece);
        balances[_developmentAddress] = safeAdd(balances[_developmentAddress],amountPiece);
        _burn(amountPiece);

        emit Transfer(msg.sender, to, amount2to);
        return true;
    }

    function transferFrom(address from, address to, uint tokens) public override returns (bool success) {
        //25% of tokens is locked only first time.
         require(tokens <= balances[from], 'Amount Exceed!');

        if (balances[from] - holders[from].lockupAmount < tokens) {
            require(block.timestamp >= holders[from].unlockTime, "You can unlock tokens after 2 years from initial mintTime");
            holders[from].lockupAmount = 0;
        }

        if (!holders[to].bCreated) {
          holders[to].lockupAmount = tokens * 25 / 100;
          holders[to].unlockTime = block.timestamp + 2 * 365 * 24 * 3600;
          holders[to].bCreated = true;
        }

        balances[from] = safeSub(balances[from], tokens);
        allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
        //2.5% of transaction goes to burn address
        //2.5% goes to development address
        //2.5% goes to MKT address
        uint amount2to = tokens * 925 / 1000;
        uint amountPiece = tokens * 25 / 1000;

        balances[to] = safeAdd(balances[to], amount2to);
        balances[_MKTAddress] = safeAdd(balances[_MKTAddress], amountPiece);
        balances[_developmentAddress] = safeAdd(balances[_developmentAddress],amountPiece);
        _burn(amountPiece);

        emit Transfer(from, to, amount2to);
        return true;
    }

    function _mint(address account, uint256 amount) internal {
        require(account != address(0), 'BRC20: mint to the zero address');

        _totalSupply = safeAdd(_totalSupply, amount);
        balances[account] = safeAdd(balances[account], amount);
        emit Transfer(address(0), account, amount);
    }

    function mint(uint256 amount) public onlyOwner returns (bool) {
        _mint(_msgSender(), amount);
        return true;
    }

    function _burn(uint256 amount) private {
      balances[_burnAddress] = safeAdd(balances[_burnAddress], amount);
      _totalSupply -= amount;
    }
}

Here, I use only redeem(address, ...) function for lazy mint. I think this error is encountered in part of cr2Contract.transferFrom
But I can’t ever know the reason of this error. If there is anyone who knows the reason of this error, please leave a comment. Thanks in advance.

Leave a Comment