Unable to get Deterministic Address for Factory Contract Across Networks using deployProxy method
Trying to deploy a factory contract using hardhat and openzeppelin defenders to have the same address across different networks when using the same salt.
The issue arises because the factory is deployed using deployProxy function, creating a TransparentUpgradeableProxy, which does not result in a deterministic address across networks. This causes inconsistencies in the deployment addresses.
Attempts Made
- Deploying the factory as a UUPS proxy instead of a
TransparentUpgradeableProxy, but this resulted in an error because the contract does not inherit fromUUPSUpgradeable. - Deploying the factory using
deployContract, but this assumes the contract is non-upgradeable, which is not the case and throws an error. - Deploying the factory using
deployProxy, which always results in aTransparentUpgradeableProxy, leading to non-deterministic addresses across networks.
Constraints
- I cannot modify the contract code.
- I can modify the deployment script.
Expected Behavior
The factory contract should have the same address across different networks when using the same salt.
Actual Behavior
The factory contract address changes across different networks due to the TransparentUpgradeableProxy deployment process.
Steps to Reproduce
- Deploy the factory contract using
deployProxyon different networks using the same salt. - Observe that the resulting address for the
TransparentUpgradeableProxyis different on each network.
Possible Solutions / Help Needed
- Is there a way to deploy the factory deterministically while still keeping it upgradeable?
- Can
deployProxybe configured to produce deterministic addresses across networks? If that's something that is possible now, am I missing some configuration? - Is there another deployment method that ensures both upgradeability and deterministic addresses?
Any insights or suggestions would be appreciated!
- Ensure you have configured your Hardhat project to use OpenZeppelin Defender according to https://docs.openzeppelin.com/upgrades-plugins/defender-deploy. This includes setting your Defender API key and secret in the Hardhat config file, and enabling
useDefenderDeploy: truein the Hardhat config or by usingdefender.deployProxyin your script. - Ensure you use the same arguments (constructor and/or initializer arguments) on each network when deploying your proxy, since the deterministic deployment address also depends on those arguments.
- The proxy address also depends on the implementation address, because the implementation address is one of the arguments for the proxy's constructor.
- If you find that a previous deployment of the implementation contract is being used, try including the
redeployImplementation: "always"option in addition to the salt when callingdeployProxy. This will ensure the implementation contract gets redeployed with the same salt as the proxy. See docs.
- If you find that a previous deployment of the implementation contract is being used, try including the
Hi @ericglau, thanks for your quick response!
Including redeployImplementation: "always" ensures that the factory contract is deployed with the same address across different networks. However, the TransparentUpgradeableProxy is still being deployed with different addresses on each network.
Is there any way to make the TransparentUpgradeableProxy have the same address across different networks as well?
TransparentUpgradeableProxy should also have the same address if you deploy it using the same salt and arguments.
Specifically, its constructor parameters are constructor(address _logic, address initialOwner, bytes memory _data), meaning the implementation address, initial owner address, and initializer call data must be the same.
You can use the initialOwner option to specify a specific initial owner address when calling deployProxy