EIP-1167 – How to Connect Call Functions from Implementation Contracts in Clone Contracts (EIP-1167)

cloneopenzeppelinproxy-contractssoliditystorage

I am building a dApp which makes use of the OpenZeppelin Clones Library (EIP-1167), which will allow my users to cheaply deploy clones and gain functionality of the implementation contract. I have written my implementation contract and have a few questions regarding creating the clones and connecting them to my front end.

Here is the CloneFactory Contract:

pragma solidity ^0.8.8;

import "./Whoopy.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";

contract WhoopFactory is Ownable {
    address public implementationContract;
    address instance;

    mapping(address => address[]) public allClones;

    // address[] public allClones;

    event NewClone(address _clone, address _whoopyCreator);

    struct whoopy {
        uint256 index;
        address whoopyCreator;
    }

    mapping(address => whoopy) whoopyList;


    constructor(address _implementation) {
        implementationContract = _implementation;
    }

    function createClone() external {
        address instance = Clones.clone(implementationContract);
        allClones[msg.sender].push(instance);
        Whoopy(instance).initialize(msg.sender);
        emit NewClone(instance, msg.sender);
    }

    function returnClones(address _whoopCreator) external view returns (address[] memory) {
        return allClones[_whoopCreator];
    }

I would like to know how call other functions from my implementation contract after creating the clone and initialising it. Would I have to code the functions I'd like to call from the implementation contract into the 'WhoopyFactory' contract, or is there another way to go about this?

(I have looked at a lot of tutorials online, however all of them only teach up to the initialisation phase and none of them go into calling other functions.)

Also, my Implementation contract inherits about 3 other contracts. Do I need to account for these contracts in the CloneFactory or is it taken care of automatically. I have already ensured to remove constructors from all ancestor contracts and use initialize instead, as directed by OpenZeppelin docs here.

Any help would be greatly appreciated!
Thanks in advance!

Best Answer

The answer is simple: just think about the cloned contract as a completely normal and independent contract.

So, to interact with it from the frontend you just need its address and the ABI. Using ethers:

const contract = new ethers.Contract(contractAddress, Whoopy_ABI, provider)

contractAddress is one returned from returnClones(_whoopCreator), Whoopy_ABI is common to everyone. To interact with it from solidity, you can use the same interface as the implementation; as a matter of fact, you're already doing it in your example: Whoopy(instance).initialize(...).

Almost never you should interact with the implementation contract itself.

Also, my Implementation contract inherits about 3 other contracts. Do I need to account for these contracts in the CloneFactory or is it taken care of automatically. I have already ensured to remove constructors from all ancestor contracts and use initialize instead, as directed by OpenZeppelin docs here.

If the compiler doesn't raise errors you're already good. Otherwise you just need to add the inherited functions in the interface/ABI.

Related Topic