I'm trying to use this deploy script for an upgradable contract

async function main () {
  const Box = await ethers.getContractFactory('NFT');
  console.log('Deploying Box...');
  const NAME = "TestName"
  const SYMBOL = "Test"
  const COST = ethers.utils.parseUnits("0.2", "ether") // 1 ETH
  const box = await upgrades.deployProxy(Box, [42], { initializer: 'store' });
  await box.deployed();
  console.log('Box deployed to:', box.address);

Initially the contract had a constructor that accepted 3 parameters on deployment; NAME, SYMBOL and COST

The contracts constructor looks like this

contract NFT is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    address public owner;
    uint256 public cost;

        string memory _name,
        string memory _symbol,
        uint256 _cost
    ) ERC721(_name, _symbol) {
        owner = msg.sender;
        cost = _cost;


My question is how do I pass those parameters to an upgradable contract. From what I'm gathering there can't even be a constructor in an upgradable contract, although I could be wrong. Any tips would be appreciated

1 Answer 1


First its important to understand how upgradable contracts work. When you deploy it, you will get 3 contracts: proxy, proxyAdmin and implementation. The contract that you posted is the implementation.

Now all the variables will be stored on the proxy side and the implementation will only get used to for function calls.

When you use upgradable contracts you should therefore have an initializer function instead of the constructor, because it should get executed on the proxy side, not the implementation side.

Your constructor should therefore look like this:

function initialize
    string memory _name,
    string memory _symbol,
    uint256 _cost
) ERC721(_name, _symbol) public  {
    owner = msg.sender;
    cost = _cost;

You can still however use a constructor, but you will never really access the variables if you will have a proxy. Developers sometimes include it, because it disallows attackers from initializing the contract before they do. But if you use hardhat, you will be fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.