Why are implementation and beacon both in ERC1967Upgrade contract?

Hi there, as I was looking into ERC1967Upgrade and UUPSUpgradeable contracts, I found out that ERC1967Upgrade contract has both implementation and beacon implemented. That means, this contract itself can have implementations and also point to a beacon that has an implementation as well.

Wondering what the rationale behind this is? Thanks.

1 Like

The contract is only meant to bundle functions to access and update the storage slots defined in EIP1967. It is not the intention that the same contract could have both implementation and beacon, but if it did, the semantics are given by EIP1967:

[The Beacon contract address] SHOULD be empty if an logic [i.e. implementation] address is used directly instead, and should only be considered if the logic contract slot is empty.

A code snippet from ERC1967Upgrade is given below. It looks to me that the implementation is something serious. It has both _upgradeToAndCall and _upgradeToAndCallSecure functions defined. Down further in the contract, _upgradeBeaconToAndCall is also defined. In summary, both implementation and beacon seem to be designed to implement serious logics in ERC1967Upgrade contract. Wondering if there is any in-depth reason. Thanks.

    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(newImplementation, data);
        }
    }

    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        }
    }

Each function implements the upgrade of a different upgrade pattern. They're not meant to be used together.

1 Like