ivan
ivan

Reputation: 35

Gas estimation errored: Returned error: {"jsonrpc":"2.0","error":"contract creation code storage out of gas","id":736521890935048}

I need heed help how can I solve this problem? The smart contract is deployable on mumbai testnet but when I tried to deploy it on polygon I got this (on the title above) error. Anyone know how can I solve this so I can deploy it on polygon mainnet on remix? Anyone knows how to fix the 'contract creation code storage out of gas' error?

Here is the code of my contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.2/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.2/contracts/token/ERC20/IERC20.sol";

contract TestNFT is ERC721 {
    using SafeMath for uint256;
    address public owner;
    string public _tokenURI;
    uint256 private _tokenIdTracker;
    uint256 private maxSupply = 10000;
    uint8 public decimal;
    address payable[] private recipients;
    uint[] private percentages;

    // nftHolders & nftMinteres mapping
    mapping(address => bool) private nftHolders;

    // Mint Fee
    uint256 private mintFee;

    // Royalty after mint
    uint256 private royaltyFee;

    // Recipients and percentages events
    event RecipientsUpdated(address payable[] recipients, uint[] percentages);

    // Nft events
    event NftWithburnt(address currentOwner, uint256 tokenId);
    event NftWithdrawn(
        address indexed recipient,
        uint256 tokenId,
        address indexed nftContract
    );
    event NftMinted(address indexed recipient, uint256 nftAmount);

    // Eth events
    event Deposit(address indexed sender, uint256 amount);
    event Forwarded(uint256 totalAmount, uint256[] amounts);

    constructor() ERC721("Project", "X") {
        decimal = 0;
        owner = payable(msg.sender);
        mintFee = 0.01 ether;
        royaltyFee = 5; //default 5%.
        recipients.push(payable(0x22AbA4c94E703e280A96713c26a1c1872AB45D9e)); 
        percentages.push(20);
        recipients.push(payable(0xCAeaA9D2DffF37c240bafC215608752c9C125B42)); 
        percentages.push(5);
        recipients.push(payable(0xe1C87F43c12a7B43Bee853e66F0BCB3dd75d9E95)); 
        percentages.push(55);
        recipients.push(payable(0x38d5a7EF9DB64D05A47c82C5E42bB45A7C82B457));
        percentages.push(20);
        require(
            percentages.length == recipients.length,
            "Recipients and percentages length mismatch"
        );
        require(
            percentages.length <= 4,
            "Cannot specify more than 4 recipients"
        );
        uint totalPercentage;
        for (uint i = 0; i < recipients.length; i++) {
            require(
                recipients[i] != address(0),
                "Recipient address cannot be zero"
            );
            require(percentages[i] > 0, "Percentage must be greater than zero");
            totalPercentage += percentages[i];
        }
        require(totalPercentage == 100, "Percentages must add up to 100");
    }

    // Modifier to onlyOwner
    modifier onlyOwner() {
        require(
            msg.sender == owner,
            "Only the contract owner can call this function."
        );
        _;
    }

    // Get total nftSupply
    function totalSupply() public view returns (uint256) {
        return _tokenIdTracker;
    }

    // Get MaxSupply
    function getMaxSupply() public view returns (uint256) {
        return maxSupply;
    }

    // Check the current tokenURI
    function _baseURI() internal view override returns (string memory) {
        return _tokenURI;
    }

    // TokenURI updatable
    function setTokenURI(string memory tokenURI) public onlyOwner {
        _tokenURI = tokenURI;
    }

    // Updating royalty fee
    function updateRoyaltyFee(uint256 newRoyaltyFee) external onlyOwner {
        require(newRoyaltyFee <= 10); //
        royaltyFee = newRoyaltyFee;
    }

    function UpdateMintFee(uint256 newMintFee) external onlyOwner {
        mintFee = newMintFee;
    }

    function getMintFee() public view returns (uint256) {
        return mintFee;
    }

    // Update maxSupply
    function updateMaxSupply(uint256 newMaxSupply) external onlyOwner {
        maxSupply = newMaxSupply;
    }

    //View contract balance
    function getETHBalance() public view returns (uint256) {
        return address(this).balance;
    }

    function getStakingAddress() public view returns (address payable) {
        require(recipients.length >= 0, "Recipient does not exist");
        return recipients[0];
    }

    function getCharityAddress() public view returns (address payable) {
        require(recipients.length >= 1, "Recipient does not exist");
        return recipients[1];
    }

    function getMarketingAddress() public view returns (address payable) {
        require(recipients.length >= 2, "Recipient does not exist");
        return recipients[2];
    }

    function getLiquidityAddress() public view returns (address payable) {
        require(recipients.length >= 3, "Recipient does not exist");
        return recipients[3];
    }

    // Receive fallback function
    receive() external payable {
        if (msg.value > 0) {
            distributeRoyalties();
        }
    }

    // Deposit or transfer Eth to contract
    function deposit() public payable {
        require(
            msg.value > 0,
            "deposit(ETH): input an amount, zero deposit is not allowed. "
        );
        distributeRoyalties();
        emit Deposit(msg.sender, msg.value);
    }

    // Forward Eth to recipients
    function distributeRoyalties() internal {
        require(
            msg.value > 0,
            "distributeRoyalties: amount is too low for distribution."
        );
        uint256 balance = address(this).balance;
        uint256[] memory amounts = new uint256[](recipients.length);
        for (uint i = 0; i < recipients.length; i++) {
            amounts[i] = (balance * percentages[i]) / 100;
            require(amounts[i] > 0, "Amount is too low");
            (bool sent, ) = recipients[i].call{value: amounts[i]}("");
            require(sent, "Failed to send Ether to recipient");
        }
        emit Forwarded(balance, amounts);
    }

    //Function to mint new NFT
    function mint(uint256 nftAmount) public payable {
        require(nftAmount > 0, "mint: zero nftAmount not allowed.");
        require(
            _tokenIdTracker.add(nftAmount) <= maxSupply,
            "mint: Minting have reached the MaxSupply."
        );

        //Calculate the minting fee (Eth)
        uint256 fee = nftAmount.mul(mintFee); // default: 10 Matic fee per NFT minted

        // Check if the sender is the contract owner
        if (msg.sender != owner) {
            require(msg.value >= fee, "mint: Incorrect mintFee amount");
            distributeRoyalties(); //Transfer the fee to the contract address
        }

        // Mint the NFT and transfer it to the minter
        for (uint256 i = 0; i < nftAmount; i++) {
            uint256 tokenId = _tokenIdTracker;
            _safeMint(msg.sender, tokenId);
            _tokenIdTracker = _tokenIdTracker.add(1);
        }

        // Add the 'msg.sender' address to the tokenHolders mapping if it doesn't already exist
        if (balanceOf(_msgSender()) > 0) {
            nftHolders[_msgSender()] = true;
        } else if (balanceOf(_msgSender()) == 0) {
            nftHolders[_msgSender()] = false;
        }
        // Refund excess ETH back to the user
        if (msg.value > fee) {
            address payable sender = payable(msg.sender);
            sender.transfer(msg.value.sub(fee));
        }
        emit NftMinted(msg.sender, nftAmount);
    }

    // any users can burn their token
    function burn(uint256 tokenId) public {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "burn: caller is not owner nor approved"
        );
        _burn(tokenId);
        _tokenIdTracker--;

        // Remove the 'msg.sender' address from the tokenHolders mapping if it no longer holds any tokens
        if (balanceOf(_msgSender()) == 0) {
            nftHolders[_msgSender()] = false;
        } else if (balanceOf(_msgSender()) > 0) {
            nftHolders[_msgSender()] = true;
        }
        emit NftWithburnt(_msgSender(), tokenId);
    }

    // Override NFTtransfers when contract is paused
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: caller is not token owner or approved"
        );
        _transfer(from, to, tokenId);
    }

    // Override NFTtransfers when contract is paused
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: caller is not token owner or approved"
        );
        _transfer(from, to, tokenId);
    }

    // Transfer with data(public)
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public virtual override {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: caller is not token owner or approved"
        );
        _safeTransfer(from, to, tokenId, data);
    }

    // Transfer with data(internal)
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual override {
        _transfer(from, to, tokenId);
        if (data.length > 0) {
            require(
                _checkOnERC721Received(from, to, tokenId, data),
                "ERC721: transfer to non ERC721Receiver implementer"
            );
        }
    }

    //check the reciever
    function isContract(address account) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    // Check the reciever and data
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual override returns (bool) {
        if (isContract(to)) {
            try
                IERC721Receiver(to).onERC721Received(
                    _msgSender(),
                    from,
                    tokenId,
                    data
                )
            returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert(
                        "ERC721: transfer to non ERC721Receiver implementer"
                    );
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    // Override the ERC721 _transfer function to add tracking
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "_transfer(): caller is not owner nor approved"
        );
        require(
            ERC721.ownerOf(tokenId) == from,
            "_transfer(): transfer from incorrect owner"
        );
        require(
            to != address(0),
            "_transfer(): transfer to the zero address not allowed"
        );

        // Add the 'to' address to the tokenHolders mapping if it doesn't already exist
        if (balanceOf(to) > 0) {
            nftHolders[to] = true;
        } else if (balanceOf(to) == 0) {
            nftHolders[to] = false;
        }

        // Remove the 'from' address from the tokenHolders mapping if it no longer holds any tokens
        if (balanceOf(from) == 0) {
            nftHolders[from] = false;
        } else if (balanceOf(from) > 0) {
            nftHolders[from] = true;
        }
        super._transfer(from, to, tokenId);
    }

    // Get the total number of unique token holders
    function totalHolders() public view returns (uint256) {
        uint256 count = 0;

        // Create an array of all the keys in the nftHolders mapping using the getKeys() function
        address[] memory keys = new address[](totalSupply());

        // Iterate over all token IDs and add the holder's address to the keys array if it hasn't already been added
        for (uint256 i = 0; i < totalSupply(); i++) {
            address holder = ownerOf(i);
            bool found = false;
            for (uint256 j = 0; j < keys.length; j++) {
                if (keys[j] == holder) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                keys[count] = holder;
                count++;
            }
        }

        return count;
    }

    // Send ERC20 token from balance to all royalty recipients
    function distributeERC20(address tokenAddress) external onlyOwner {
        require(
            msg.sender == owner,
            "Only the owner can withdraw ERC20 tokens"
        );
        require(recipients.length > 0, "No recipients specified");
        require(
            percentages.length == recipients.length,
            "Recipients and percentages length mismatch"
        );
        require(
            percentages.length <= 4,
            "Cannot specify more than 4 recipients"
        );

        // Get ERC20 token balance in contract
        IERC20 token = IERC20(tokenAddress);

        uint256 tokenBalance = token.balanceOf(address(this));
        require(tokenBalance > 0, "Contract has no tokens to withdraw");

        uint256[] memory amounts = new uint256[](recipients.length);
        uint256 totalPercentage;

        for (uint i = 0; i < recipients.length; i++) {
            totalPercentage += percentages[i];
        }

        for (uint i = 0; i < recipients.length; i++) {
            amounts[i] = (tokenBalance * percentages[i]) / totalPercentage;
            require(amounts[i] > 0, "Amount is too low");
            token.transfer(recipients[i], amounts[i]);
        }
        emit Forwarded(tokenBalance, amounts);
    }

    // Function to receive NFT
    function onERC721Received(
        address,
        address,
        uint256,
        bytes memory
    ) public virtual returns (bytes4) {
        return this.onERC721Received.selector;
    }

    // Forward Eth to recipients
    function callDistribution() external payable onlyOwner {
        uint256 balance = address(this).balance;
        uint256[] memory amounts = new uint256[](recipients.length);
        for (uint i = 0; i < recipients.length; i++) {
            amounts[i] = (balance * percentages[i]) / 100;
            require(
                amounts[i] > 0,
                "callDistribution: amount is too low for distribution."
            );
            (bool sent, ) = recipients[i].call{value: amounts[i]}("");
            require(sent, "Failed to send Ether to recipient");
        }
        emit Forwarded(balance, amounts);
    }

    // Function to rescue NFT
    function rescueNft(
        address nftContract,
        uint256 tokenId
    ) external onlyOwner {
        require(_exists(tokenId), "ERC721Metadata: nonexistent token");
        require(
            ownerOf(tokenId) == address(this),
            "The NFT is not in this contract's balance"
        );
        IERC721(nftContract).safeTransferFrom(
            address(this),
            msg.sender,
            tokenId
        );
        emit NftWithdrawn(msg.sender, tokenId, nftContract);
    }
} ```

Upvotes: -1

Views: 2177

Answers (1)

Alon Ben Yaakov
Alon Ben Yaakov

Reputation: 329

Short answer - you have an insufficient amount of Matic in your wallet to deploy.

Long answer - I will address both your error message & the contract code.

The Error Message

This error occurs when trying to deploy a new contract to the network with insufficient gas, therefore it fails.

Gas is the fee required to execute a transaction/ deploy contract on the blockchain. The gas is paid with the native coin of the network. For Ethereum, it's ETH, for Polygon & Mumbai(polygon testnet) it's Matic.

So to deploy your contract on Polygon you need to:

  1. Make sure you have enough Matic in the wallet you are using to deploy the contract
    • You can check your wallet's matic balance here: https://polygonscan.com/
    • If you don't have Matic on your polygon wallet you will need to charge it.
  2. When deploying the contract you need to specify the amount of gas you are willing to pay. In your case using remix is supposed to automatically calculate the appropriate gas limit(default is 3000000). Just make sure you connected your wallet and selected the Mumbai network(I am using Metamask).

If you want to learn more about the gas standard you can read the official EIP-1559 regarding the newest gas payment standard.

The remix deploy panel is supposed to look like this:

Deploy Panel

I've tested and successfully deployed the contract to Polygon

The Contract Code

The contract code should be minimized and simplified. You are inheriting the ERC721 contract but you also manually added the ERC721 to your contract, for example, the _checkOnERC721Received function. And by that increasing your contract byte size. If you will continue to add code to the current state of your contract you will receive another error : Contract code size exceeds 24576 bytes (a limit introduced in Spurious Dragon). Meaning your contract is too large for deploying.

I've tried to use your code in remix but some of your imports don't exist so I've replaced them with the updated version.

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.8/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

Upvotes: 0

Related Questions