Deploying factory contract which deploys ERC721 & ERC20 exceeds block gas limit

I have a main contract to help me deploy ERC721 && ERC20 token

but it seems to have some problems when i tried deploy both ERC20 and ERC721 in a same factory contract.

i use @openzeppelin/contracts": "^2.5.1" in package.json

My ERC721 contract

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721Mintable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721MetadataMintable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol";
import "@openzeppelin/contracts/drafts/Counters.sol";

contract myERC721 is
    ERC721Full,
    ERC721Mintable,
    ERC721MetadataMintable,
    ERC721Holder
{
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    event awardNewItem(uint256 indexed newID);

    constructor(
        string memory name,
        string memory symbol,
        string memory baseURI 
    ) public ERC721Full(name, symbol) {
        _setBaseURI(baseURI);
    }

    function awardItem(
        address player,
        string memory _tokenURI
    ) public returns (uint256) {
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();
        mint(player, newItemId);
        _setTokenURI(newItemId, _tokenURI);

        return newItemId;
    }
}

My ERC20 contract

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol";

contract myERC20 is ERC20, ERC20Detailed, ERC20Burnable, ERC20Mintable {
    constructor(
        string memory name, 
        string memory symbol,
        uint8 decimals, 
        uint256 initialSupply
    ) public ERC20Detailed(name, symbol, decimals) {
        _mint(msg.sender, initialSupply * (10**uint256(decimals)));
    }
}


My main factory contract

pragma solidity ^0.5.0;

import "./myERC721.sol";
import "./myERC20.sol";

contract tokenFactory {

    address[] tokenAddress;
 
    function deploy721Contract(
        string calldata name,
        string calldata symbol,
        string calldata baseUrl
    ) external returns (myERC721 cardAddress) {

        myERC721 newCards = new myERC721(name, symbol, baseUrl);

        tokenAddress.push(address(newCards));
        return newCards;
    }

    function deploy20Contract(
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        uint256 initialSupply
    ) external returns (myERC20 creditsAddress) {

        myERC20 newCredits = new myERC20(
            name,
            symbol,
            decimals,
            initialSupply
        );

        tokenAddress.push(address(newCredits));
        return newCredits;
    }

}


Problem

  1. when i comment out the deploy20Contract function code. the factory contract can deploy and use 3598155 gas
    image image

  2. when i comment out deploy721Contract function code. the factory contract can deploy and use 2208084 gas
    image image

BOTH 1 and 2 do not have cost much gas.

  1. when i don’t comment out any code, both have the deploy20Contract and deploy721Contract in the factory contract

it will get out of gas. and i increase the gasLimit. it still out of gas and finally tell me Exceeds block gas limit

image

image

image

It seems that when i depoy both ERC20 && ERC721 contract in the same contrat. it will stuck in an endless loop and use unlimited gas.

how should i do? Is there any conflict about importing the 721 & 20 contract at the same contract?

1 Like

Hi @Serenity,

Welcome to the community forum :wave:

The tokenFactory contract is failing to deploy as it is over the bytecode size limit of 24577 or greater (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-170.md)

With optimization disabled the bytecode size is as follows:

$ jq '.deployedBytecode | length / 2 - 1' build/contracts/tokenFactory.json
26394

With optimization enabled, 200 runs the bytecode size is reduced and can be deployed:

$ jq '.deployedBytecode | length / 2 - 1' build/contracts/tokenFactory.json
17403

When you change the optimization settings, we need to rebuild (either remove the build directory or use npx truffle compile --all)


You are currently using OpenZeppelin Contracts 2.x. You may want to look at using OpenZeppelin Contracts 3.x.


Assuming that you are deploying multiple ERC20 tokens and ERC721 tokens, I would suggest looking at deploying an implementation contract for each and then deploy minimal proxies: https://blog.openzeppelin.com/deep-dive-into-the-minimal-proxy-contract/

This would reduce the amount of gas required to create new tokens.

but why still i can’t deploy it after i enabled optimization in remix?
image

1 Like

Hi @Serenity,

I deployed in Remix to Ropsten with optimization enabled and was then able to use the factory to create an ERC20 and an ERC721

I converted your contracts to use GitHub imports so I could deploy using Remix.

myERC721.sol

pragma solidity ^0.5.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC721/ERC721Full.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC721/ERC721Mintable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC721/ERC721MetadataMintable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC721/ERC721Holder.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/drafts/Counters.sol";

contract myERC721 is
    ERC721Full,
    ERC721Mintable,
    ERC721MetadataMintable,
    ERC721Holder
{
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    event awardNewItem(uint256 indexed newID);

    constructor(
        string memory name,
        string memory symbol,
        string memory baseURI 
    ) public ERC721Full(name, symbol) {
        _setBaseURI(baseURI);
    }

    function awardItem(
        address player,
        string memory _tokenURI
    ) public returns (uint256) {
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();
        mint(player, newItemId);
        _setTokenURI(newItemId, _tokenURI);

        return newItemId;
    }
}

myERC20.sol

pragma solidity ^0.5.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC20/ERC20Detailed.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC20/ERC20Burnable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC20/ERC20Mintable.sol";

contract myERC20 is ERC20, ERC20Detailed, ERC20Burnable, ERC20Mintable {
    constructor(
        string memory name, 
        string memory symbol,
        uint8 decimals, 
        uint256 initialSupply
    ) public ERC20Detailed(name, symbol, decimals) {
        _mint(msg.sender, initialSupply * (10**uint256(decimals)));
    }
}

tokenFactory.sol

pragma solidity ^0.5.0;

import "./myERC721.sol";
import "./myERC20.sol";

contract tokenFactory {

    address[] tokenAddress;
 
    function deploy721Contract(
        string calldata name,
        string calldata symbol,
        string calldata baseUrl
    ) external returns (myERC721 cardAddress) {

        myERC721 newCards = new myERC721(name, symbol, baseUrl);

        tokenAddress.push(address(newCards));
        return newCards;
    }

    function deploy20Contract(
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        uint256 initialSupply
    ) external returns (myERC20 creditsAddress) {

        myERC20 newCredits = new myERC20(
            name,
            symbol,
            decimals,
            initialSupply
        );

        tokenAddress.push(address(newCredits));
        return newCredits;
    }

}

Hi @Serenity,

I wanted to check that you were able to deploy with optimization?