How to decide in my design pattern which contracts set to be upgradeable and which non-upgradeable?

Hello. I'm trying to implement an upgradeable contract and by checking the docs I can't see implementations of using upgradeable contracts with non-upgradeable ones. What is the proper way to do this?

I am assuming that you need to make explicitly upgradeable the ones you intend to modify in the future but what happen with the dependencies they have?

For example let's say I want my upgradeable contract to be also pausable, but as I don't see its pausable features changing so much I just go for (is Pausable). If I upgrade my contract to use PausableUpgradeable.sol, does it have any conflict with the inheritance brought by Pausable.sol y the first place? Thank you in advance for your help!

Hi @nicolas.guasca,

If you intend for your contracts to be upgradable (in other words, you will be using a proxy), your contracts and their parent contracts cannot use constructors. This restriction applies even to the first version of your implementation.

So in your upgradable contract, use dependencies from @openzeppelin/contracts-upgradeable instead of @openzeppelin/contracts in the first and subsequent versions of your contract regardless of whether you intend to change certain features, because @openzeppelin/contracts-upgradeable uses initializers instead of constructors.

For your example, use PausableUpgradable in the first and subsequent versions of your contract.

Thank you so much for the prompt reply @ericglau !
Totally understood. I'm using what this post suggested.
Now that I am trying to create a factory that creates an instance of my upgradeable contract, this is what it looks like:

//SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import "./MyUpgradeable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.1/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.4.1/contracts/proxy/utils/Initializable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.4.1/contracts/security/PausableUpgradeable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.4.1/contracts/access/AccessControlUpgradeable.sol";


contract FactoryContract is Initializable, PausableUpgradeable, AccessControlUpgradeable {
  bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE");
  bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
  address immutable myUpgradeableImplementation;
  event MyUpgradeableDeployed(address tokenAddress);
  address payable public factoryManagerAccount;
  MyUpgradeable[] public myUpgradeablesArray;

  function initialize() initializer public {
    factoryManagerAccount = payable(msg.sender);
    __AccessControl_init();
    __Pausable_init();
    _grantRole(DEFAULT_ADMIN_ROLE, factoryManagerAccount);
    _grantRole(PAUSER_ROLE, msg.sender);
    
    }

*ERROR LINE IS THE FOLLOWING*
  function createMyUpgradeable(uint8 _Number, string _Name) external returns (address) {
    ERC1967Proxy proxy = new ERC1967Proxy(myUpgradeableImplementation, abi.encodeWithSelector(MyUpgradeable(address(0)).initialize.selector, _Number, _Name));
    emit MyUpgradeableDeployed(address(proxy));
    return address(proxy);
  }

  function supportsInterface(bytes4 interfaceId)
        public
        view
        override(
          // ERC1155Upgradeable, 
          AccessControlUpgradeable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}

I'm using remix with the 0.8.7 compiler version and it throws on the ERROR LINE:

TypeError: Data location must be "memory" or "calldata" for parameter in external function, but none was given.
-->
What am I missing from the proxy creation?

I have made my createMyUpgradeable function public and the error goes away. Could you explain to me what are the implications between making my "proxy creation function" external vs making it public?

Since you are using external, the string _Name parameter needs to be declared with memory or calldata.

Could you explain to me what are the implications between making my "proxy creation function" external vs making it public?

It depends how you want to restrict visibility of that function. See https://docs.soliditylang.org/en/latest/cheatsheet.html#function-visibility-specifiers