How to deploy a Proxy Upgradeable Contract from a contract?

Greetings.

I would like to understand how I can upgrade a contract that was deployed from another contract.

 vault.logic = new CompoundVault();    <--- stores implementation address of upgradeable
        vault.logic.initializeIt(
            address(this),
            deployer,
            cToken,
            asset,
            fees,
            feeBase,
            mentissa,
            symbol,
            name
        );

I notice that the deployment is returning the implementation address directly.

How would I upgrade this contract from my deployer contract?

If I set myself as the owner of the implementation, would that restrict the proxy?
If for instance, I find a bug in my contract. and want to upgrade them.
I would probably need to upgrade the deployer contract with the (fix) So it would deploy fixed version in the future. But I want to upgrade the previously deployed as well.

Right now I only store the address of the implementation, I'm not sure if I can just call initialize again as the owner.

I would like a function that would upgrade the previously deployed contract.

I am not sure which proxy do you use, do you use the plugin to deploy a proxy contract?
For hardhat: Upgrading smart contracts - OpenZeppelin Docs
For Truffle:

const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');

const Box = artifacts.require('Box');
const BoxV2 = artifacts.require('BoxV2');

module.exports = async function (deployer) {
  const instance = await deployProxy(Box, [], { deployer });
  const upgraded = await upgradeProxy(instance.address, BoxV2, { deployer });
}

Depends on your proxy contract.

If you find a bug in your implementation contract, you can fix the bug in the new implementation contract, and upgrade your original proxy contract with the new fixed contract.

I think the function initialize() should only be called once.

Hello @Skyge !

I am using
"@openzeppelin/contracts-upgradeable": "^4.0.0",
"@openzeppelin/hardhat-upgrades": "^1.6.0",

There is 2 thing I don't get. I deploy my main contract. This contract deploys other contract.

I store the contract in a library (struct). But I don't know what is the address of the proxy.
I only get the address of my main contract (deployer). This contract, when it deploys another contract, only record the address of the implementation.

I understand how I can upgrade the main one with Hardhat. But not all the deployed contract. Etherscan is also not showing these as Proxy.

Are they all using the same proxy?

In Solidity, unless you explicit deploy a Proxy contract, your contracts will not be upgradeable. This is why you're only seeing implementation addresses.

If you want to deploy upgradeable contracts, you will have to import a proxy contract from OpenZeppelin Contracts and deploy it using new as well, where one of its parameters will be the logic address you get from new CompoundVault.

1 Like

Humm ok that is a bit confusing!

First my contract (CompoundVault) is already upgradeable when I use hardhat to deploy.
But I deploy it from my main contract.

I'm not sure I understand.
I have to pass the address of CompVault to the proxy? so already deployed? but deployed with the proxy? Which contract i have to deploy first.

Does the proxy take the deployment as the argument? Would it look like

Proxy.initialize(args...)??

Have you read this tutorial? I think it can give you some idea.

Yes this is my procedure for all my contract.

But im unable to do it like that because it's not the hardhat plugin that is deploying my contract.
It's a contract.

import ".CompoundVault.sol"                    <---- is upgradeable 
import "./lib/CVault.sol";                 <---- struct Lib where I store contract data
 
myConctract is initializable {

    using CVaults for CVaults.CompVault;

    initialize (some args) initializer {
    }

    fuction deployContract(some args){

         CVaults.CompVault storage vault = vaults[vaultCount];
                                                       <---- I guess I need a proxy here 
            vault.logic = new CompoundVault();
            vault.logic.initializeIt(
             someArg ...
          );
    }
}

I found this!

and also this

However this contract seems a bit hold. Is there a Proxy Factory for solidity 0.8.0?

We don't have a ProxyFactory contract for Solidity 0.8 but you can take a look at this one that a user built recently:

1 Like

This look like what I want! Reading trough!

Thank you @frangio And @Skyge

1 Like

I forgot to mention, do note that the code I linked is using UUPS proxies. For transparent proxies you will need to use TransparentUpgradeableProxy rather than ERC1967Proxy, and refer to its documentation, particularly the constructor parameters.

1 Like

I tried with UUPS

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.2;

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

contract Vault is Initializable, UUPSUpgradeable, OwnableUpgradeable  {
    string public name;
  
    function initialize() initializer public {
      __Ownable_init();
      transferOwnership(msg.sender);
      name = 'VaultV1';
    }

   function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {}
   function upgradeTo(address newImplementation) external virtual override {}
}

So this vault contract is a proxy contract I assume, and the implementation pass to upgradeTo() do not need to be upgradeable? Do I need to make all subsequent implementation upgrade as UUPS contract as well?

No, your Vault contract by itself is not a proxy contract. This is the "implementation" contract. You would need to deploy an ERC1967Proxy and set its implementation to your Vault contract.

The implementation passed to upgradeTo needs to be "upgradeable" in the sense of using @openzeppelin/contracts-upgradeable, and it needs to inherit UUPSUpgradeable as well.

1 Like

Could I have multiple proxy with the same interface then? If i need to upgrade, all the vault will point to that new implementation but each proxy would have is own state? Or should i look into the beacon for that?

What do you mean by "interface"? If you want to upgrade all vaults simultaneously, you should use Beacon proxies. If you want the vaults to be upgraded independently, use either transparent or UUPS proxies.