Contracts cloned are not independent?

Hi there, suppose I’m using Clones.clone to create new contracts for a given template, as given in the code below. Now for a newly creately contract by cloning, the function calls to the new contract are delegated to the template contract as internal transactions. For example, in the graph below, the highlighted contract is the original template contract. And all newly created contracts are supposed to be independent from each other. I am wondering what is happening under the hood. Thanks.

address newTemplateAddr = Clones.clone(templateAddr);
ITemplate(newTemplateAddr).initialize(uint256 para1, string memory str1);

I’m not sure I understand the problem.

Let’s say contract X deploys a clone Y of contract Z. Then if X.f() calls Y.g(), Y.g() will actually delegatecall Z.g() under the hood. That’s the expected behavior.

1 Like

In my case, there is a contract factory, let’s say it’s called groupFactory, generating group contracts. In the groupFactory, a template group contract A is used to make clones B, C, D, etc. By design, B, C, D have all needed functions to perform actions independently from each other. But what I observed is a function call to B is actually delegated to A as shown in the graph above. This is unexpected, since no delegate call is designed in A and B, C, D, in my understanding, are just runtime code deployed at different addresses. Why is there a delegate call to A then?

1 Like

Emmmm, I think, when you use groupFactory to clones A to get B, just like the common proxy pattern, B is the proxy, A is the implementation, that is B stores data, A stores logic.

Hey @Skyge , we can take the createpair function from psc for example. It is generating all independent pair contracts by create2. Is the Clones.clone function not doing the same?

    function createPair(address tokenA, address tokenB) external returns (address pair) {
        require(tokenA != tokenB, 'Pancake: IDENTICAL_ADDRESSES');
        (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(token0 != address(0), 'Pancake: ZERO_ADDRESS');
        require(getPair[token0][token1] == address(0), 'Pancake: PAIR_EXISTS'); // single check is sufficient
        bytes memory bytecode = type(PancakePair).creationCode;
        bytes32 salt = keccak256(abi.encodePacked(token0, token1));
        assembly {
            pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
        }
        IPancakePair(pair).initialize(token0, token1);
        getPair[token0][token1] = pair;
        getPair[token1][token0] = pair; // populate mapping in the reverse direction
        allPairs.push(pair);
        emit PairCreated(token0, token1, pair, allPairs.length);
    }

Emmmmm, I think they are different, just like the original defined for the EIP-1167, it is Minimal Proxy Contract, so I think what you get after cloning is a proxy contract