I am currently relearning Solidity to solidify some of the details and create a "WTF Solidity Crash Course" for beginners (advanced programmers may want to find another tutorial). I will update 1-3 lessons weekly.
Twitter: @0xAA_Science
Community: Discord|WeChat Group|Official website wtf.academy
All code and tutorials are open source on Github: github.com/AmazingAng/WTF-Solidity
In this lesson, we will introduce another solution to the selector clash problem in proxy contracts: the Universal Upgradeable Proxy Standard (UUPS). The teaching code is simplified from UUPSUpgradeable provided by OpenZeppelin and should NOT BE USED IN PRODUCTION.
UUPS
In the previous lesson, we learned about "selector clash", which refers to the presence of two functions with the same selector in a contract, which can cause serious consequences. As an alternative to transparent proxies, UUPS can also solve this problem.
UUPS (Universal Upgradeable Proxy Standard) puts the upgrade function in the logic contract. This way, if there is a "selector clash" between the upgrade function and other functions, an error will occur during compilation.
The following table summarizes the differences between regular upgradeable contracts, transparent proxies, and UUPS:

UUPS contract
First, let's review WTF Solidity Minimalist Tutorial Lesson 23: Delegatecall. If user A delegatecalls contract C (logic contract) through contract B (proxy contract), the context is still the context of contract B, and msg.sender is still user A rather than contract B. Therefore, the UUPS contract can place the upgrade function in the logical contract and check whether the caller is an admin.

UUPS proxy contract
The UUPS proxy contract looks like an un-upgradable proxy contract and is very simple because the upgrade function is placed in the logic contract. It contains three variables:
implementation: address of the logic contract.admin: address of the admin.words: a string that can be changed by functions in the logic contract.
It contains 2 functions:
- Constructor: initializes the admin and logic contract address.
fallback(): a callback function that delegates the call to the logic contract.
UUPS Logic Contract
The UUPS logic contract is different from the one in Lesson 47 in that it includes an upgrade function. The UUPS logic contract contains 3 state variables to be consistent with the proxy contract and prevent slot conflicts. It includes 2 functions:
upgrade(): an upgrade function that changes the logic contract addressimplementation, which can only be called by theadmin.foo(): The old UUPS logic contract will change the value ofwordsto"old", and the new one will change it to"new".
Implementation with Remix
- Deploy the upgradeable implementation contracts
UUPS1andUUPS2.

- Deploy the upgradeable proxy contract
UUPSProxyand point theimplementationaddress to the old logic contractUUPS1.

- Use the selector
0xc2985578to call thefoo()function in the proxy contract, which will delegate the call to the old logic contractUUPS1and change the value ofwordsto"old".

- Use an online ABI encoder, like HashEx, to get the binary encoding and call the upgrade function
upgrade(), which will change theimplementationaddress to the new logic contractUUPS2.


- Using the selector
0xc2985578, call thefoo()function of the new logic contractUUPS2in the proxy contract, and change the value ofwordsto"new".

Summary: In this lesson, we introduced another solution to the "selector clash" in proxy contracts: UUPS. Unlike transparent proxies, UUPS places upgrade functions in the logic contract, making "selector clash" unable to pass compilation. Compared to transparent proxies, UUPS is more gas-efficient but also more complex.