Initialize contracts with _init and _init_unchained

Hello,

I generated a contract using the Wizard. The initialize function of the contract calls

__AccessControl_init();
__UUPSUpgradeable_init();

I have 3 simple questions :smiley: :

  1. The __AccessControl_init() , __UUPSUpgradeable_init() are empty in version 5.0.1 , which means I really don't need to call them. Is this correct ?

  2. Why is XXX_init() used and not XXX_init_unchained, is it because they are empty and don't have parents? For these 2 contracts could I use XXX_init_unchained and it will make no difference ?

  3. Assuming that AccessControlUpgradeable and UUPSUpgradeable have a shared parent that must be initialized.

    1. Must I initialize that parent contract manually calling its _init() method. After that I can call __AccessControl_init_unchained() and __UUPSUpgradeable_init_unchained()
    2. Or Could I call
      __UUPSUpgradeable_init() which will initialize the parent and then call AccessControll_init_unchained() because the parent is already initialized by the first call ?

Thank you very much :slight_smile:

:1234: Code to reproduce

The code was generated using the Wizard

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

contract MyContract is Initializable, AccessControlUpgradeable, UUPSUpgradeable {
    bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address defaultAdmin, address upgrader)
        initializer public
    {
        __AccessControl_init();
        __UUPSUpgradeable_init();

        _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
        _grantRole(UPGRADER_ROLE, upgrader);
    }

    function _authorizeUpgrade(address newImplementation)
        internal
        onlyRole(UPGRADER_ROLE)
        override
    {}
}

:computer: Environment

Any

Please see this thread: Why keep "__Ownable_init" beside "__Ownable_init_unchained"?