Upgradeable Contracts
Why Use Upgradeable Smart Contracts?
When developing smart contracts, upgrades are sometimes necessary. Once deployed, a smart contract is immutable, meaning it can’t be changed directly. If there’s a bug or you want to add new features, redeploying the entire contract is impractical because:
User data: Redeplying would erase all data stored in the contract.
User experience: Users would need to switch to the new contract address, which can be confusing.
Gas efficiency: Redeploying can be costly for both developers and users.
Instead, upgradeable smart contracts separate storage (user data) from logic (contract functions). When you want to upgrade, you just switch out the logic, while keeping the storage the same. This is done through proxy patterns.
What is a Proxy Pattern?
In a proxy pattern, we have:
Proxy Contract: The contract that users interact with. This contract holds the user’s data and “delegates” or “forwards” calls to the logic contract.
Implementation Contract: Also known as the “logic” or “upgrade” contract. This is where the business logic lives, and it can be changed without affecting user data.
Admin Account: For upgradeable contracts, an admin account (often the contract owner) controls upgrades. Only the admin can change the logic contract address to a new one.
When users interact with a function, the proxy forwards their requests to the implementation (logic) contract, allowing the contract to be upgraded without affecting the data or address users interact with.
The Two Main Upgradeable Patterns: Transparent Proxy and UUPS Proxy
Now that we know the basics of proxy patterns, let’s dive into the two main patterns: Transparent Proxy and UUPS Proxy.
1. Transparent Proxy Pattern
The Transparent Proxy Pattern is one of the original patterns used for upgradeable contracts. It’s simple but reliable and widely adopted.
How Transparent Proxy Works
User and Admin Access Separation:
Users: Regular users send their function calls through the proxy, which forwards them to the logic contract. Users don’t need to worry about how the forwarding works; they interact with the proxy as if it were the logic contract.
Admin: The admin account, often the contract’s owner, has special permissions. It’s the only account that can trigger upgrades by updating the address of the logic contract.
Storage Separation:
The proxy holds all user data, while the logic contract is stateless (doesn’t store data directly). When upgrading, the proxy simply points to a new logic contract address, and the stored data remains intact.
Implementation:
Only the admin can access upgrade functions, which means there’s a clear separation between users who interact with regular functions and the admin, who manages upgrades. This is enforced by adding checks in the proxy contract.
Advantages of Transparent Proxy
Security: Since only the admin can upgrade the contract, it’s easy to prevent unauthorized upgrades.
User Simplicity: Users only interact with the proxy and are unaware of the underlying logic changes.
Disadvantages of Transparent Proxy
Higher Gas Costs: The extra checks (for user vs. admin access) make it slightly more expensive in gas compared to other methods.
Complexity in Design: The proxy contract has to manage both user interactions and admin upgrade logic, adding complexity.
2. UUPS (Universal Upgradeable Proxy Standard) Proxy Pattern
The UUPS Proxy Pattern is a more recent and gas-efficient approach, designed to simplify upgradeable contracts. Instead of having the proxy manage upgrade logic, the implementation (logic) contract itself manages its upgrades.
How UUPS Proxy Works
Proxy Contract:
The proxy contract only stores data. It forwards function calls to the logic contract but doesn’t include any upgrade logic.
Implementation Contract with Upgrade Logic:
The logic contract includes the upgrade functions, specifically
_authorizeUpgrade
, which allows only authorized users to change the implementation address.This function is usually restricted to an admin account, so only the admin can authorize upgrades.
When an upgrade is needed, the proxy points to a new version of the logic contract by calling
upgradeTo
in the current implementation contract.
Reduced Gas Costs:
By keeping upgrade logic in the implementation rather than the proxy, UUPS saves on gas costs by simplifying the proxy.
Advantages of UUPS Proxy
Lower Gas Usage: UUPS is more efficient because it doesn’t include upgrade functions in the proxy, which reduces costs.
Flexible Design: All upgrade logic is in the logic contract, meaning that only one function
_authorizeUpgrade
manages upgrades.
Disadvantages of UUPS Proxy
Security Concerns: Because the upgrade function is in the logic contract, the function must be secured carefully to prevent unauthorized upgrades.
Newer Approach: Since UUPS is more recent, it may not be as widely understood, which could lead to issues if misused.
Comparison of Transparent Proxy vs. UUPS Proxy
Where Upgrade Logic Is
Proxy Contract
Implementation Contract
Admin/User Separation
Yes, enforced by proxy
Handled in _authorizeUpgrade
function
Gas Costs
Higher due to additional checks
Lower, since upgrade logic is in logic contract
Complexity
More complex due to proxy role
Simpler proxy; logic contract manages upgrades
Adoption
Widely adopted
Gaining popularity, supported by OpenZeppelin
Security Model
Clear admin/user distinction
Requires careful authorization handling
When to Use Each Pattern
Use Transparent Proxy if: Security and access separation are a priority, or you’re comfortable with a slightly more complex proxy design.
Use UUPS Proxy if: You need a gas-efficient solution, are working with the latest standards, and have a trusted admin setup for managing upgrades.
Both the Transparent Proxy and UUPS Proxy patterns are valuable for creating upgradeable contracts. Understanding the differences helps to choose the best pattern for the project’s security, cost, and complexity needs.
Last updated