Software development tailored to your needs!
Rumble Fish helps entrepreneurs build and launch bespoke digital products.
We take care of the technology, so you can focus on your business
Hi there! We're Rumble Fish - a team of world-class experts in bespoke software development. Our engineers are highly skilled in blockchain, cloud solutions, and defi/fintech development. Our strength and pride is the ability to take ownership of the entire development process and be a true partner and advisor for our customers. Our mission is to craft state-of-the-art digital products using battle-tested technologies. Try us!
The blockchain industry thrives on trustlessness, decentralization, and immutability. These principles are the cornerstones of its rapid growth in recent years. However, like any innovative field, blockchain technology is not without its challenges. One major challenge is the immutability of smart contracts—once deployed, they cannot be changed. But what if a smart contract contains a vulnerability that could lead to funds being lost, or if you simply want to enhance its functionality or optimize gas usage? In this article, I’ll explain the concept of Non-Proxy Upgradeability Pattern.
Trustlessness, decentralization, security. Immutability. The beauty of the blockchain. This is why this cutting-edge technology has been growing so rapidly for the last couple of years and surely there are still a lot of new ideas and concepts waiting to be discovered. But there’s no innovation without mistakes and as always new technologies can suffer from infancy problems. For sure those problems should be solved, but how can they be solved once the code is already deployed and can’t be changed (immutability, right?)? Aren’t smart contracts (self-executing programs) immutable by design? And shouldn’t they be as simple as possible? Yeah, but what if the contract is vulnerable and can lead to funds lost? Shouldn’t a bug be fixed? Or what if we simply want to improve functionality or optimize gas usage?
Welcome to the Blockchain.
So many questions, so few answers? Not really! Fortunately, some Big Brains were also thinking about the Upgradeability Dilemma, and some solutions have already been found and developed. I’m not gonna present and explain all of them, but for context let’s take a look at two: the Proxy Patterns and the Clones.
In this approach, a smart contract acts as a proxy (storage layer) that delegates all calls to another contract with the logic implementation (logic layer). The address of the logic implementation can be changed, enabling upgradability. The typical structure looks like this:
In this method, each instance of the clone contact has an identical bytecode, so only one instance of the implementation (logic layer) needs to be deployed and all clone instances behave as proxies. This approach, often referred to as the "minimal proxy," is defined in the EIP-1167 standard.
Although the Clone Factory Pattern aims to clone contract functionality simply and cost-effectively, it can still raise questions about its "purity" since it relies on a "proxy" pattern.
Hold on, but what’s wrong with that? I assume you know what the gas is and why we need it on the Ethereum blockchain. Notably, the .transfer() and .send() functions, used for ETH transfers, come with a fixed 2300 gas stipend, which is non-adjustable. Furthermore, the delegatecall function, fundamental to proxy patterns, incurs a gas cost of 21,000 (as msg calls in the EVM have an inherent base fee of 21,000 gas, and for proxy cases, delegatecall is treated as a transaction). As a result, if the wallet uses .send() function to send the ETH to the Proxy it is not gonna work!
Alright, so what can we do about this? Ladies and gentlemen, let me introduce the Non-Proxy Upgradeability Pattern! This approach enables you to deploy a contract to a specific address and later, if necessary, replace its logic while preserving the contract's state and balance. Here's how it works in a few simple steps:
You need a factory that deploys contracts. This factory must have a fixed address, which can be achieved through deterministic deployment, e.g. via Hardhat extensions.
The Factory has a method that deploys static bytecode which is “clone-contract constructor” (CCC). This constructor once deployed asks the deployer (msg.sender) about initial parameters via STATICCALL. To deploy the clone the CREATE2 method is used, which means the address depends only on:
the deployer address - and this is a fixed factory address
a random salt
That means the address of the cloned contract depends only on the salt.
The CCC uses EXTCODECOPY to load the contract logic code to the memory and finishes the entire process with RETURN, which points to the freshly cloned code.
Call from the Factory contract Init() function to use the calldata (which was passed with STATICCALL from step 2) and initialize the contract-clone.
Magic! The code was cloned without a proxy pattern!
Alright, so how can we upgrade the contract code if we don’t have a proxy? To achieve this we need two separate transactions because the contract's balance (as a result of the SELFDESTRUCT) is sent at the end of tx. So here it is:
Clone-contract uses the SELFDESTRUCT opcode to clear all the contract data and sends the factory address as the contract's balance receiver.
The factory finishes the upgrade by calling the finalizeUpgrade() function, which copies the new contract implementation the same way as it was done at the creation step 1 and sends all the native coin amounts received in the previous step.
And that’s it!
If you want to learn more, let me show you some code behind the magic explained above.
call templateAddress() on msg.sender and store it under storage slot 0x1234
{{codeSnippet,OPCODES}}
copy contract's code to memory
{{codeSnippet,memory}}
return and point to the copied code
{{codeSnippet,return}}
In Solidity it can be implemented like this:
{{codeSnippet,solidity}}
The Non-Proxy Upgradeability Pattern offers an alternative path to upgrade smart contracts without relying on a proxy pattern. By addressing gas costs and enabling deterministic deployments, it opens up new possibilities for blockchain developers to enhance contract functionality and security. This approach exemplifies the ever-evolving nature of blockchain technology, where challenges lead to innovative solutions.
I really hope this blog post will help those of you struggling with creating upgradeable contracts. If you have any questions or would like to discuss the methodology - drop us a line at hello@rumblefish.dev. In the meantime, stay tuned for more coding stories!
Once again we’ve partnered with the Swiss-Polish Blockchain Association to co-organize their annual Beyond Blockchain symposium. The event, this time happening in Warsaw, will take place on September 4th, 2023. The focus of this edition is the role of blockchain and AI in finance, the luxury goods market, and sports and entertainment. Rumble Fish is an official partner of the event.
Swiss-Polish Blockchain Association, which we are a member of, is known for the high quality of its conferences. The key to success lies in the exquisite lineup of speakers, thought-provoking panel discussions, and excellent networking.
This year, the emphasis is put on blockchain and AI and its impact on finance, luxury goods, and sports and entertainment. Attendees can also count on lots of regulatory discussions which are always in high demand as we’re facing a big change in lawmakers' attitudes towards crypto and Web3. With 4 discussion panels packed with industry experts and professionals, Beyond Blockchain Annual Symposium is a must-attend event for all blockchain enthusiasts.
Rumble Fish will be proudly represented by our co-founder and CTO, Marek Kowalski, and Head of Growth, Sylwia Bień-Chudarek. Sylwia and Marek will be making an introduction for one of the discussion panels, which Marek will be also joining afterward. The title of the panel is Beyond the Hype: Blockchain and Digital Technology's Game-Changing Role in Sports and Entertainment. Marek will be joined by industry experts: Bartosz Błach (Fortuna 1 Liga), Mariusz Gąsiewski (Google), Artur Pszczółkowski (GG3), Monika Górska (Wardyński & Partners), and Paweł Łaskarzewski (Nomad Fulcrum).
See you in Warsaw!
The tickets are still available here.
Full info on the event, including the details agenda is available here.
We are a proud member of:Together with our partners we're working to create a networking space for blockchain enthusiasts and share our knowledge and experience in building blockchain-based solutions.