UUPS Proxies: Tutorial (Solidity + JavaScript)

@nonseodion Have you see the section about proxies in our verification guide?

There are instructions.

Thanks for the help I just saw it, I am having an issue with the ABI encoded arguments for the constructor. Cronoscan says " Error! Invalid constructor arguments provided. Please verify that they are in ABI-encoded format"

One thing that's really confusing is where the ERC1967 admin is used in all of this. Is the idea that it can optionally be used in _authorizeUpgrade? Seems like there's no benefit to binding this storage space to the proxy itself, though.

ERC1967 admin is not used in the UUPS pattern. It could be used but it's not needed in the same way as for Transparent Proxies.

Hello,
how deploy manually an uups contract ? in my case I use an EVM chain (Hydra) incompatible with Hardhat, and I think I can't call constructor with argurments.

1 Like

Is initialize() is only meant to be called once for the entire proxy's lifecycle? If new variables are introduced in a new upgraded implementation, what is the right pattern for initializing them?

1 Like

Call initialize on the new logic contract.
You can call initialize once by contract, so you can't call it anymore on the proxy contract, but you can call it once on new logic contract deployed

What do you mean? The initialize would be called through the proxy if an upgrade happens.

You can pass data on upgrade to call your logic contract with initialize info

@youtpout You need to deploy the implementation contract and then an instance of ERC1967Proxy

@leeren It's a good question. For testing you will probably want to have an initialize() function where you initialize all available variables. But for upgrading you will need a new method, something like initializeV2 where you only initialize the new things.

1 Like

Thanks, that clears it all up.

Hello I resolve my problem, it's just because I didn't reattach my proxy to my market contract in hardhat, so hardhat didn't recognize the method called.

Great tutorial! In your example, what is the significance of adding the initializer modifier to the constructor function?

@frangio Also another follow up question. If I understand this correctly, functions of the proxy itself (not the implementation contract) can only be called by ProxyAdmin. How can we get the ProxyAdmin object? I have only seen docs on using the Upgrade Plugin (i.e. the upgradeProxy function) to update a proxy's implementation.

Edit: nvm I think Error: No ProxyAdmin was found in the network manifest - #2 by ericglau answered my question. For those who might have the same question: for uups standard, there is no ProxyAdmin, and the deployer of the proxy can directly call those proxy admin functions (e.g. updating implementations)

1 Like

The initializer modifier in the constructor makes sure that the real initializer function can't be invoked on the implementation contract directly. In some cases, if the implementation can be initialized, that can be used as part of an exploit.

1 Like

Is there a part 2 to this article showing deployment, V2 and the upgrade?

There is no part 2 but feel free to create a new post and ask a question.

A post was split to a new topic: Use Chainlink AggregatorV3Interface with UUPSUpgradeable

Strangely I'm getting an error when attempting to deploy the proxy for a UUPS contract:

@openzeppelin/contracts/utils/Address.sol:191: Use of delegatecall is not allowed

I'm pretty sure the offending use is coming from UUPSUpgradeable itself... which the contract inherits from. I've made sure to specify kind: 'uups' in the deploy args as follows, hope this is correct (using typescript):

await upgrades.deployProxy(MyContractFactory, [args.name, args.symbol], {initializer: 'initialize', kind: 'uups'}) as MyContract

It works fine if I remove UUPSUpgradeable and deploy the transparent (default) type.

Any thoughts?