You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Our use of UUPS proxies allows for significant runtime gas cost savings vs transparent proxies. What enables this performance enhancement is the fact that UUPS proxies hold the admin upgradeability code (upgradeTo) in the implementation instead of in the proxy. This allows the proxy to not have a Solidity dispatcher or "function hub" that needs to check if the call is an admin call or something to be forwarded to the implementation.
However, the danger of having upgradeTo in the implementation instead of in the proxy, is that a proxy could be upgraded to a "sterile" implementation that no longer has upgradeTo (or more precisely that cannot write into the address storage slot that the proxy forwards calls to). I.e. the proxy could be "bricked" in an upgrade.
This can also be tested manually by deploying an instance of one of our packages (E.g. spartan-council), and then re-deploying without the UpgradeModule.
The gist of the technique is to simulate an upgrade back to the old implementation whenever a new implementation is proposed. The simulation always reverts in a second EVM thread, so there are no side effects. The main EVM execution thread doesn't revert, but overlooks the second thread, using it to determine the "sterility" of the incoming implementation.
When we developed the technique, we looked into OpenZeppelin's anti-bricking implementation, but didn't like it because it had side effects (and was also vulnerable to an attacker being able to destroy the implementation code and hence brick the proxy). Maybe OZ has changed this. We would need to check.
The text was updated successfully, but these errors were encountered:
Our use of UUPS proxies allows for significant runtime gas cost savings vs transparent proxies. What enables this performance enhancement is the fact that UUPS proxies hold the admin upgradeability code (
upgradeTo
) in the implementation instead of in the proxy. This allows the proxy to not have a Solidity dispatcher or "function hub" that needs to check if the call is an admin call or something to be forwarded to the implementation.However, the danger of having
upgradeTo
in the implementation instead of in the proxy, is that a proxy could be upgraded to a "sterile" implementation that no longer hasupgradeTo
(or more precisely that cannot write into the address storage slot that the proxy forwards calls to). I.e. the proxy could be "bricked" in an upgrade.To ensure that this doesn't happen, we've come up with an anti-bricking mechanism that can be found here:
https://github.com/Synthetixio/synthetix-v3/blob/main/packages/core-contracts/contracts/proxy/UUPSImplementation.sol#L31-L33
And is tested here:
https://github.com/Synthetixio/synthetix-v3/blob/main/packages/core-contracts/test/contracts/proxy/UUPSProxy.test.js
This can also be tested manually by deploying an instance of one of our packages (E.g.
spartan-council
), and then re-deploying without the UpgradeModule.The gist of the technique is to simulate an upgrade back to the old implementation whenever a new implementation is proposed. The simulation always reverts in a second EVM thread, so there are no side effects. The main EVM execution thread doesn't revert, but overlooks the second thread, using it to determine the "sterility" of the incoming implementation.
When we developed the technique, we looked into OpenZeppelin's anti-bricking implementation, but didn't like it because it had side effects (and was also vulnerable to an attacker being able to destroy the implementation code and hence brick the proxy). Maybe OZ has changed this. We would need to check.
The text was updated successfully, but these errors were encountered: