In the proxy pattern, we have two smart contracts: proxy contract and implementation contract.
The proxy contract acts as a proxy, delegating all calls to the contract it is the proxy for. In this context, it will also be referred to as the Storage Layer. The implementation contract is the contract that you want to upgrade or patch. This is the contract that the Proxy contract will be acting as a proxy for. In this context, it is the Logic Layer.
The Proxy contract stores the address of the implementation contract or logic layer, as a state variable. Unlike normal contracts, the user doesn't actually send calls directly to the logic layer - which is your original contract. Instead, all calls go through the proxy and this proxy delegates the calls to this logic layer - the implementation contract at the address that the proxy has stored, returning any data it received from the logic layer to the caller or reverting for errors.
The key thing to note here is that the proxy calls the logic contract through delegatecall function. Therefore, it is the proxy contract which actually stores state variables i.e. it is the storage layer. It is like you only borrow the logic from the implementation contract (logic layer!) and execute it in the proxy's context affecting the proxy's state variables in storage.
Openzeppelin provides a library to create an upgradeable proxy pattern called TransparentUpgradeableProxy.
When you deploy, the package behind the scene creates a ProxyAdmin and a TransparentUpgradeableProxy as well. In the Hardhat configuration, you just need to verify the TransparentUpgradeableProxy. The hardhat utility will also verify the ProxyAdmin and the logic smart contract, Box. Unfortunately, in the Truffle configuration, we can’t do this. We can only verify the logic smart contract.
Creating the proxy and proxy admin explicitly
We can create the proxy and proxy admin explicitly by inheriting TransparentUpgradeableProxy in @openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol and ProxyAdmin in @openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol.
Below are two samples of creating the proxy and proxy admin explicitly.