Programmatically deploying upgradeable proxies

Hi
I am currently deploying minimal (non upgradeable) proxies using ProxyFactory.

I want to make these upgradeable and therefore want to shift from using ProxyFactory to deploying upgradeable proxies using OZ upgrades. However, I see only usage from truffle migrations. Is there any way (and is it advisable) to deploy upgradeable proxies programmatically from a solidity contract ? I want to ideally replace the deployminimal() with a deployproxy(). Reason I want to do this programmatically is because the application needs to create multiple proxies at run time, all of which point to a single implementation contract.

Any advice will be greatly appreciated !

:computer: Environment
Truffle

1 Like

Hi
I followed this link Creating upgradeable contracts from Solidity, is it mandatory to use App.sol? - SDK - OpenZeppelin Community in the forum and could deploy the upgradeable proxies using ProxyFactory - I am deploying 3 proxies all pointing to the same implementation contract. I am not sure how to upgrade them - do I call deploy() again in ProxyFactory with the same data parameters but with a new implementation address ? Will that retain the data in the current proxies deployed before the upgrade ?

I am also facing another issue after deploying upgradeable proxies using ProxyFactory. My tests are failing with a Error: Returned error: VM Exception while processing transaction: revert Cannot call fallback function from the proxy admin

It is coming from this line which was working fine with minimal proxies earlier.
console.log("Account Via-USD cash token balance before sending ether:", await web3.utils.hexToNumberString(await web3.utils.toHex(await viausdCash.balanceOf(accounts[0]))));

Any feedback will be much appreciated.

1 Like

Hi @kallolborah,

Welcome to the community :wave:.

You can deploy upgradeable contracts from Solidity. The proxy contracts are included in OpenZeppelin Contracts: https://docs.openzeppelin.com/contracts/3.x/api/proxy

I recommend using OpenZeppelin Upgrades Plugins where you can so you don't have to deal with the proxies yourself, though at the very least I recommend using Upgrades Plugins for high level testing so that you can check that your implementation contracts are upgrade safe.

There is a closed PR that you could look at as an example of creating upgradeable contracts programmatically from a factory: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2371

You would need to deploy the new implementation contract, and then for each proxy call upgradeTo from the admin of the proxy.

It sounds like you are trying to call a function on your upgradeable contract from the admin of the proxy which then reverts. See: https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#transparent-proxies-and-function-clashes

With minimal proxies, there isn't an admin from the proxy, which is why you didn't run into this issue.

@abcoathup thank you, Andrew !

Proxy deployments are working. However, when we try to upgrade proxies using the upgrades plugin, we get Error: Deployment at address 0x1FFF0Bc2821633720E9E800C8B357Ecf023a01E5 is not registered and Error: Proxy admin is not the one registered in the network manifest in the prepare upgrade stage.

Is it therefore advisable to use a separate upgrade script in migrations or is there some workaround this ?

1 Like

Hi @kallolborah,

This error means that a previous implementation contract isn't in your <network_name>.json file in the .openzeppelin directory.

I recommend adding your public <network_name>.json files to version control: https://docs.openzeppelin.com/upgrades-plugins/1.x/network-files#configuration-files-in-version-control

This is used to check the upgrade safety of your contract when you prepare the upgrade.

I recommend creating higher level tests to test the upgrade from one version to another to check for upgrade safety.

I assume this is that the Proxy admin in the <network_name>.json file doesn't match the admin that was used to deploy the contract.


What network are you deploying to?
Can you share the command you used to migrate and the full error?
Are you doing a dry run?

This error means that a previous implementation contract isn’t in your <network_name>.json file in the .openzeppelin directory.

Is this only created when using deployProxy ? We are basically using the proxy factory posted here, and unless I'm misunderstanding something it's not possible to be able to deploy this kind of proxy factory using the deployProxy command from the upgrades plugin.

As such we're using the same proxies that would be created by deployProxy, except wrapping them in the proxy factory linked earlier to allow us to create new proxy instance at runtime. The issue is coming from tests attempting to use prepareUpgrade when upgrading the implementation. This is where the issue is coming from

What network are you deploying to?

Deploying to rinkeby, running tests against ganache.

Can you share the command you used to migrate and the full error?

The Deployment at address 0x1FFF0Bc2821633720E9E800C8B357Ecf023a01E5 is not registered error is being given from test runs doing truffle test --stacktrace --debug --show-events. I think the issue is stemming from us not being able to use deployProxy in combination with the proxy factory mentioned earlier.

1 Like

I also have another question with regards to the network file. Take the following example snippet

  "impls": {
    "aaa148c474cd10e1a6cd0a52c0b55f1aa9b7bb7b42d7f1cb5acaea4f42f04bc8": {
      "address": "0x68754933D337c201a7d2cf2B657c9587d2d7cc3D",
      "txHash": "0xcac4607818179d07e41ea4f610d7e446b360ac4daddbb189b424c2a0b6001b5b",
      "layout": {
        "storage": [],
        "types": {}
      }
    }
  },

What is aaa148c474cd10e1a6cd0a52c0b55f1aa9b7bb7b42d7f1cb5acaea4f42f04bc8? Is it a checksum of contract bytecode or something similar? I took a look at the network files documentation and it doesn’t indicate how this value is derived

Hi @bonedaddy and @kallolborah,

If you are deploying proxy contracts using a factory, then you won't currently be able to use Upgrades Plugins to do prepareUpgrade.

For some automated testing to test upgrade safety using a proxy, you could deploy your upgradeable contract using Upgrades Plugins deployProxy and then perform upgradeProxy in your test. See the testing example in OpenZeppelin Upgrades: Step by Step Tutorial for Truffle

For testing your deployment using the factory, you can't currently use Upgrades Plugins to prepare the upgrade, instead you would need to deploy the new implementation contract and then call the proxy to upgrade.

It is a hash of the contact creation code, see: https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/175

1 Like

If you are deploying proxy contracts using a factory, then you won’t currently be able to use Upgrades Plugins to do prepareUpgrade.

Would there be any way to get it to work, or is that just not possible?

For some automated testing to test upgrade safety using a proxy, you could deploy your upgradeable contract using Upgrades Plugins deployProxy and then perform upgradeProxy in your test. See the testing example in OpenZeppelin Upgrades: Step by Step Tutorial for Truffle
For testing your deployment using the factory, you can’t currently use Upgrades Plugins to prepare the upgrade, instead you would need to deploy the new implementation contract and then call the proxy to upgrade.

Good idea that appears to be the best route

1 Like

Hi @bonedaddy

It may be possible. See this open issue: https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/175

A post was split to a new topic: Object.getLinkedBytecode (node_modules/@openzeppelin/truffle-upgrades/src/validate.ts:150:46)

Hello @abcoathup
Is there any solution to upgrade without .openzeppelin folder?
By my mistake previous folder was deleted, and i am going to upgrade UUPS proxy now.

Could you tell me how can i do that?

Continuing the discussion from Programmatically deploying upgradeable proxies:

Hello you can restore .openzeppelin folder by running forceImport function.

const nft2ContractFactory = await hre.ethers.getContractFactory("Ryu");
nftContract = await upgrades.forceImport("0x2ca0507d72e3d30badea3d3b558103d192026251", nft2ContractFactory, {});
console.log(nftContract.address)

Running this script will generate <network_name>.json file in .openzepplin folder

1 Like