0

I've noticed that when a contract factory creates a new contract with the 'new' keyword, the transaction costs an absurd amount of gas as if it were deploying the contract for the first time. I don't understand why such a high gas cost, if the contract has been deployed before and the code is already 'in the blockchain' then why does it need to deploy the whole code again.

Here's an example:

    pragma solidity >=0.4.22 <0.6.0;
    
    contract OwnedToken {
        // `TokenCreator` is a contract type that is defined below.
        // It is fine to reference it as long as it is not used
        // to create a new contract.
        TokenCreator creator;
        address owner;
        bytes32 name;
    
        // This is the constructor which registers the
        // creator and the assigned name.
        constructor(bytes32 _name) public {
            // State variables are accessed via their name
            // and not via e.g. `this.owner`. Functions can
            // be accessed directly or through `this.f`,
            // but the latter provides an external view
            // to the function. Especially in the constructor,
            // you should not access functions externally,
            // because the function does not exist yet.
            // See the next section for details.
            owner = msg.sender;
    
            // We do an explicit type conversion from `address`
            // to `TokenCreator` and assume that the type of
            // the calling contract is `TokenCreator`, there is
            // no real way to check that.
            creator = TokenCreator(msg.sender);
            name = _name;
        }
    
        function changeName(bytes32 newName) public {
            // Only the creator can alter the name --
            // the comparison is possible since contracts
            // are explicitly convertible to addresses.
            if (msg.sender == address(creator))
                name = newName;
        }
    
        function transfer(address newOwner) public {
            // Only the current owner can transfer the token.
            if (msg.sender != owner) return;
    
            // We ask the creator contract if the transfer
            // should proceed by using a function of the
            // `TokenCreator` contract defined below. If
            // the call fails (e.g. due to out-of-gas),
            // the execution also fails here.
            if (creator.isTokenTransferOK(owner, newOwner))
                owner = newOwner;
        }
    }
    
    contract TokenCreator {
        function createToken(bytes32 name)
           public
           returns (OwnedToken tokenAddress)
        {
            // Create a new `Token` contract and return its address.
            // From the JavaScript side, the return type is
            // `address`, as this is the closest type available in
            // the ABI.
            return new OwnedToken(name);
        }
    
        function changeName(OwnedToken tokenAddress, bytes32 name) public {
            // Again, the external type of `tokenAddress` is
            // simply `address`.
            tokenAddress.changeName(name);
        }
    
        // Perform checks to determine if transferring a token to the
        // `OwnedToken` contract should proceed
        function isTokenTransferOK(address currentOwner, address newOwner)
            public
            pure
            returns (bool ok)
        {
            // Check an arbitrary condition to see if transfer should proceed
            return keccak256(abi.encodePacked(currentOwner, newOwner))[0] == 0x7f;
        }
    }

The 'createToken' function of the TokenCreator contract, creates an object of the OwnedToken contract. But why does it cost as much to call the function as does deploying the OwnedToken contract, if the code is always the same?

Thank you.

2
  • Yes, deploying instances of a contract repeats deployment and costs the same. But, there are ways to radically reduce the cost to each deployment event so that the payload to deploy each time is VERY small. It involves radical restructuring, heavy use of libraries and proxy contracts so the payload to deploy each time is incredibly small. Jul 5 '20 at 0:25
  • The answer to "why" is because that's what it costs to repetitiously deploy a large contract. The surprise factor possibly implies you expected it to use the code that was deployed before and gain some efficiency from re-use. That doesn't happen automagically. You have to tell the deployed contracts to use code found elsewhere - that you want to carve out and deployed once and re-use. You can optimize for deployment cost with this and other techniques but the design is your responsibility. Jul 5 '20 at 0:35
3

As @goodvibration was saying, you always create different instances. So the byteCode is duplicated and thus costs always the same amount of gas.

To avoid this you could use a clone factory: https://github.com/optionality/clone-factory. It creates a new contract which delegates all calls to the given library contract. The library is only deployed once, so the clone factory deployments are much cheaper.

Update: Wrote a blog post about clone factories if anyone is interested: https://soliditydeveloper.com/clonefactory.

1
  • Very cool! Thanks.
    – John Smith
    Jul 4 '20 at 4:15
1

if the contract has been deployed before and the code is already 'in the blockchain' then why does it need to deploy the whole code again

Because the same contract may have different instances of it deployed at different addresses and holding state-variables of different values.

18
  • yes, but the source code is the same
    – John Smith
    Jul 4 '20 at 1:44
  • For example, I'm creating a contact object where the constructor stores 4 address variables and one uint256 variable. However, the creation of the contract object from another contract costs 3 million gas.
    – John Smith
    Jul 4 '20 at 1:46
  • It's impossible that creating an instance with only 4 address variables and one uint256 variable, costs 3 million gas. The rest is just functions, events and the like.
    – John Smith
    Jul 4 '20 at 1:58
  • @JohnSmith: The cost is actually for the functions, not for the state variables!!! Functions are the part which is compiled into bytecode, and the size of the bytecode determines the cost of the deployment (almost entirely, to be more accurate). Jul 4 '20 at 2:01
  • And regarding your first comment - please read the answer again. Jul 4 '20 at 2:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.