Writing Upgradable Smart Contracts: Proxies Explained
Smart contracts are immutable, so how do you fix bugs or add new features? This guide explains the Transparent Proxy Pattern, the industry standard for.
One of the core properties of a smart contract is immutability. Once deployed to the blockchain, its code cannot be changed. This is a powerful feature for security and trust, but it presents a major challenge: What do you do if you find a bug, or if you want to add a new feature?
Deploying a completely new contract and migrating all the data and users is a complex and expensive process. The solution to this problem is to use an upgradability pattern. The most common and battle-tested method is the Transparent Proxy Pattern.
This guide will explain how this pattern works and how you can use it to build flexible and maintainable smart contracts.
The Core Idea: Separating State and Logic
The proxy pattern works by splitting your application into two separate contracts:
-
The Proxy Contract: This is the contract that users interact with. It holds all of the state (the data and user balances) for your application. Crucially, it contains very little logic. Its only real job is to forward all function calls to another contract. The address of this proxy contract never changes.
-
The Implementation Contract (or Logic Contract): This contract contains all of the actual business logic for your application. It is stateless and simply executes the functions that are forwarded to it by the proxy.
How it Works: delegatecall
The magic that connects these two contracts is a special EVM opcode called delegatecall.
When the Proxy contract receives a function call (e.g., deposit()), it doesn't execute the function itself. Instead, it uses delegatecall to pass the function call on to the current Implementation contract.
delegatecall is special: It executes the code of the Implementation contract, but it does so in the context of the Proxy contract's state. This means the Implementation contract can read and write to the Proxy's storage as if it were its own.
The Proxy contract has a state variable that stores the address of the current Implementation contract. This address can be updated by the owner of the proxy.
How to Perform an Upgrade
The upgrade process is simple but powerful:
-
Deploy a New Implementation: You find a bug or want to add a feature, so you write a new version of your logic contract (
ImplementationV2.sol). You deploy this new contract to the blockchain, and it gets a new address. -
Update the Proxy: As the owner of the Proxy contract, you call a special administrative function on the Proxy (e.g.,
upgradeTo(newImplementationAddress)). -
The Change Takes Effect: The Proxy contract updates its state to point to the address of
ImplementationV2.sol.
That's it. The upgrade is complete. Users continue to interact with the same, unchanged Proxy address, but all their calls are now being delegated to the new logic contract. All the application's state, which is stored in the Proxy, is preserved.
Using OpenZeppelin for Upgradable Contracts
You should never try to write your own proxy contracts from scratch. It is a complex and high-risk task. The industry standard is to use the OpenZeppelin Upgrades Plugins.
- @openzeppelin/hardhat-upgrades
- @openzeppelin/foundry-upgrades
A typical workflow with Hardhat:
-
Write your V1 contract: Write your initial
MyContract.solas you normally would, but initialize state variables in aninitializerfunction instead of aconstructor. -
Deploy as upgradable: Instead of a normal deployment script, you use the OpenZeppelin plugin:
const MyContract = await ethers.getContractFactory("MyContract"); const instance = await upgrades.deployProxy(MyContract, [arg1, arg2]); await instance.waitForDeployment();The plugin will automatically deploy your implementation contract, deploy a proxy contract, and link them together.
-
Upgrade: When you're ready to upgrade, you write
MyContractV2.soland run:const MyContractV2 = await ethers.getContractFactory("MyContractV2"); const upgraded = await upgrades.upgradeProxy(instance.address, MyContractV2);The plugin handles deploying the new implementation and calling the
upgradeTofunction on the proxy.
Important Considerations and Risks
- Storage Collisions: When writing a new version of your implementation contract, you must be extremely careful not to change the order or type of the existing state variables. Doing so can lead to "storage collisions" where your contract's state becomes corrupted. The OpenZeppelin plugins have tools to help detect this.
- Centralization: The ability to upgrade a contract introduces a new trust assumption. Users must trust that the owner of the proxy (usually the development team or a multisig) will not upgrade the contract to a malicious version. For mature protocols, it is common to transfer ownership of the proxy to a community-governed DAO or to a timelock contract to decentralize this power.
Upgradability is a powerful tool that allows projects to evolve and adapt over time. By using standard, battle-tested solutions like the OpenZeppelin Upgrades Plugins, developers can build robust dApps that are both secure and future-proof.
Why This Matters
Understanding this concept is crucial for your professional success. In today's dynamic workplace environment, professionals who master this skill stand out, earn higher salaries, and advance faster. This is especially true in Web3 organizations where communication and collaboration are paramount.
Step-by-Step Guide
Step 1: Understand the Fundamentals
Begin by grasping the core principles. This foundation will inform everything else you do in this area. Take time to read about best practices from industry leaders and thought leaders.
Step 2: Assess Your Current Situation
Evaluate where you stand today. Are you strong in some aspects and weak in others? What specific challenges are you facing? Understanding your baseline is critical.
Step 3: Develop Your Personal Strategy
Create a plan tailored to your situation. Everyone's circumstances are different, so your approach should be customized. Consider your role, team dynamics, organization culture, and personal goals.
Step 4: Implement Gradually
Don't try to change everything at once. Start with one small change and build from there. Track what works and what doesn't. This iterative approach leads to sustainable improvement.
Step 5: Measure and Adjust
Monitor your progress. Are you seeing results? Adjust your approach based on feedback and outcomes. This continuous improvement mindset is essential.
Real-World Examples
Example 1
Consider Sarah, a developer at a blockchain startup. She struggled with {topic} until she implemented these strategies. Within 3 months, she saw dramatic improvements in her {relevant metric}.
Example 2
Juan, a product manager in DeFi, faced similar challenges. By following this framework, he was able to {achieve outcome}. His experience demonstrates how universal these principles are.
Example 3
Maya, transitioning from Web2 to Web3, used this approach to quickly adapt. Her success shows that this works regardless of your background or experience level.
Common Mistakes to Avoid
-
Rushing the Process - Don't expect overnight results. Sustainable change takes time.
-
Ignoring Feedback - Your colleagues, managers, and mentors see things you might miss. Listen to their input.
-
One-Size-Fits-All Approach - What works for someone else might not work for you. Adapt these strategies to your context.
-
Giving Up Too Soon - Change is uncomfortable. Push through the initial discomfort to reach better outcomes.
-
Not Tracking Progress - You can't improve what you don't measure. Keep metrics on your progress.
FAQ
Q: How long will this take to implement? A: Most people see initial results within 2-4 weeks, with significant improvements visible within 8-12 weeks. The timeline depends on your starting point and how consistently you apply these strategies.
Q: What if my workplace environment doesn't support this? A: Even in challenging environments, you have more agency than you might think. Start with small actions and build momentum. If the environment truly prevents progress, it might be time to consider other opportunities.
Q: How does this apply specifically to Web3? A: Web3 organizations often have flatter hierarchies, more remote teams, and faster pace than traditional companies. This makes these skills even more critical for success.
Q: Can I implement this alongside my current role? A: Absolutely. You don't need extra time-just intentionality in your current work. Integrate these practices into your daily activities.
Q: What resources can help me go deeper? A: Check the related articles section below for deeper dives into specific aspects. Also consider finding a mentor who excels in this area.

